Agent 应用开发会员账号
← 返回研究目录

EVALUATION

Agent 怎么验收:从真实轨迹到失败回归

把成功条件写成测试合同,读取实际事件和业务回执;看懂 基础测试与审批测试能证明什么,怎样继续做语义与成本评测。

01 · 先拆开“成功”:答案、执行、业务结果不是一回事

继续上一章的研究报告案例。最终回答“报告已保存”,只能证明模型输出了这句话;publish 检查点存在,说明本地记录了回执;远端 receipts 中只有一条记录,才是本次实验中重复发布未发生的证据。评测要分别读取这些事实,而不是让 Agent 自报一个 success=true。

维度 可观察证据 不能推出什么
执行可靠性 认领、提交、重试、取消事件 任务走完不能证明回答正确
结果结构 summary 非空,citations 为合法 ID 数组 ID 合法不能证明论点被来源支持
业务结果 独立发布库中的操作键、内容摘要、回执 单次实验不能保证所有网络故障下恰好一次
语义质量 论点与证据片段逐项核对 模型评分器的高分不是人工真值
资源消耗 实际调用次数、计费 token、墙钟时间 离线替身的耗时不能代表模型服务延迟

Anthropic 的评测方法区分 task、trial、grader、trajectory 和 outcome,并建议结合代码、模型与人工评分。我们采用这一基本区分,但下面的样本、门槛、代码与结果均为本站独立设计。

Anthropic · Agent 评测:用于核对评测对象、轨迹与实际结果的区别,以及评分器类型。(核对:2026-09-25)

本次成绩的正确读法: 基础 18 项软件机制测试通过;第三版增加 18 项审批测试;没有进行真实模型能力排名、语义质量评分或线上吞吐测试。测试里包含模拟 HTTP,默认摘要为确定性替身。

02 · 把需求变成样本合同:输入、故障、期望和证据一起写

一个测试只有输入问题是不够的。还要记录前置状态、故障注入点、合法终态和禁止出现的业务影响。尤其是取消、权限不足与记忆失效:正确停止可能就是通过,不能统一要求所有任务 succeeded。

测试合同示例

{
  "case_id": "effect-before-checkpoint/v1",
  "input_version": "report/v1",
  "provider": "fixture",
  "precondition": "fresh task + empty publisher database",
  "fault": "after_effect",
  "resume": "advance virtual clock by 31 seconds; rerun without fault",
  "expected": {
    "status": "succeeded",
    "checkpoint_count": 4,
    "publisher_receipts": 1,
    "publish_deduplicated": true
  },
  "evidence": [
    "jobs",
    "checkpoints",
    "events",
    "publisher.receipts"
  ]
}
已实现测试组 场景 核心断言
恢复与业务效果 collect 后宕机;外部成功后宕机;重复投递 已提交步骤不再执行,最终回执唯一
并发与任务控制 两个进程认领;旧代次写回;取消;deadline 只一个认领者;非法提交失败;到期停止
输入与报告 同 ID 不同输入;未知来源 ID;幂等键内容冲突 拒绝复用旧身份;失败任务不发布
重试 模拟 429 连续失败 2 秒、4 秒退避;最多 3 次认领
记忆 租户/用户/项目隔离;过期;未确认;更新;删除后恢复 不合格记录不入候选;旧快照失效
评测与适配器 事件变异;真实 CLI 退出;模拟 HTTP 成功/429 错误轨迹被拒绝;退出码 75;错误分类正确

测试组不是生产事故统计。比如隔离测试使用可信 scope 参数,只能验证过滤函数;它没有攻击真实认证网关,不能据此声称“企业权限隔离已验证”。把证据强度写进样本合同,能防止结果在汇报时被放大。

03 · 从事件和检查点评分,不读取模型隐藏推理

本站事件表记录提交、认领、步骤开始、步骤提交、重试和取消。它保留 job_id、generation、时间和详情,足够还原本例状态转换。日志由运行时写入,模型输出不能改写这些记录。生产系统还应限制数据库写权限,避免工作进程之外的操作者伪造审计。

事件形状示意;真实序号见 evidence.json

{
  "seq": 9,
  "job_id": "evidence-001",
  "at": 1031,
  "generation": 2,
  "kind": "step_started",
  "detail": "publish"
}

这里使用虚拟时钟测试租约,1000、1031 是测试时间坐标,不是线上时间戳。事件序号由数据库产生;在本数据库中可排序,但扩展到多个服务后不能仅用各机器时钟确定因果关系。应加入 span_id、parent_span_id、operation_id 与 attempt_id。

记录位置 可保存 避免直接保存
任务元数据 输入摘要、版本、授权引用、预算 API Key、会话 cookie
工具事件 工具名、状态、耗时、资源 ID、错误分类 整份账户流水或敏感文档明文
模型计量 请求 ID、input/output token、重试次数 未经评估的全部用户对话
证据库 受控文档引用、片段哈希、读取权限 把引用可访问性误认为每个用户都有权限

不要要求收集隐藏推理来做轨迹评测。工具调用、显式输出、检查点与业务回执足以验证多数执行不变量。若必须保存完整工具输出,应独立设置访问控制与保留期限,不要把它们和普通调试日志一起公开。

04 · 可运行评分器:哪些规则能自动判,哪些必须留空

evaluate.py · 实际评分规则

def grade(snapshot, expected_status='succeeded'):
    events = snapshot['events']
    commits = [e['detail'] for e in events if e['kind'] == 'step_committed']
    cp = snapshot['checkpoints']
    checks = {'expected_terminal_state': snapshot['status'] == expected_status,
              'no_duplicate_checkpoint_commit': len(commits) == len(set(commits)),
              'trace_matches_checkpoints': set(commits) == set(cp)}
    if expected_status == 'succeeded':
        checks['all_steps_present'] = set(cp) == set(STEPS)
        checks['source_id_gate_passed'] = cp.get('verify', {}).get('schema_and_source_ids') is True
        checks['receipt_present'] = bool(cp.get('publish', {}).get('receipt'))
    return {'passed': all(checks.values()), 'checks': checks,
            'semantic_support': 'not_scored', 'model_quality': 'not_scored'}

下载完整 evaluate.py

这段代码检查终态是否符合预期、同一步骤是否重复提交、事件与检查点集合是否一致。对于 succeeded,还检查四步齐全、来源 ID 门槛通过且回执存在。它只断言机械一致性,不声称日志不可篡改,也不会把 semantic_support 自动填成 true。

评测故意不强制每个工具只能调用一次。崩溃恢复时 publish 可以有两次 step_started,但只能有一次 step_committed,远端业务记录也只能有一条。如果简单把“工具调用次数大于一”判失败,会把正确的恢复机制误判为坏路径。

反过来,只看最终状态也会漏错。test_grader_rejects_trace_mutation 会复制一条提交事件,证明评分器能够拒绝重复提交轨迹。它针对明确不变量做变异验证,而不是写一个永远返回通过的示例。

对实际任务库运行评分

python3 evaluate.py --db lab.sqlite --job report-001
# 如果是在验证明确取消的任务:
python3 evaluate.py --db cancel.sqlite --job report-001 --expected-status cancelled

05 · 本次运行记录:先看证据,再看结论

观察量 宕机时 恢复后
任务状态 running succeeded
认领代次 1 2
本地检查点数 3 4
模拟发布库回执数 1 1
publish 去重标记 本地尚无 publish 结果 true

这组数据来自本次 after_effect 实验。复现使用两个真实 SQLite 文件与虚拟时钟;检查点提交之后人为注入进程中断语义,再推进时钟让租约到期。另一个独立测试以 CLI 子进程执行 os._exit(75),验证退出后数据库仍保留已经提交的 collect。

evidence.json:完整前后快照与评分 · validation.json:环境、测试名称与已知未验证项 · test_lab.py:断言源码

本次 unittest 实际输出节选;耗时依运行环境变化

Ran 18 tests in 0.304s
OK

0.304 秒是这次离线测试集合的执行时间,不是 Agent 响应时延,也不能用来宣传 QPS。两进程认领测试只检验一个竞争场景,不代表高负载下所有调度正确性都已证明。一个失败场景的成功恢复,也不能转换为“恢复成功率 100%”。

06 · 语义评测怎么补:把一句话拆成可核对的论点

模型常见的失误是“引用真的存在,但并不支持这句话”。例如 s1 只说明检查点存储,却被用来支撑“系统效率提升 30%”。当前来源 ID 校验会放行这一引用;必须增加论点级核对才能发现问题。

待核对论点 要求的证据 建议标签
恢复后跳过已提交 collect 运行事件中 collect 提交一次,恢复后没有再次开始 supported
任何外部接口都恰好一次 本例没有这样的证据,且反例存在 unsupported
平均节省 30% token 同任务、新旧方案的真实计费数据 insufficient_evidence
删除后所有副本已彻底抹除 主库、缓存、检查点、备份的完整删除记录 unsupported

落地时,为每份报告建 claim_id → source_id → 证据片段 → 标签 → 理由的映射。第一批保留 20 个来自业务的争议论点,由两位熟悉业务的人独立标注;分歧先讨论规则,再校准评分模型。20 是起步工作量建议,不是统计学充分样本量。

人工标注记录模板

{
  "claim_id": "c1",
  "claim": "恢复后 collect 未重复执行",
  "source_id": "run-evidence-001",
  "evidence": "generation=2 无 collect 的 step_started",
  "label": "supported",
  "reviewer": "human-label-required",
  "rubric_version": "grounding/v1"
}

评分模型只能读取任务、候选答案和允许证据;不得调用发布工具。固定 rubric 版本,并保存它与人工标签的混淆矩阵。若模型经常把“证据不足”判为“支持”,应先修评分器,不要立刻拿它优化被测 Agent。当前实验包尚未实现这一语义评分层。

07 · 比较两个方案:用配对任务,别比较两次演示

假设你准备把 prompt-v1 换为 prompt-v2。先冻结材料版本、模型版本、工具环境、任务预算与评分器版本,对同一组任务配对运行。每个任务重复若干次,保存所有试验,不只选最好的一次。模型别名背后可能更新,能使用固定版本时优先记录固定版本。

指标 计算口径 解读限制
任务成功率 符合该任务验收合同的 trial 数 / 全部有效 trial 数 明确基础设施故障如何归类,不无声删样本
安全/业务硬失败 越权、未审批写入、重复业务记录分别计数 不能靠答案质量平均分抵消
引用支持率 supported 论点数 / 需要证据的论点数 区分无证据与证据反驳
成功任务成本 所有试验成本(含失败)/ 成功任务数 只算成功调用费用会低估真实成本
端到端时延 提交到终态,含排队和退避 另报模型调用时延,避免混淆

例如一个方案要试三次才能成功,pass@3 会好看,但单次用户体验可能变差。业务只允许一次提交时,应优先比较单次成功与重试开销;每次都必须可靠的流程,还要看重复试验的一致性。不要把“至少一次成功”和“每次成功”混为同一个指标。

小样本报告建议直接给出分子/分母、每任务差异和失败列表。没有足够样本时写“探索性结果”,不宣称统计显著。若新旧方案用不同输入、不同模型或不同工具数据,无法把改善单独归因于提示词变化。

08 · 把评测接到研发流程:什么错误阻止发布

对 Java 老系统,先从现有集成测试与生产缺陷中选择样本,再引入模型判断。涉及数据库更新和外部接口的 Agent,优先用隔离沙箱与受控工具;评测账号权限应小于等于试点用户,禁止为了跑测试临时放大权限。

  1. 每次代码改动运行本实验的机械回归,失败则保留输出并停止流水线。
  2. 涉及提示词、模型或检索变更,运行冻结开发集;保存输入摘要、输出、轨迹与评分器版本。
  3. 在保留集上比较候选方案,硬失败逐条审查;不要反复看保留集并针对题目改提示词。
  4. 小范围接入只读业务,记录人工纠正和失败类型;将复现条件明确的事故转成回归样本。

离线回归门槛;第二条要求先按 README 生成正常任务

python3 -m unittest discover -s . -p test_lab.py -v
python3 evaluate.py --db lab.sqlite --job report-001

当前 18 项测试既有成功路径,也有拒绝路径:来源 ID 非法应 failed、取消应 cancelled。CI 通过不是所有任务都 succeeded,而是每个任务都符合预先定义的合法结果。

升级时真正该问的是:“哪些失败被修复?是否引入新的重复写入、越权或成本问题?证据是否可重放?”这三个问题都需要记录级证据,单张评分截图无法回答。

09 · 评测失败的定位顺序

失败表现 先区分 下一步动作
最终文本不错,任务却失败 硬门槛还是语言分数 按事件定位未知来源、deadline 或非法状态,不先改文案
输出里有引用,语义评分低 来源不存在还是不支持论点 逐条建立 claim → evidence 映射
机械评分通过,却出现重复报告 本地提交还是远端真实效果 查询独立业务库;修复幂等协议,不能只增加日志
换模型后成本明显升高 单次 token 还是重试变多 按 trial 汇总含失败成本,检查格式错误与超时
不同运行波动很大 模型随机性还是工具环境变化 固定数据快照,再做多次配对试验
评分模型与人经常冲突 rubric 模糊还是证据不足 先校准评分器,保留 disputed 标签

评分器也要维护版本和测试。增加一条规则时,至少准备一个应通过的反例和一个应失败的反例;确认没有把合法路线误杀。对“答案要完整”“代码要优雅”这类主观描述,先给可操作定义,再引入自动评分。

同一套案例,三篇文章共用

Python 3.10+ · 标准库 · 默认离线 · 含源代码、36 项测试和运行记录

下载完整实验包 ZIP运行说明

10 · 增加审批以后,验收不再只有 succeeded

期望终态 样本必须断言 常见误判
waiting_approval 已有草稿,发布记录为 0,重复 run 不重新生成 把等待当超时失败
failed / rejected / expired 未发出且发布记录为 0 只断言状态,漏掉先执行后拒绝
succeeded 有效批准先于派发,只有一条业务记录 最终成功掩盖未经批准的第一次调用
reconciling 没有新发送;保留未知状态和核对线索 找不到回执就当没发生
effect_confirmed 回执匹配原 payload_hash,fresh_write_performed=false 把过去的业务效果当成新的授权

第三版新增 18 项审批测试,与原 18 项基础测试合计 36 项。新增案例包括两个进程同时批准/拒绝、重复回调、内容改写、角色和作用域拒绝、审批过期、取消后的回执核对及无回执不重发。身份测试只检查本地 Principal 夹具规则,没有验证真实认证系统。

运行完整回归;仅 test_lab.py 不包含审批扩展

python3 -m unittest discover -s . -p 'test_*.py' -v

基础 evaluate.py 主要检查原四步任务。审批场景的业务效果和授权顺序由 test_approval.py 直接断言;不要把基础 passed=true 当作审批合规证明。完整源码与结果见 test_approval.py、validation.json。

11 · 如何证明恢复没有偷偷再发一次

仅看报告表最终只有一行不够:幂等服务即使收到第二次写请求,也可能返回同一行。本次审批测试在恢复时将 publish 方法替换为“一旦调用就抛错”的替身,再运行 reconcile 路径;同时核对真实 SQLite 回执。这同时验证没有新派发和原业务结果仍可追踪。

证据 实际检查 证明范围
test_crash_after_effect_and_expiry_reconciles_without_write 批准过期后,调用 publish 即报错;恢复仍完成 本代码路径只做回执查询
test_no_receipt_after_dispatch_stays_unknown 查不到回执,连续恢复仍不调用 publish 未知状态不自动重发
test_cancel_after_effect_does_not_claim_rollback 取消后仍查到一条原回执,保留取消意图 状态报告没有伪造撤销
test_concurrent_approve_reject_one_decision_wins 两个真实子进程竞争,同一请求只有一个决定 本地数据库事务下的单请求竞争

测试没有跨区域网络、真实第三方队列或远端数据库灾备。生产核对服务需要定义查询的一致性、回执可见延迟、幂等记录保留期和最终失效条件;这些契约不同,结案规则也不同。

来源与验证

官方资料用于核对具体机制;表结构、程序与实验为本站独立设计。

验证记录 · 审批恢复证据