即使有周密的规划和明确的目标,LLM代理在尝试执行任务时也可能遇到问题。工具可能失效,信息可能无法获得,或者LLM本身可能误解了某个中间步骤。提供了代理可以用来应对这些简单执行失败的基本策略,以提升其可靠性和用户友好度。执行中为何会发生失败执行障碍是代理运行的正常部分,尤其是在与外部系统交互或依赖LLM对每一步的理解时。造成这些中断的一些常见原因包括:LLM误解: 在计划的任何阶段,LLM都可能误解特定步骤的指令,或者生成的动作与当前情境不太匹配。工具问题: 外部工具,例如搜索API、数据库连接或计算器功能,可能暂时不可用。它也可能返回意料之外的错误,这可能是由于代理提供的输入格式不正确,或者工具端出现了问题。例如,如果天气工具被提供了拼写错误的城市名称,或者其自身服务出现故障,它可能会失效。环境变化: 代理与之交互的环境并非总是静态的。它预期要读取的文件可能已被移动或删除,或者它需要访问的网站可能暂时离线或改变了结构。模糊的中间目标: 如果多步骤计划中的某个步骤没有定义得足够清晰,代理可能难以正确执行它,从而导致错误或无益的结果。理解这些潜在的失败点是构建更具弹性的代理的第一步。应对失败的简单策略当代理出现问题时,有几种基本的恢复或报告策略可以带来很大的不同。识别和记录问题在代理能够处理失败之前,它必须首先识别到有失败发生。正如我们之前讨论如何追踪任务执行时所提及的,彻底的日志记录是很必要的。当代理尝试执行一个动作,尤其是涉及外部工具的动作时,它应该记录:预期的动作或导致该动作的thought。被调用的特定tool及其获得的input。收到的原始observation,即工具的输出或错误信息。这些记录的信息不仅仅是为了供您(开发者)稍后调试问题。它可以作为LLM下一个推理周期的一部分反馈给LLM,使其能够理解哪里出了问题,并可能自我修正。简单的重试有时,最简单的解决方案就是再次尝试相同的动作。这种策略对于临时性的、短暂的问题特别有效,例如代理尝试调用API时短暂的网络故障。运作方式: 如果工具调用因可能是临时性的错误(例如超时)而失败,代理可以被编程为等待一小段时间(例如几秒钟),然后再次尝试完全相同的调用。何时使用: 这最适合那些在第二次尝试时无需任何更改就有合理机会成功的错误。重要考量: 限制重试次数很重要。如果问题持续存在,代理不应无限期尝试。常见做法是允许2或3次重试,如果动作仍然失败,代理则应认为失败更严重,并尝试不同的策略或报告问题。下图描述了一个包含重试机制的动作尝试基本流程。digraph G { rankdir=TB; bgcolor="transparent"; node [shape=box, style="rounded,filled", fontname="Arial", fontsize=10, margin="0.25,0.1", fillcolor="#e9ecef", color="#495057"]; edge [fontname="Arial", fontsize=9, color="#495057"]; Start [label="请求代理动作", fillcolor="#a5d8ff"]; AttemptAction [label="尝试动作\n(例如,调用工具)", fillcolor="#bac8ff"]; CheckSuccess [label="动作成功?", shape=diamond, fillcolor="#ffec99"]; Success [label="继续下一步", fillcolor="#b2f2bb"]; Failure [label="动作失败", fillcolor="#ffc9c9"]; LogFailure [label="记录失败详情"]; RetryDecision [label="重试次数 < 最大重试次数?", shape=diamond, fillcolor="#ffec99"]; IncrementRetry [label="增加重试计数\n短暂等待"]; ReportError [label="报告错误 / 停止任务", fillcolor="#f03e3e", fontcolor="#ffffff"]; Start -> AttemptAction; AttemptAction -> CheckSuccess; CheckSuccess -> Success [label="是"]; CheckSuccess -> Failure [label="否"]; Failure -> LogFailure; LogFailure -> RetryDecision; RetryDecision -> IncrementRetry [label="是"]; IncrementRetry -> AttemptAction; RetryDecision -> ReportError [label="否"]; }一个动作尝试流程,在初始失败时包含重试循环。使用工具的错误消息当工具以非短暂的方式失败时,它通常会提供错误消息。这个消息非常有价值。代理不应该直接放弃,而是可以将其作为observation的一部分传回给LLM。运作方式: LLM作为其下一个推理步骤(其“思考”过程)的一部分,接收错误消息。例如,如果代理使用search_product(product_name)工具,它返回“错误:产品类别未指定”,LLM可以分析这一点。LLM的作用: 根据错误,LLM可能:如果它理解原因,尝试修正输入。对于上面的例子,如果它能推断出类别,它可能会尝试search_product(product_name="laptop", category="electronics")。如果当前工具看起来不合适,或者错误表明缺少某种功能,决定使用不同的工具。如果它自己无法解决错误,它可以报告特定错误,这比通用的失败消息有用得多。考虑一个被赋予执行计算任务的代理:5除以0。目标: 计算 $5 / 0$。计划: 使用calculator工具,操作为divide,数字为5和0。动作: 代理尝试calculator.divide(numerator=5, denominator=0)。工具输出 (Observation): “错误:除以零未定义。”代理的下一步(反馈给LLM): LLM收到:“Observation: 计算器工具失败,并显示消息:'错误:除以零未定义。'”LLM思考: “计算 $5 / 0$ 无法执行,因为除以零是数学错误。我无法直接满足此请求。我应该将此问题告知用户。”代理输出: “我无法计算5除以0,因为除以零不是有效的数学运算。”这是一个比代理简单停止或反复尝试不可能的计算要智能和有帮助得多的响应。定义回退或替代方法对于某些任务,可能存在多种达到目标的方式,有些比其他更可靠或更精确。如果代理的主要方法因简单重试或输入修正无法解决的原因而失败,它可以尝试预定义的替代方案。例子: 代理需要查找特定商品的当前价格。其主要方法可能是使用专门的PriceCheckAPI工具。如果此API不可用或返回“未找到商品”之类的错误,代理可以有一个回退策略:使用通用WebSearchTool在购物网站上搜索商品价格。这种回退方法结构性可能较差,但仍能获得所需信息。实现: 这要求您(代理设计者)做到:为代理提供多种可以达到类似结果的工具。在代理的指令(其主要提示词)或其编码控制流中包含逻辑,以便按优先顺序或根据遇到的失败类型尝试这些工具。优雅停止并清晰报告并非所有失败都能由基本代理自主解决。很重要的是,代理不会陷入无限尝试和失败的循环,从而消耗资源或让用户感到沮丧。最大尝试次数: 对于给定的子任务,始终对重试或替代方法设定限制。清晰报告: 如果代理耗尽其定义的策略,或遇到它无法处理的错误,它应该停止处理该特定任务或子任务,并清晰地报告情况。一份好的报告应包含:它试图实现什么。它尝试的最后一个动作。它遇到的特定错误消息(如果有的话)。一个表明它无法在该特定动作线上进一步进行的声明。这种信息丰富的失败比代理默默停止或返回模糊的错误要有用得多。提升弹性的提示您可以通过在其主要系统提示词中包含具体指令,来很大程度上影响代理如何处理失败。这些指令会指导LLM在遇到指示错误的observation时的推理过程。例如,您可以在代理的提示词中添加: “你是一个乐于助人的助手。当你使用工具时,如果它返回错误,请在你的思考过程中仔细分析错误消息。如果错误似乎是您输入中的小问题(例如,格式错误、您可以识别的拼写错误或缺少常见参数),请尝试纠正它,并使用修改后的输入再次尝试该动作,但对于该特定修正只尝试一次。如果工具似乎已停止运行,错误很复杂,或者您的修正尝试也失败了,请在此步骤中不要再次尝试该工具。清晰地报告错误,解释您正在尝试做什么,并表明您无法使用该工具完成该特定子任务。”这为LLM提供了基本的错误处理协议,鼓励一定程度的自我修正,同时确保它不会陷入困境。这些基本策略的局限性这里讨论的技术,包括重试、使用错误消息、简单的回退和清晰报告,旨在处理相对常见和直接的执行失败。它们相比完全没有错误处理的代理,能显著提高其可靠性。然而,这些是基本方法。它们无法解决所有问题,特别是:需要详尽诊断推理的复杂错误。失败原因无法从错误消息中明确的模糊情况。需要复杂多步恢复计划或动态重新规划的失败。更高级的代理设计包含更复杂的错误诊断、从过去失败中学习的机制以及更灵活的重新规划能力。这些是更高级学习的主题。目前,实施这些基本的故障处理方法将使您的第一个LLM代理在操作中更具实用性。