---
title: 'Cookbook解读｜Macro Evals 如何找到 Agent 系统的故障根因'
description: '沿着 OpenAI Cookbook 的 Macro Evals 工作流，拆解它如何从大量 Agent Trace 中归并重复故障、排序高影响模式并回溯根因候选。'
pubDate: 2026-07-31
slug: macro-evals-agentic-systems
tags: [agent, eval, observability, Cookbook解读]
lang: zh-CN
draft: false
---

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

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

OpenAI Cookbook 的 [Macro Evals for Agentic Systems](https://developers.openai.com/cookbook/examples/partners/macro_evals_for_agentic_systems/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 文档](https://developers.openai.com/api/docs/guides/trace-grading) 也把 Trace 定义为端到端的决策、工具调用与推理记录，并用它定位编排或行为中的错误。Macro Eval 没有替代这层判断，而是继续追问：当错误出现了几百次以后，我们能不能看见它的分布？

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

```mermaid
flowchart LR
  S([开始：业务场景与环境变化]) --> A["业务场景<br/>订单与环境变化"]
  A --> 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/>验证、修复、重跑"] --> Z([结束：确定改进动作])
```

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

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

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

整个分析使用四个面向读者的标签：`case_type`、`run_outcome`、`eval_finding` 和 `behavior_pattern`。

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

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

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

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

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

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

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

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

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

```mermaid
flowchart LR
  S([开始：输入 Trace Document]) --> A["Trace Document"]
  A --> B["Sentence Embedding"]
  B --> C["UMAP 降维"]
  C --> D["HDBSCAN 聚类"]
  D --> E["关键词抽取"]
  E --> F["模式命名"] --> G([结束：得到模式标签])
```

问题出在实现边界。公开 helper 的 [`reduce_embeddings()`](https://github.com/openai/openai-cookbook/blob/main/examples/partners/macro_evals_for_agentic_systems/helpers/macro_eval_pipeline.py#L384-L428) 默认把 Embedding 降到二维，再直接将二维结果交给 HDBSCAN。二维很适合画散点图，却不一定适合承担最终聚类。[BERTopic 官方降维文档](https://maartengr.github.io/BERTopic/getting_started/dim_reduction/dim_reduction.html) 给出的聚类示例使用 5 维，而它的[可视化文档](https://maartengr.github.io/BERTopic/getting_started/visualization/visualization.html) 才明确把 2 维用于展示。

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

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

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

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

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

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

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

最后，公开源码的 [`FAILURE_LABEL_HINTS`](https://github.com/openai/openai-cookbook/blob/main/examples/partners/macro_evals_for_agentic_systems/helpers/macro_eval_pipeline.py#L79-L86) 内置了 `WHEEL_TRIM_CONFLICT`、`BASE_MSRP_DRIFT`、`FULFILLMENT_REROUTE` 等提示；[`_label_from_keywords()`](https://github.com/openai/openai-cookbook/blob/main/examples/partners/macro_evals_for_agentic_systems/helpers/macro_eval_pipeline.py#L2266-L2313) 还会按价格、合规、重试、澄清和供应等关键词命名 Topic。

因此，更准确的说法是：

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

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

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

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

```text
impact_score = prevalence_share × severity_weighted_prevalence
```

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

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

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

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

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

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

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

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

公开实现确实按这组固定权重计算[嫌疑节点分数](https://github.com/openai/openai-cookbook/blob/main/examples/partners/macro_evals_for_agentic_systems/helpers/macro_eval_pipeline.py#L859-L906)。文章也很克制：它说这是“先检查哪里”，不是 causality proof。

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

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

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

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

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

OpenAI 当前的 [Evaluation best practices](https://developers.openai.com/api/docs/guides/evaluation-best-practices) 明确要求用 human feedback 校准自动评分，并让测试反映真实生产分布。Anthropic 的 [Demystifying evals for AI agents](https://www.anthropic.com/engineering/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](https://arxiv.org/abs/2604.05336) 对比成功与失败轨迹，识别缺失能力，再生成定向训练环境并验证训练后的变化；[Tracing Agentic Failure from the Flow of Success](https://arxiv.org/abs/2607.12747) 则学习成功轨迹的动态模式，用偏离程度定位失败步骤。这些论文不等于已经解决生产 RCA，但都说明单独围着失败簇打转，并不是唯一入口。

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

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

**表 2：Agent Reliability 的六层 Eval；每一层回答不同问题，不能用上一层分数替代下一层验证**

| 层级              | 观察对象                       | 主要问题                     | 典型产物                  |
| ----------------- | ------------------------------ | ---------------------------- | ------------------------- |
| L0 业务结果       | task success、SLA、真实状态    | 用户要的事情完成了吗         | 业务结果与损失            |
| L1 组件 Eval      | tool、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 闭环里真正能推动系统变好的那一层。

## 参考资料

- [OpenAI Cookbook：Macro Evals for Agentic Systems](https://developers.openai.com/cookbook/examples/partners/macro_evals_for_agentic_systems/macro_evals_for_agentic_systems)
- [OpenAI Cookbook：`macro_eval_pipeline.py`](https://github.com/openai/openai-cookbook/blob/main/examples/partners/macro_evals_for_agentic_systems/helpers/macro_eval_pipeline.py)
- [OpenAI：Trace grading](https://developers.openai.com/api/docs/guides/trace-grading)
- [OpenAI：Evaluation best practices](https://developers.openai.com/api/docs/guides/evaluation-best-practices)
- [Anthropic：Demystifying evals for AI agents](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents)
- [BERTopic：Dimensionality Reduction](https://maartengr.github.io/BERTopic/getting_started/dim_reduction/dim_reduction.html)
- [Who&When：Which Agent Causes Task Failures and When?](https://arxiv.org/abs/2505.00212)
- [Holistic Evaluation and Failure Diagnosis of AI Agents](https://arxiv.org/abs/2605.14865)
- [TRACE：Capability-Targeted Agentic Training](https://arxiv.org/abs/2604.05336)
- [Tracing Agentic Failure from the Flow of Success](https://arxiv.org/abs/2607.12747)
