第 6 课:让 Agent 记住对话
6.1 你的目标
多轮对话中,AI 能记住前面说了什么:
You: 查一下订单 ORD-001
AI: 您的订单 ORD-001(智能蓝牙耳机 Pro)已发货
You: 这个保修多久? ← 用户期望 AI 知道说的是"耳机"
AI: 智能蓝牙耳机 Pro 提供 12 个月质保。 ← 没忘!
6.2 问题和解决方案
为什么 AI 会忘?
每次请求的 state["messages"] 都是空列表。Agent 没有上下文,每次都是"第一次见到用户"。
解法:把历史消息传进去
python
# main.py 中
sessions: dict[str, list] = defaultdict(list)
conv_id = req.conversation_id or str(uuid.uuid4())
history = sessions[conv_id]
initial_state = {
"user_message": req.message,
"messages": history, # ← 把历史传进去!
...
}
result = agent_graph.invoke(initial_state)
# 保存本轮对话
history.append({"role": "user", "content": req.message})
history.append({"role": "assistant", "content": result["final_response"]})
为什么不能存所有历史?
聊 50 轮后,history 会有 100 条消息,几千个 token。LLM 的上下文窗口是有限的。
解法:滑动窗口
python
MAX_HISTORY = 10 # 最多保留 10 轮
def save_history(conv_id, user_msg, reply):
history = sessions[conv_id]
history.append({"role": "user", "content": user_msg})
history.append({"role": "assistant", "content": reply})
# 只保留最近 10 轮
if len(history) > MAX_HISTORY * 2:
sessions[conv_id] = history[-MAX_HISTORY * 2:]
为什么是 10 轮? 这不是一个固定的答案。取决于你的业务场景:
- 客服对话通常 3-5 轮解决问题,10 轮足够
- 如果是长周期跟进(如售后多次沟通),可能需要更多
6.3 Agents 怎么使用历史
之前每个 Agent 的 LLM 调用只传 user_message,现在加上历史:
python
def tool_node(state):
history = state.get("messages", []) # ← 拿到历史
msg = call_llm(
messages=[
{"role": "system", "content": TOOL_PROMPT},
*history, # ← 展开到 prompt 中
{"role": "user", "content": state["user_message"]},
],
tools=TOOLS,
)
Router Agent 看到历史后,能理解"这个"指的是什么。Tool Agent 看到历史后,知道用户之前已经提供过订单号。
6.4 内存存储的局限
当前会话存在 Python 进程的内存里。服务重启后所有会话丢失。
生产环境应该用 Redis 或数据库存储会话:
python
# 当前(内存)
sessions: dict[str, list] = defaultdict(list)
# 生产(Redis)
import redis
r = redis.Redis()
history = json.loads(r.get(f"session:{conv_id}") or "[]")
但第 6 课的重点是理解"有状态"这个模式,而不是具体的存储方案。
6.5 三种记忆策略对比
| 方案 | 实现复杂度 | 信息保留 | Token消耗 | 适用场景 |
|---|---|---|---|---|
| 滑动窗口 | 低 | 丢失早期信息 | 可控 | 短对话(<20轮) |
| 摘要压缩 | 中 | 保留核心信息 | 低 | 中等长度对话 |
| 向量检索记忆 | 高 | 几乎不丢失 | 中 | 超长对话、知识型对话 |
本课使用滑动窗口,因为简单且适配电商客服的场景。
本课知识点
| 概念 | 你做了什么 | 为什么 |
|---|---|---|
| 有状态 | conversation_id + 历史存储 | LLM 无状态,上下文全靠 messages 传 |
| 滑动窗口 | 保留最近 N 轮 | Token 消耗有上限,不会撑爆窗口 |
| 历史注入 | history 展开到 messages 里 | 每个 Agent 都能参考上文 |
课后作业
- 把 MAX_HISTORY 改成 2,看第 3 轮还能不能记住第 1 轮的信息
- 给 sessions 加一个过期时间(比如 30 分钟不活跃就删除)
面试可能会问
"Agent 系统的会话管理和传统 Web 应用的 Session 有什么不同?"
Web Session 存的是用户登录状态。Agent 存的是对话历史(messages 数组),而且影响 LLM 的推理质量。管理不好 Agent 就会"失忆"。