一次 Agent 失败后,到底该改模型、Prompt 还是 Router?

0 阅读9分钟

一次 Agent 失败后,到底该改模型、Prompt 还是 Router?

图01

摘要:一条失败 Trace 往往同时暴露模型、Prompt、Router、工具合同和产品逻辑问题。本文给出四步归因顺序,并用 change_candidate 把可推翻的责任面假设、单一主要变化、固定上下文、评测版本和回退门槛绑定在一起。

关键词:Agent 失败归因、Run Trace、Prompt、Router、Regression Eval

目录

  • Trace 为什么不能直接指定修复组件
  • 官方产品为何把日志、评测与发布拆成不同对象
  • 工具、Prompt、Router、模型的四步排除顺序
  • change_candidate 最小记录
  • 发布前应检查什么

客服 Agent 收到“帮我查一下订单能不能退款”。它没有先查询订单状态,而是直接调用退款工具。工具返回权限错误后,Agent 又重试两次,最后回复用户“退款已提交”。

这条 Trace 里同时出现了四个问题:模型过早选择副作用工具,Prompt 没有强调先查后改,工具层允许同类参数重复提交,结果判定又只看到了模型的成功话术。复盘会上,每个人都能提出一个合理修复:改系统提示、换更强模型、让 Router 把退款请求送到专用 Agent、收紧工具 Schema,或者增加幂等保护。

如果五件事一起改,下一次回归通过也无法回答最重要的问题:到底是哪一项修复了失败,哪一项只是顺便变化,哪一项可能制造了新的回退。

图02

Trace 记录了发生什么,却没有替团队决定为什么

OpenAI Agents SDK 当前的 tracing 会记录模型生成、工具调用、handoff、guardrail 和自定义事件。OpenAI 的 Trace grading 又把评分对象扩展到端到端决策、工具调用和推理步骤,用于识别错误、比较变化和发现回归。

图03

这两个能力之间有一道经常被忽略的边界:Trace 是观察,grader 是判定。看到 refund_order 被调用,只能证明动作发生过;要判断它是否错误,还需要当时用户意图、订单状态、权限策略、正确动作和外部结果。即使 grader 判定整条轨迹失败,也没有自动证明应该换模型。

工具返回 403 可能是模型选错工具,也可能是权限配置漂移。重复调用可能是 Prompt 没写停止条件,也可能是工具响应没有明确返回“不可重试”。最终回复错误则可能来自模型,也可能是产品把“工具请求已发送”误标成“业务状态已完成”。

因此,第一步不是选修复方案,而是把“失败发生在哪”和“为什么发生”分开记录:

记录回答的问题例子
observed failure读者或系统实际看到了什么错误未退款却声称已提交
failed span哪个步骤最先偏离预期未查询订单便调用退款
attribution hypothesis当前认为哪个责任面导致偏离Prompt 缺少先决条件,或工具合同未阻止危险调用
disconfirming evidence什么现象会推翻这个判断相同 Prompt 在工具合同收紧后仍稳定失败

“归因假设”必须允许被推翻。只写一个 root_cause=model,很容易把团队带进先换模型、再解释数据的循环。

图04

官方产品都把 Trace 到更新拆成了多步

LangSmith 当前文档把生产 Run、dataset example 和 experiment 分成不同对象。生产 Run 有输入、输出和中间步骤,却通常没有 reference output;进入离线评测后,experiment 才会在同一 dataset 上比较不同 Prompt、模型或应用配置。

图05

Dataset 自身也有版本,筛选后的 Trace 需要被显式加入,而不是自动成为永久真相。

MLflow 的当前文档也使用“curate”描述从历史 Trace 构建评测集:先按失败、反馈或其他属性筛选,再补 expectation,然后用同一数据集比较不同 Prompt、模型或应用逻辑。

两套产品实现不同,却共同暴露了一个工程事实:线上日志、可判定样本、候选配置和实验结论不是同一个对象。把 Trace 直接送去改 Prompt 或训练模型,会跳过中间最关键的归因与判定。

图06

Prompt 和模型的发布机制也说明了同一件事。LangSmith 用 commit history 保存 Prompt 版本,并让 staging、production 指向具体 commit;MLflow Model Registry 用版本 tag 表达 validation_status=pending/passed,再用 alias 指向部署版本。它们都没有把“文件被修改”当作“生产已经改进”。

真正应进入飞轮的,不是原始 Trace,而是一个可以被实验和否决的变更候选。

图07

一次只让一个主要责任面进入候选

对前面的退款失败,可以先按下面顺序排除。

第一,检查外部系统和工具合同。若权限配置错误、工具返回语义含糊、幂等键缺失,模型再强也无法稳定完成任务。先修工具或产品逻辑,因为它们是确定性前置条件。

第二,检查 Agent 是否拥有正确事实和约束。若正确动作能用一条明确、可执行、对相邻任务不过度约束的指令表达,优先生成 Prompt 候选。例如:“退款类请求必须先查询订单状态;仅在 refundable=true 且用户明确确认后调用退款工具。”

第三,检查分流条件。若失败只集中在高风险退款,而普通订单查询正常,可以生成 Router 候选:把满足明确风险特征的请求送入带审批和专用工具集的流程。Router 解决的是任务分配,不应被用来掩盖所有下游组件都失败的问题。

第四,只有当工具、环境、Prompt 和分流都已固定,失败仍稳定指向语言理解、规划或领域能力不足时,才生成模型候选或训练候选。换模型是影响面最大的变化之一;它可能同时改变工具选择、措辞、延迟、成本和安全行为,不适合作为默认第一步。

这不是说永远不能同时改两项。真正的事故可能要求“收紧工具权限 + 回滚 Prompt”一起止血。区别在于:紧急控制用于降低当前风险,归因实验用于证明长期修复。两者必须留下不同记录,不能拿一次多变量止血结果宣称已经找到根因。

图08

change_candidate 才是飞轮的最小工作单元

一条候选记录至少应包含这些字段:

change_candidate_id: CHG-20260827-0042
source_failures:
  - failure.refund-before-lookup
attribution_hypothesis:
  component: system_prompt
  mechanism: missing_precondition
primary_change:
  from: prompt@sha256:old
  to: prompt@sha256:new
frozen_context:
  model: model@snapshot
  router: router@2.4.0
  tools: tools@2026-08-27
  policy: refund-policy@7
evaluation_contract:
  dataset: refund-regression@12
  scorers: [tool_order@3, external_state@2]
  must_not_regress: [duplicate_side_effect, unauthorized_refund]
decision:
  status: pending
  evidence: []

这里最重要的不是字段数量,而是三个约束。

其一,primary_change 只有一个主要责任面。其他组件进入 frozen_context,让结果仍可归因。

其二,候选绑定的是 dataset 版本和 scorer 版本,不是一个漂移的“线上平均分”。同一批失败样本如果修改过 expectation,或判定器提示词发生变化,旧实验结果不能直接与新结果拼在一起。

其三,must_not_regress 要把高风险回退单独列出。平均正确率提高,不能抵消重复副作用、越权退款或错误完成声明增加。

图09

发布决定需要回答“改对了什么”,而不只是“总分涨了多少”

候选完成回归后,评审至少要看到四类证据:目标失败类别是否下降;相邻正常任务是否回退;成本和延迟是否仍在边界内;高风险副作用是否为零或满足业务门槛。

如果 Prompt 候选只修复了退款任务,却让所有查询都要求二次确认,它不是成功,只是把失败从安全侧转移到可用性侧。如果 Router 候选提高平均分,却把少数高风险请求送进了没有审批的通用 Agent,也不能发布。如果模型候选整体更强,却在工具参数上更激进,必须保留旧模型或增加新的控制面,而不是被单一总分覆盖。

通过评测后,变更仍应先成为可识别版本,再改变生产指针。Prompt commit、模型 version、Router 配置和工具合同都要能回答:当前线上到底是哪一版,谁依据哪份实验批准,失败时如何回退。

这也是为什么数据飞轮不能画成“Trace → 训练 → 新模型”的圆。大多数 Agent 失败未必需要训练。一次高质量循环更像:

观察失败
→ 建立可推翻的归因假设
→ 生成单一主要变更候选
→ 在固定数据集与判定器上比较
→ 检查目标修复与关键回退
→ 晋级、继续实验或否决

有时出口是 Prompt,有时是 Router、工具合同、权限策略或产品逻辑,只有一部分最终指向模型或训练。

日志规模不会自动产生这个判断。真正让生产 Trace 形成复利的,是每次失败都能留下一个可验证、可否决、可回退的变更候选。团队不必先拥有一套庞大的“数据飞轮平台”,但必须能回答:这次为什么改这个组件,其他条件冻结了什么,哪份证据允许它进入生产。

FAQ

事故中可以同时改多项吗?

可以。回滚、限权和补保护条件属于紧急止血;但它们不能直接证明长期根因。止血记录与后续单一主要变更候选应分开保存。

平均分上涨就能发布吗?

不能。还要分别检查目标失败类别、相邻正常任务、延迟与成本,以及重复副作用、越权操作和错误完成声明等高风险回退项。

所有问题最后都要靠换模型吗?

不需要。工具合同、权限策略、Prompt、Router 和产品逻辑都可能是更小、更确定的修复面;只有其他条件固定后,失败仍稳定指向理解、规划或领域能力,模型才成为主要候选。

主要来源

  1. OpenAI Agents SDK Tracing(2026-08-27 检查) openai.github.io/openai-agen…
  2. OpenAI Trace grading(2026-08-27 检查) developers.openai.com/api/docs/gu…
  3. LangSmith Evaluation concepts / Manage datasets / Manage prompts(2026-08-27 检查) docs.langchain.com/langsmith/e… docs.langchain.com/langsmith/m… docs.langchain.com/langsmith/m…
  4. MLflow GenAI datasets / Model Registry workflow(2026-08-27 检查) mlflow.org/docs/latest… mlflow.org/docs/latest…
  5. OpenTelemetry GenAI attributes(2026-08-27 检查) opentelemetry.io/docs/specs/…