从零搭建 Agent Harness 系列(二十五)剧本回放评测与 Trace 尺子

系列二十四把 MCP 和自家信封的 A2A 接进 Registry。之后又补了官方 SendMessage / Agent Card,以及把 spawn_subagent 挂上 Factory。阶段十二要回答另一件事:固定任务上行为有没有回退,一次 Run 慢在哪。

一到十一的 go test 测的是函数。评测测的是整条 ReAct:终态对不对、调了哪些工具、取消后是否成对。性能先有尺子,再谈优化。这一刀两件事一起做:剧本回放,以及在已有 Trace 上记三个数。

本文对应 go-tiny-claw 提交:

1
8fd935d  feat: 用剧本回放评测 Agent,并在 Trace 上记下延迟尺子

官方 A2A 与 spawn_subagentee4048b,不在本篇展开。

一、评测不是再写一遍 engine 测试

test/engine 里已经有预算、取消、断档。每份测试自己捏一个假 Provider,证明某一个分支。评测要的是同一套入口、多条固定任务:给一句 prompt,跑完 Engine.Run,对历史和工作区打分。

1
2
3
4
5
任务是否完成
是否调用正确工具
是否越权写入
取消后 Observation 是否成对
Token 超了会不会停

真模型贵、飘、难进 CI。第一刀只用剧本:按轮吐固定的 assistant / ToolCall,工作区是 t.TempDir()

二、eval 在根上,只调用 internal

评测不是 Engine 的一部分,循环不该 import eval。它和 cmd/claw 一样,是消费方:

1
2
3
4
eval  →  internal/engine
→ internal/context
→ internal/tools
→ internal/observability

放根目录 eval/,一个包,先不分 cases/go test ./eval 就能跑。以后要 cmd/claw_eval,直接 import 这个包,不必从 test/ 里往外搬。

1
2
3
4
5
eval/script.go     剧本 Provider,可带 Delay
eval/run.go 组 Engine / Session / Gate,调用 Run
eval/assert.go 历史、工具名、Observation
eval/metrics.go 从 Agent.Run 读尺子
eval/cases_test.go 六条任务

Run 自己 StartSpan("Eval"),Engine 再挂上 Agent.Run。评测结束时父 span 还在,尺子从子 span 读,不用改 Run 的返回值。

默认 Registry 只有 read_file / write_file / edit_file,不接 MCP、不拉 Factory。审批默认 AllowOnce;要测拒绝就传入 DenyHandler

三、六条任务证明什么

任务过线条件
只读作答终态含文件原文,只调了 read_file
唯一编辑edit_file 一次,磁盘内容变对
危险写入被拒write_file 被 Deny,文件不存在,Observation 写「拒绝」
取消半截工具工具堵住后 cancel,该 ToolCallID 仍有 Observation
Token 预算停MaxTokensPerRun 触顶,Generate 不再打第二次
TTFB + 墙钟剧本延迟 40ms、工具睡 40ms,尺子都 ≥ 30

预算那条复用阶段九的闸:第一次调用用满额度,第二次 checkRunBudget 直接错。评测断言的是「停了,而且假模型只被叫过一次」,不是再实现一遍预算。

四、尺子写在已有 Trace 上,不另打日志

机制早就有:首 Token 超时 15 秒、Session 累计 Token、工具墙钟。缺的是数字。超时逻辑不动,只在 generate 里记下第一次吐字(或非流式 Generate 成功返回)距开始的毫秒,属性名 ttfb_ms。同一 span 只记一次。

endRunBudget 会把 toolElapsed 清零。所以根 span 的 defer 必须先快照再清:

1
2
3
4
prompt_tokens / completion_tokens
tool_wall_ms
把子 span 上第一个 ttfb_ms 抄到 Agent.Run
然后 endRunBudget、EndSpan、写盘

eval.MetricsFrom 找到 Agent.Run,读这四个数。CI 只跑假 Provider。真模型的「首 Token 800ms」是夜间任务,不要进 go test

五、阶段十二还没做完的

1
2
3
4
5
真模型评测(同一套断言,分数允许浮动)
Trace 异步写盘
cmd/claw_eval
并发 Run 压测、连接复用
部署:密钥、租户、健康检查、SLO

TotalCostCNY 仍是 0。MCP 工具热刷新也还没做。评测集以后加任务,往 cases_test.go 里加函数即可;框架不必跟着涨。

总结

二十四解决「手和同事从哪来」。二十五解决「怎么知道没回退,以及慢在哪」:

1
2
3
4
5
6
7
8
9
eval/ 单向调用 internal,不进 Engine

剧本 Provider + TempDir,六条固定任务

同一条 Engine.Run,对历史和工作区打分

根 span:ttfb_ms、Token、tool_wall_ms

CI 只跑假模型

有回放才能改循环而不瞎;有尺子才知道慢的是模型、工具还是写 Trace。部署治理另开。