2019年,Elizabeth Smart在健美比赛舞台上头发被树枝缠住,她扯掉假发继续微笑。后来她说:“我的身体承载了我,我不想再为它感到羞耻。”她把创伤称为“绕路”(detour)——一条你没计划过、也不想要的路,但你可以选择怎么走完它。
作为做Agent系统的开发者,我在这段故事里看到了我们一直在解决的核心问题:当Agent的执行路径被意外中断时,它应该怎么办?
多数Agent框架(比如AutoGPT、BabyAGI)在工具调用失败后只会重试几次,然后卡死或返回错误。但真正有用的Agent,应该像Elizabeth那样——把意外当成重新规划的信号,而不是任务终止。 下面是我在几个生产级Agent项目中验证过的做法。
失败不是错误,是信号
大多数Agent的实现里,规划器生成步骤序列,执行器按顺序调用工具。如果工具返回错误,常见处理是:重试N次、返回默认值、或直接崩溃。
问题在于:工具失败的原因可能是外部环境变化(比如API限流),也可能是原本的规划假设错了。 这时候重试没有意义,需要的是重新规划。

我的做法是:在记忆模块里维护一个“失败日志”,每次工具调用失败后,记录三样东西:
- 失败时的完整上下文(步骤号、输入参数、错误信息)
- 当前执行到哪一步
- 失败前成功完成的所有步骤
执行器不直接重试,而是把失败日志传给规划器,让规划器决定是否要“绕路”。
核心实现:DetourPlanner
下面伪代码展示核心逻辑(完整可运行版本在我的GitHub仓库中):
class DetourPlanner:
def __init__(self, llm, memory):
self.llm = llm
self.memory = memory # 包含成功步骤和失败日志
def plan_with_recovery(self, objective, failure_log):
# 1. 将失败日志还原为结构化信息
failed_step = failure_log["step"]
error_info = failure_log["error"]
completed_steps = self.memory.get_completed_steps()
# 2. 构造新的规划提示:告诉LLM“之前的假设导致失败,需要替代路径”
prompt = f"""Objective: {objective}
已完成步骤:{completed_steps}
第{failed_step}步因{error_info}失败。
请提供一个替代方案(detour)来继续完成任务,要求:
- 不能依赖失败的步骤假设
- 利用已完成的成果
- 如果失败步骤是工具调用,考虑使用不同工具或改变参数
"""
new_plan = self.llm.generate(prompt)
# 3. 将新计划插入到原计划中,覆盖失败点之后的部分
self.memory.update_plan(new_plan, insert_after=failed_step-1)
return new_plan
# 使用时
try:
result = execute_step(current_step)
except ToolError as e:
failure_log = {
"step": current_step_index,
"error": str(e),
"context": get_step_context()
}
new_plan = planner.plan_with_recovery(objective, failure_log)
# 继续执行新计划
关键点:规划器拿到失败日志后,不是简单重试,而是要求LLM生成一条新路径。 这个新路径可以跳过失败工具、换一个API、甚至改变任务拆解方式。
踩坑记录:别让Agent陷入循环
最早版本里,我们没有限制规划器绕路的次数。结果Agent在同一个失败点反复生成新路径,每次都失败,变成死循环。解决方案:在记忆里增加“失败历史计数器”,同一目标下如果超过3次不同的绕路仍然失败,则降级为“最大努力完成”——跳过该步骤,用默认值替代,并在最终汇报里标记异常。
另外,要区分暂时性失败和永久性失败。暂时性失败(如网络超时)应该重试2次后再绕路;永久性失败(如API密钥无效)应直接绕路。判断方式:看错误是否包含“retryable”特征。
更进一步:动态代价感知
现实场景中,绕路可能增加成本(时间/金钱)。我曾在电商Agent中引入代价函数:每次绕路前,估算新路径的执行成本,并与“放弃该子任务”的成本比较。如果绕路成本超过预期收益的30%,就放弃该子任务,重新调整整体目标优先级。
类似Elizabeth选择撕掉假发继续微笑——有时候放弃一部分,比强行修补更优雅。
你的Agent也该学会绕路
下周你写Agent时,可以试试这个改动:
- 把失败日志结构化存入记忆;
- 失败后让规划器生成替代路径,而不是重试;
- 设置绕路次数上限并监控代价。
这样你的Agent就不再是个脆皮对话机器人,而是能像人一样——被绊倒之后,拍拍土,换条路继续走。