KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
08. 失败、取消和重启怎样保持可解释? — keel 龙骨
生产运行最危险的不是“明确失败”,而是“结果不确定”。例如创建工单请求超时,客户端不知道工单是否已经创建;立刻重试可能产生两张工单。
生产运行最危险的不是“明确失败”,而是“结果不确定”。例如创建工单请求超时,客户端不知道工单是否已经创建;立刻重试可能产生两张工单。
先区分三种时间限制
| 概念 | 管什么 | 例子 |
|---|---|---|
| Timeout | 一次模型或工具调用等待多久 | 查询最多等 2 秒 |
| Deadline | 整次运行最晚什么时候结束 | 本次诊断最多 30 秒 |
| Cancellation | 用户或上游主动停止 | 用户点击取消 |
局部 timeout 不能超过剩余 deadline。取消后仍可能有迟到结果,Harness 必须检查运行当前状态,不能让迟到结果把 cancelled 改回 completed。
错误要对应恢复动作
unknown_tool -> 拒绝并修正工具描述/模型决策
invalid_arguments -> 返回结构化错误,允许有限修正
policy_denied -> 终止,不能让模型绕过
tool_timeout -> 先判断副作用和结果是否可查询
tool_unavailable -> 按策略退避重试
outcome_unknown -> 查询状态或人工确认
错误分类不是日志装饰,它决定了系统能否安全重试。
幂等保护业务效果
请求发出
-> 服务端成功
-> 响应丢失
-> 客户端超时
-> 客户端重试
对于创建工单这类写操作,需要把业务请求绑定到幂等键,并持久化第一次结果:
idempotency_key = tenant + tool + stable_business_request_id
同一个 key 配上不同参数必须返回冲突,不能悄悄复用旧结果。
运行失败实验
运行工具调用项目中的 04_idempotency.py,用同一个 key 创建两次工单。第二次应该返回第一次的结果,而不是创建新工单。这个实验不需要真实模型,因为幂等是 Harness 与业务存储的确定性责任。
在 Harness 项目中,再让 fake model 永远请求工具,把 max_steps 设置为 2。你应该看到运行以 limit_reached 结束,而不是无限等待。
重启恢复需要什么
至少持久化:
run_id、当前状态、step 和 deadline;- 已提交的 Decision、Action、Result;
- 工具调用的
call_id和幂等记录; - 取消、审批和错误事件。
消息历史只解决模型“看见什么”,不能单独解决 worker 重启后“哪些动作已经发生”。
本章自测
send_email 超时后能否重试?答案取决于邮件服务是否支持幂等发送或能否查询业务结果,而不取决于模型是否再次请求它。