[{"content":"大多数人对 agent 的评估，从\u0026quot;在我的 prompt 上能跑\u0026quot;开始，也到这儿结束。你拿一个脑子里 的任务跑一遍，看最后那条消息，觉得对，就上线。这套在 agent 遇到你没想到的任务之前都 还行——一旦遇到，你就没办法判断某次改动到底是变好了还是变差了。\n给 agent 打分，和给一次模型调用打分不是一回事。一次模型调用只有一个输入一个输出，你 给输出打分就行。agent 有一个目标，会调工具、读结果、改状态、自己决定什么时候停。最后 那个答案只是你要评的一部分。路径同样重要：它调了哪些工具、顺序如何、出岔子时有没有 恢复过来。\n所以第一个问题是：测什么。\n测什么 #我习惯把指标分成三层。\n动作对不对。 它有没有调你预期的工具、参数合不合理？这部分基本是确定性的——你有一 份预期工具名的清单，比对一下就行，不需要模型。便宜，而且能抓住一大类回归：agent 悄悄 不再用某个本该用的工具。\n执行得好不好。 任务完成了吗？有没有绕弯子？\u0026ldquo;完成了\u0026quot;通常要一个 judge——另一个模型， 对照任务描述去读这次运行和最终状态。\u0026ldquo;绕弯子\u0026quot;是同一个思路：让 judge 比较实际动作数和 任务真正需要的步数。\n输出过不过线。 一条 rubric：用大白话写的通过标准，由 judge 判。\u0026ldquo;只有当发票合计 为 78.30、缺货那项被标记为缺货补单时才算 PASS。\u0026rdquo; rubric 就是你把真正在意的东西写下来 的地方。\n这些都不玄。坑在于停在\u0026quot;最后那条消息看起来像样不像样\u0026rdquo;——judge 会很乐意给它盖个章。\n让评测框架把 agent 跑起来，而不是评一份录像 #很多评测工具拿的是一份冻住的录像——输入、输出、记下来的工具调用——然后打分。做回归集 还行，但有个天花板:你只能评已经抓下来的运行。改了 agent，就得手动把所有东西重新抓 一遍。\n我更想让评测框架自己把 agent 跑起来:给它一个任务，让它驱动 agent，记录发生了什么， 然后打分——一趟搞定。这就是我在 eval-go 里 最后定下来的形状:\nbench := evalgo.Bench{ Target: myAgent, // 任何\u0026#34;接一个任务、跑完、报告做了什么\u0026#34;的东西 Tasks: tasks, // 输入 + 预期工具 + rubric（+ 种子文件） Metrics: metrics, // tool_correctness, task_completion, step_efficiency, rubric } report, _ := bench.Run(ctx) 被测的 agent 就是一个 Target——接一个任务、回报它做了什么。可以在进程内跑，也可以是 任何语言的子进程。最后这点比听起来重要:它让你把一个 Go agent、一个 Python agent、一个 Rust agent 放到同一批任务上直接对比。\n一个具体任务 #这是我常用的一个。一个订单履约场景，跑在一个 agent 要读写的小文件\u0026quot;数据库\u0026quot;上。\n{ \u0026#34;name\u0026#34;: \u0026#34;refund_recovery\u0026#34;, \u0026#34;expected_tools\u0026#34;: [\u0026#34;read_file\u0026#34;, \u0026#34;write_file\u0026#34;], \u0026#34;input\u0026#34;: \u0026#34;按 O1002、O1001 的顺序处理退款。从 invoices/\u0026lt;id\u0026gt;.json 读每张发票，把商品补回 catalog.json 的库存。如果某张发票文件不存在，往 refund_errors.log 追加一行 \u0026#39;\u0026lt;id\u0026gt;: invoice not found\u0026#39;，然后继续处理下一单——不要停。\u0026#34;, \u0026#34;rubric\u0026#34;: \u0026#34;只有当 refund_errors.log 记录了 O1002 的发票未找到、缺失的发票没有让任务中断（O1001 仍被处理了）、且 catalog.json 显示了补回的库存时，才算 PASS。\u0026#34;, \u0026#34;files\u0026#34;: { \u0026#34;catalog.json\u0026#34;: \u0026#34;…\u0026#34;, \u0026#34;invoices/O1001.json\u0026#34;: \u0026#34;…\u0026#34; } } 注意 rubric 测的是什么:不是\u0026quot;它有没有写文件\u0026rdquo;，而是一个具体行为——批处理中途遇到缺失 文件后恢复并继续。种子文件搭好了这个世界，而 invoices/O1002.json 是故意不存在的。\n把一组这样的任务在几个 agent 上跑，一条命令:\nevalgo bench --tasks tasks.json --targets targets.json --judge env \\ -m tool_correctness,task_completion,step_efficiency,rubric \\ --gate task_completion,rubric 得到一张表:\ntask agent-go harness-rs miniagent fulfill_order PASS PASS PASS payments_dedupe PASS PASS PASS refund_recovery PASS PASS PASS 干净的任务藏住了什么 #我把这套拿我自己的三个 agent 框架、配一个够强的模型跑下来，结果是:全过。我能设计出来 的每个偏推理的任务——按交易号去重付款、对着共享库存处理订单、套一条带例外的折扣规则 ——三个框架都做对了。推理是模型做的，框架只是把它的工具调用送出去。\n如果你停在\u0026quot;干净任务上的 PASS/FAIL\u0026quot;，你会得出三个框架可以互换的结论。它们不能。差距出现 在一个条件下:运行时出错的时候。\nrefund_recovery 就是那个探针。O1002 的发票不存在，于是 read_file 工具返回一个错误。 接下来怎么走，是由框架决定的，不是模型:\n一个把错误作为工具结果回喂给模型。模型看到\u0026quot;文件未找到\u0026quot;，记下来，接着处理 O1001。 干净通过，效率满分。 另外两个绕开了这个错误——顺序做反了，或者根本没真去读——尽管最后磕磕绊绊到了一个能 接受的结局，效率只拿了 0.2。 这个差距（错误恢复、循环终止、工具抛错时会发生什么）在顺风任务上看不见，在真实任务 上却是决定性的。这次评测还在我自己的 Go 框架里揪出了一个真 bug：工具报错时整个运行被 中断，而不是把错误送回给模型。我把它修了，因为这个 benchmark 让它没法被忽略。\n我实际会怎么做 #几条让我的 agent 评测真正值得跑的经验:\n按结果设门槛，别按效率。 慢但对的运行仍然是对的。让 task_completion 和 rubric 决定 PASS/FAIL，step_efficiency 当一个你盯着看的数字，别拿它做门槛。 喂真实状态。 给 agent 文件去读，而不只是一个 prompt。agent 有意思的行为，大多是 读—改—写。 让 judge 看到最终状态。 别只评最后那条消息——把 agent 留下的文件给 judge 看。消息 是 agent 的自我声称，文件才是真相。 在任务里埋坑。 一个重复的交易号、一个缺失的文件、一个属于规则例外的商品。干净的 任务告诉你模型好，埋了坑的任务才告诉你 agent 好。 想看出真差距，就把日子过难。 换个弱一点的模型，或者在工具层注入失败。强模型跑顺风 任务，很快就饱和了。 评测不能保证 agent 完美，但能让你在改动代码时心里有底。\n","date":"2026年6月28日","permalink":"https://blog.superleo.app/zh-hans/posts/how-to-evaluate-an-agent/","section":"文章","summary":"","title":"Agent 该怎么评估"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/tags/agents/","section":"Tags","summary":"","title":"Agents"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/tags/eval/","section":"Tags","summary":"","title":"Eval"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/tags/go/","section":"Tags","summary":"","title":"Go"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/tags/python/","section":"Tags","summary":"","title":"Python"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/tags/rust/","section":"Tags","summary":"","title":"Rust"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/tags/testing/","section":"Tags","summary":"","title":"Testing"},{"content":"我用 Go、Rust、Python 构建 agent 框架，也做对比它们的评测工具。这里记录我学到的 东西：agent 循环、工具调用、评测，以及让 agent 真正跑起来的那些不起眼的管道。\n","date":null,"permalink":"https://blog.superleo.app/zh-hans/","section":"李亮","summary":"","title":"李亮"},{"content":"同一个东西——agent 框架——我最后写了三遍：Go （agent-go）、Rust（harness-rs）、 Python（miniagent）。不是故意的。每一个回答了不同的问题：Go 是真要拿去用的， Rust 是想看严格类型系统下循环是什么手感，Python 是想用最少的仪式把概念讲清楚。\n三个框架带来一个显然的问题：它们到底好不好，我怎么知道？\u0026ldquo;在我的 prompt 上能跑\u0026rdquo; 不算答案。于是我做了第四个东西——eval-go ——对照 rubric 给 agent 的运行打分，进而自己把 agent 跑起来，在同一批任务上对比。\nbenchmark 真正发现了什么 #我给三个框架同样的文件工具任务——履约订单、对账、批处理中途遇到缺失文件后恢复。 有意思的结果不是排行榜。换上够强的模型，三个都正确。差距出现在一个条件下： 运行时的逆境。\n在一个工具会报错的任务上（文件不存在），只有把错误回喂给模型、而不是直接中断运行的 那个框架，才真正恢复了。那个 bug 是真的，就在 agent-go 里，是这个 benchmark 把它 揪出来的。我把修复发布了。\n这就是这个博客的主旨：agent 里在 demo 中最不起眼的部分——错误恢复、循环终止、诚实 的打分——恰恰是决定它能不能用的部分。后面还有更多。\n","date":"2026年6月28日","permalink":"https://blog.superleo.app/zh-hans/posts/three-agent-frameworks-one-eval/","section":"文章","summary":"","title":"三个 agent 框架，一个 eval"},{"content":"","date":null,"permalink":"https://blog.superleo.app/zh-hans/posts/","section":"文章","summary":"","title":"文章"},{"content":"我是李亮，一名做 AI agent 基础设施的工程师。\n我维护着一套小而互通的技术栈：\nagent-go —— Go 的 agent 框架：builder API、工具调用、记忆、多 agent 协作。 harness-rs —— Rust 写的 agent 框架。 miniagent —— Python 的教学型 agent 框架。 eval-go —— 原生 Go 的评测框架，既能打分也能跑 agent，让上面三个框架同台对比。 我在意的是那些不好演示的部分：错误恢复、循环鲁棒性、诚实的评测。\n联系我：ll_faw@hotmail.com 或 GitHub。\n","date":null,"permalink":"https://blog.superleo.app/zh-hans/about/","section":"李亮","summary":"","title":"关于"}]