# 智能体没有标准答案：怎么看一次运行，怎么把每次改动变成能比较的数字

终态、轨迹、多次运行三层判据：环境终态才是第一判据，轨迹上要查「必须发生」和「绝不能发生」，再用 pass^k 把波动压成能比较的可靠性数字

> 可靠性 · 护栏 · ReAct 循环 · 约 7 分钟 · 10 月 13 日

## 本篇要点

1. 智能体的「行不行」要拆成三个可分别回答的问题：环境终态对不对、过程合不合规、失败坏在哪一步。
2. 第一判据是环境终态，也就是运行结束时环境里真实变成了什么样，而不是模型最后说的那句话。
3. 只查终态会漏掉两类失败：跳过校验却碰巧做对的运气型成功，和结果正确但中途做了越权动作的危险过程，所以轨迹必须一起查。
4. 轨迹检查按「必须发生什么、绝不能发生什么」来写，而不是逐字比对参考路径；只有当顺序本身就是业务规则时才锁死顺序，否则用 unordered、subset、superset 这类宽松档位。
5. 确定性的断言（必备工具、禁忌动作、关键参数、步数花销上限、终止正确性）写在前面，需要读懂语义的维度才交给 LLM 评委，且评委必须先用人工标注校准。
6. 同一个任务要跑多次：pass@k 是至少成功一次，随 k 上升；pass^k 是全部成功，随 k 下降。单次 75% 成功率跑三次全对只有约 42%，τ-bench 里单次约 61% 的组合 pass^8 掉到不足 25%。
7. 评测集从真实失败中取案例，每条记录输入、期望终态、必备与禁止动作、各项上限；同时维护能力集（通过率低，用来爬坡）和回归集（接近满分，用来防回退），并随模型、提示、工具 schema 一起打版本。
8. 通过率 0% 多数是题目或判据坏了而非模型不行；不读轨迹就会被判据骗；harness 不同时，跨团队分数不可直接比较。

---

前面几篇把循环拆得差不多了：它怎么转、什么时候该停、工具报错之后怎么办。剩下一块拼图是：**它跑起来之后，你怎么知道它到底行不行。**

这块难，是因为智能体和你以前测的过程序不一样。普通函数有标准答案，输出对不上就是错。智能体没有唯一正确的走法——同一个任务跑两次，可能调了不同的工具、换了顺序、绕了条远路，但都对；也可能走了一条看着很顺的路，最后拿到一个错的终态。

所以别急着问「它对不对」，先把它拆成三个能分别回答的小问题：

- **任务真的完成了吗？** 看的是环境的终态，不是它最后那句话。
- **过程合规吗？** 有没有做不该做的事、跳不该跳的步骤。
- **如果失败，坏在哪一步？** 多步任务里，出错的那一步常常不是报错的那一步。

三个词后面会反复用，先说清。**一次运行（trial）** 是把同一条任务完整跑一遍；**轨迹（trajectory，也叫 transcript）** 是这次运行的完整记录，每一步的模型输出、工具调用、参数、工具返回都留在里面；**环境终态（outcome）** 是运行结束时环境里真实变成了什么样，比如数据库里到底有没有那条记录。**任务（task）** 是一条具体的测试用例，**判据（grader）** 是给它打分的逻辑，把这两样和一个能自动跑完的流程凑齐，就是一个**评测集（eval suite）**。

## 第一判据是环境终态

最容易踩的坑是拿它最后那句话当结论。订票智能体在结尾说「您的航班已预订成功」，这句话本身不证明任何事情——真正的判据是那条预订记录在不在数据库里[1]。

这正是上一篇那个道理的另一种出现方式：**验证器要验得住。** 一次成功的写库只能证明格式合法、字段齐全，证明不了写进去的航班号就是用户要的那个。所以终态检查要尽量贴着事实走，查那条记录本身，而不是查它的日志。

## 光看终态会漏掉两类失败

终态检查是必要的，但会放过两种东西：

- **运气型成功**：它跳过了核对步骤，但凑巧落到了正确答案上。这次过关，下次输入一变就露馅。
- **危险的过程**：结果看起来完全正确，但中间它没等用户确认就把全部预订删了。这类动作不改变最终可见的结果，除非你专门去查「不该变的地方变了没有」。

所以还要看轨迹。但看的方式很关键：**不要拿它去逐字比对一条参考路径。**

Anthropic 在总结大量团队实践后给了一条反直觉的建议：逐字检查工具调用顺序的做法太脆，会惩罚那些设计者没预料到、但同样有效的解法；应该判断它**产出了什么、有没有违规**，而不是它**走的哪条路**[1]。

具体做法是把轨迹上的检查分成两档，按成本从低到高排。

**第一档，确定性的断言**，能直接写成代码，便宜、快、不会漂移：

- **必须发生的事**：要办成这个任务，至少得调用过 `book_flight`。
- **绝不能发生的事**：没拿到用户确认，就不许出现 `delete_booking`。这类禁忌序列一旦触发就直接判失败，不管终态多漂亮。
- **关键参数**：搜索航班的出发地填的是不是 `SFO`，日期是不是用户说的那天。
- **上限**：步数、token、耗时、花销有没有超过事先定好的线。
- **终止是否正确**：是提前放弃了，还是成功后还在继续跑。

至于顺序，只有在**顺序本身就是规则**的时候才锁死：先查退款政策、再执行退款，这个前后关系是业务要求；如果两个查询先做哪个都行，就别管它。LangChain 的 `agentevals` 把这件事做成了几个严格度档位：`strict` 要求顺序和集合都对，`unordered` 只要求集合对、顺序不限，`subset` 禁止它多调参考之外的无关工具，`superset` 只要求关键工具都出现过、允许它多做几步[3]。

## 确定性的查完，剩下的才交给模型评委

拿模型给模型打分（LLM-as-judge）只在一种情况下值得用：这个维度必须读懂意思才能判。用法上有三条纪律：让它给出结构化的结论——哪条标准通过、哪条没通过、证据是哪句话；允许它回「信息不足，判不了」，否则它会硬编一个理由；启用之前先用一批人工标好的样例跟它对一遍，对不齐就先改评分标准[1]。没校准过的评委比没有评委更危险，因为它会给你一串看着像数字的东西。

## 从一次运行到一个数字

同一个任务跑多次，结果本来就会变。所以值得记的不是「这次过没过」，而是这条任务的成功率。两个指标长得有点像，方向却相反：

- **pass@k**：跑 $k$ 次，至少成功一次的概率。往上走，试得越多越容易中。适合「多出几个方案，有一个能用就行」。
- **pass^k**：跑 $k$ 次，全部成功的概率。往下掉，k 越大越难。适合用户每次都指望它对的场景。

k=1 时两个数相等，都等于单次成功率；k 一大，它们讲的完全是相反的故事[1]。

举个能自己算的例子：单次成功率 75%，跑三次全对的机会是 $0.75^3 \approx 42\%$。也就是说，一个「平均四次里对三次」的智能体，连着三次都靠得住的概率不到一半。

这不是纸上推导。τ-bench 用模拟用户和真实数据库状态测了一批函数调用智能体：零售域里最好的组合单次成功率约 61%，但同一个任务跑八次都成功的比例掉到不足 25%[2]。平均成功率看着还行，一致性很差。

这和上一篇里「每步 99%、十步只剩 90%」是同一笔账，只是乘的地方换了：那次是步数把折扣叠起来，这次是多次运行把折扣叠起来。用户不会「平均」体验你的智能体，他遇到的是其中一次。

## 一小套评测集怎么搭

不需要几百条，**十几条选得准的用例，比几百条随手写的更有用**。搭法就这几步：

1. **从真实失败里取案例，不要凭想象写。** 每次线上出问题，把当时的输入存下来，变成一条新用例。
2. **每条用例记住这几样**：输入、期望的环境终态、必须调用的工具、禁止的动作、步数与花销上限、这次的失败属于哪一类。
3. **每次运行从干净环境开始。** 上一次留下的文件、缓存、登录状态会让结果失真，甚至凭空抬高成功率[1]。
4. **分成两个集合**：**能力集**装它现在还做不好的任务，通过率本来就该低，用来看改进有没有用；**回归集**装它已经能做好的任务，通过率应接近 100%，用来发现「改了这里坏了那里」。能力集里爬上去的任务，可以毕业进回归集[1]。
5. **挂进 CI**，每次提交自动跑一遍，通过率掉了就拦下来。
6. **给数据集打版本。** 模型、提示词、工具 schema、评委提示里任何一个变了，都要用同一个数据集版本在改动前后各跑一次；不然你比较的不是两次改动，而是两套测量工具。

## 两个会骗你的地方

**通过率 0% 通常说明题目坏了。** 一条任务跑一百次全失败，更可能是题目描述有歧义，或者判据暗中假定了一个没写出来的文件路径，而不是模型不行[1]。所以每条任务最好先有一个已知能过的参考解，证明它可解、判据也没配错。

**只看分数不看轨迹，你迟早会被判据骗。** 任务失败时要读那条轨迹，才能分清「它真做错了」和「判据把有效解法判成了失败」[1]。另外要记住，被评测的不只是模型，还有跑智能体的那套代码和环境；两边环境不一样时，61% 和 75% 之间可能什么信息都没有[1]。

回到最开始那个问题：判断一个智能体行不行，第一眼看环境终态，第二眼在轨迹上查「必须发生的」和「绝不能发生的」，第三眼用多次运行把它压成 pass^k 这类衡量稳定性的数字，最后拿它守住一套会跟着代码一起演进的评测集。这四步做完，你对每次改动的判断就不再是感觉，而是一个能比较的数。

## 术语表

- 轨迹（trajectory / transcript）：一次运行从头到尾的完整记录，包含每一步的模型输出、工具调用、参数和工具返回，用来回答「它这一路是怎么走的」。
- 环境终态（outcome）：运行结束时环境里真实状态的快照，比如数据库里到底有没有那条记录，用来回答「事情到底办成没有」。
- 任务、运行、判据三件套：一条测试用例（task）、把这条用例完整跑一遍（trial）、给这次运行打分的逻辑（grader），三样凑齐才是一个能自动跑的评测。
- 禁忌序列：无论结果多好看都算失败的危险动作组合，比如没拿到用户确认就执行删除，是轨迹上的硬性红线。
- pass@k 与 pass^k：前者是跑 k 次至少成功一次的概率，后者是 k 次全部成功的概率；k=1 时两者相等，k 变大后一个趋近 100%、一个趋近 0。
- 能力集与回归集：能力集装当前做不好的任务、通过率本来就低，用来看改进有没有生效；回归集装已经做好的任务、通过率应接近满分，用来防止改坏别处。

## 来源

1. [Anthropic: Demystifying evals for AI agents — 智能体评测的组件定义、终态与轨迹判据的选择、pass@k 与 pass^k 的差别，以及任务与判据的常见错误](https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents)
2. [τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains — 提出 pass^k 可靠性指标；零售域最强函数调用智能体单次成功率约 61%，pass^8 不足 25%](https://arxiv.org/abs/2406.12045)
3. [LangChain: How to evaluate your agent with trajectory evaluations — 轨迹匹配的 strict、unordered、subset、superset 档位与轨迹级 LLM 评委用法](https://docs.langchain.com/langsmith/trajectory-evals)

---

原文：https://pangzhengboyin.com/articles/evaluating-agents-trajectory-and-pass-k-ad55b98b

> **庞征博引** · 想学的，慢慢都会
>
> 庞征博引是把想学的东西写成连载的 AI 学习工具。说出想学什么，它会先了解你的基础，再把主题写成一篇篇 5–10 分钟能读完的文章；边读边问，接下来学什么跟着你走。这篇就是这样写出来的。
>
> 开始你自己的连载 → https://pangzhengboyin.com
