上一节,我们已经把 Working Memory 做出来了。
Agent 不再只依赖完整 Conversation History,而是可以用一份结构化短期认知记录:
{
"goal": "",
"plan": [],
"completed": [],
"errors": [],
"important_files": [],
"next_action": ""
}
这样一来,Agent 在一个 Run 里连续工作十几步,不需要每轮都重新理解“我做到哪里了”。
但很快你又会遇到一个更现实的问题。
用户今天上午和 Agent 聊了 20 分钟:
User:
帮我分析这个项目为什么测试失败。
Agent:
已经定位到 requirements.txt 缺少 requests,
目前下一步是修复依赖并重新跑 pytest。
然后用户关掉页面。
下午重新打开。
如果系统没有 Session,Agent 会像第一次见面一样:
“请告诉我你想做什么?”
那前面的:
messages
working_memory
tool_history
runs
全部没了。
所以多轮 Agent 系统必须再多一层,Session。
这一节我们要正式实现:
session_id
↓
messages
↓
working_memory
↓
tool_history
↓
runs
并设计一个:
SessionManager
支持:
创建 Session
恢复 Session
读取历史 Session
关闭 Session
从这一节开始,Agent 才真正具备“用户离开以后,还能继续回来接着做”的工程基础。
开场引入
我们先把场景做得更真实一点。
假设现在我们已经有一个 Coding Agent。
用户第一次打开页面:
POST /chat
message:
“帮我修复这个 Flask 项目启动失败问题。”
Agent 做了很多事:
list_files
read README.md
read app.py
run_shell("python3 app.py")
read requirements.txt
最终 Working Memory 变成:
Goal:
修复 Flask 项目启动失败
Completed:
- 已确认项目入口 app.py
- 已复现 ModuleNotFoundError
- 已确认 requirements.txt 缺少 requests
Errors:
- ModuleNotFoundError: requests
Important Files:
- app.py
- requirements.txt
Next Action:
补充依赖并重新验证
用户这时候说,“先到这里,我下午再继续。”
如果我们的所有状态都只存在:
state = AgentState(...)
这个 Python 进程里的内存对象,只能在当前进程还活着时继续使用。页面刷新或一次 HTTP 请求结束,不一定会清空服务端内存;但只要服务重启、切换到另一个 Worker,或者对象没有被稳定索引,状态仍然可能找不回来。后面说“恢复”,我们要同时问两件事:Session 还在不在,以及当前请求能不能定位到它。
下午用户回来以后说,“继续刚才那个问题。”
系统必须先回答一个问题,“刚才那个问题”到底是哪一个?
这就需要一个稳定 ID:
session_id
例如:
sess_8f19c2
用户每一次后续请求都带:
session_id=sess_8f19c2
系统就可以找到:
历史消息
Working Memory
Tool History
过去的 Run
当前 Session 状态
然后继续。
这里要非常注意一个常见误区,Session 不是简单的 messages 列表。
因为真实 Agent 会话除了 Conversation 之外,还需要很多状态:
用户说了什么
Agent 回了什么
Working Memory 现在是什么
之前调用过哪些 Tool
哪些 Run 已经完成
哪些 Run 失败
这个 Session 是否还活跃
最后更新时间是什么
所以一个更真实的 Session 对象应该类似:
Session(
session_id="sess_xxx",
messages=[...],
working_memory=...,
tool_history=[...],
runs=[...],
status="ACTIVE",
)
这里先不要把这些字段当成一张“数据表”去背。更容易理解的方式,是把 Session 看成一个长期存在的会话档案袋:session_id 负责定位,messages 保存原始对话,working_memory 保存当前认知,tool_history 和 runs 则记录真正发生过的动作。
![图片[1]-Session:多轮会话怎么管理?-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1534.png)
这张图里有一个很重要的边界:Session 负责保存状态,不负责执行任务。 调 LLM、跑 Tool、推进 Main Loop 仍然属于 Agent Engine 和 Tool Executor。把“状态”和“执行”拆开以后,后面无论做持久化还是服务化,都更容易演进。
我们还要再进一步区分,Session 和 Run 不是一回事。
一个 Session 可以持续几小时、几天,甚至被多次恢复。
而 Run 是,Session 里的一次具体任务执行。
比如:
Session:
“修复这个项目”
Run 1:
“先分析为什么测试失败”
Run 2:
“继续修复依赖”
Run 3:
“跑完整 pytest 并给我总结”
所以:
Session = 会话容器
Run = 一次任务生命周期
这个区别非常重要。
后面进入 Flask 服务化时,我们会专门实现 Run Manager。
这一节先把 Session 管好。
知识地图
![图片[2]-Session:多轮会话怎么管理?-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1535.png)
Session 生命周期:
![图片[3]-Session:多轮会话怎么管理?-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1536.png)
生命周期如果只看几个字符串状态,初学时很容易把 CLOSED、EXPIRED、DELETED 混在一起。把状态转换画出来以后,语义就清楚很多:
![图片[4]-Session:多轮会话怎么管理?-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1537.png)
可以看到,CLOSED 和 EXPIRED 都不等于“数据没了”,它们仍然可能被显式恢复;真正进入 DELETED 才意味着数据被删除。也正因为这些状态的恢复能力不同,实际系统里不太适合只用一个 active=False 来代替完整生命周期。
















请登录后查看评论内容