快速回答:聊天机器人就是聊天补全加上记忆。sgcWebSockets 提供了一个专用的 TsgcAIChat 组件,它替你保存完整的消息历史,所以每一轮都会连同到目前为止的对话一起发送,模型就能在上下文中作答。拖入组件,设置 API 密钥和模型,然后调用 Chat 获取一个回复,或调用 ChatStream 获取实时的、逐 token 的打字效果。清空对话只需一次 ClearHistory 调用。
如果你已经从 Delphi 调用过 LLM,你大概注意到一件令人沮丧的事:问一个追问,模型表现得好像从没和你说过话。这不是 bug,这就是一次性补全的工作方式。把它变成一个真正的对话助手,是玩具和聊天机器人之间的区别,而它归结为一个想法:记忆。
一次性补全 vs 聊天机器人
LLM API 是无状态的。每个请求都是独立的,所以模型只知道你在那一个请求中放入的内容。一次性调用发送单个提示词:
// User: "What is the capital of France?" -> "Paris."
// User: "And its population?" -> "Population of what?"
第二个问题失败了,因为服务器没有保留第一个问题的任何东西。聊天机器人通过每次重新发送整个对话来解决这个问题:系统消息、每一个用户轮次,以及每一个助手回复,按顺序排列。模型读取历史,看到“它的”指的是 Paris,于是正确作答。你不需要数据库或会话服务器,只需要一个随对话增长的消息列表。唯一真正的工作是构建和维护那个列表,而这正是聊天机器人组件替你做的。
TsgcAIChat 组件:记忆替你打理
与其手动接线一个消息数组,不如把一个 TsgcAIChat 拖到你的窗体上。它在内部拥有对话历史,自动追加每条用户消息和每条助手回复,并在每次调用时发送累积的上下文。你设置提供商、API 密钥和模型,然后只需调用 Chat。
uses
sgcAI, sgcAI_Chat;
var
Bot: TsgcAIChat;
begin
Bot := TsgcAIChat.Create(nil);
Bot.Provider := aicpOpenAI;
Bot.ChatOptions.ApiKey := 'sk-...';
Bot.ChatOptions.Model := 'gpt-4o-mini';
Bot.SystemMessage := 'You are a concise assistant for Delphi developers.';
// Each call adds to the same conversation:
ShowMessage(Bot.Chat('What is the capital of France?')); // "Paris."
ShowMessage(Bot.Chat('And its population?')); // answers about Paris
end;
因为组件记住了第一轮,追问就直接奏效。SystemMessage 设定助手的人设,并随每个请求一起包含进去。当你想要一段全新的对话时,调用 Bot.ClearHistory;要检查或持久化已经说过的内容,Bot.GetHistory 返回消息列表。你也可以用 MaxHistoryMessages 给记忆设上限,使一段长聊天不会无限增长(较早的轮次会被自动裁剪)。
同一个组件与 sgcWebSockets 支持的每个提供商对话。把 Provider 切换为 aicpAnthropic、aicpGemini、aicpDeepSeek、aicpOllama、aicpGrok 或 aicpMistral,更改模型名称,你聊天机器人代码的其余部分保持原样。见 ChatBot 组件页面 和 AI & LLM 组件中心。
流式输出实时回复
等上好几秒才看到完整答案出现,感觉很慢。真正的聊天机器人会流式输出回复,让词语在生成时就显示出来,也就是那种熟悉的打字效果。TsgcAIChat 通过 ChatStream 加上 OnChatStream 事件暴露这一点,后者会在每个文本块到达时触发。
Bot.OnChatStream := BotChatStream;
Bot.ChatStream('Explain WebSockets in two sentences.');
procedure TForm1.BotChatStream(Sender: TObject; const aChunk: string;
var Cancel: Boolean);
begin
Memo1.Text := Memo1.Text + aChunk; // append each token as it arrives
// set Cancel := True to stop the response early
end;
这些文本块在底层通过 Server-Sent Events 增量交付,但你从不接触 SSE 的底层管道。当流结束时,完整的助手回复会像一次非流式调用那样被加入历史,所以下一轮仍拥有完整上下文。Cancel 参数让你能实现一个“停止生成”按钮。还有 OnChatMessage 用于获取最终组装好的消息,以及 OnChatError 用于暴露任何 API 失败。
一个完整的语音聊天机器人
如果你想让助手能听会说,TsgcAIOpenAIChatBot 组件包装了整个循环:它捕获麦克风音频,用 Whisper 转写它,把文本发送给 Chat Completions,并通过文本转语音提供商把答案说回来。接入一个音频录制器和一个文本转语音引擎,设置密钥,然后调用 Start。
uses
sgcAI, sgcAI_OpenAI_Audio_ChatBot,
sgcAI_AudioRecorder_MCI, sgcAI_TextToSpeech_System;
var
ChatBot: TsgcAIOpenAIChatBot;
begin
ChatBot := TsgcAIOpenAIChatBot.Create(nil);
ChatBot.OpenAIOptions.ApiKey := 'sk-...';
ChatBot.AudioRecorder := TsgcAudioRecorderMCI.Create(nil);
ChatBot.TextToSpeech := TsgcTextToSpeechSystem.Create(nil);
ChatBot.OnChatCompletion := ChatBotChatCompletion;
ChatBot.Start; // begin listening; Stop ends it
ChatBot.ChatAsUser('Tell me a joke'); // or push a turn programmatically
end;
OnChatCompletion 事件给你每个回复的角色和内容,而 OnTranscription 让你能在内容被发送前检查或编辑所听到的话。这与 TsgcAIChat 是同一个对话思路,只是两端都加上了音频。
更愿意自己管理列表?
你不一定要使用聊天机器人组件。如果你想要完全的控制,保留你自己的一份 { role, content } 消息列表,并在每次调用时用 TsgcHTTP_API_OpenAI._CreateChatCompletion 发送它。追加用户消息,发送数组,然后在下一轮之前把助手的回复追加回同一个列表。这正是 TsgcAIChat 在内部做的记账工作,所以大多数人让组件来处理它。底层 API 在 Delphi 中的 OpenAI API 教程和 OpenAI 组件页面上有介绍。
开始使用
这里的一切都随 sgcWebSockets 一起提供。获取免费试用版,把一个 TsgcAIChat 拖到窗体上,设置 API 密钥和模型,你只需几行代码就能拥有一个能回答追问、具备上下文感知的聊天机器人。准备好时,加上 ChatStream 实现实时打字效果。
有疑问、反馈,或需要帮你把它接入你的应用?联系我们 — 你会收到来自代码编写者本人的回复。
