KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
09. 一个 Agent 失败后,团队怎样收束? — keel 龙骨
并行运行中,Change Agent 查询部署服务超时。此时 Metrics Agent 已经成功返回。你不能简单地把整次运行标成成功,也不能把已完成结果全部丢掉。
并行运行中,Change Agent 查询部署服务超时。此时 Metrics Agent 已经成功返回。你不能简单地把整次运行标成成功,也不能把已完成结果全部丢掉。
多 Agent 失败处理要回答三个问题:发生了什么、哪些结果仍可信、下一步是否安全。
先把失败分层
| 层级 | 例子 | 默认处理 |
|---|---|---|
| 协议失败 | task ID 不匹配、输出 schema 错误 | 拒绝结果,通常不重试原始内容 |
| Agent 失败 | 模型服务错误、输出无法解析 | 按任务类型和预算有限重试 |
| 工具失败 | 查询超时、外部 API 5xx | 由 Tool Calling 的错误和幂等策略处理 |
| 编排失败 | assignment 写入失败、状态冲突 | 恢复状态或安全终止 |
| 业务失败 | 没有找到负责人、证据不足 | 结构化返回,不一定是系统故障 |
| 结果未知 | 写动作超时,不知道是否已发生 | 先查询状态,不能盲目重试 |
“模型没有给出答案”和“数据库写入可能已经成功”不是同一种失败。
失败传播由任务必需性决定
metrics(required) -> succeeded
deployment(required) -> failed
owner(optional) -> succeeded
all_required 应进入 degraded 或 failed,并保留 metrics 与 owner 工件;best_effort 可以生成部分报告,但必须列出缺失的 deployment 证据。最终报告不能用“没有结果”掩盖任务失败。
Retry 应该发生在任务边界
重试整个 TeamRun 会重复成功任务,也可能重复现实动作。更安全的边界是:
task attempt 1 failed
-> 判断错误是否 retryable
-> 新建 attempt 2
-> 使用相同 task_id、不同 attempt_id
-> 重新验证剩余 deadline 和预算
可重试通常包括短暂网络错误、限流和模型服务暂时不可用;协议错误、权限拒绝和无效参数不能靠重试修复。
Agent 层幂等和 Tool 层幂等不同
Agent 层防止同一个分析任务产生多个互相冲突的 Artifact;Tool 层防止同一个现实动作产生多次业务效果。
task_id + attempt_id -> 任务执行关联
idempotency_key -> 业务动作去重
例如两次相同的只读分析可以接受相同内容;两次创建工单必须由业务唯一键或服务端幂等保证只产生一张工单。
Timeout、Deadline 和 Cancellation
timeout:某个 Agent 调用最多等待多久;deadline:整个 TeamRun 最晚什么时候结束;cancellation:用户或上游主动停止运行。
子任务 timeout 不能超过剩余 deadline。取消后:
- 不再创建新的任务;
- 尽可能通知正在运行的 Agent;
- 把迟到结果标记为 late,不写入已取消运行的最终状态;
- 若存在不可取消的外部操作,转入
outcome_unknown或人工处理。
Worker 崩溃与 lease
进程内示例可以直接捕获异常。生产 worker 可能在任务完成后、提交结果前崩溃,因此需要租约:
assigned -> lease(owner, expires_at)
worker heartbeat
completed result commit
lease released
租约过期允许其他 worker 接手,但不等于前一个 worker 已停止。提交结果时仍要用 attempt/version 条件,拒绝旧 worker 覆盖新结果。
失败轨迹至少要保留什么
task.failed
run_id
task_id
agent_name
attempt_id
error_code
retryable
elapsed_ms
input_artifact_refs
remaining_budget
敏感输入应脱敏或只保留引用,但不能为了隐私删除定位失败所需的因果信息。
本章实验
运行并行示例,让一个 Worker 返回失败:
python courses/advanced/multi-agent-collaboration/course/project/examples/03_parallel_team.py
检查:
- 其他成功 Artifact 是否仍可引用;
all_required和best_effort的最终状态是否不同;- 失败任务是否拥有稳定错误码;
- 运行是否在预算内停止。
检查理解
- 为什么不能因为一个可选任务失败就丢掉全部结果?
- 为什么重试 TeamRun 比重试单个 Task 危险?
- lease 过期为什么不代表旧 worker 已经停止?
- outcome unknown 为什么不能直接当作失败后重做?
下一章把“谁能做什么”从 prompt 中拿出来,建立真实的协作权限边界。