LLM Agent 生产化:从失败分类到实时检测与修复的实践指南
去年我做了一个“自动收集产品资料并生成竞品分析摘要”的实验项目。第一次跑通时整个流程顺畅得让人产生错觉模型完成了目标拆解、调用了搜索工具、最后输出了一份结构化报告。我一度以为这事就这么成了。真正让我改变判断的是把它变成定时任务放到真实环境之后。跑了两天问题接二连三地出现有一次模型返回的 JSON 被截断解析直接失败有一次它拿一个不存在的工具名反复尝试一个步骤烧掉了大量的 token还有一次整条链路没有报错但它输出了一份只有一句话、没有任何实际分析内容的“报告”。这个经历让我想清楚了一个问题LLM Agent 能不能生产化重点从来不是“能不能完成任务”而是它失败以后你有多快能发现、多低成本能恢复。换句话说LLM Agent 的稳定性本质上是一套实时检测和修复能力而不只是模型本身的能力。如果你也在把 LLM Agent 从 demo 推向真实工作流这篇文章会是一个可以参考的构建思路。我会从失败分类、实时检测、修复策略、落地框架和适用边界几个角度展开文中的代码和设计模式偏通用你可以结合自己的业务场景做取舍。1. 先定位问题Agent 失败不是一种情况而是一类问题很多人在排查 LLM Agent 故障时习惯用一个词来概括——“跑挂了”。但传统程序“挂掉”和 Agent “挂掉”之间有本质差异。传统程序出错时有调用栈、有报错信息LLM Agent 出错时可能没有任何异常甚至模型还会用非常合理的语言告诉你“任务已完成”。所以我建议你动手写检测逻辑之前先把 Agent 的失败做一次分类。分类的意义在于不同层级的失败需要完全不同的检测手段和修复动作。1.1 把失败拆成四层模型、工具、流程、环境从工程实践看LLM Agent 的失败大致可以分成四类。为了方便说明我用前面那个“生成竞品分析报告”的例子来做对照。第一类是模型层失败。这类失败直接来自 LLM 的输出质量。典型表现包括JSON 格式错误、输出被截断、字段类型不对、幻觉内容混进结果。比如模型本应返回一个包含“报告标题、分析纬度、结论”三个字段的 JSON结果它少返回一个字段或者把字符串写成了数组。这类失败往往不抛异常解析完才发现数据不对。第二类是工具层失败。Agent 需要调用外部工具或 API工具本身可能不存在、参数不匹配、执行超时或者外部服务返回了异常结构。比如模型调用“search_product”时把参数 count 写成了字符串工具层直接抛出类型错误。这类失败通常能捕获到明确报错但它会引发连锁反应——模型看到工具报错后很可能误判为“工具不存在”然后转向一个更不靠谱的工具。第三类是流程层失败。Agent 在执行多步任务时出现的循环、漏步骤、目标漂移和状态丢失都算这一类。最常见的例子是模型在同一个决策点上反复调用同一个工具每次只改一个无关紧要的参数看起来每次都不一样实际上没有任何进展。这类失败最难检测因为每一步单独看都是正常的但整个流程陷入了死循环。第四类是环境层失败。包括 API 配额耗尽、鉴权过期、网络波动、依赖版本被改动、上下文长度达到模型窗口上限等。这类失败通常不是模型的问题而是整个运行环境出了问题。四层失败经常连锁发生。比如环境层超时导致工具调用失败工具调用失败导致模型误判并产生流程循环流程循环又让上下文变长最后触发新的模型输出问题。这也是为什么“实时检测”不能只盯一层。1.2 为什么 Agent 的失败比传统程序更难排查传统程序里函数调用失败会抛异常日志里能看到完整的调用链。LLM Agent 的世界里你需要接受一个事实模型会“用合理的方式犯错”。它可以在根本不知道工具有哪些的情况下一本正经地发明一个工具名也可以在工具明确报错后把错误归因到网络问题然后选择重试同一个动作。更麻烦的是概率性。同样一段 prompt、同样一个任务模型这次能跑通下次未必能跑通。你很难通过“复现”来定位问题。有一次我在测试时遇到一个失败连续重试三次都成功第四次才又失败。这类偶发性失败你根本没法靠肉眼盯日志来排查。所以Agent 的可观测性必须被设计在流程里。你要记录的不只是“报错了没有”而是“模型每一步做了什么、工具的返回结果是什么、当前状态流转到了哪里”。只有拿到了这些语义层面的信息你才能判断一个失败是从哪一层开始的。2. 实时检测不要等整个任务失败才介入检测是修复的前提。如果你等任务全部跑完再检查最终结果一次失败的消耗可能已经非常大。我会建议把检测节点拆散贯穿 Agent 的整个执行生命周期。2.1 检测顺序先结构再语义最后业务很多人在做 LLM 输出校验时只做一步——能不能 JSON 解析。但真实场景里结构校验通过只是最基础的一层。我的建议是至少分三层做检测按顺序执行结构校验输出的 JSON 能否被解析必需字段是否存在字段类型是否正确这一步可以用 JSON Schema 或者 Pydantic 之类的工具做。语义校验字段的值是否合理比如工具名是否在已注册工具列表里步骤编号是否连续日期字段是否在合理范围业务校验结果是否真正满足任务目标这一步往往需要结合业务规则。比如“竞品分析报告”至少要包含两家竞品的信息并且每个维度都有内容。如果输出只有一句“已完成”结构校验和语义校验都看不出问题但业务校验能发现它是不合格的。这三层的优先级不能乱。结构不过关语义校验没有意义语义不过关业务校验的结果也不可信。2.2 用状态机看住 Agent 的全过程如果你把 Agent 的执行看成一个黑盒只在“开始”和“结束”两个点做检查那中间出现的任何问题你都看不到。更好的做法是给 Agent 的执行定义一个有限状态机。常见的状态集合可以是INIT初始化准备上下文PLANNING模型拆解任务、生成计划EXECUTING执行某个具体动作TOOL_CALLING正在调用外部工具VERIFYING对当前步骤结果做检测COMPLETED任务成功FAILED_REPAIRABLE出现可恢复失败FAILED_FATAL出现不可恢复失败在每个状态转换点你可以记录时间和上下文。一旦状态在某个节点停留过久或者反复在 COMPLETED 之前绕圈就说明流程可能有问题。状态机把 Agent 的执行过程从“只看结果”变成“可以看到过程”这是实时检测的一个基础能力。2.3 五个不能漏掉的监控信号除了结构校验和状态机还有五个信号值得重点监控。这些信号本身不代表失败但它们是失败的前兆。重试次数。模型在同一个步骤上反复重试通常是流程陷入循环的信号。我在实际项目里会让每次重试都带上“第几次”信息超过三次就进入检测流程而不是盲目继续。动作序列是否重复。比重试次数更隐蔽的问题是模型“换个说法做同一个事情”。这时候只统计次数还不够最好把“工具名 参数摘要”哈希后记录下来如果相同的动作签名在短时间内出现多次就触发预警。上下文长度。当上下文接近模型窗口上限时模型输出质量会明显下降甚至出现截断。提前监控上下文长度可以在溢出之前做压缩或摘要。单任务耗时和成本。Agent 任务不像单次 API 调用一次任务可能涉及几十次模型推理。如果成本增长异常往往意味着流程出了问题。成本阈值应该和任务价值匹配不能完全放开。工具调用失败率。如果短时间内某个工具连续失败大概率不是模型的问题而是外部服务或环境发生了变化。这时需要优先检查环境而不是反复让模型重试。注意检测逻辑别一开始就设计得特别复杂。先把“结构、语义、业务”三层校验和核心状态监控跑通再逐步加入动作重复检测、成本阈值等高级信号。3. 修复策略从重试到自愈检测只能告诉你“出问题了”真正决定 Agent 能不能稳定运行的是修复机制。但修复不是一个简单“失败就再来一次”的动作。修复要讲究分级、策略和边界。3.1 修复分级不是所有错误都值得同一个办法我在实践里会按严重程度和错误类型把修复动作分成几级。每一级都对应一个明确的触发条件和处理方式。错误是瞬时错误比如网络超时、API 限流这时候延迟几秒后重试往往就能解决。但做这类重试必须带上限不能无限重试。模型输出格式错误比如 JSON 解析失败。这时候直接把完整错误信息回传给模型并指向具体出错的位置让它重新生成。这个过程要保留历史上下文而不是完全重新开一个任务。工具参数校验失败比如模型把数字参数传成了字符串。这时可以把工具的报错信息原样返回给模型并附上工具的参数 Schema让模型自己修正。流程循环比如同一个动作重复执行多次。这时候不适合继续重试需要强制终止当前路径让模型重新进入规划阶段并且限制它不要再使用刚才的方案。上下文溢出比如长任务执行后上下文太长。修复策略是摘要压缩历史或者从最近一个检查点恢复。致命错误比如重试多次仍然失败、费用超限、或者业务规则校验不通过。这些场景不能靠自动修复硬扛应该直接转人工处理。3.2 反馈重试不是简单地说“再来一次”把错误信息回传给模型是整个自修复机制里最关键的环节。很多人只是把程序报错用字符串拼接起来发给模型这远远不够。正确的做法是给模型一套结构化的错误反馈至少包含三部分出错步骤的上下文、错误类型、以及可执行的修复建议。比如一个工具参数错误可以这样反馈当前工具名search_products期望参数{keyword: string, limit: integer}实际收到{keyword: 手机, limit: 3个}错误原因limit 应该是整数不是字符串修复要求只修正参数不要改变任务目标我用过的最有效反馈格式是把错误信息单独放在一个error_feedback字段里而不是混在对话历史中。这样模型能更清晰地定位问题而不是被一长串报错信息干扰。3.3 检查点机制让 Agent 的执行不是一场不可逆的赌博长任务最怕什么做到第八步挂了结果要从第一步重新来。这不仅浪费成本还增加了再次失败的概率。正确做法是给 Agent 的执行加入检查点。我把检查点理解为每当一个工具调用成功结束就把当前状态完整保存下来。状态包括已经完成的步骤列表、每步的产出、当前目标列表、上下文摘要。一旦任务失败就能从最近的检查点恢复而不是从头开始。状态快照的 JSON 大致是这个样子{ task_id: task_20250101_001, completed_steps: [step1_search, step2_extract], current_goal: 生成竞品分析报告, pending_steps: [step3_compare, step4_write_report], context_summary: 已经获取到A公司和B公司的产品信息各有3个核心维度..., checkpoint_time: 2025-01-01T12:30:00Z }有了这个机制后续修复会变得简单很多。模型可以在恢复时直接读取这条摘要继续执行剩余步骤。对于 LLM Agent 来说“从失败点继续”比“重新开始一个新任务”要可靠得多。3.4 什么时候必须让人介入自动修复不是万能的更不应该让系统无限尝试。我会在下面几种情况里直接转人工。修复次数超过上限。比如同一个错误已经自动修复 3 次仍然没有成功说明这个问题大概率超出了当前模型能力的边界。继续重试只是烧钱。检测到错误但无法定位。有时错误反馈本身不完整比如工具返回了一个空结果你不知道是数据源的问题还是参数的问题。这时再自动重试意义不大。任务涉及高风险决策。如果是财务报销、合同生成、对外发布之类的场景即便自动修复成功也应该先让人工确认。一个经验判断自动修复的目标是处理那些高频、低风险、可重复的错误而低频率、高影响、不可预测的错误适合直接交给人。不要在自动修复上追求 100% 的覆盖。4. 可落地的设计模式一个检测修复框架前面的讨论偏概念接下来给一个可以直接参考的工程框架。这个框架不绑定任何具体框架只抽象出五个核心组件。4.1 五个组件Monitor、Detector、Diagnoser、Repairer、Verifier我把检测修复流程拆成了五个角色Monitor监控器负责收集 Agent 执行过程中的事件包括模型的输出、工具调用记录、状态转换、耗时和成本等。Detector检测器基于 Monitor 收集的数据判断是否失败。Detector 输出的是结构化的失败信号比如“STEP_TOOL_CALL_ERROR”“OUTPUT_PARSE_ERROR”。Diagnoser诊断器根据失败信号分析失败原因和严重程度。它是修复策略的决策者。Repairer修复器执行实际的修复动作比如重试、反馈重试、上下文压缩、切换工具、转人工等。Verifier验证器修复完成后重新验证结果是否满足要求。只有通过 Verifier 的任务才算真正修复成功。这套设计的核心思想是“职责分离”。检测、诊断、修复、验证是四个不同的关注点如果全部写进一个大的try...except块里后续加策略会非常痛苦。4.2 一个最小实现骨架下面我用 Python 伪代码写一个最简化的运行时骨架便于你理解各组件如何协同。它不是生产级代码但你可以在此基础上扩展。from dataclasses import dataclass from enum import Enum class FailureLevel(Enum): TRANSIENT transient REPAIRABLE repairable FATAL fatal dataclass class RepairResult: success: bool final_state: object repair_actions: list[str] class AgentRuntime: def __init__(self, detector, diagnoser, repairer, verifier, max_repair_rounds3): self.detector detector self.diagnoser diagnoser self.repairer repairer self.verifier verifier self.max_repair_rounds max_repair_rounds def run_with_repair(self, task, stateNone): for round_no in range(self.max_repair_rounds 1): if state is None: state self.execute(task) else: state self.execute(task, init_statestate) failure self.detector.detect(state) if failure is None: return RepairResult(successTrue, final_statestate, repair_actions[]) diagnosis self.diagnoser.analyze(failure) if diagnosis.level FailureLevel.FATAL: return RepairResult(successFalse, final_statestate, repair_actions[escalate_to_human]) state self.repairer.repair(state, diagnosis) if not self.verifier.verify(state): continue # 验证通过但需要重新执行检查 return RepairResult(successFalse, final_statestate, repair_actions[max_repair_exceeded]) def execute(self, task, init_stateNone): # 这里是 Agent 的实际执行逻辑可以是 LangChain、AutoGPT 之类的自建 Runner raise NotImplementedError注意目标并不是让你照抄这个代码。我想强调的有两点一个是修复动作要记录到repair_actions后续复盘时可以知道系统到底做了哪些干预另一个是 Max repair rounds 必须存在防止流程进入无限修复的循环。4.3 参数调优为什么很多配置项不适合拉满框架搭好之后参数的设置会直接影响稳定性。下面几个参数是我在项目里反复调过的重试上限。不能设置成“不限制”。每多一次重试成本和故障时间都在增加。把重试上限调成 2 到 3 次同时把每次重试的反馈质量做高比无限重试更有效。单步超时。Agent 的不同步骤耗时差异很大。比如工具调用可能只要 2 秒但整个规划步骤可能要 30 秒。建议不要设置一个全局固定超时而是按动作类型分别设置。上下文长度阈值。一般建议在模型窗口上限的 70% 到 80% 处设置预警。不要等到 100% 溢出时才处理那时模型已经大概率会输出退化。成本上限。给单次任务设置一个成本阈值。超过之后自动触发修复或转人工可以避免一个失控任务把预算烧光。修复并发。如果系统同时处理大量 Agent 任务修复任务也要控制并发否则一次性大量重试可能会击穿外部 API 限流。4.4 用指标评估检测修复系统我见过不少团队把检测修复机制做得非常复杂但没有任何数据能证明它有效。要想知道这套机制有没有真正提升稳定性必须记录几个关键指标。首次成功率FSR不经过任何修复第一次执行就成功的比例。修复成功率RSR经历自动修复后最终成功的比例。平均恢复时间MTTR从失败发生到成功恢复的平均耗时。人工介入率失败任务中转人工的比例。这些指标最大的价值在于反推系统瓶颈。如果 FSR 很低说明问题不在修复而在模型选型、任务拆分或工具设计如果 RSR 很低说明修复策略本身需要改进如果人工介入率很高说明自动修复的覆盖度不够。实践建议刚开始做检测修复时可以把“记录失败类型 记录修复动作 记录最终结果”这三件事放在第一位。数据积累两周之后再决定优化哪个环节。5. 适用边界能修复失败但修复不了所有东西聊完设计思路也要认真说说边界。检测与修复机制能提升系统的可靠性但它不是银弹。我在实际项目中就吃过“把修复机制当成万能兜底”的亏。5.1 这套机制真正适合什么场景最适合的场景是这几类多步骤、长流程、工具调用频繁的 Agent。这类 Agent 的失败概率高但失败类型相对集中修复的价值也大。每一次成功的自动修复都能省下一次完整重跑的成本。自动化流水线中的定时任务。比如每天早上自动生成报表、自动同步数据、自动收集信息。这类任务没有人在旁边盯一旦失败必须能被系统自动发现并恢复。面向用户的自助工具。用户提交一个任务Agent 自动完成。如果中途失败好的修复机制可以让用户体验从“任务失败”变成“稍等片刻后成功完成”。5.2 这套机制不太适合什么场景单次短对话类应用。用户只问一个问题模型直接回答。这类场景失败率低即使失败用户重新提一次问题成本也不高。引入复杂的检测修复框架反而会拖慢响应速度。模型能力本身就撑不起业务场景。如果一个 Agent 用了小模型导致逻辑推理频繁出错再强的修复策略也只是不断反馈错误让它重新推理最终效果有限。这时候换更大的模型或重新设计任务拆分可能比修复合算。任务目标本身模糊。如果连人都说不清楚“成功”是什么样检测器就无法定义业务校验规则修复也就没有方向。这类场景先要解决任务定义问题。5.3 一个更底层的判断我现在的看法是检测与修复是稳定性体系中的“兜底层”而不是“主力层”。真正决定 Agent 是否稳定的往往是更早的设计环节——任务拆得是否足够细、工具是否设计得足够简单、输入是否做了完备校验、模型选择是否匹配场景。但兜底层依然不可或缺。因为再好的设计也避免不了概率性失败而有了检测和修复机制每一次失败都能变成一个改进信号。我建议你建立自己的“失败样本库”把每次失败的类型、上下文、修复动作和最终结果记录下来定期复盘。这些样本会成为你调优 prompt、优化工具设计和选择模型的重要依据也会让 Agent 系统从“单独跑通”真正走向“长期可用”。回到开头那个让我头疼的竞品分析 Agent。后来我给它加上了检查点、结构化错误反馈和循环检测它依然会失败但每次失败之后系统会告诉我“失败发生在哪一步、发生了什么、已经试过哪几种修复方式、还剩哪些风险”。这让我第一次觉得这个 Agent 是可以放心留在定时任务里跑的。LLM Agent 的可靠性不是“永不失败”而是“失败后可恢复、可观测、可改进”。把实时检测与修复当作一个正式的设计模块来建设才是 Agent 真正进入生产环境的那道门槛。