ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI Agent错误处理与工程化实践:从能跑到扛得住

AI Agent错误处理与工程化实践:从能跑到扛得住

做Agent开发的朋友应该都有同感:写一个能跑通的Demo不难,难的是让它稳定、可控、出了问题还能快速定位。我见过太多项目卡在“本地能跑、上线就妖”的阶段,本质问题往往不在模型能力,而在错误处理和工程化基建没有跟上。这篇是Agent系列的第9.4篇,标题就聚焦在这两件事上:一是Agent运行中到底会踩到哪些坑,二是怎么用工程手段把这些坑填平。开发AI Agent、做Agent框架选型,或者正在被“Agent执行到一半诡异报错”折磨的同学,这篇应该能帮你少走不少弯路。

1. Agent出错和普通程序出错,完全是两回事

很多从传统后端转来做Agent的朋友,第一个不适应的地方就是:错误处理怎么这么难搞?以前写接口,参数不对返回400,逻辑异常抛异常,数据库连不上直接报超时,错误类型清晰、链路明确。但Agent不是这样的,它的错误通常不是“一个明确的异常”,而是“行为偏离预期”,而且往往没有任何堆栈给你看。

传统程序是确定性系统,同样的输入走同样的代码路径,结果可复现。Agent是概率性系统,模型每次生成都有随机性,工具调用的参数可能是错的,步骤的顺序可能是错的,甚至模型会“幻觉”出一个根本不存在的工具执行结果。这就意味着,你不能用传统“try-catch + 日志 + 告警”三板斧处理Agent的错误,得建立一套更立体的容错体系。

举一个最常见的例子:Agent执行多步任务,第一步调天气API拿到结果,第二步根据天气结果做分析。看起来很简单对吧,但实际运行中模型可能把天气API返回的JSON理解错、可能跳过了第二步直接给结论、可能第一步重试了五次把token烧干净了、还可能工具本身超时但模型告诉你“调用成功”了。这些都不是“崩溃型错误”,但都会让整个任务失败,而且失败原因埋在十几次模型调用和工具执行里,查询成本极高。

所以我一直建议团队在架构Agent时,先建立一套“错误分层”的思维模型。不要把Agent当成一个大函数,而是把它拆成几个有明确职责的层次,每一层独立处理自己的错误。我通常分四层:LLM模型层、工具执行层、编排逻辑层、上下文管理层。模型层处理输出格式不稳定、token超限的问题;工具层处理超时、限流、参数非法的问题;编排层处理循环、死锁、路由错误的问题;上下文管理层处理信息丢失、记忆污染的问题。

这四层的关系大致像流水线:编排逻辑调用模型,模型决定调用工具,工具返回结果写回上下文,上下文又影响下一步的决策。任何一个环节出错,都可能在下一步被放大。如果不分层治理,错误会像滚雪球一样从一个小瑕疵膨胀成整个链路的失败。下面几节我按这四层逐一展开讲。

2. 错误分层:LLM层、工具层、编排层、上下文层各有什么坑

2.1 LLM层:模型输出不听话怎么办

LLM层的错误,核心是“模型的输出和预期格式/逻辑不一致”。这不是bug,是模型的天性。大模型是概率生成器,不是编译器,你没法保证它100%输出合法的JSON、100%遵循你给的指令模板、100%不重复同一个动作。

实践中我遇到得最多的是工具调用参数解析失败。现在主流Agent框架都支持function calling,模型会输出一个结构化的工具调用请求,底层通常是JSON。但实测下来,即便是GPT-4级别的模型,在复杂场景下也会输出格式不完整的JSON,比如字段名被截断、多了一个逗号、字符串里的引号没转义。一旦解析失败,整个步骤就卡死了。

我处理这个问题的方式是三管齐下。第一层是容错解析器:不要用JSON.parse一把梭,写一个能容忍常见格式错误的小解析器,比如自动补全缺失的引号、去掉注释、提取最外层花括号。第二层是自纠错重试:解析失败后,把原始错误信息作为prompt的一部分回传给模型,要求它“根据错误修正输出”,实测成功率能有90%以上。第三层是few-shot锚定:在system message里放一个目标工具的精确输出示例,让模型有所参照,能显著降低畸形输出的概率。

还有一个容易被忽略的点:长上下文中模型对最新指令的遵循度会下降。有研究表明,越靠近上下文末尾的指令,模型的遵循概率越高。所以如果Agent有“当前任务清单”这种东西,我建议放在上下文的末尾,而不是开头,效果会好很多。

2.2 工具层:超时、限流和“假成功”

工具层是另一个重灾区。这里的“工具”泛指Agent能调用的一切外部资源:HTTP API、数据库查询、代码解释器、文件系统操作,甚至另一个Agent服务。工具层的错误通常很“工程化”——超时、限流、参数校验失败、数据格式不兼容。

超时是最常见的坑。外部API响应时长是不可控的,尤其现在很多Agent要调用的工具本身就是一个LLM服务,响应时间可能从几百毫秒到几十秒不等。如果Agent框架里的工具执行没有超时机制,一个卡住的请求会占住整个Agent的执行线程,连锁拖垮整个任务。

我的建议是给每个工具调用设置独立的超时时间,并且要分场景配置。简单的query类工具,3到5秒超时足够;涉及RAG检索的可以放宽到10秒;调用另一个Agent或复杂工作流的,才允许到30秒以上。超时后不要直接判定任务失败,可以降级处理——比如缓存命中失败就跳过缓存读主库,主源不可用就切换到备用源。

限流是第二个高频问题。很多外部API有QPS限制,Agent在循环里快速调用同一接口时特别容易触发。React模式里模型发现自己信息不够,会反复调用同一个搜索工具,可能在几秒钟内打上十几次请求,直接触发429。

限流的应对除了指数退避重试之外,我强烈建议在框架层面做请求合并和缓存。比如同一个查询条件在短时间内(30秒内)重复出现,直接返回上一次的结果或者并发合并成一个请求,既降了延迟也避免触发限流。另外重试本身也要做jitter,就是用随机化的退避间隔,避免多个Agent实例同时重试形成“重试风暴”。

还要警惕“假成功”。有些Agent框架在工具调用后只检查HTTP状态码,只要不是4xx、5xx就算成功,然后把返回内容塞给模型。但实际上有些API会在HTTP 200的body里返回业务错误,比如支付接口返回“余额不足”但状态码还是200。如果只按状态码判定,模型就会基于错误的数据继续推理,整个后续步骤都是错的。

所以工具执行结果的判定逻辑要升级为一个标准化的包一层,统一做状态码校验、body格式校验、业务结果校验,只有完整通过才标记为成功,并且把原始body、处理后的结构化数据和校验结果一并存进日志。这样出了问题能回放,也方便后面排查。

2.3 编排层:死循环、重复动作、错误路由

编排层是Agent的“大脑中枢”,负责决定下一步执行什么。这一层的错误往往最隐蔽,因为代码逻辑本身没有bug,但Agent陷入了死循环或者不停地重复同一个动作。

典型的循环场景是这样的:Agent的任务是“查询A城市本周的天气并给出出行建议”,它先调用了天气API,得到数据。但随后模型可能觉得“我还需要空气质量数据来提高建议质量”,于是再次调用天气API想顺带拿空气质量。发现没拿到,又换个说法再查一次。几次下来,token消耗涨了三倍,任务还是没结束。

解决循环问题,业界有标准的三板斧:最大步数限制、重复动作检测、语义相似度检测。最大步数最简单,在Agent启动时设定一个上限,比如最多20步,超过就强制终止,返回已完成的部分结果。重复动作检测是记录每一步的“动作+入参hash”,如果连续N步的hash相同或高度相似,就触发保护机制。语义相似度检测更智能一些,判断模型当前要执行的动作和目标是否已经达成,如果已经达成,就引导它收敛输出而不是继续探索。

终止条件本身是编排层需要精细设计的。不能只有“成功”和“失败”两种状态,我想分享一个三态模型:完成(目标达成,可以输出最终结果)、无法完成(目标不可达,如实告知用户并给出已有的部分结果或替代建议)、需要协助(模型已尽力但还需要用户输入信息才能继续)。这三个状态要显式地成为Agent输出协议的一部分,而不是让模型自由发挥。实测下来,显式定义好终止条件能让任务在一半的步骤内收敛。

错误路由又是另一个问题。多Agent编排的时候,如果主Agent把任务错误地下发给了某个专长不匹配的子Agent,就会引发一连串无效执行。比如一个处理图片识别的任务,被发给了擅长文本总结的Agent,后者要么瞎猜答案,要么反复请求重新分配任务。这个问题我建议在编排层加一层“路由前置校验”,中心Agent在决定调用哪个子Agent之前,先让一个轻量级分类器做校验,判断任务类型是否匹配子Agent的能力声明,不匹配就不分发,直接重新规划。

2.4 上下文层:上下文溢出,记忆坍塌

上下文管理是Agent开发中最容易被低估的一环。模型输入长度有限、输出质量受上下文长度影响,而Agent每执行一步,工具返回的数据和中间推理过程都在往上下文里堆。堆到后面,要么触发token上限直接报错,要么信息过载导致模型“选择困难”,开始胡言乱语。

如果你用的是OpenAI的API,最直接感受就是context_length_exceeded错误。这个错误名很直白,但实际触发原因没那么简单,不一定是总量超了,可能是单条消息太大,比如工具返回了一个几万字符的完整数据库表,直接把输入窗口塞爆。

应对策略核心是“分层压缩”。我的一套做法是:感知层面用摘要,把工具返回的原始数据先用一个小模型压缩成关键信息摘要(比如“共返回128条记录,匹配关键词'故障'的有39条,取前5条如下”),再把摘要放回上下文。记忆层面用滚动窗口,最近的N步交互完整保留,更早的交互改写为持续推进的进展摘要。决策层面锁定“上层目标”,把系统提示词中的任务目标、进度状态单独维护,不随工具结果滚掉,保证模型随时知道自己在干什么。

还有一个经常被忽视的坑是JSON截断。工具返回的数据如果在写入上下文时被框架截断,但截断后又没有标记“此处有内容被省略”,模型不知道数据不完整,可能会基于残缺数据下结论。这个必须在工具结果包装层做防护,检测到截断就显式追加一行“数据已截断,下列仅为前K条记录”,阻断模型产生错误前提。

3. 工程化核心:从“能跑”到“扛得住”

好,说完了错误分层,聊工程化。Agent的工程化和传统后端有相似之处,但有几个特殊点,我总结下来最核心的是这四件事:并发架构、可观测性、弹性和回归保障。

3.1 并发:Agent请求到底怎么扛

先说并发。“AI Agent怎么扛并发”这个话题最近在技术社区讨论得很热。Agent请求和普通HTTP请求完全不是一个量级——普通请求可能几百毫秒就返回了,一个Agent任务动辄几十秒到几分钟,期间要调用多次模型、多个工具。如果每个Agent请求独占一个线程,那么8核机器同时跑的Agent任务数量会非常有限,在线程池满之前系统就已经被拖垮了。

我建议的架构思路是“非阻塞 + 事件驱动”。Agent执行的每个阶段,比如“调用模型 → 模型返回 → 执行工具 → 工具返回”,都是IO密集型的,都可以异步化。把Agent执行器设计成状态机,每个Agent实例不是一个线程,而是一组状态转移的注册信息。收到用户请求时,创建一个任务实例并注册到任务管理器,模型响应到达后通过回调/事件触发下一步状态转移。

这套方案实战中确实让服务的承载量提升了不止一个量级。很多相对成熟的Agent框架,用的就是这类模型——AsyncAgents、任务队列配合Worker池。Worker只负责任务调度,不阻塞等待单个Agent的完整生命周期。简单说,你的目标应该是让系统“同时处理1000个Agent任务”,而不是“同时运行1000个Agent执行流程”。

另一个和并发紧密相关的问题是饱和控制。Agent服务特别怕突发流量,因为每增加一个并发Agent任务,就意味着对模型API的调用量、对下游工具的压力成比例上涨。如果下游限流,整个Agent链路的失败率会暴涨。所以我在生产环境里都会加一层“入口闸门”:维护一个滑动窗口的并发任务计数和平均步数预测,计算出当前系统的饱和水位,超过阈值就对入口返回“繁忙,请稍后再试”,而不是让任务涌入后大面积超时失败。

3.2 超时预算、重试和幂等:Agent工程化的三大支柱

Agent调用链格外的长,从用户请求到最终回复,中间隔了模型API、工具API,可能还有子Agent的内部链路。这种情况下,超时预算体系尤为重要。我的做法是给整个任务分配一个总预算,比如60秒,然后逐层往下拆分:模型调用占40%,工具调用占40%,编排开销占10%,预留10%。每一层有自己的超时时间,嵌套组合起来不超过总预算。

单次工具调用超时重试时,重试次数和退避策略也要纳入预算。假设一个工具调用分配了8秒预算,首次调用4秒超时,剩余4秒还能支持一次快速重试。如果重试也失败,就不再纠结这个工具,直接跳过或走降级路径。很多人的Agent卡死是因为重试逻辑写得太“慷慨”,一重试就是三次,每次等满超时时间,预算被吃掉一大半。

幂等性则是重试的基石。工具调用如果会产生副作用,比如发送邮件、扣费、写入数据,就必须支持幂等。实现方式是调用方生成一个agent_run_id加step_id的组合作为幂等键,透传给下游工具。下游工具先查这个幂等键是否处理过,处理过就返回上一次的结果,不重复执行副作用。

我踩过一个很真实的坑:支付回调场景下,Agent调用支付工具超时了,框架自动重试,结果用户被扣了两次费。排查下来就是因为支付工具没有做幂等校验,工具层只检查了“请求是否到达”,没检查“这个请求是否已完成”。把这个案例写进你们团队的教育手册里,你们能少踩很多次坑。

3.3 弹性:降级、隔离与快速失败

Agent系统的外部依赖非常多,任何一个依赖抖一下,都可能引发Agent任务的连锁失败。所以工程化上必须做好弹性设计。我的原则是“快速失败,优雅降级”。

快速失败的意思是,不要在无效的地方消耗时间。如果模型API连续返回5xx或超时,不要重试到死,而是快速返回一个可理解的错误。如果某个工具连续失败多次,就把它的状态标记为退化,倾向于直接用规则替代或者跳过。优雅降级则是说,某个步骤失败后,Agent不要整体失败,而是基于已有信息给出最多可用的答案。

依赖隔离是另一个容易被忽视的点。如果多个Agent任务共享同一个工具连接池,一个工具出问题可能导致所有Agent任务排队。我建议按工具维度做独立的连接池、独立的超时配置、独立的熔断器。某个工具的熔断器打开后,只影响使用这个工具的Agent分支,不影响全局。

3.4 “脚手架式Agent”:把不确定性关进笼子里

讲一个架构层面的心得。很多人写Agent追求“完全自主”——模型自己决定一切。但工程实践告诉我,完全自主 = 完全不可控。你看到的“codex不会发消息”、“Agent执行异常终止”这类问题,根源往往是模型在不该自主的时候做了自主决策。

所以我在推荐“脚手架式Agent”的架构哲学,核心是:确定性逻辑写进代码,不确定性推理交给模型。用代码控制流程的骨架——任务解析、工具注册、权限边界、终止门槛全部硬编码。模型只负责两个纯推理动作:决策——选哪个工具、下一步做什么;生成——写回复内容或生成结构化参数。然后整个Agent的执行是一个明确定义的有限状态机,模型在每个状态里输出一个“受限动作”,代码校验动作合法性后执行。

这其实呼应了热词里那个“手写React Agent”的讨论。React模式的本质就是Reasoning(推理)+ Acting(行动)循环,但如果你完全交给模型自由发挥,那它会在推理和行动之间反复横跳。正确的做法是把循环次数、行动参数规模、行动顺序都编进代码,模型只是在代码搭好的轨道里做选择。

还有权限边界的工程化实现。要给Agent的工具调用设置白名单,不是所有工具都能随时调用。写操作的工具必须走审批流,敏感数据的读取工具要做字段级脱敏。这个权限控制放在Agent框架的“中间件”层统一实现,不要指望模型自己“自律”。

3.5 配置管理:面向多环境可切换的策略组合

Agent工程化的另外一个关键基础是配置管理要跟上。不同的环境(开发、测试、生产)要使用不同的模型配置、不同的工具地址和不同的提示词策略。原因很简单:你在开发环境用GPT-4o跑通了Agent,不代表生产环境用某个更快的模型也能同样稳定。模型替换、环境参数变化都会直接改变Agent的响应质量。

所以配置管理的核心是“策略包”而不是“配置文件”。每个环境有一整套配置:模型参数(temperature、top_p、max_tokens)、工具超时、重试策略、提示词版本、工具降级顺序。上线前在灰度环境跑一遍完整的预发测试,用固定的评测用例集对比每个候选配置的完成率、耗时、token消耗,选指标最优的配置发布生产。

3.6 验证与评测:Enough with “看起来能跑”

工程化再往后,是“验证”。Agent不能像传统代码那样只测正常路径和异常路径,因为Agent的输出空间是开放的。业界逐渐形成的共识是三种验证手段并行:

  • 基于规则的断言:跑完Agent任务后,用一组预定义的规则检查输出。比如“输出包含指定的关键字段”“没有调用被禁止的工具”“步骤数小于上限”。
  • 基于模型的评估:用另一个模型给Agent的输出打分,评估指标包括正确性、完整性、有用性。这比规则覆盖的维度更广,但评估模型本身也有误差,最好还是用经典评估标准配上几个标注样本校准。
  • 错误注入测试:主动构造故障场景验证弹性设计。比如先把某个工具地址改成不存在的端口,再跑一遍典型任务,看Agent能不能正常降级;或者把模型API的响应速度调慢到5倍,看超时链路能不能正常触发。这些测试都是传统后端没有的,但对Agent相当关键。

还有一种验证值得单独提:用户反馈闭环。Agent上线后,要对每一次任务记录用户反馈(满意/不满意),定期拉取不满意样本,人工分析失败模式,再反馈为新的few-shot样本或规则修补进系统。

4. 可观测性:没有Trace,你就等着痛苦吧

Agent开发最痛苦的事情是什么?不是模型不给力,是出了问题你不知道它干了什么。传统程序的日志是一行一行的方法调用栈,Agent的“运行日志”本质上是整条思考链:模型的每一轮思考、每一次工具调用、每一个中间结论。它既是调试的依据,也是判断失败原因的唯一线索。所以可观测性建设得花大力气。

4.1 结构化日志:记录决策链,而不是只记状态码

Agent的日志记录要求比普通后端高得多。我在生产环境的结构化日志字段大致长这样:

字段含义
trace_id一次完整Agent任务的唯一ID
task_name任务名,对应配置里的哪个场景
step_index当前是第几步
agent_state当前状态(thinking、calling_tool、tool_finished)
model_input_preview发送给模型的输入摘要(截断)
model_output模型的完整输出(尽力保留)
tool_name / tool_params / tool_result工具名、参数、结果摘要
error_type错误类型(格式错误、超时、限流、循环检测等)
lantency_ms / cost_token耗时和token消耗
version代码版本和提示词版本

这套日志方案的好处是,你可以在任何一个环节点开日志,完整还原模型当时看到了什么、做了什么决定、为什么导致最终结果不对。我之前排查过一个“Agent告诉我们某个文件已删除但实际没删”的诡异问题——如果不是Step 5的日志显示模型在调用删除接口时把路径参数拼错了,这种问题靠猜是永远定位不到的。

4.2 追踪与回放:把Agent拉回现场

光是结构化日志还不够,Agent的问题往往需要“回放”才能定位。所谓回放,就是把一次任务里所有步骤的输入输出完整保存,然后离线重现整个执行过程,配合调试器逐帧观察。这有点像前端的浏览器DevTools里的Network面板,只不过记录的是“模型每一轮想了什么、干了什么”。

实现回放我觉得不难,但有个细节要注意:只记录输出还不够,要把每次调用模型的完整输入也存档,包括系统提示词、历史对话截断后的内容、工具返回的结果。没有这些,你回放的时候只能看到模型“做了一件蠢事”,但看不到它为什么做。数据量大不是问题,用对象存储做冷存即可,按trace_id建索引,留30天够了。

做好回放之后,我甚至会在本地写一个“时间旅行调试器”:指定一个trace_id,加载这趟任务的所有快照,可以逐步向前或向后翻阅模型的每一步决策,并在任何一步上“分支重放”——修改这一步的输入然后重新从这个节点生成后续结果。这个工具的内部价值极高,新同学上手排障的时候特别有用。

4.3 指标与告警:别等用户来告诉你,出事了

可观测性第三层是指标和告警。要盯的指标几类,我列一个实用清单:

  • 任务层面:成功率、平均步数、平均Token消耗、超时率、用户满意度评分。
  • 模型层面:模型调用失败率、平均首token延迟、上下文长度分布。
  • 工具层面:每个工具的调用成功率、平均耗时、熔断器状态。
  • 资源层面:并发Agent数量、任务队列深度、API调用配额消耗。

告警阈值要用心定。我踩过的坑是把阈值定太死,结果误报太多,团队都麻木了。比如“模型失败率升高到5%”不一定值得告警,一次正常的服务滚动更新就会触发。但是“任务成功率连续5分钟低于80%伴随平均步数翻倍”这类组合指标,就非常值得告警,因为它往往预示着模型行为发生了系统性偏移。

4.4 灰度发布与回滚:Agent版本更新的安全网

Agent的更新太频繁了,提示词调一句话、模型升个版本、工具加个参数,都可能让行为大变。所以灰度发布对Agent项目来说不是加分项,而是必需品。

我的做法是:把“版本”绑定到整个Agent的定义上,代码版本 + 提示词版本 + 工具版本 + 模型版本,四者组成一个可发布的“策略单元”。发布时先切5%的流量新版本,跑一段时间,同时开着自动对比——同一个任务集分别跑旧版本和新版本,对比成功率、答案质量分、平均步数、平均费用。指标不劣化再逐步放大流量。发现任何异常,一键把配置切回旧版本,整个回滚操作不超过一分钟。

灰度发布还有一层作用:可以拿真实流量做A/B测试,验证某个新提示词策略的实际收益。比如你怀疑加一段“不要重复调用同一个工具”的指令能降低循环率,不要拍脑袋,直接在灰度中先试5%流量,跑一小时看真实数据再决定全量上不上。这种数据驱动的做法,比所有“专家经验”都稳。

5. 常见问题与排查技巧实录

最后整理一份高频问题的排查速查表,都是真实巡线场景里的经典案例,大家可以直接对照排障。

症状可能原因排查手段预防方案
Agent反复调用同一个工具循环检测未生效或阈值太高;模型对信息置信度低查看step日志中重复动作hash序列开启重复动作检测;在Prompt中显式声明“信息足够即停止”
模型断言“工具执行成功”但实际未调用模型“幻觉”了工具结果;工具结果校验不严对比工具日志与模型输出时间戳工具执行结果强制走结构化包裹层并校验;结果不落库不算成功
Token消耗异常爆炸上下文未压缩或循环步数过多查每步token记录和上下文长度分布引入滚动窗口与摘要压缩策略
任务正常但结果质量差提示词版本变更或模型升级对比新旧版本在固定评测集上的评分建立回归评测集,每次变更跑全量测试
某工具故障导致整个Agent失败缺少隔离与熔断机制查熔断器状态和依赖监控每个工具独立超时/限流/熔断配置
日志无法追溯到具体哪一步日志缺少trace_id或step_index检查日志结构和链路打通情况统一结构化字段,开发环境强制开启全链路trace
上线后同一类任务批量失败模型API限流/配额耗尽看API用量曲线和错误码入口闸门 + 配额管理 + 自动降级

再补充几个踩坑后特别想分享的经验。

第一个是关于重试的。重试不是越多越好,尤其调用模型API时,重试不仅烧钱,还会把延迟拉高,而且大多数失败重试也救不回来,因为模型服务的高负载不是短暂抖动,是持续性的。与其无限重试,不如快速失败触发降级策略。我现在的默认值是:首次失败后重试一次,带50ms起步、指数退避、上限2秒的间隔,两次都失败就放弃,交回编排层走降级。

第二个是关于循环检测的“谐振问题”。重复动作检测如果只比对“动作名 + 参数”的完全一致,会漏掉一类情况:Agent用不同的话术、不同的参数组合反复查询同一个信息,参数hash不同但意图相同。后来我加了语义近似检测:把动作意图embedding化,向量余弦相似度超过0.95且连续出现3次,就触发循环保护。效果有明显提升,但注意向量相似度的阈值要按场景调,太灵也会误杀合法分支。

第三个是关于回放日志的“版本对齐”。做回放的时候一定要记录代码版本、提示词版本、模型版本三者的标识。我遇到过因为提示词版本没记清,回放一个老trace时用新版提示词重现,怎么都对不上。把这些版本号写进trace的header字段,一条都不能少。否则你辛苦做出来的回放系统,在关键排障时刻反而会误导你。

还有一个非常现实的经验是:不要等到出事故了才做日志补全。Agent一旦在生产环境出问题,线路压力极大,你根本没有时间再去补埋点。我见过的成熟做法是在写Agent框架的初期就把“全量事件日志”作为基础能力内置:所有模型调用、工具调用、状态转移、错误捕捉全部自动记录,业务代码一行日志都不写,框架层全量兜底。宁可多存一些用不到的数据,也别漏掉关键排障信息。

结尾:工程化是在给不确定性上保险丝

做Agent做到这个阶段,我最大的体会是:问题往往不在模型的能力边界,而在系统能不能驾驭这种“概率性”本质——该等的等,该断的断,该退的退,每一步都有痕迹,每一处异常都有预案。与其试图把每一类错误穷举成规则,不如在架构层面搭好“保险丝”:超时止损、循环熔断、降级兜底、全链路可观测。这套东西越早做,后面踩的坑越少。

给刚开始做Agent工程化的团队一个建议:第一篇代码上线前,先把trace、结构化日志、循环保护、超时预算这四件事排进排期,不要指望“等出了问题再补”。Agent开发最贵的时间不是写代码,是排一个没有日志、没有trace、没有熔断的幸存者偏差系统。等你补完基建再回头看,那些让你头疼的“模型不听话”问题,一半以上其实可以被工程手段拐回正轨。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进