BLOGE
0.9.8-RC1在线版 · 事实校验 2026-09-15 · English
第 14 章 —— 多轮 Session
承诺: 读完本章后,你将知道什么时候应该从一次性 graph 升级到
session(多轮交互会话),如何用ONCE/ROUND两类 phase 建模多轮交互,以及如何让整段交互在重启、超时和恢复之后仍然保持清晰。
学习目标
- 区分“只挂起一次的 graph”和“跨越多次信号、多段 phase 边界的
session”。 - 把
session建模成一组有序的 phase,并理解ONCE与ROUND的职责边界。 - 使用
ctx.round.input、yield_on、until和then来表达真实的多轮交互。 - 配置空闲超时、历史保留、所有权和恢复逻辑,而不丢失运行时心智模型。
- 知道什么时候
session是正确抽象,什么时候 第 12 章 或 第 13 章 里的普通 graph 仍然更简单。
前置条件
- 第 12 章 —— 等待世界的回应 —— 你需要先有挂起 / 信号的心智模型
- 第 13 章 —— 持久执行 —— session 建立在同一套检查点和恢复基础之上
- 第 7 章 —— 设计良好的 Operator —— 多轮交互只有在 operator 边界清晰时才会保持可读
源示例
| 文件 | 展示内容 |
|---|---|
ch13/customer-service-session.bloge | 典型 session DSL:问候 → 多轮分诊 → 处理 → 收尾 |
ch13/interactive-review-session.bloge | 更小的 collect → review 轮次 → finalize 模式,用于本章引导式重写 |
CustomerServiceSessionExample.java | 用 PhaseBuilder.once(...) / PhaseBuilder.round(...) 构建同一个 session 的 Java Fluent API 版本 |
bloge-session-ext/README.md | 内存 session 运行时、手动恢复边界和嵌套状态机说明 |
docs/session-phase-round-specification.md | session / phase / round 的精确 DSL 与运行时契约 |
为什么这很重要
在 第 12 章 中,你已经学会了让一张 graph 挂起,然后在稍后恢复。这已经能解决很多真实工作:等待审批、等待支付、等待外部事件。
但有些工作流不 是“一个 graph + 一次等待”,而是一段真正的对话式交互:
- 先打招呼
- 再问更多细节
- 等用户回复
- 不够清楚时继续追问
- 最后转人工或结束对话
同样的行为也可以用 await、分支和上下文拼装在一张 graph 中表达。代价是对话身份、轮次边界和恢复状态仍隐含在 graph 结构里,不容易检查和解释。
session 的价值就在这里:它把“多轮交互本身”提升为一等运行时模型。你不再把所有轮次都压进一张巨大 DAG,而是明确写出:
- 哪些步骤只执行一次
- 哪些步骤会按轮次重复
- 哪些信号属于同一段业务交互
- 这段交互该如何超时、恢复和继续推进
先读对话,再读 Session 模型
客户说包裹显示已送达,但自己没有收到。助手读取事实、问一个收窄问题、收到 回答,再把工单交给人工路径。Session 要保留的是这段四轮交换,而不是一个 抽象的“支持聊天”目标。
每个对话事实只翻译一次
| 对话事实 | Session owner | 为什么保留 |
|---|---|---|
| 工单与客户 identity | Session context | 每一轮都稳定 |
| 当前客户消息 | ctx.round.input.userMessage | 只属于当前 round |
助手回答与 done | respond.output | 决定 yield 与退出 |
action=handoff | phase transition 条件 | 把 owner 从 triage 交给 solve |
| 最终处理结果 | wrap-up output | 给调用方稳定的 terminal result |
第 2 轮在 respond 后 yield,因此调用方能显示问题,而 Session 仍停留在
triage。第 3 轮回答成为下一次 round input。第 4 轮返回 done=true 与
action=handoff,phase 才迁移到 solve;它不会因为模型文本里写了“转人工”
就暗中修改工单。
现在术语有了存在理由:phase 负责一个对话阶段,round 负责一次重复
交换,yield_on 标出外部可见暂停,until 说明重复何时结束。