跳到正文
Elaine Blog
返回

执行过程怎样交给用户:事件流、断线重连与取消

更新于:
Agent Runtime

用户点击“申请退款”,页面显示正在处理,随后网络断开。十分钟后重新打开页面,系统应该知道发生了什么。只把模型输出逐字推送给浏览器,不能回答这个问题:浏览器收到的最后一句话可能是“正在退款”,而支付已经成功。

Runtime 需要同时处理两种进展:让人感受到系统正在工作,以及让人能够确认业务发生了什么。前者可以短暂,后者必须能够重新读取。

Token 流不等于任务历史

模型生成“我正在核对订单”时,应用可以把 Token 转发到界面。这是一段展示内容,不是订单已经核对完成的证明。即使整句话生成完毕,后续工具仍可能失败。

持久业务事件表达已经提交的状态变化,例如 task.created、approval.accepted、payment.reconciling、task.completed。它们应来自运行时或业务执行器,而不是解析模型自然语言推断。

以 A1042 为例,界面可以临时显示“正在提交退款”,但只有收到包含支付回执的完成状态,才显示“已退款 299 元”。支付超时则显示“结果正在核对”,不能把连接错误直接转换成“退款失败”。

这并不要求保存每一个 Token。可以保存最终回答、必要的工具调用摘要与业务事件,再根据成本决定是否保留原始流。审计需要的是可验证的行为记录,不是无限保存所有调试文本。

一个任务内怎样排序

给任务事件分配单调递增的 seq。事件唯一标识可以是 event ID,展示顺序可以是 task ID 加 seq;二者用途不同。

{
  "task_id": "T17",
  "seq": 8,
  "type": "payment.reconciling",
  "payload": {"operation_id": "O17", "reason": "response_lost"}
}

seq 应在持久化事务中分配。若两个 Worker 先各自在内存里读取“当前最大序号”,再写入下一条,就可能冲突。配套 SQLite 示例在写事务持锁期间分配,并用复合主键保护;生产数据库可以使用任务行锁或其他明确的并发控制。

一个任务内有序,不代表所有任务都有一个经济且必要的全局顺序。跨任务因果关系可以用 parent task ID、correlation ID 和业务版本表达,不必为了界面排序引入全局串行瓶颈。

断线后怎样接上

客户端保存最后应用成功的 seq,例如 7。重连请求从 7 之后读取,服务端返回 8、9、10。客户端可能再次收到 7 或 8,因此渲染端也应按标识去重,避免重复插入同一条进度。

“应用成功”意味着本地状态已经更新,不只是网络库读到了字节。若先保存游标再更新界面,中途崩溃会跳过尚未展示的事件。浏览器通常可以通过重新读取任务快照修正,但仍应明确恢复顺序。

SSE 的 Last-Event-ID 可以携带恢复游标;WebSocket 也可以设计相同机制。两种传输方式本身都不会替应用保存业务事件。恢复能力来自后端存储和游标协议。

快照与增量怎样避免漏消息

直接“先查询快照,再开始订阅”,两步之间可能发生新事件。若订阅仅转发之后的新消息,就会漏掉间隙。

一种设计是:快照返回其覆盖的 seq=N,订阅从 N 之后开始补读持久日志,然后进入实时推送。实时通知只用于提醒有更新,最终仍能从存储补齐。另一种设计在服务端将订阅与快照读取协调起来,但也要说清竞态怎样关闭。

如果日志已清理,客户端请求的旧游标不能被静默当作最新位置。服务端返回“需要重新获取快照”,客户端重建当前状态。保留时间、归档和审计读取可以有不同策略。

用户离开页面后,任务要不要停

浏览器断开连接通常不应取消业务任务。用户可能只是切换网络,退款申请仍然有效。连接生命周期与任务生命周期必须分开。

取消应是一个明确命令。它先被记录成 cancel_requested,再由执行流程在可安全停止的边界检查。等待人工时可以取消;正在调用支付且结果未知时,需要核对后才能确定终态。

考虑两条时间线:

取消先被执行器确认 → 尚未发送支付 → canceled
支付已经提交 → 取消请求到达 → 查询回执 → completed,并记录取消来晚

停止本地协程或杀掉 Worker 只说明本地不再等待,不能撤回远端已经接收的请求。真正支持撤销的外部系统,需要独立撤销协议;补偿也是新的业务动作。

慢客户端不能拖住执行器

若用户网络很慢,Token 缓冲不断增长,不能让执行器无限等待浏览器读取。可以合并展示增量、限制内存队列,必要时断开连接并要求重连补读。

关键业务事件先持久化,推送失败不回滚已经完成的业务。执行队列、事件发布与浏览器连接分别设置容量和限流,避免一个慢连接占住稀缺模型或 Worker 资源。

命令行示例下载提供 events 命令,按任务和游标查询已经提交的事件。它没有实现 SSE 服务,目的是先把恢复协议背后的存储语义讲清。多个 Agent 参与同一任务时,这些事件还需要区分父子任务,下一篇继续展开。


分享这篇文章:

上一篇
Worker 怎样调度任务:队列、租约、心跳与背压
下一篇
多 Agent 怎样运行:子任务生命周期、并行与失败传播