案例分析二:Data Analysis Agent 同一 Session 内执行三个 Run,为什么 Session 和 Run 必须分开

场景背景

业务用户问,“昨天收入为什么下降?”

Run 1:

确认整体异常

Agent 得出:

收入 -20%
eCPM -35%

用户继续,“继续看看是哪个媒体。”

Run 2:

按媒体下钻

得出:

media_B 是主要异常来源

用户再说,“那再按广告位拆。”

Run 3:

最终定位:

position_17 eCPM 异常

如果 Session 和 Run 是一个东西

每次 Run 都新开独立 ID。

那么 Run 2 很可能拿不到 Run 1 的:

收入下降
eCPM 异常

除非用户反复重新描述。

正确结构

Session:
sess_ads_001

Working Memory:
- 收入下降 20%
- eCPM 下降 35%
- media_B 主要异常
- 当前继续按广告位下钻

Runs:
- run_001 overall
- run_002 media
- run_003 position

Session 保存长期上下文。

每个 Run 保存自己的执行生命周期。

结果

同一个会话可以不断深化。

而每个 Run 又可以独立统计:

耗时
Step
Token
错误
状态

这就是为什么后面 Run Manager 必须独立出来。

常见误区

误解: Session 就是把 messages 存起来,其他状态都可以重新算。
正解: 对普通聊天来说,messages 可能已经够用;但 Agent 还需要 Working Memory、Tool History、Run History、状态和更新时间。只恢复 messages,模型仍然可能需要重新从大量历史提炼当前任务状态,也无法知道前面有哪些 Tool 已经执行过。Session 更准确的定义是“会话状态容器”,而不是“聊天记录数组”。

误解: 一个用户只需要一个 Session,直接用 user_id 当 session_id 最简单。
正解: 同一个用户可能同时处理多个项目和多个任务。如果 user_id 等于 session_id,就会把不同上下文混在一起,例如 Coding Agent 和 Data Analysis Agent 的历史互相污染。更合理是 user_id 表示用户身份,session_id 表示某一段独立会话,一个用户可以拥有多个 Session。

误解: Run 完成以后 Session 就应该自动关闭。
正解: Run 只代表一次任务执行结束,用户可能马上在同一上下文里继续追问。例如“分析完以后继续修”“查完媒体以后继续按广告位拆”。如果 Run 完成就关闭 Session,会破坏多轮连续性。Session 应该由用户主动关闭、超时策略或生命周期规则决定,而不是简单绑定某个 Run 的完成状态。

误解: close_session() 和 delete_session() 是一回事。
正解: 关闭表示 Session 不再接受新的写入,但历史仍然可以保留、读取甚至显式恢复;删除则意味着数据真正移除。真实产品通常会保留关闭会话用于历史回看,所以生命周期里应该明确区分 ACTIVE、CLOSED、EXPIRED、DELETED 等状态,而不是一个布尔值全部解决。

误解: Working Memory 既然已经在 Session 里,就没必要每个 Run 再考虑自己的状态。
正解: 当前课程为了简化,把 Working Memory 先挂在 Session 上。但复杂系统里一个 Session 可以包含多个 Run,不同 Run 有自己的 Goal、Step、Error 和生命周期。后面会进一步拆成 Session-level Context 与 Run-level State。现在先建立 Session 容器,是为了后续演进时不会推翻整体架构。

误解: 内存字典版 SessionManager 能工作,就已经可以直接用于生产。
正解: 内存版只适合教学与本地 Demo。服务重启后数据会丢失,多进程部署时不同 Worker 也看不到彼此内存。真实服务需要持久化 Store,例如 SQLite、MySQL、PostgreSQL 或缓存层,并考虑并发更新、版本控制和过期策略。本节重点是接口与数据模型,后面会正式做持久化。

误解: 只要 session_id 足够随机,拿到它的人就一定有权访问会话。
正解: 随机 ID 只是难猜的定位符,不是授权凭据。服务端仍要把 Session 与用户或租户关联,并在读取、追加消息、恢复和关闭时检查归属。否则链接、日志或浏览器历史里一旦泄漏 ID,其他人就可能读到不属于自己的上下文。

误解: 客户端请求超时后原样重试,不会影响 Session 内容。
正解: 超时不等于服务端没有执行。第一次写入可能已经完成,只是响应丢失;直接重试会重复追加消息或创建 Run。写请求应携带独立的幂等键,服务端识别相同请求并返回已有结果。

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

昵称

取消
昵称

    请登录后查看评论内容