本节摘要:智能体没有记忆就是"失忆症患者"——上句问完下句忘。会话管理解决"记得住":用会话 ID 组织历史、在请求间传递上下文、让智能体跨轮保持连贯。本节讲清会话的基本概念、实现方式与设计要点。
阅读完本节,你应当能够:
"用户问'那刚才说的价格呢'——智能体一脸茫然"——这是无状态运行的尴尬。真实产品里,智能体需要"记得"前面的对话。会话管理就是把"刚才"存下来:每次请求带上会话 ID,SDK 自动拼接历史,智能体就有了"连续性"。
为什么会话比想象中重要?因为真实交互从来不是一问一答:用户会说"那第二个方案呢"、"改成明天"、"价格再低点行吗",这些句子单独看都不完整,只有结合历史才能理解。没有会话管理的智能体,做不了任何真实的业务对话——这是从"演示"走向"产品"的分水岭。
会话 = 按 ID 组织的一组历史消息。每次请求取历史、拼上下文、处理完再存——这就是"记忆"的机制。
| 类型 | 内容 | 范围 | 例子 |
|---|---|---|---|
| 对话记忆 | 本会话的历史 | 会话内 | 刚才问过什么 |
| 用户记忆 | 用户偏好画像 | 跨会话 | 喜欢简洁回答 |
对话记忆解决"这一轮聊得顺",用户记忆解决"下次来还认识你"。生产级助手通常两者都要:对话记忆靠会话历史,用户记忆靠独立的用户画像存储。
from agents import Agent, Runner agent = Agent( name="购物助手", instructions="帮用户挑选商品,记住用户已经表达过的偏好。", ) # 第一次请求 r1 = Runner.run_sync(agent, "我想买一台笔记本,预算五千以内。", session_id="user-1001") # 第二次请求:带上同一个 session_id,助手记得预算 r2 = Runner.run_sync(agent, "那推荐一款办公用的吧。", session_id="user-1001") print(r2.final_output)
session_id 是会话的钥匙:同一个 ID 共享历史,不同 ID 互不干扰。在 Web 服务里,通常用"用户 ID + 会话编号"拼接成 session_id,这样既能区分用户,又能区分同一用户的多次会话。
| 状态 | 存什么 | 放哪 |
|---|---|---|
| 对话历史 | 消息序列 | 会话存储 |
| 用户信息 | 偏好、身份 | 用户画像库 |
| 业务状态 | 订单、进度 | 业务数据库 |
经验法则:对话历史跟着会话走,用户信息跟着用户走,业务状态跟着业务走。不要把业务状态塞进对话历史——模型上下文放不下,也不该放下。
历史越长 → 上下文越大 → 成本越高 策略:滚动窗口(只留最近 N 轮) 策略:摘要压缩(历史转摘要) 策略:分层记忆(重要长期存,其余会话内)
三个策略可以组合:最近 10 轮原文保留,更早的压成摘要,关键事实(用户预算、订单号)单独提取存入结构化字段。
💡 关键直觉:记忆是"选择性保留"——全记住成本爆炸,全忘掉体验崩塌。按重要性分层:核心信息长期存,细节随会话滚动。
⚠️ 常见坑:无限保留历史。长对话会撑爆上下文、烧光成本——设上限、做摘要,让记忆"够用且可控"。
⚠️ 常见坑:会话 ID 泄露串号。如果 session_id 是用户可篡改的(比如直接传用户 ID),别人就能"接上"你的对话——服务端要校验会话归属,别把不该暴露的信息带进上下文。
测连续性:跨轮引用是否记得("那刚才说的价格呢") 测一致性:改口后是否跟得上("还是选第一个吧") 测上限:长对话是否退化(50 轮后是否胡言乱语) 测隔离:不同会话是否串号(A 的对话不能被 B 看到)
排错思路:先按 session_id 找到会话,再打开该会话某次运行的 Trace 两者配合:会话给"上下文",追踪给"过程"
生产环境排查用户问题,标准动作就是:用 session_id 还原现场,用 trace_id 看过程。所以设计阶段就要把两个 ID 都记进日志。
记得住了,下一节开口说话——语音交互支持。