1100美元复刻Next.js之后:Agent时代,测试用例才是真正的护城河

0 阅读10分钟

上个月,Cloudflare工程师Steve Faulkner干了一件让整个前端圈炸锅的事儿——他用Claude花了一周时间、烧了1100美元API token,就把Next.js的核心功能在Vite上重写了一遍。构建速度快了4.4倍,客户端包体积缩了57%。

他没有去读Next.js的源码。他用的是Next.js公开的2000多个测试用例——把这些测试当成"机器可读的技术规格说明书",让AI一个接一个地把它们跑通。测试全绿,功能就算复刻完成。

tldraw团队看到这个消息后,24小时内就把自己的测试套件从公开仓库挪到了私有仓库。虽然后来澄清说"有玩笑成分",但他们保留了那个Issue让社区继续讨论。

这件事儿给了我很大触动。不是因为AI能复刻框架——这在当前大模型的能力下已经不足为奇了。而是它用一种极其直白的方式告诉所有做技术的人:你精心编写的测试套件,可能比你的源码更值钱。

先聊一个被忽视的工程概念:Harness Engineering

做Agent的人太多了,但大部分人把精力花在调prompt和上下文工程上。模型换了一版、system prompt改了两句,效果飘了,又从头调。或者塞入更多的上下文,但是有可能其它场景又有问题。这跟十年前手动部署服务器然后线上出了bug全靠肉眼看日志,本质上没区别。

Harness Engineering是从另外一个方向来解决这个问题——给Agent搭一套能运行、验证、修复、回归的工程化环境

说白了就是几个原则:

让你的应用对Agent可读——日志要结构化、追踪要有trace ID、测试结果要机器能解析,不是人肉看截图;把知识沉淀在代码仓库里而不是某个人的脑子里——因为Agent读不到你的脑子;把验证机制编码成系统,别指望在prompt里写一句"请确保输出正确"就能管用。

举个具体例子,你的Agent调了一个外部API做数据清洗,某天这个API的返回格式从v1悄悄升级成了v2——多嵌套了一层JSON。如果你的Harness里集成了contract test,这个变动在CI阶段就会被拦住,你收到一条告警然后去适配。如果你没有这个门控呢?Agent照常跑,只是输出开始静默地丢字段、错解析。你可能过了两周才从下游的业务报表里发现数据不对,然后花三天回溯到底是哪个环节出了问题。

Harness Engineering是Agent从"demo能跑"到"生产可用"之间那道最关键的工程门槛。

传统软件工程里,我们花了二十年时间才从"手动构建部署"进化到CI/CD全自动流水线。Agent工程化也在走同一条路,只是速度快得多。你搭了一个Agent pipeline,接了工具调用,串了几个子Agent做多步推理——跑通了,挺高兴。

然后呢?

模型供应商升了一个小版本,某个工具的API返回格式变了,或者你加了一条新的system prompt——任何一个微小的变动都可能让Agent的行为漂移。你甚至不知道它漂了,因为Agent不会像传统程序一样直接报错,它只是开始犯一些微妙的、不容易察觉的判断失误。

代码会crash,Agent只会quietly drift。这才是最危险的。

这就是为什么光搭了Harness还不够,你得有持续的测试和评估体系来兜底。

当测试用例变成最值钱的资产

回到开头那个1100美元复刻Next.js的故事。

这件事在开源社区引发了一场严肃的讨论:如果AI可以把你的公开测试用例当"规格说明"来用,那开源的边界在哪里?

实际上,这不是一个全新的话题。SQLite——全世界被部署最多的数据库——很早就想明白了这件事。SQLite的核心代码是公有领域(Public Domain),谁都能用。但它的核心测试框架TH3是闭源付费的。这套测试有50000多个用例、超过100万行代码,能达到航空级别的100% MC/DC覆盖率。

你品品这个策略:代码随便拿,但你拿不到让它真正可靠运行的那张"验收清单"。

vinext事件之后,这个讨论直接从理论层面变成了现实威胁。Simon Willison在他的博客里分析tldraw这件事时指出:全面的测试套件足以让任何人用不同语言从零重建任何开源库。Simon Willison写技术评论多年了,这个判断我觉得不夸张。

在AI时代,代码的可复制成本趋近于零。真正有门槛的是那些精心设计的测试用例——它们蕴含的是你对业务边界、异常场景、性能极限的深层理解,这些东西prompt复制不了。

Agent测试的真实困境

道理都明白了。但做过Agent测试的人知道,落到实操层面,坑多得离谱。

非确定性输出是第一个拦路虎。 传统程序,输入确定,输出确定,assert一下就完事。Agent不一样——同一个prompt跑十次,可能出来十个不同的结果,而且每个看起来都"说得过去"。你怎么判断哪个是对的?用精确匹配?废了。用人肉看?你有一千个用例,每个跑五轮trial,看到眼瞎也看不完。

评估维度炸裂是第二个坑。 一个Agent的输出可能需要同时检查:格式对不对(JSON schema匹配)、关键信息有没有漏(contains检查)、有没有触碰安全红线(constraint检查)、整体质量如何(需要LLM来评)——每个维度的评判逻辑完全不同,传统单元测试框架根本hold不住这种复杂度。

成本和速度的矛盾是第三个。 每次评估都要调API,tokens要烧钱的。你想做回归测试,每次改了prompt都跑一遍全量用例?CI pipeline得跑到天荒地老。但如果不跑,你就不知道改动有没有引入负向影响。

还有一些更琐碎但真实的麻烦——跑到一半网络抖了怎么办,评估结果怎么持久化方便回溯,两次跑的结果怎么diff出差异,怎么跟现有的CI/CD流水线集成让它自动挡住质量不达标的发布……

这些问题每一个都不大,但叠在一起,就足以让大部分团队的Agent测试停留在"手动跑几个case看看效果"的阶段。

AgentEval,开源Agent原生测试框架

AgentEval(github.com/wallezhang/… 是一个用Go写的Agent评估框架。YAML驱动配置,SQLite持久化结果,命令行一把梭。设计它的时候,我脑子里就一个念头:把上面那些琐碎但致命的工程问题,一次性解决干净。

它是怎么解决"非确定性"这个核心难题的呢?

AgentEval实现了Anthropic提出的pass@k和pass^k指标。每个测试用例你可以配置跑多轮trial——pass@k衡量的是"k次里至少成功一次"的概率,代表Agent的能力天花板;pass^k衡量的是"k次全部成功"的概率,代表Agent的可靠性地板。

这两个数字一起看才有意义。一个Agent如果pass@5很高但pass^5很低,说明它"能做到但不稳定"——这种Agent你敢上生产吗?

框架内置了8种Grader:

类型干什么用典型场景
exact_match精确匹配分类任务、选择题
contains关键词包含检查输出是否提及关键信息
regex正则匹配格式校验、数据提取验证
json_matchJSON字段校验结构化输出验证
llm用LLM做裁判开放式回答的质量评估
constraint约束检查安全合规、字数限制、禁用词检测
pairwiseA/B对比模型切换前后的质量比较
command自定义脚本任何你想得到的自定义校验逻辑

这些Grader支持加权组合——给一个task同时挂多个Grader,每个占不同权重,最后算综合得分。这就不是简单的pass/fail了,而是一个多维度的质量画像。

同时,为了节省成本和提高速度,框架实现了两种机制:响应缓存断点续跑。缓存开启后,同样的prompt+模型组合不会重复调API,省钱;跑到一半网络抖了,--resume​一下从断点继续,不用从头来。

然后是CI/CD集成——我觉得这是最被低估但最实用的设计。跑完评估后加一个失败的阈值--fail-under 0.8​,通过率低于80%直接返回非零退出码,pipeline可以根据非零退出码自动拦截流程。配合生命周期钩子(hooks),你可以在评估开始前自动部署Agent、评估结束后自动发通知、甚至在每个task执行前做环境清理:

hooks:
  before_run:
    - "echo 'Deploying agent to staging...'"
  after_run:
    - "python notify.py --channel slack"

多次评估之后,框架还支持历史的评测结果对比。每次评估的结果存SQLite,你可以agent-eval compare ​直接看两次跑之间的diff——哪些用例从pass变成了fail,延迟的P99分布有没有恶化,token消耗涨了还是降了。HTML报告可以直接发给不写代码的PM或技术负责人看,不用再额外做一份汇报材料。

测试不是跑一次就完事的。Agent会drift,模型会升级,prompt会迭代——你需要的是一条持续运行的质量基线,不是一次性的手动验收。

回到那个更大的问题

vinext事件之后,很多人在讨论"开源项目要不要闭源测试用例"。我觉得这个问题问反了。

真正该问的是:你有没有一套足够好的测试体系,好到值得被保护?

大部分Agent项目的现状是——连像样的测试都没有。prompt写了一版又一版,每次改完全凭手感判断"好像效果还行"。这跟2005年那些不写单元测试、靠人肉点点点来验收的Web项目,何其相似。

Agent工程化的路径其实很清楚:Harness Engineering搭好运行环境,持续测试保证质量不漂移,测试用例本身作为最核心的知识资产被管理和保护。这三件事是一个完整的链条,缺了任何一环都立不住。

AgentEval解决的是中间那一环——但我觉得它同时也在倒逼你去认真思考前后两环。当你开始认真写评估用例的时候,你会被迫去定义"什么叫好的Agent行为"。这个定义过程本身,就是最有价值的工程产出。


你的Agent有多少个评估用例?如果答案是"零"或者"几个手动跑的"——那我觉得比起调prompt,你可能更需要先把测试跑起来。