Delphi から LLM を呼び出す
VCL、FMX、コンソールのいずれのアプリケーションからでもプロンプトを送信し、OpenAI や Anthropic Claude のようなホスト型モデル、あるいは Ollama 経由で自分のマシン上で動くモデルから回答を受け取ります。このページは空のフォームから動作する呼び出しまでを案内し、続いてどのプロジェクトでも次にぶつかる 3 つの事柄、すなわちストリーミング、ツール呼び出し、そしてホスト型モデルとローカルモデルの選択を扱います。
VCL、FMX、コンソールのいずれのアプリケーションからでもプロンプトを送信し、OpenAI や Anthropic Claude のようなホスト型モデル、あるいは Ollama 経由で自分のマシン上で動くモデルから回答を受け取ります。このページは空のフォームから動作する呼び出しまでを案内し、続いてどのプロジェクトでも次にぶつかる 3 つの事柄、すなわちストリーミング、ツール呼び出し、そしてホスト型モデルとローカルモデルの選択を扱います。
プロバイダー非依存のチャットコンポーネントと、ベンダーごとの専用 REST クライアントがあります。どちらも同じライブラリに含まれているため、一方から始めて、プロジェクトを変えずにもう一方へ降りていくことができます。
Provider、API キー、モデルを設定し、Chat を呼び出します。コンポーネントがベンダー用の JSON を組み立て、会話履歴を保持し、アシスタントのテキストを返します。OpenAI から Claude へ、あるいはローカルの Ollama モデルへ切り替えるのは代入 1 行です。実装はユニット sgcAI_Chat の TsgcAI_Chat で、パレットには TsgcAIChat として登録されています。
TsgcHTTP_API_OpenAI、TsgcHTTP_API_Anthropic、TsgcHTTP_API_Ollama は各ベンダー API をすべて公開しており、中立レイヤーでは扱えない部分も含まれます。画像入力、ドキュメント入力、拡張思考、バッチ、ファイル、埋め込み、画像生成、文字起こしなどです。特定のエンドポイントが必要な場合はこちらを使います。
AI および LLM クライアントは sgcWebSockets の Enterprise 機能で、Standard にも Professional にも含まれません。単体パッケージの sgcAI を購入することもできます。
ここではプラットフォームが重要です。3 つの REST クライアントは Windows、macOS、Linux、iOS、Android でコンパイルできます。TsgcAIChat は違います。Windows 専用にコンパイルされているため、Linux のサービス、macOS 向けビルド、モバイル向けターゲットでは REST クライアントを直接呼び出します。このページのサンプルは、どちらの経路でも通用するように書かれています。
コンポーネントを配置し、キーとモデルを設定して、プロンプトを送ります。まず使うプロバイダーのタブを選んでください。最後のタブは API キーをまったく必要としません。モデルが自分のマシン上で動くからです。
uses
Classes, SysUtils,
// sgc
sgcAI_Chat;
procedure TfrmMain.btnAskClick(Sender: TObject);
var
oChat: TsgcAI_Chat;
begin
oChat := TsgcAI_Chat.Create(nil);
try
oChat.Provider := aicpOpenAI;
oChat.ChatOptions.ApiKey := GetApiKey;
oChat.ChatOptions.Model := 'gpt-4o-mini';
oChat.ChatOptions.MaxTokens := 1024;
oChat.SystemMessage := 'You are a concise assistant inside a Delphi ERP.';
memoAnswer.Lines.Text := oChat.Chat(memoPrompt.Lines.Text);
finally
oChat.Free;
end;
end;
ベンダーの変更は 1 行です。Provider は aicpOpenAI、aicpAnthropic、aicpGemini、aicpDeepSeek、aicpOllama、aicpGrok、aicpMistral を受け付けます。コード内のそれ以外はそのままです。
Windows 専用です。TsgcAI_Chat とそのパレットコンポーネント TsgcAIChat は Windows、Win32 と Win64 向けにコンパイルされています。macOS、Linux、iOS、Android ではユニット自体がコンパイルされないため、ターゲットが Linux のサービスやモバイルアプリの場合は、他の 3 つのタブにあるベンダー REST クライアントを使ってください。そちらにプラットフォームの制限はありません。
uses
Classes, SysUtils,
// sgc
sgcHTTP_API_OpenAI;
var
oOpenAI: TsgcHTTP_API_OpenAI;
begin
oOpenAI := TsgcHTTP_API_OpenAI.Create(nil);
try
oOpenAI.OpenAIOptions.ApiKey := GetApiKey;
// Shortcut: model plus one user message, raw JSON back
memoAnswer.Lines.Text := oOpenAI._CreateChatCompletion(
'gpt-4o', 'Say hello');
finally
oOpenAI.Free;
end;
end;
アンダースコア付きのメソッドは、生のレスポンスボディを返す文字列版のショートカットです。解析済みのオブジェクトが欲しい場合は、TsgcOpenAIClass_Request_ChatCompletion を組み立てて CreateChatCompletion を呼び出します。このページの後半で示します。
uses
Classes, SysUtils,
// sgc
sgcHTTP_API_Anthropic;
var
oAnthropic: TsgcHTTP_API_Anthropic;
begin
oAnthropic := TsgcHTTP_API_Anthropic.Create(nil);
try
oAnthropic.AnthropicOptions.ApiKey := GetApiKey;
oAnthropic.AnthropicOptions.AnthropicVersion := '2023-06-01';
// Model, prompt, max tokens
memoAnswer.Lines.Text := oAnthropic._CreateMessage(
'claude-sonnet-4-20250514',
'Summarise RFC 6455 in three bullet points.', 1024);
finally
oAnthropic.Free;
end;
end;
Claude は API バージョンヘッダーを必要とするため、キーとあわせて AnthropicVersion を設定します。_CreateMessageWithSystem はシステムプロンプトを追加し、_CountTokens は送信前にプロンプトの費用を見積もります。
uses
Classes, SysUtils,
// sgc
sgcHTTP_API_Ollama;
var
oOllama: TsgcHTTP_API_Ollama;
begin
oOllama := TsgcHTTP_API_Ollama.Create(nil);
try
// Local server, no API key required
oOllama.OllamaOptions.Host := 'http://localhost:11434';
// Which models are pulled on this machine?
memoModels.Lines.Text := oOllama._GetTags;
memoAnswer.Lines.Text := oOllama._CreateMessage(
'llama3', 'Summarise this invoice in one line.');
finally
oOllama.Free;
end;
end;
Host の既定値は http://localhost:11434 なので、既定のインストールならそのままで構いません。_PullModel はモデルをダウンロードし、_GetTags はディスク上にあるものを一覧表示し、_ShowModel はその詳細を読み取ります。
一括の呼び出しはモデルが書き終わるまでブロックするため、長い回答では固まったように見えます。ストリーミングは応答を断片で届けるので、モデルがまだ考えている間にテキストがメモ欄へ現れます。ここは多くの人がつまずく部分なので、両方のレベルを示します。
Chat の代わりに ChatStream を呼び出し、OnChatStream を処理します。コンポーネントはプロバイダーにストリーミング応答を要求し、各 Server-Sent Event を解析して aChunk を渡します。これは新しいテキストそのもので、それ以外は含みません。追記するだけで実装は完了です。
ストリーミング時の JSON の形はプロバイダーごとに異なります。OpenAI、DeepSeek、Ollama、Grok、Mistral はテキストを choices[0].delta.content に、Claude は delta.text に、Gemini はさらに深く candidates の中に入れます。TsgcAIChat は選択したプロバイダーに該当する形をすでに把握しているため、ハンドラーが JSON を目にすることはありません。
ハンドラー内で Cancel を True に設定すると、暴走した回答を止められます。その時点でリクエストは破棄され、以降のチャンクは届きません。ストリームが終わると、組み立てられたテキストが履歴に追加されて ChatStream から返り、OnChatMessage が完全な回答とともに 1 度だけ発火します。
procedure TfrmMain.btnStreamClick(Sender: TObject);
begin
FChat.Provider := aicpAnthropic;
FChat.ChatOptions.ApiKey := GetApiKey;
FChat.ChatOptions.Model := 'claude-sonnet-4-20250514';
FChat.OnChatStream := OnChatStream;
FChat.OnChatError := OnChatError;
memoAnswer.Lines.Clear;
FChat.ChatStream(memoPrompt.Lines.Text);
end;
procedure TfrmMain.OnChatStream(Sender: TObject;
const aChunk: string; var Cancel: Boolean);
begin
memoAnswer.Text := memoAnswer.Text + aChunk;
Cancel := FUserPressedStop;
end;
procedure TfrmMain.OnChatError(Sender: TObject;
const aError: string);
begin
memoAnswer.Lines.Add('ERROR: ' + aError);
end;
REST クライアントもストリーミングに対応します。OnHTTPAPISSE を割り当て、ストリーミング用のショートカットを呼び出します。Claude と Ollama では _CreateMessageStream、OpenAI では Stream を True に設定した TsgcOpenAIClass_Request_ChatCompletion です。イベントは Server-Sent Event の名前である aEvent と、そのイベントのペイロードである aData を、ベンダーが送ってきたそのままの形で渡します。
このレベルでは JSON を自分で解析します。それが狙いです。ツール呼び出しのデルタ、停止理由、使用量の記録、そのほかベンダーが回線に流すものすべてを見られます。ネットワークの部分読み取りはすでに再構成されているため、2 回の TCP 読み取りに分割されたイベントも 1 つのまとまりとして届きます。Ollama の改行区切り JSON も同じイベント経由で届きます。
終端の示し方はベンダーによって異なります。OpenAI はリテラルの [DONE] で終了し、Claude は message_stop という名前のイベントで終了します。両方を対象にするコードなら、どちらも処理してください。
procedure TfrmMain.FormCreate(Sender: TObject);
begin
FAnthropic := TsgcHTTP_API_Anthropic.Create(nil);
FAnthropic.AnthropicOptions.ApiKey := GetApiKey;
FAnthropic.AnthropicOptions.AnthropicVersion := '2023-06-01';
FAnthropic.OnHTTPAPISSE := HandleSSE;
FAnthropic.OnHTTPAPIException := HandleException;
end;
procedure TfrmMain.btnStreamClick(Sender: TObject);
begin
memoRaw.Lines.Clear;
FAnthropic._CreateMessageStream(
'claude-sonnet-4-20250514',
'Write a haiku about Object Pascal.', 1024);
end;
procedure TfrmMain.HandleSSE(Sender: TObject;
const aEvent, aData: string; var Cancel: Boolean);
begin
if (aEvent = 'message_stop') or (aData = '[DONE]') then
Exit;
memoRaw.Lines.Add(aEvent + ': ' + aData);
end;
procedure TfrmMain.HandleException(Sender: TObject;
E: Exception);
begin
memoRaw.Lines.Add('ERROR: ' + E.Message);
end;
スレッド。Chat と ChatStream は同期実行なので、ボタンのクリックから直接呼び出すとリクエストの間フォームが固まります。Delphi 2010 以降では、ChatAsync がワーカースレッド上で呼び出しを実行し、IsgcFuture<string> を返します。結果には ThenProc を、失敗には OnError を連結し、実行中のリクエストを破棄するには Cancel を呼び出します。ThenProc のコールバックはメインスレッドでディスパッチされるため、そこから直接 UI を操作できます。
ツール呼び出し(関数呼び出しとも呼ばれます)は、モデルがアプリケーションに何かを調べさせたり、処理を実行させたりする仕組みです。関数を JSON Schema で記述すると、モデルが必要な引数を返してくるので、Pascal のコードを実行して結果を返します。基幹業務アプリケーションの中で役に立つアシスタントは、すべてこの仕組みの上に成り立っています。
TsgcAnthropicClass_Request_Messages を組み立て、1 つ以上の TsgcAnthropicClass_Request_Tool エントリを添付して CreateMessage を呼び出します。各ツールは Name、Description、そして引数の JSON Schema である InputSchema を持ちます。
応答は TsgcAnthropicClass_Response_Messages で、その Content はブロックの配列です。ContentType が 'tool_use' のブロックには、ツールの Name、Input 内の引数、そして Id が入っています。自分の関数を実行したら、ContentType を 'tool_result' に設定した TsgcAnthropicClass_Request_Content_Block に、同じ ToolUseId と回答を Content に入れて、続きのメッセージとして送信します。呼び出しが失敗した場合は IsError を設定すると、モデルは推測せずに立て直せます。
所有権に注意してください。Anthropic のリクエストは、添付したメッセージやツールを所有しないため、サンプルのように自分で解放します。
var
oRequest: TsgcAnthropicClass_Request_Messages;
oMessage: TsgcAnthropicClass_Request_Message;
oTool: TsgcAnthropicClass_Request_Tool;
oMessages: TsgcAnthropicArray_Request_Messages;
oTools: TsgcAnthropicArray_Request_Tools;
oResponse: TsgcAnthropicClass_Response_Messages;
i: Integer;
begin
oRequest := TsgcAnthropicClass_Request_Messages.Create;
try
oRequest.Model := 'claude-sonnet-4-20250514';
oRequest.MaxTokens := 4096;
oMessage := TsgcAnthropicClass_Request_Message.Create;
oMessage.Role := 'user';
oMessage.Content := 'What is the stock of SKU 8841?';
SetLength(oMessages, 1);
oMessages[0] := oMessage;
oRequest.Messages := oMessages;
oTool := TsgcAnthropicClass_Request_Tool.Create;
oTool.Name := 'get_stock';
oTool.Description := 'Read the on-hand stock for a SKU';
oTool.InputSchema :=
'{"type":"object","properties":{"sku":{"type":"string",' +
'"description":"The product code"}},"required":["sku"]}';
SetLength(oTools, 1);
oTools[0] := oTool;
oRequest.Tools := oTools;
oResponse := FAnthropic.CreateMessage(oRequest);
try
for i := 0 to Length(oResponse.Content) - 1 do
if oResponse.Content[i].ContentType = 'tool_use' then
// .Name is the tool, .Input the JSON arguments,
// .Id the value to echo back as ToolUseId
RunTool(oResponse.Content[i].Name,
oResponse.Content[i].Input, oResponse.Content[i].Id)
else if oResponse.Content[i].ContentType = 'text' then
memoAnswer.Lines.Add(oResponse.Content[i].Text);
finally
oResponse.Free;
end;
finally
sgcFree(oMessage);
sgcFree(oTool);
sgcFree(oRequest);
end;
end;
考え方は同じで、形が異なります。TsgcOpenAIClass_Request_ChatCompletion を埋め、Messages 配列を割り当て、ツール定義を JSON 配列として Tools に入れ、必要なら ToolChoice でモデルを誘導します。ParallelToolCalls はモデルが複数のツールを同時に要求できるかどうかを制御し、ResponseFormat は解析が必要なときに回答を JSON に固定します。
CreateChatCompletion は解析済みの TsgcOpenAIClass_Response_ChatCompletion を返します。回答は Choices[0]._Message.Content から、要求された呼び出しは Choices[0]._Message.ToolCalls から、モデルが停止した理由は Choices[0].FinishReason から、かかった費用は Usage.PromptTokens、Usage.CompletionTokens、Usage.TotalTokens から読み取ります。Anthropic のリクエストとは違い、こちらは添付したメッセージオブジェクトを所有し、自身とともに解放します。
従来の Functions と FunctionCall プロパティも、OpenAI の当初の関数呼び出しの形に合わせて書かれたコードのために残されています。
var
oRequest: TsgcOpenAIClass_Request_ChatCompletion;
oResponse: TsgcOpenAIClass_Response_ChatCompletion;
oSystem, oUser: TsgcOpenAIClass_Request_Completion_Message;
oMessages: TsgcOpenAIArray_Request_Completion_Messages;
begin
oRequest := TsgcOpenAIClass_Request_ChatCompletion.Create;
try
oRequest.Model := 'gpt-4o';
oRequest.MaxTokens := 1024;
oRequest.Temperature := 0.2;
oSystem := TsgcOpenAIClass_Request_Completion_Message.Create;
oSystem.Role := 'system';
oSystem.Content := 'You are a warehouse assistant.';
oUser := TsgcOpenAIClass_Request_Completion_Message.Create;
oUser.Role := 'user';
oUser.Content := 'What is the stock of SKU 8841?';
SetLength(oMessages, 2);
oMessages[0] := oSystem;
oMessages[1] := oUser;
oRequest.Messages := oMessages;
// Tool definitions as a JSON array
oRequest.Tools :=
'[{"type":"function","function":{"name":"get_stock",' +
'"description":"Read the on-hand stock for a SKU",' +
'"parameters":{"type":"object","properties":' +
'{"sku":{"type":"string"}},"required":["sku"]}}}]';
oRequest.ToolChoice := 'auto';
oResponse := FOpenAI.CreateChatCompletion(oRequest);
try
if Length(oResponse.Choices) > 0 then
begin
memoAnswer.Lines.Text := oResponse.Choices[0]._Message.Content;
memoTools.Lines.Text := oResponse.Choices[0]._Message.ToolCalls;
lblStop.Caption := oResponse.Choices[0].FinishReason;
end;
lblTokens.Caption := IntToStr(oResponse.Usage.TotalTokens);
finally
oResponse.Free;
end;
finally
// frees the attached Messages too
oRequest.Free;
end;
end;
プロンプトに顧客の記録、医療データ、契約書、あるいはデータ処理契約の対象となるものが含まれる場合、これは性能の問題ではなくコンプライアンスの問題です。以下が比較です。
| ホスト型、OpenAI または Claude | ローカル、Ollama | |
|---|---|---|
| プロンプトの行き先 | ベンダーへ、HTTPS 経由で、ベンダーの規約のもとに送られます | どこにも送られません。リクエストは http://localhost:11434 に向かいます |
| 資格情報 | ソース管理にもバイナリにも入れてはならない API キーが必要です | 既定では不要です。プロキシ経由やリモートのインスタンス向けに OllamaOptions.ApiKey があります |
| 回答の品質 | 現在利用できる最も強力なモデルです | 良好で向上を続けていますが、難しい推論では最先端に明らかに及びません |
| コスト | トークン単位で、使い続ける限り発生します。Usage.TotalTokens を確認してください |
自分のハードウェアに 1 度だけ。実用的なモデルは多くの RAM か GPU を必要とします |
| レイテンシ | ネットワークの往復に加え、混雑時にはベンダー側のキューイングが加わります | ネットワークはありません。速度は自分のマシンの性能次第です |
| オフラインとエアギャップ | 不可 | 可 |
| レート制限と障害 | ベンダー側で発生します。RetryOptions を使い、Retry-After を尊重してください |
制約は自分の処理能力だけです |
| コンポーネント | TsgcHTTP_API_OpenAI、TsgcHTTP_API_Anthropic |
TsgcHTTP_API_Ollama |
よくある答えは「両方」です。TsgcAIChat がすべてのプロバイダーを 1 つの API の背後にまとめるため、実行時にデータの分類で振り分けられます。顧客レコードに触れるものはローカルへ、それ以外はホスト型へという具合です。切り替えは Provider で、プロバイダーが Ollama の場合はあわせて ChatOptions.BaseUrl を設定します。
if aContainsPersonalData then
begin
FChat.Provider := aicpOllama;
FChat.ChatOptions.BaseUrl := 'http://localhost:11434';
FChat.ChatOptions.Model := 'llama3';
end
else
begin
FChat.Provider := aicpOpenAI;
FChat.ChatOptions.ApiKey := GetApiKey;
FChat.ChatOptions.Model := 'gpt-4o-mini';
end;
memoAnswer.Lines.Text := FChat.Chat(memoPrompt.Lines.Text);
自分の机の上で動くデモと、レート制限、遅いモデル、そして「急に止まった」というサポートチケットに耐えるクライアントは別物です。
各クライアントは RetryOptions ブロックを持ちます。Enabled、Retries、Wait、Multiplier、MaxInterval、Jitter、HonorRetryAfter です。これを有効にすると、一時的な失敗は例外として表面化する代わりに指数バックオフでリトライされます。HonorRetryAfter を設定すると、クライアントは推測ではなくベンダーの Retry-After ヘッダーに従います。
引き上げるべきは HttpOptions.ReadTimeout です。長い生成、特にローカルモデルでの生成は、既定の HTTP 読み取りタイムアウトを超えることがあり、順調だった回答が途中で失敗します。
LogOptions.Enabled と LogOptions.FileName を設定すると、通信内容がファイルに書き出されます。本番でプロンプトの挙動が変わったとき、コードが実際に送った JSON を確認する最短の方法です。
TsgcAIChat はやり取りを保持し、次の呼び出しで再送します。これが追加の質問を成立させています。MaxHistoryMessages で上限を設けると、長いセッションでプロンプトが、ひいては請求額が、際限なく膨らむのを防げます。ClearHistory で最初からやり直せ、GetHistory は Count と個々のメッセージを公開します。
OpenAIOptions.Provider を oapvAzure に設定し、AzureOptions.ResourceName、AzureOptions.DeploymentId、AzureOptions.APIVersion を埋めます。コードの残りは変わりません。通信を自社の Azure テナント内に留めるよう調達部門が求める場合、これが効いてきます。
OnHTTPAPIException は REST クライアントの失敗を、OnChatError は TsgcAIChat の失敗を通知します。HTTP エラーは EsgcHTTPAPIProtocolException として届きます。これは EIdHTTPProtocolException の派生のままで、加えてレスポンスヘッダーも保持します。自分で行う呼び出しには、クライアント上の CircuitBreaker と RateLimit を利用できます。
チャットボックスは出発点です。この作業が向かう先はたいてい次の 4 方向で、そのいずれもすでにライブラリに入っています。
TsgcAIOpenAIEmbeddings でドキュメントをベクトルに変換し、TsgcAIDatabaseVectorFile または TsgcAIDatabaseVectorPinecone に保存して、最も近い一節を取り出してプロンプトに入れます。これが検索拡張生成(RAG)で、自社の業務についてモデルが答えをでっち上げるのを防ぐ方法です。
TsgcAIOpenAIChatBot はレコーダー、文字起こし、チャット呼び出し、音声合成を 1 つのコンポーネントにまとめるため、ユーザーはアプリケーションと音声で会話できます。TsgcAIOpenAITranslator はライブ翻訳について同じことを行います。
Model Context Protocol は、アシスタントがツールを発見して呼び出すための仕組みです。TsgcWSServer_API_MCP は Delphi アプリケーションを、Claude などのクライアントから操作できる MCP サーバーに変えます。TsgcWSAPI_Client_MCP は他のサーバーをコードから利用します。パレット上では TsgcWSAPIServer_MCP と TsgcWSAPIClient_MCP として現れます。
知っておく価値があるのは、チャットコンポーネントとは違い、MCP のユニットは Windows に限定されないという点です。Delphi で書いた MCP サーバーは Linux でも動きます。
コンポーネントリファレンスは、すべてのプロパティとイベントを解説しています。すぐ実行できるデモプロジェクトは Demos\AI 以下にライブラリ同梱で提供されます。
リファレンス、OpenAI クライアント
TsgcHTTP_API_OpenAI のすべてのメソッド、オプション、イベント。
|
開く | |
リファレンス、Anthropic クライアント
TsgcHTTP_API_Anthropic のメッセージ、ツール、画像、バッチ、トークン数の計測。
|
開く | |
| チュートリアル、Delphi から Claude を使う Anthropic クライアントを最初から最後までたどる詳細な解説。 | 開く | |
| チュートリアル、Ollama によるローカルモデル モデルを取得し、クライアントを localhost に向けて、オフラインで実行します。 | 開く | |
| チュートリアル、関数呼び出し モデルを自分の Pascal 関数につなぐ手順を、順を追って解説します。 | 開く | |
| ユーザーマニュアル(PDF) ライブラリのすべてのコンポーネントを網羅した総合マニュアル。 | 開く |
さらに読む:Delphi から使う OpenAI クライアント、AI チャットボットを作る、AI エージェントを作る、MCP クライアント。コンポーネントのランディングページは Delphi OpenAI クライアントと Anthropic API です。
このページは Delphi ユースケースの 1 つで、いずれも 1 つのタスクを最初から最後まで扱います。現時点でのほかのページは、OAuth2 と PKCE でユーザーをサインインさせると2 つのアプリケーションを WebRTC でピアツーピア接続するです。
sgcAI_Chat の TsgcAI_Chat を生成し、Provider に使いたいベンダーを設定し、ChatOptions.ApiKey と ChatOptions.Model を設定してから、Chat('your prompt') を呼び出します。回答が文字列として返ります。1 つのベンダー API と直接やり取りしたい場合は、TsgcHTTP_API_OpenAI、TsgcHTTP_API_Anthropic、TsgcHTTP_API_Ollama のいずれかを使い、_CreateChatCompletion または _CreateMessage を呼び出します。どちらの方法も sgcWebSockets と単体パッケージの sgcAI に含まれ、Delphi 7 から RAD Studio 13 まで動作します。
Chat ではなく ChatStream を呼び出し、OnChatStream を処理します。このイベントは各デルタのデコード済みテキストである aChunk と、途中で止めるために設定できる Cancel フラグとともに発火します。REST クライアントのレベルでは、OnHTTPAPISSE を割り当てて Claude と Ollama のクライアントで _CreateMessageStream を呼び出すか、TsgcOpenAIClass_Request_ChatCompletion の Stream を True に設定します。このイベントは生の Server-Sent Event の名前とデータを渡し、ネットワークの部分読み取りはすでに再構成されています。
TsgcHTTP_API_Ollama をそこへ向けます。OllamaOptions.Host の既定値はすでに http://localhost:11434 なので、既定のインストールならモデルを選んで _CreateMessage を呼び出すだけです。マシンの外へ出るものはなく、API キーも不要で、アプリケーションはオフラインで動作します。TsgcAIChat からは、Provider を aicpOllama に設定し、サーバーが localhost にない場合は ChatOptions.BaseUrl も設定することで、同じサーバーに到達できます。
TsgcAnthropicClass_Request_Messages の Tools 配列に、Name、Description、InputSchema を持つ TsgcAnthropicClass_Request_Tool を追加します。すると応答には ContentType が tool_use のコンテンツブロックが含まれ、Name、Input、Id を持ちます。こちらは同じ ToolUseId を引用した tool_result ブロックで応答します。OpenAI では、定義を TsgcOpenAIClass_Request_ChatCompletion の Tools プロパティに入れ、要求された呼び出しを Choices[0]._Message.ToolCalls から読み取ります。
TsgcHTTP_API_OpenAI、TsgcHTTP_API_Anthropic、TsgcHTTP_API_Ollama は Windows、macOS、Linux、iOS、Android 向けにコンパイルされ、TsgcAIChat は Windows のみ、Win32 と Win64 向けにコンパイルされます。MCP のクライアントとサーバーも Windows に限定されません。
ChatOptions.ApiKey や OpenAIOptions.ApiKey などのベンダーオプションに割り当てます。使用量はそのベンダーがあなたのキーに対して課金し、応答ごとに Usage.PromptTokens、Usage.CompletionTokens、Usage.TotalTokens で追跡できます。Ollama はモデルがローカルで動くためキーを必要としません。
Chat と ChatStream は同期実行です。Delphi 2010 以降では代わりに ChatAsync を呼び出してください。ワーカースレッド上でリクエストを実行し、文字列の IsgcFuture を返すので、ThenProc を連結して回答を受け取り、OnError で例外を受け取り、Cancel で実行中のリクエストを破棄します。ThenProc のコールバックはメインスレッドでディスパッチされるため、そこから UI を更新しても安全です。あわせて HttpOptions.ReadTimeout を引き上げてください。長い生成は既定の読み取りタイムアウトを超えることがあります。
OpenAIOptions.Provider を oapvAzure に設定し、AzureOptions.ResourceName、AzureOptions.DeploymentId、AzureOptions.APIVersion を埋めます。クライアントは自社の Azure デプロイを対象にするようになり、すでに書いたコードはまったく変わりません。