可靠性机制

Agent 怎样在中断后仍保持一致?

可靠性不是简单地 catch 所有错误。系统要区分取消请求与真正静止、把局部失败变成可记录结果、保持事件边界完整,并从日志重建模型历史与请求配置。错误可以发生,但不能让下一步建立在含糊状态上。

问题 01

调用 cancel() 后,为什么不能立刻认为 Agent 已停止?

答案:cancel() 发出取消意图并中止当前活动的 AbortSignal;真正停止仍需要模型流、工具和子资源协作响应,已启动的工具要被排空,生命周期事件要完整落下。只有这些拥有者都完成收尾,系统才达到静止状态。

取消是传播协议,不是同步赋值。没有活动时 cancel 是 no-op,也不会预先武装下一次工作;keepInbox 只保留未开始输入,当前活动仍会中止。

资源拥有者的义务:dispose 不仅要发出 kill 或 abort,还要等待子进程、监听器和后台任务退出;否则“主对象已销毁”与“真实资源仍在运行”会同时发生。

问题 02

局部异常为什么不应该破坏整个 Agent?

答案:模型供应商失败、工具业务失败、监听器缺陷和调度器内部错误并不是同一类结果。系统在各自拥有的边界归一化它们:预期的外部失败成为可记录的终止 chunk 或 tool result;真正的框架缺陷继续抛出并关闭当前边界,但不能污染后续队列。

模型请求失败

适配器可抛错或产生 error / aborted finish;LLM Runtime 对消费方暴露统一的终止形式。

工具执行失败

失败被归一化为 isError: true 的工具结果,模型能读取反馈并决定补救。

观察者失败

通知型回调的异常由分发器隔离,不能饿死后续监听器或反向破坏核心 Promise。

关键不是“永不抛错”,而是每类失败只影响它拥有的操作区间,并留下明确、可判断的结束事实。

问题 03

上下文压缩等于删除旧消息吗?

答案:不是。原始事件仍保留在追加式日志中;压缩创建一条摘要消息,并用 surfaceOp: replace 在模型可见 Surface 上替换一段旧节点。这样模型读取更短的历史,同时回放、审计和恢复仍知道摘要替代了哪些事实。

日志中的 compaction/start、summary、end 记录操作生命周期;真正进入模型历史的是带 replace 操作的摘要 user/message。

为什么要 replace 而不是 append:只追加摘要会让模型同时看到摘要和全部旧内容,既没有降低 token,也可能让重复叙述产生冲突。

问题 04

恢复会话时,怎样避免下一次请求悄悄变化?

答案:恢复从持久事件创建新的 Session 生命周期:Surface 操作重新折叠出当前消息,最新 request/header 恢复调用配置、系统提示和工具 schema;新的循环实例再记录 resume 快照。运行时不变量比较实际请求与日志重建结果。

恢复并不是把旧 JSON 直接塞回模型;它重新执行同一套投影规则。格式不认识时应尽早拒绝,而不是用不完整兼容逻辑继续。