从 Delphi 调用 LLM

从 VCL、FMX 或控制台应用发送一段提示词并拿到回答,模型可以是 OpenAI 或 Anthropic Claude 这样的托管模型,也可以是通过 Ollama 跑在你自己机器上的模型。本页带你从一个空白窗体走到一次能跑通的调用,然后进入每个项目随后都会遇到的三件事:流式输出、工具调用,以及托管模型与本地模型之间的取舍。

OpenAI, Claude, Gemini, Grok, DeepSeek, Mistral, Ollama
基于 Server-Sent Events 的流式输出
从 Delphi 7 到 RAD Studio 13

两种发起调用的方式

既有一个与厂商无关的聊天组件,也有针对每家厂商的专用 REST 客户端。两者都在同一个库里,因此你可以先用其中一个,需要时再切到另一个,不用更换工程。

TsgcAIChat,一套 API 覆盖所有厂商

设置 Provider、一个 API 密钥和一个模型,然后调用 Chat。组件会构造对应厂商的 JSON,维护会话历史,并返回助手的文本。从 OpenAI 切换到 Claude,或者切换到本地的 Ollama 模型,只是一次赋值。它由单元 sgcAI_Chat 中的 TsgcAI_Chat 实现,在组件面板上注册为 TsgcAIChat

分厂商的 REST 客户端

TsgcHTTP_API_OpenAITsgcHTTP_API_AnthropicTsgcHTTP_API_Ollama 完整暴露各家厂商的 API,包括任何中立层都覆盖不了的部分:视觉输入、文档输入、扩展思考、批量任务、文件、向量嵌入、图像生成和语音转写。当你需要某个特定端点时就用它们。

版本与平台

AI 与 LLM 客户端属于 sgcWebSockets 的 Enterprise 功能,Standard 和 Professional 都不包含,你也可以单独购买 sgcAI 包。

平台在这里很关键。三个 REST 客户端可在 Windows、macOS、Linux、iOS 和 Android 上编译。TsgcAIChat 不行,它只为 Windows 编译,因此在 Linux 服务、macOS 构建或移动端目标上,你要直接调用 REST 客户端。本页的示例写法保证两条路线都能用。

你的第一次调用,大约十行代码

放下组件,设置密钥和模型,发送提示词。选择你打算开始使用的厂商对应的标签页。最后一个标签页完全不需要 API 密钥,因为模型跑在你自己的机器上。

uChat.pas
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;

更换厂商只需要改一行。Provider 接受 aicpOpenAIaicpAnthropicaicpGeminiaicpDeepSeekaicpOllamaaicpGrokaicpMistral。代码里的其他部分都原封不动。

仅限 Windows。TsgcAI_Chat 及其面板组件 TsgcAIChat 只为 Windows 编译,包括 Win32 和 Win64。在 macOS、Linux、iOS 和 Android 上该单元根本不参与编译,因此如果你的目标是 Linux 服务或移动应用,请使用其他三个标签页中的厂商 REST 客户端,它们没有平台限制。

uOpenAI.pas
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,本页后面有示例。

uClaude.pas
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 则在发送之前先算出一段提示词的开销。

uOllama.pas
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 读取模型详情。

边生成边显示回答

一次性调用会一直阻塞到模型生成完毕,遇到长回答时会让人以为程序卡死了。流式输出分片返回回复,模型还在思考时文字就已经出现在备注框里。这一块是大多数人卡住的地方,所以这里把两个层面都讲清楚。

用 TsgcAIChat,增量已经解码好

调用 ChatStream 而不是 Chat,并处理 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 会带着完整回答触发一次。

uChatStream.pas
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 上则是把 TsgcOpenAIClass_Request_ChatCompletionStream 设为 True。事件会给你 aEvent,也就是 Server-Sent Event 的名称,以及 aData,也就是该事件的有效载荷,与厂商发出的内容完全一致。

在这个层面上,JSON 由你自己解析,而这正是重点:你能看到工具调用增量、停止原因、用量记录,以及厂商放到线路上的任何其他内容。网络的部分读取已经替你重新拼装好,因此一个被拆到两次 TCP 读取里的事件仍然会完整到达,而 Ollama 的换行分隔 JSON 也通过同一个事件送达。

终止标记因厂商而异。OpenAI 以字面量 [DONE] 结束,Claude 则以名为 message_stop 的事件结束。如果你的代码同时面向两家,就把两种都处理掉。

uRawStream.pas
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;

线程。ChatChatStream 是同步的,所以直接在按钮点击里调用它们,会让窗体在整个请求期间失去响应。在 Delphi 2010 及以后的版本上,ChatAsync 会把调用放到工作线程上执行,并返回一个 IsgcFuture<string>。用 ThenProc 链接结果,用 OnError 链接失败,调用 Cancel 可以放弃一个进行中的请求。ThenProc 回调在主线程上派发,因此你可以直接在里面操作界面。

让模型调用你的 Pascal 代码

工具调用,也叫函数调用,是模型请求你的应用去查询某些内容或执行某个动作的方式。你用 JSON Schema 描述这个函数,模型回复它想要的参数,你执行 Pascal 代码并把结果送回去。业务线应用里每一个真正好用的助手,背后都是这套机制。

Claude,使用带类型的工具对象

构造一个 TsgcAnthropicClass_Request_Messages,挂上一个或多个 TsgcAnthropicClass_Request_Tool 条目,然后调用 CreateMessage。每个工具带有 NameDescriptionInputSchema,后者就是它参数的 JSON Schema。

回复是一个 TsgcAnthropicClass_Response_Messages,它的 Content 是一个块数组。ContentType 等于 'tool_use' 的块携带工具的 Name、位于 Input 中的参数,以及一个 Id。执行你的函数,然后发送一条后续消息,其中包含一个 TsgcAnthropicClass_Request_Content_Block,把 ContentType 设为 'tool_result',带上同一个 ToolUseId,并把你的答案放在 Content 里。调用失败时请设置 IsError,好让模型能够纠正而不是靠猜。

注意所有权:Anthropic 请求并不拥有你挂上去的消息和工具,所以要像示例里那样自己释放它们。

uToolUse.pas
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;

OpenAI,使用带类型的请求

思路相同,形态不同。填好一个 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.PromptTokensUsage.CompletionTokensUsage.TotalTokens 读取开销。与 Anthropic 请求不同,这个请求拥有你挂上去的消息对象,并会随自身一起释放它们。

较早的 FunctionsFunctionCall 属性依然保留,供按照 OpenAI 最初的函数调用形态编写的代码使用。

uTypedRequest.pas
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 供代理或远程实例使用
回答质量 当前可用的最强模型 不错且在进步,在高难度推理上明显落后于前沿水平
成本 按 token 计费,长期如此。请留意 Usage.TotalTokens 一次性的硬件投入。一个好用的模型需要大量内存或一块 GPU
延迟 一次网络往返,繁忙时段还要加上厂商侧的排队 不走网络。速度就是你机器的速度
离线与物理隔离环境
速率限制与服务中断 由厂商侧决定。使用 RetryOptions 并遵守 Retry-After 只受你自己的容量限制
组件 TsgcHTTP_API_OpenAI, TsgcHTTP_API_Anthropic TsgcHTTP_API_Ollama

常见的答案是两者都要。由于 TsgcAIChat 把所有厂商放在同一套 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 配置块:EnabledRetriesWaitMultiplierMaxIntervalJitterHonorRetryAfter。打开它之后,瞬时故障会以指数退避方式重试,而不是直接抛出异常。HonorRetryAfter 让客户端遵守厂商的 Retry-After 响应头,而不是靠猜。

超时

需要调大的是 HttpOptions.ReadTimeout。一次长时间生成,尤其是在本地模型上,可能超过默认的 HTTP 读取超时,让一个本来进行得很顺利的回答中途失败。

日志

LogOptions.Enabled 加上 LogOptions.FileName 会把流量写入文件。当一段提示词在生产环境中表现不同时,这是查看你的代码究竟发出了什么 JSON 的最快方式。

会话历史

TsgcAIChat 会保留对话内容,并在下一次调用时重放,这正是追问能生效的原因。用 MaxHistoryMessages 给它设上限,避免长会话让提示词,进而让账单无限增长。ClearHistory 用于重新开始,GetHistory 则公开 Count 和逐条消息。

Azure OpenAI

OpenAIOptions.Provider 设为 oapvAzure,并填写 AzureOptions.ResourceNameAzureOptions.DeploymentIdAzureOptions.APIVersion。代码的其余部分不变,当采购部门坚持流量必须留在你自己的 Azure 租户内时,这一点很重要。

错误处理与断路

OnHTTPAPIException 暴露 REST 客户端的失败,OnChatErrorTsgcAIChat 起同样的作用。HTTP 错误以 EsgcHTTPAPIProtocolException 的形式到达,它依然派生自 EIdHTTPProtocolException,并额外携带响应头。客户端上还提供 CircuitBreakerRateLimit,供你自己发起的调用使用。

第一次调用之后,人们通常会做什么

一个聊天框只是开始。下面是这项工作通常会走的四个方向,而每一个方向库里都已经有了。

基于你自己的数据作答

TsgcAIOpenAIEmbeddings 把你的文档转成向量,存进 TsgcAIDatabaseVectorFileTsgcAIDatabaseVectorPinecone,再检索出最相近的段落放进提示词。这就是检索增强生成,也是你阻止模型凭空编造与你业务有关的答案的方法。

向量嵌入向量数据库

对它说话,也让它开口回答

TsgcAIOpenAIChatBot 把录音、语音转写、聊天调用和语音合成串在一个组件里,让用户可以和你的应用进行语音对话。TsgcAIOpenAITranslator 则以同样的方式实现实时翻译。

AI 聊天机器人AI 翻译器

把你的应用开放给 AI 智能体

Model Context Protocol 是助手发现并调用工具的方式。TsgcWSServer_API_MCP 把你的 Delphi 应用变成一个 MCP 服务器,供 Claude 和其他客户端驱动,而 TsgcWSAPI_Client_MCP 则让你的代码去消费其他服务器。它们在组件面板上显示为 TsgcWSAPIServer_MCPTsgcWSAPIClient_MCP

值得一提:与聊天组件不同,MCP 单元并不限于 Windows,因此用 Delphi 写的 MCP 服务器可以跑在 Linux 上。

MCP 概览MCP 服务器MCP 客户端

用上各家厂商 API 的其余部分

OpenAI 上有图像生成、语音转写、内容审核、批量任务和微调。Claude 上有视觉、文档、扩展思考、网络搜索和 token 计数。Ollama 上有向量嵌入和模型管理。每个厂商页面都列出了对应客户端公开的能力。

OpenAIClaudeOllama

参考文档、示例与教程

组件参考文档记录了每一个属性和事件。可直接运行的示例工程随库一起发布,位于 Demos\AI 目录下。

参考文档,OpenAI 客户端 TsgcHTTP_API_OpenAI 上的每一个方法、选项和事件。
参考文档,Anthropic 客户端 TsgcHTTP_API_Anthropic 上的消息、工具、视觉、批量任务和 token 计数。
教程,从 Delphi 使用 Claude Anthropic 客户端的长篇完整讲解,从头到尾。
教程,用 Ollama 运行本地模型 拉取一个模型,把客户端指向 localhost,然后离线运行。
教程,函数调用 一步步把模型接到你自己的 Pascal 函数上。
用户手册(PDF) 覆盖库中每一个组件的完整手册。

延伸阅读:从 Delphi 使用 OpenAI 客户端构建 AI 聊天机器人构建 AI 智能体,以及 MCP 客户端。相关组件的产品页是 Delphi OpenAI 客户端Anthropic API

本页属于 Delphi 使用场景之一,每一篇都把一个任务从头做到尾。目前还有 用 OAuth2 和 PKCE 完成用户登录,以及 用 WebRTC 让两个应用点对点连接

常见问题

从单元 sgcAI_Chat 创建一个 TsgcAI_Chat,把 Provider 设为你想要的厂商,设置 ChatOptions.ApiKeyChatOptions.Model,然后调用 Chat('your prompt'),它会以字符串形式返回答案。如果你更想直接对接某一家厂商的 API,就使用 TsgcHTTP_API_OpenAITsgcHTTP_API_AnthropicTsgcHTTP_API_Ollama,并调用 _CreateChatCompletion_CreateMessage。两种做法都随 sgcWebSockets 和独立的 sgcAI 包一起发布,并且从 Delphi 7 到 RAD Studio 13 都可用。
调用 ChatStream 而不是 Chat,并处理 OnChatStream,它会带着 aChunk 触发,也就是每一个增量解码后的文本,以及一个 Cancel 标志,你可以设置它来提前停止。在 REST 客户端层面,给 OnHTTPAPISSE 赋值,并在 Claude 和 Ollama 客户端上调用 _CreateMessageStream,或者把 TsgcOpenAIClass_Request_ChatCompletionStream 设为 True。该事件会给你原始的 Server-Sent Event 名称和数据,并且网络的部分读取已经重新拼装好。
可以。安装 Ollama,拉取一个模型,然后把 TsgcHTTP_API_Ollama 指向它。OllamaOptions.Host 已经默认为 http://localhost:11434,所以在默认安装下你只需要选一个模型并调用 _CreateMessage。没有任何数据离开这台机器,不需要 API 密钥,应用也能离线工作。通过 TsgcAIChat 访问同一个服务器,只要把 Provider 设为 aicpOllama,如果服务器不在 localhost 上,再设置 ChatOptions.BaseUrl
用 JSON Schema 描述这个函数,并把它挂到请求上。在 Claude 上,把一个带有 NameDescriptionInputSchemaTsgcAnthropicClass_Request_Tool 加入 TsgcAnthropicClass_Request_MessagesTools 数组。随后回复中会包含一个 ContentTypetool_use 的内容块,携带 NameInputId,你则用一个引用相同 ToolUseIdtool_result 块作答。在 OpenAI 上,把定义放进 TsgcOpenAIClass_Request_ChatCompletionTools 属性,并从 Choices[0]._Message.ToolCalls 读取它请求的调用。
AI 与 LLM 客户端属于 sgcWebSockets 的 Enterprise 功能,Standard 和 Professional 版本都不包含。如果你不需要 sgcWebSockets 的其余部分,独立的 sgcAI 包含有同样的组件以及它们所需的运行时。该库支持从 Delphi 7 到 RAD Studio 13,以及对应的 C++ Builder 版本。在平台方面,REST 客户端 TsgcHTTP_API_OpenAITsgcHTTP_API_AnthropicTsgcHTTP_API_Ollama 可为 Windows、macOS、Linux、iOS 和 Android 编译,而 TsgcAIChat 只为 Windows 编译,包括 Win32 和 Win64。MCP 客户端和服务器同样不限于 Windows。
对于托管厂商,是的。这些组件是 REST 客户端,所以你要从自己的 OpenAI、Anthropic、Google、xAI、DeepSeek 或 Mistral 账户拿到密钥,并把它赋给 ChatOptions.ApiKey,或者赋给诸如 OpenAIOptions.ApiKey 这样的厂商选项。用量由该厂商按你的密钥计费,你可以通过 Usage.PromptTokensUsage.CompletionTokensUsage.TotalTokens 逐次响应地追踪。Ollama 不需要密钥,因为模型跑在本地。
ChatChatStream 是同步的。在 Delphi 2010 及以后的版本上,改为调用 ChatAsync:它会把请求放到工作线程上执行,并返回一个字符串的 IsgcFuture,于是你可以链接 ThenProc 来接收答案,链接 OnError 来接收异常,调用 Cancel 来放弃进行中的请求。ThenProc 回调在主线程上派发,因此从中更新界面是安全的。另外请调大 HttpOptions.ReadTimeout,因为一次长时间生成可能超过默认的读取超时。
可以。把 OpenAIOptions.Provider 设为 oapvAzure,并填写 AzureOptions.ResourceNameAzureOptions.DeploymentIdAzureOptions.APIVersion。客户端随后会指向你的 Azure 部署,而你已经写好的调用完全不用改。

准备好从你的 Delphi 应用调用 LLM 了吗?

下载免费试用版,今天就完成你的第一次调用。