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 结束,而不是无限等待。

重启恢复需要什么

至少持久化:

消息历史只解决模型“看见什么”,不能单独解决 worker 重启后“哪些动作已经发生”。

本章自测

send_email 超时后能否重试?答案取决于邮件服务是否支持幂等发送或能否查询业务结果,而不取决于模型是否再次请求它。

下一章:模型想做危险的事时谁来暂停?

进入 keel 阅读