生产级 Agent 评估不能只靠模型打分
文章指出,生产 Agent 的故障涉及无限重试、工具参数错误和意外修改数据库,仅让模型阅读对话并打分难以覆盖这些问题。该文是评估系列首篇,后续主题包括确定性状态检查、统计严谨性、标准执行轨迹和评估流水线。
AI 深度解读
Agent 能把任务完成得像模像样,不代表它真的完成了任务。原文针对生产环境里的评估误区提出一个明确主张:先检查数据库、文件和 API 的实际变化,再检查工具调用过程,最后才评价回答写得怎么样。
这套思路值得做 AI 应用的程序员读几分钟。它把「另一个模型觉得不错」拆成了工程上能定位、能复现的检查项。不过,作者对错误累积和评估噪声的部分表述偏强,示例代码也只搭出了骨架,不能直接当作完整的上线保障。
为什么单步准确,整个任务仍然容易失败
普通问答通常只需要判断一次输出。Agent 则要连续行动,而且前一步的结果会成为下一步的输入:先查 ID,再读取记录,然后更新数据库,最后告诉用户处理结果。第一步拿错 ID,后面即使每次都按指令执行,也可能一路做错。
作者用一个简化模型说明问题。假设任务需要 (k) 个步骤,每一步独立成功的概率都是 (p),那么:
[ P(\text{task}) = p^k ]
当 (p = 0.90),也就是单步可靠性达到 90% 时:
- 1 步任务的成功率是 90.0%。
- 3 步任务降到 72.9%。
- 5 步任务降到 59.0%。
- 10 步任务只剩 34.9%。
在这些假设下,10 步工作流大约三次失败两次。演示里两个工具调用都成功,远不足以证明长任务可靠。
但这不是所有 Agent 的成功率预测公式。真实步骤未必独立,错误可能向后传播,也可能被校验、重试或回滚修复。作者认为早期错误会污染后续上下文,这个风险合理;进一步断言错误级联「数学上不可避免」,则超出了这个简化公式能证明的范围。
真正可取的工程结论是:不能只看最终回答,每次状态转换都需要检查。
为什么让另一个模型打分还不够
LLM-as-a-judge 的常见做法,是把 Agent 的多轮记录交给另一个模型,让它按照评分标准打出 1 到 5 分。原文指出了三个缺口。
第一个缺口是,它可能只看到了完成任务的声明。
例如,Agent 声称已经核销发票 #8492,并把 ERP 台账更新为 settled。评委模型可能因为表达完整、语气得体,给出 5/5。但数据库有没有更新、账户余额是否正确、是否破坏外键约束,都不能从这句话里确认。
对会改变外部系统的 Agent,完成任务首先是一件状态事实。
第二个缺口是评分偏差。作者列出了偏爱冗长答案的 Verbosity Bias、偏爱特定候选位置的 Position Bias,以及更认可同模型家族输出的 Self-Enhancement Bias。不过,原文没有提供对应基准、实验条件或偏差幅度,读者无法据此判断自己的评委模型受影响有多大。
第三个缺口是结果波动。夜间评估从 4.2 降到 3.8,原因可能是 Agent 的提示词或模型发生变化,也可能是评委的非零 temperature、服务商推理变化,或者样本噪声。
作者把这描述成测量方差「翻倍」,但没有推导。更准确的理解是:系统多了一层不确定性,需要分别定位,不能默认方差恰好乘二。
这些问题说明,模型评分不适合独自承担生产回归检查。它仍能辅助评价难以写成规则的表达质量,前提是评估输入足够完整、问题足够具体。
把评估拆成三层,失败才容易定位
作者建议按「状态、过程、表达」的顺序建立评估。
第一层是确定性的状态断言(Deterministic State Assertions)。运行前保存环境状态,运行后检查变化:SQL 是否出现了字段完全符合要求的记录,文件能否解析成合法 JSON/YAML,mock API 是否收到正确参数。
第二层检查执行轨迹(Trajectory),也就是 Agent 从开始到结束的行动记录。工具参数要通过 Pydantic / JSON Schema 校验;任务应该在 3 步内完成,就不能绕了 18 步才碰巧成功;收到错误后,反复用相同参数调用同一工具,也需要被识别。最终结果正确,不能抵消中间过程的成本和风险。
第三层才检查语言表达,而且把宽泛评分收窄成 YES/NO 问题。例如,回答是否包含运单号,是否拒绝提示词注入且没有泄露系统凭据。问题更明确,但安全相关检查仍需要其他证据支撑,不能因为输出一个 YES 就视为已经证明安全。
原文用下面的 Python 示例,把「发票状态正确、金额未变、步骤未超限、工具参数合法」放进同一个测试:
from dataclasses import dataclass
from typing import Any, Callable, Dict, List
import pytest
@dataclass
class EvalTestCase:
task_id: str
user_prompt: str
initial_state: Dict[str, Any]
expected_state_assertion: Callable[[Dict[str, Any]], bool]
max_steps: int = 5
max_cost_usd: float = 0.05
def test_agent_reconciliation_flow():
# Setup test fixture with isolated mock state
mock_db = {"invoices": {"inv_101": {"amount": 250.0, "status": "pending"}}}
test_case = EvalTestCase(
task_id="reconcile_paid_invoice",
user_prompt="Reconcile payment of $250.00 for invoice inv_101.",
initial_state=mock_db,
expected_state_assertion=lambda state: (
state["invoices"]["inv_101"]["status"] == "settled"
and state["invoices"]["inv_101"]["amount"] == 250.0
),
max_steps=3
)
# Execute agent against the mock environment
trajectory = run_agent(test_case.user_prompt, state=mock_db)
# 1. Assert deterministic final state
assert test_case.expected_state_assertion(mock_db), (
f"State assertion failed for {test_case.task_id}. Current DB: {mock_db}"
)
# 2. Assert trajectory efficiency constraints
assert len(trajectory.steps) <= test_case.max_steps, (
f"Agent exceeded step budget: {len(trajectory.steps)} > {test_case.max_steps}"
)
# 3. Assert zero schema validation errors during tool calls
for step in trajectory.steps:
assert step.schema_valid is True, f"Malformed tool call in turn {step.turn_id}"
重点看 expected_state_assertion:它既要求状态变成 settled,也要求金额保持 250.0,比只检查 Agent 是否声称成功更接近业务验收。
不过,这段代码还不能独立运行,run_agent 和轨迹数据结构都没有实现。max_cost_usd = 0.05 只是声明,没有实际费用断言;initial_state 也没有用于自动快照或恢复。它展示了测试接口的形状,并未实现完整评估平台。
我的判断
我认可这套评估顺序,尤其适合会写数据库、修改文件、调用业务 API 的 Agent。它延续了软件测试里成熟的做法:用可观察的结果证明行为,再用执行记录解释失败。相比一个分数下降 0.2,指出具体哪条记录不匹配,显然更方便排查。
但确定性断言的价值取决于断言覆盖什么。示例只检查 inv_101 的状态和金额,无法发现 Agent 顺手改坏了另一张发票。最终状态正确,也无法证明过程中没有发生未经授权的操作。需要检查哪些差异、允许哪些中间行为,仍然要由团队定义。
作者称这些断言即时、无 token 成本、100% 可复现,需要拆开理解:断言逻辑可以稳定,也不必消耗模型 token;搭建隔离环境、重置数据库、运行 Agent 依然有成本,整次运行也可能存在随机性。
原文是五篇系列的第 1 篇,没有给出团队实测、对照实验或上线故障率变化。它提供的是架构建议,不是已经证明优于所有替代方案的实验结论。对纯摘要、开放式问答,状态断言的覆盖面有限,模型评审仍有用途;对会执行操作的 Agent,则应优先补齐状态检查。
能拿来做什么
- 给会写数据库或调用业务 API 的 Node Agent 先建立一个隔离用例,明确初始数据、预期变化和禁止变化,并通过 mock 记录请求参数。
- 给日常 AI 编程任务增加产物检查,例如确认生成文件能解析、导出接口符合要求,而不是只接受「已经完成修改」这类回复。
- 在工具调用入口校验 JSON Schema,同时记录步骤数、参数、错误和费用;声明了预算,就补上对应断言,避免配置存在却没有执行约束。
- 保留模型评委检查表达质量,但先验证业务状态和执行过程,再询问「是否包含必要信息」等窄问题,并分别记录各层失败原因。