Session:多轮会话怎么管理?

上一节,我们已经把 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:多轮会话怎么管理?-大赛人网

这张图里有一个很重要的边界: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:多轮会话怎么管理?-大赛人网

Session 生命周期:

图片[3]-Session:多轮会话怎么管理?-大赛人网

生命周期如果只看几个字符串状态,初学时很容易把 CLOSED、EXPIRED、DELETED 混在一起。把状态转换画出来以后,语义就清楚很多:

图片[4]-Session:多轮会话怎么管理?-大赛人网

可以看到,CLOSED 和 EXPIRED 都不等于“数据没了”,它们仍然可能被显式恢复;真正进入 DELETED 才意味着数据被删除。也正因为这些状态的恢复能力不同,实际系统里不太适合只用一个 active=False 来代替完整生命周期。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发
头像-大赛人网
欢迎您留下宝贵的见解!
提交
头像-大赛人网

昵称

取消
昵称

    请登录后查看评论内容