# 从一句聊天到 ChatGPT 级对话系统:Chat 链路设计的演化思维 ## 引言 很多人在第一次实现 AI 聊天应用时,会认为 Chat 系统非常简单: > 用户输入一句话 → 调用大模型 → 返回答案。 例如: ```text 用户 ↓ 输入问题 ↓ 调用 LLM ↓ 返回结果如果只是做一个 Demo,这种设计完全可行。
但是,当系统真正面向用户使用时,会不断出现新的问题:
- 用户为什么需要登录?
- 如何保存聊天记录?
- 模型如何知道之前聊过什么?
- 为什么回答可以实时输出?
- 如果生成过程中失败怎么办?
- 多个模型同时生成怎么办?
- 如何支持长期记忆?
这些问题不断推动 Chat 系统演化。
因此,设计 Chat 系统的关键不是记住某个框架,而是理解:
一个系统如何从最简单方案开始,在不断解决问题的过程中演化成复杂架构。
一、最初的问题:如何让用户和模型交流?
最开始需求非常简单:
用户输入一句话,模型返回一句话。
最简单实现:
response = llm.generate(prompt)系统结构:
用户输入 ↓ 模型 ↓ 返回回答但是这个系统存在一个核心问题:
HTTP 请求本身是无状态的
例如:
第一次:
用户: 我叫 Terry模型:
好的,我记住了。第二次:
用户: 我叫什么?如果只发送:
我叫什么?模型并不知道 Terry 是谁。
因为第二次请求和第一次请求没有关联。
于是第一个核心问题出现:
聊天系统必须保存上下文。
二、Conversation:从一次请求到连续对话
为了让模型知道之前发生了什么,需要保存历史。
系统从:
一次请求 一次回答演化为:
一次会话 多个消息因此产生:
Conversation(会话)
Conversation 表示:
用户和 AI 之间的一段连续交流。
例如:
User ↓ Conversation ↓ Message Message Message数据库:
conversation id user_id title created_at updated_at但是新的问题出现:
Conversation 中应该保存什么?
三、Message:为什么聊天记录不能只是文本?
最简单方式:
把所有聊天内容拼成一段字符串。
例如:
你好 你好,我是 AI 介绍一下 RAG RAG 是一种...但是系统不知道:
- 哪句话是用户说的?
- 哪句话是 AI 说的?
- 哪句话是系统规则?
因此聊天记录必须结构化。
于是产生:
Message(消息)
Message 表示:
一次具体的信息事件。
例如:
message id conversation_id role content created_at其中:
role:
system user assistant tool最终:
Conversation | | +---- Message | +---- Message | +---- Message四、Context Builder:数据库消息不是模型输入
保存 Message 后,又出现一个问题:
数据库里的消息能直接发送给模型吗?
不能。
数据库保存的是业务数据。
模型需要:
[ { "role":"system", "content":"你是AI助手" }, { "role":"user", "content":"介绍RAG" }, { "role":"assistant", "content":"RAG是一种..." } ]因此需要:
Context Builder
职责:
历史消息 ↓ 筛选 ↓ 排序 ↓ 格式转换 ↓ 模型输入五、Memory:为什么需要长期记忆?
继续思考:
如果用户和 AI 聊一年怎么办?
假设:
10000 条消息每次全部发送:
会产生:
1. Token 超限
模型上下文有限。
2. 成本增加
输入 Token 越多,费用越高。
3. 响应速度下降
上下文越长,处理越慢。
最简单方案:
只保留最近消息。
例如:
最近20条但是又出现问题:
用户半年前说:
我是 Python 开发者半年后:
帮我设计项目最近20条消息可能没有这个信息。
于是产生:
Memory(记忆)
Memory 解决:
短期信息和长期信息的问题。
短期记忆:
当前聊天上下文长期记忆:
用户偏好 用户背景 历史重要信息区别:
Conversation:
这次聊天发生了什么。
Memory:
这个用户长期是什么样的人。
六、Streaming:为什么回答不是一次返回?
传统方式:
请求 ↓ 等待30秒 ↓ 返回完整答案体验较差。
因此产生:
Streaming(流式输出)
模型生成一个 Token。
立即返回一个 Token。
链路:
LLM ↓ Token Stream ↓ Backend ↓ Frontend ↓ 更新页面这就是为什么 ChatGPT 的回答像打字一样出现。
七、为什么提前创建 Assistant Message?
这是实时聊天系统的重要设计。
用户发送:
介绍一下 Agent前端先创建:
用户消息:
message_id=100 content: 介绍一下 Agent然后创建:
助手消息:
message_id=101 content: 空为什么?
因为后续模型返回:
Agent 是一种...这些 Token 必须知道:
应该追加到哪条消息。
因此:
Token ↓ message_id ↓ 更新 Assistant Message提前创建 Assistant Message 的本质:
提前创建未来数据写入的位置。
不是提前生成答案。
八、状态管理:Chat 本质是状态机
继续思考:
如果模型生成过程中失败怎么办?
例如:
已经生成:
Agent 是一种能够...突然:
网络断开。
数据库:
用户消息: 完成 助手消息: 生成一半系统不知道当前状态。
因此需要状态。
Message 状态:
pending ↓ streaming ↓ completed失败:
pending ↓ failed所以:
Chat 系统不是简单:
输入 → 输出而是:
状态不断变化 事件不断发生九、SSE / WebSocket:为什么需要实时通信?
普通 HTTP:
客户端请求 ↓ 服务器响应 ↓ 结束但是聊天:
请求 ↓ 持续返回数据 ↓ 持续更新因此需要长连接。
常见方案:
SSE
特点:
服务器单向推送。
适合:
AI 流式输出。
WebSocket
特点:
双向通信。
适合:
实时协作场景。
十、Chat 系统最终架构
经过不断演化:
最终形成:
User ↓ Conversation ↓ Message Store ↓ Context Builder ↓ Memory System ↓ LLM Runtime ↓ Streaming Layer ↓ Frontend Update ↓ Persistence生产级系统还需要:
用户系统
Authentication Authorization数据系统
PostgreSQL Redis工程能力
日志 监控 错误恢复 限流 缓存十一、为什么 Chat 最终演化成 Agent?
普通 Chat:
用户 ↓ 模型 ↓ 回答只能完成:
信息生成。
但是现实任务:
例如:
帮我分析这个公司的财报。
可能需要:
- 搜索资料
- 读取文件
- 调用工具
- 执行代码
- 保存结果
于是系统需要:
规划 ↓ 调用工具 ↓ 执行任务 ↓ 保存状态 ↓ 恢复任务这就是 Agent。
因此:
Chat 是 AI 应用入口,Agent 是复杂任务执行能力的扩展。
十二、总结:如何用工程思维设计 Chat?
设计 Chat 系统,不应该从:
我要使用什么框架?开始。
应该从:
我要解决什么问题?开始。
完整推导过程:
需要聊天 ↓ 需要连续上下文 ↓ Conversation ↓ 需要保存每句话 ↓ Message ↓ 需要模型理解历史 ↓ Context Builder ↓ 历史太长 ↓ Memory ↓ 等待时间长 ↓ Streaming ↓ 流式过程可能失败 ↓ State ↓ 任务复杂 ↓ Agent真正优秀的系统设计,不是提前知道所有技术。
而是在问题出现后:
发现问题 ↓ 拆解问题 ↓ 设计方案 ↓ 发现新问题 ↓ 继续抽象最终形成完整架构。
一个成熟的 Chat 系统,不是一次设计出来的。
而是在不断解决问题的过程中,被逐渐推导出来的。
```