断线恢复、超时与终态

为什么需要

移动网络切换、浏览器休眠、电话转接、provider 连接时限和进程重启都会中断会话。“socket 重新打开”不能证明旧输出停止、上下文恢复或工具没有执行两次。没有显式终态的会话还会长期占用麦克风、资源和审批。

怎样实现

把恢复拆成三步,并分别留下证据:

  1. 传输恢复:重新建立 WebRTC/WebSocket/电话媒体路径;
  2. 会话恢复:使用短期、绑定用户/租户的 resume handle,协商最后确认的 event/sequence;
  3. 业务核对:从 durable event log/checkpoint 重建 turn、response、未决 call,查询副作用 receipt。

第 2 步成功后不是“恢复监听”,而是进入一个副作用核对门。该门只处理旧调用的查询、receipt 或明确的超时/人工交接,不接受新 turn、response 或写工具:

核对结论runtime 可做什么不能做什么
没有未决调用解除门禁,接受新工作把旧 response 当作仍可播放
有 receipt,结果为已提交/失败持久化结果、向用户说明已知状态,再按策略继续靠模型文字假定已回滚
确认未开始记录结论;若仍有业务需求,作为新的有授权动作发起自动重放旧写请求
unknown、receipt 冲突或权限失效保持门禁,转 needs_human 或受控 reconciliation接受新写工作、宣称结果确定

checkpoint 至少保存 session/version、最后已确认事件、活动 turn/response、播放 generation、未决工具及 intent digest、审批、deadline 和可接受终态。原始音频通常不应因方便恢复而默认长期保存;可保存受控指针、摘要或必要窗口,并按隐私策略到期。

断线时先冻结新副作用,取消/隔离旧 response 并让客户端清缓冲。重连后旧 generation 的 chunk 即使迟到也因 response ID/version 不匹配被丢弃。resume token 不是永久身份凭据;应有短期有效期、作用域、轮换和服务端验证。

终态至少区分:

  • completed:verifier 已证明目标完成;
  • canceled:用户/runtime 明确取消,副作用已核对;
  • timed_out:deadline 到期,未决动作进入 reconciliation;
  • failed:不可恢复错误并记录失败阶段;
  • needs_human:状态未知或风险不允许自动继续。

timeout 不是异常字符串,而是确定性状态迁移:停止继续生成/调用、清播放、持久化未决项、释放媒体资源,并向用户说明已知/未知边界。

常见失败

  • 只依赖供应商 session;其过期后审批、receipt 和业务进度一起丢失。
  • 重连后自动重放最后工具请求,造成重复扣款/预约。
  • 客户端断线但服务端仍生成并执行高风险动作。
  • resume token 写入可公开日志或长期存储,且不绑定用户/租户。
  • 把 timeout 标记为 failed 后直接丢弃未知副作用。

怎样验证

在关键 crash window 注入故障:提交 turn 前后、tool request 发出前后、外部 commit 前后、receipt 保存前后、response audio 缓冲期间。每次恢复都验证副作用次数、旧音频泄漏、未决状态、终态和资源释放。还要测试错误/过期/跨用户 token 与断线期间迟到事件。

实践任务

画出一个 10 分钟实时会话的 checkpoint 结构,并为“网络断线时付款状态 unknown”写恢复协议:哪些字段持久化、先查询谁、何时允许重试、何时转人工、用户听到什么。

动态实现样例与下一步

Google Live session management在 2026-07-18 展示了连接终止通知、session resumption handle 和 context compression;这些是产品机制,不替代应用 checkpoint。其他服务的有效期和兼容性可能完全不同。下一步:隐私、安全与信任边界。