/ #agent #eval #observability #Cookbook解读

Cookbook解读|Macro Evals 如何找到 Agent 系统的故障根因

沿着 OpenAI Cookbook 的 Macro Evals 工作流,拆解它如何从大量 Agent Trace 中归并重复故障、排序高影响模式并回溯根因候选。

一个 Agent 运行失败时,我们还可以打开 Trace,一步步找它在哪里走偏。可要是每天有 1,000 条 Trace,其中 200 条失败,难道真要让工程师逐条欣赏 Agent 的迷惑行为吗?

单条 Eval 能告诉我们“这次工具参数错了”“这次 handoff 不对”,却很难回答另一个更像生产问题的问题:这些错误是不是同一种系统性故障,它集中在哪些场景,又该先找谁处理?

OpenAI Cookbook 的 Macro Evals for Agentic Systems 正在补这一层。它没有继续围着某一条失败 Trace 打转,而是先从整个 Trace 群体中找出重复模式,再沿执行图回溯上游的可疑节点。

先说结论:

Cookbook 把“寻找根因”拆成三步:归并反复出现的故障、按影响排序、沿执行图回溯根因候选。它能把排障范围从海量 Trace 缩小到少数 Agent、工具或 handoff,但最后得到的是调查入口,不是因果证明。

换句话说,这套方法确实在“找根因”,只是它先找出最值得验证的嫌疑对象。照着搭第一版系统很有价值,拿它直接做质量门禁或自动 Root Cause Analysis,就走得太快了。

数据快照

  • 最后核验:2026-07-31
  • 主要对象:2026-05-19 发布的 OpenAI Cookbook 文章及其 GitHub main 分支代码
  • 示例数据:1,000 个合成订单,其中 992 个包含可分析的 Trace bundle
  • 对照资料:OpenAI、Anthropic 当前 Eval 文档,以及 2025—2026 年 Agent 故障定位研究
  • 本文不复跑 Notebook,也不报告新的聚类结果;对实现的判断来自公开文章与源码

#第一步:从单条 Eval 上升到群体模式

这里的 “macro” 容易让人想到 macro-F1,但文章说的不是这个。它指的是从单条运行上升到整个 Trace 群体,观察系统反复以什么方式失败。

文章把 Eval 分成两层:

  • Lower-level evals 评价单个 Agent、工具调用、handoff 和一次完整运行;
  • Macro evals 聚合许多底层 finding,寻找重复问题、集中场景和优先检查的系统组件。

OpenAI 当前的 Trace grading 文档 也把 Trace 定义为端到端的决策、工具调用与推理记录,并用它定位编排或行为中的错误。Macro Eval 没有替代这层判断,而是继续追问:当错误出现了几百次以后,我们能不能看见它的分布?

图 1:Cookbook 从单次业务运行到人工排障入口的完整链路;箭头表示分析产物,不表示已经证明因果

flowchart LR
  A["业务场景<br/>订单与环境变化"] --> B["Agent 系统运行<br/>工具、handoff、状态"]
  B --> C["Lower-level Eval<br/>为每条 Trace 产生 finding"]
  C --> D["Trace Document<br/>压缩场景、路径与终态"]
  D --> E["Embedding + UMAP<br/>HDBSCAN 聚类"]
  E --> F["行为模式<br/>频率与严重度排序"]
  F --> G["执行图回溯<br/>嫌疑节点排名"]
  G --> H["人工检查<br/>验证、修复、重跑"]

这条链的价值,是把几千个事件变成少量可讨论的问题族。它的限制也在图里:从 finding 到 pattern 是统计归并,从 pattern 到 suspect 是启发式回溯,只有最后的验证、修复和重跑才可能把“相关”推进到“确实是原因”。

#第二步:把一千条订单压成几个问题族

Cookbook 构造了一个电动车订单工作流。定价、合规、供应、工厂路由、排期和放行等 specialist Agent 会在市场与运营条件变化时协作处理订单。公开数据包含 1,000 个合成订单,992 个订单有完整 bundle,因此 Notebook 可以离线读取 Trace 和已保存的 Promptfoo 标签,不需要重新调用模型。

整个分析使用四个面向读者的标签:case_typerun_outcomeeval_findingbehavior_pattern

前三项在聚类前已经存在:业务场景、运行结果和底层 Eval finding。最后一项才是聚类得到的行为模式。这样,业务人员可以从订单类型追到风险模式,工程人员也可以从某个模式回到工具、handoff 和状态变化。

#Trace Document 决定了系统看得见什么

原始 Trace 太长,也混着模型回复、工具输入输出、状态变化和重复日志。文章因此为每次运行构造 doc_structured_summary,保留场景、路由、状态转换、handoff、finding 与终态,再把它交给后面的文本模型。

这一步看起来像数据清洗,其实已经是 Eval 设计:

  • 不记录 handoff,就很难发现路由问题;
  • 不记录环境信号,就很难发现某个市场状态下的集中失败;
  • 把多个错误压成一句摘要,后面的 Embedding 也无法把顺序和传播关系重新变回来。

所以文章最值得保留的判断,不是“UMAP 配什么参数”,而是:Trace 的表示方式决定了 Macro Eval 可以发现什么,也决定了它必然漏掉什么。

#聚类流程成熟,但还只是探索性分析

文章采用一条 BERTopic 风格的常见路径:

图 2:Trace Document 经降维、聚类和关键词抽取后形成可读问题模式

flowchart LR
  A["Trace Document"] --> B["Sentence Embedding"]
  B --> C["UMAP 降维"]
  C --> D["HDBSCAN 聚类"]
  D --> E["关键词抽取"]
  E --> F["模式命名"]

问题出在实现边界。公开 helper 的 reduce_embeddings() 默认把 Embedding 降到二维,再直接将二维结果交给 HDBSCAN。二维很适合画散点图,却不一定适合承担最终聚类。BERTopic 官方降维文档 给出的聚类示例使用 5 维,而它的可视化文档 才明确把 2 维用于展示。

二维聚类不等于一定错误,但至少应该补做:

  • 不同随机种子下,问题族是否稳定;
  • 更换 Embedding、维度和 HDBSCAN 参数后,主要模式是否仍然存在;
  • 新一批 Trace 能否稳定映射到旧模式;
  • 聚类结果与人工故障分类的一致性如何。

在这些验证完成前,散点图可以帮助探索,不适合摇身一变成为发布门禁。

#聚类找到的是问题族,不是未知根因

从流程图看,系统像是在没有标签的日志里自动发现问题。但源码给出了更窄的边界。

首先,主要聚类对象不是全量线上流量,而是已经带有 failure、review、runtime 或 Promptfoo 失败信号的 Trace。文章自己也说明,这是为了把注意力集中到需要处理的运行上。

其次,Trace Document 已经包含业务场景、终态、finding 和失败窗口等强信号。聚类更像把已知局部告警归并成几个语义相近的问题族,而不是从一片无标签日志中发现完全未知的故障。

最后,公开源码的 FAILURE_LABEL_HINTS 内置了 WHEEL_TRIM_CONFLICTBASE_MSRP_DRIFTFULFILLMENT_REROUTE 等提示;_label_from_keywords() 还会按价格、合规、重试、澄清和供应等关键词命名 Topic。

因此,更准确的说法是:

这套流程用无监督聚类组织 Trace,但问题空间和最后的可读标签都受已有业务字段、Eval finding 与规则提示引导。

这不是缺点。把几十种局部告警压成五个可以分配 owner 的问题族,本身就很有生产价值。真正需要避免的,是把“归并已知信号”宣传成“自动发现未知根因”。

#第三步:用影响分决定先追哪种故障

聚类完成后,文章用下面的公式给行为模式排序:

impact_score = prevalence_share × severity_weighted_prevalence

直觉很自然:一个模式出现得越多,其中的失败越严重,就越应该先看。文章也明确说它不是通用风险公式,只是一个 triage score。

这里有两个容易被图表藏起来的限制。

第一,prevalence_share 主要是在“已经被标记为失败或需要审查的 Trace”中计算,而不是该问题占全部生产请求的真实发生率。它能回答“问题样本内部谁最多”,不一定能回答“线上谁影响最大”。

第二,严重度来自预先设定的状态权重,没有直接纳入真实损失、受影响用户数、可逆性、合规后果、传播范围和尾部风险。一个罕见但不可逆的合规事故,很可能被高频小故障压到后面。

所以,这个分数适合排调查队列,不适合替代业务风险模型。生产系统至少还要把流量基数、业务损失、置信区间和风险上限放回同一张表里。

#第四步:沿执行图回溯根因候选

找到高影响模式后,Cookbook 会重建一张轻量执行图:节点是 Trace 事件,边表示时间顺序、handoff、工具调用与邻近上下文。随后从 failure 或 review anchor 向前回溯,并给上游节点计算:

suspect_score =
0.4 × proximity
+ 0.3 × frequency
+ 0.2 × bridge
+ 0.1 × role

公开实现确实按这组固定权重计算嫌疑节点分数。文章也很克制:它说这是“先检查哪里”,不是 causality proof。

离失败近、反复出现、连接多个阶段、角色看起来相关,都只能提高怀疑程度。一个日志节点可能只是记录得更完整,一个工具可能同时大量出现在成功和失败轨迹中,最后一个报错节点也可能只是替上游错误背锅。

故障定位本身是一项需要单独评测的任务。2025 年的 Who&When 为多 Agent 失败标注了责任 Agent 和决定性错误步骤;论文报告的最佳方法能以 53.5% 准确率找到责任 Agent,却只有 14.2% 的步骤定位准确率。这个结果至少提醒我们:把“先看谁”推进到“谁导致失败”,远比设计一组可解释权重困难。

2026 年的 Holistic Evaluation and Failure Diagnosis 进一步把全局 Agent 级诊断与独立的 span 级评测结合起来。它代表的方向不是给整条长 Trace 再问一次大模型,而是保留结构、拆分 span,并对定位器本身计算 category F1、localization accuracy 等指标。

#前提:Macro 层会放大底层 Judge 的误差

Macro Eval 的输入并不是真相,而是底层 Eval 产生的 finding。如果 Judge 把正常 Trace 判成失败,Macro 层可能聚类出一个很稳定的“虚假故障”;如果 Judge 漏掉某类错误,后面的聚类算法再高级也无从发现。

OpenAI 当前的 Evaluation best practices 明确要求用 human feedback 校准自动评分,并让测试反映真实生产分布。Anthropic 的 Demystifying evals for AI agents 也建议组合代码、模型和人工 grader,并让 LLM rubric 持续对齐专家判断。

这意味着 Macro Eval 上线前,至少要先回答:

  • 底层 Judge 与人工专家的 precision、recall 和一致性是多少;
  • 哪些场景最容易误判或漏判;
  • Judge、Prompt 或模型版本变化后,历史 Topic 是否还能比较;
  • 高影响 Topic 是否只是某个 Judge 偏差被重复放大。

Macro 层不是用来掩盖单条 Eval 不可靠的。它会把底层信号规模化,也会把底层错误一起规模化。

#把根因候选推进为结论,还缺五道验证

下面五项是本文根据前述证据做的分析性拆解,不是 Cookbook 已经定义或完成的验收体系。

表 1:Macro Eval 原型的五个补强点;“成功信号”是生产验收建议,不是 Cookbook 已报告结果

环节当前原型能回答什么还要补什么一个可检查的成功信号
Judge 校准哪些 Trace 被标记为问题与人工金标准对照,按场景拆误差关键类别的 precision、recall 和一致性达到预设门槛
Pattern Discovery问题样本里有哪些语义簇多随机种子、多参数、跨时间稳定性主问题族在重复实验中可复现
成功—失败对照失败内部什么最常见计算行为在成功与失败中的 lift 或 odds ratio高风险信号能区分失败,而不是到处都出现
Failure Localization哪些节点应先检查标注责任 Agent、决定性步骤和可恢复点Top-K recall、step accuracy 与置信度校准可接受
修复闭环哪个模式和节点值得怀疑修改、反事实 replay、回归集与线上验证修复后目标故障下降,其他能力没有明显回退

其中,成功—失败对照尤其重要。只看失败样本,我们最多知道“失败里经常出现什么”。如果某工具出现在 80% 的失败 Trace,也出现在 90% 的成功 Trace,它就不该因为常见而成为头号嫌疑。

近期研究已经在向闭环前进。TRACE 对比成功与失败轨迹,识别缺失能力,再生成定向训练环境并验证训练后的变化;Tracing Agentic Failure from the Flow of Success 则学习成功轨迹的动态模式,用偏离程度定位失败步骤。这些论文不等于已经解决生产 RCA,但都说明单独围着失败簇打转,并不是唯一入口。

#Macro Eval 应该放在 Agent Reliability 的哪一层

Macro Eval 不应该单独成为一座新平台。更合适的做法,是把它放进从业务结果到持续改进的六层链路中。

表 2:Agent Reliability 的六层 Eval;每一层回答不同问题,不能用上一层分数替代下一层验证

层级观察对象主要问题典型产物
L0 业务结果task success、SLA、真实状态用户要的事情完成了吗业务结果与损失
L1 组件 Evaltool、routing、handoff、policy哪个局部行为不符合要求finding 与 grader 证据
L2 轨迹 Eval完整 Trace、错误传播最早从哪里开始走偏span 标签与传播路径
L3 Macro Analysis大量 Trace 的分布什么问题反复出现、集中在哪里pattern、slice 与版本回归
L4 诊断与验证suspect、对照与 replay它真的是原因吗反事实结果与修复验证
L5 持续改进回归集、监控与 owner修复是否持续有效回归门禁、告警与责任归属

这六层里,Macro Eval 位于 L3。它的输入依赖 L0—L2 是否记录准确,输出还必须经过 L4 验证,最后由 L5 把已确认故障变成回归集和持续监控。

如果现在要搭第一版,我会先做三件事:保留结构化 Trace 和版本字段;用人工样本校准底层 Judge;把 Macro 输出定位成“调查队列”,明确显示证据、基数和不确定性。等这些稳定后,再讨论自动 owner、影响排序和根因候选。

#总结

Macro Evals 抓住了 Agent 系统里的一个真实缺口:单条 Trace 可以解释一次失败,却无法自动告诉我们系统反复以什么方式失败。Cookbook 先把底层 finding 归并成问题族,再按影响排序,最后沿执行图回溯上游节点。这条链确实能把海量日志压缩成少数根因候选。

但压缩不是证明。文本聚类不能自动发现所有未知故障,频率乘严重度不是完整业务风险,固定权重排出的嫌疑节点也不是根因。底层 Judge 没校准时,Macro 层甚至会把误差包装成一张很漂亮的故障地图。

所以,最合适的用法是:

用 Macro Eval 找到“最应该先验证的根因候选”,用成功—失败对照和结构化定位缩小范围,再用 replay、修复后重跑与回归集回答“它是不是原因、修复是否有效”。

做到这一步,Macro Eval 才不是一个新的观测看板,而是 Agent Reliability 闭环里真正能推动系统变好的那一层。

#参考资料

Share this post

Diagram
100%