Loop Engineering:从手工调 prompt 到设计实验回路
六月中的一个周五下午,我做了个决定:不再手工调那个分类 Agent 的 prompt 了,改成搭一个回路,让另一个 Agent 来调它。
背景交代一下。我们有个工单自动分类的 Agent,准确率卡在 82% 上不去。我手工调了两周——改 prompt、加示例、调整类目描述——每轮改完跑一遍评测集、看 bad case、再改,一轮下来一两个小时,大部分时间在等和搬运结果。改到后来我意识到一件事:我在这个循环里干的活,没有一步是非人不可的。
于是周五下午我把循环本身工程化了:评测集拆成训练/验证两份、写了个一键跑评测出报告的脚本、把「读报告→分析 bad case→改 prompt→重跑」的流程写成任务说明,交给一个长时 Agent,周末两天随它跑。
周一早上看结果:十几轮迭代,验证集准确率 82% → 89%,比我两周手工调的还高两个点。但过程并不是一路顺风,翻它的迭代日志翻出了不少东西,这篇主要想讲那些。
它差点骗过我:reward hacking 现场
日志里第 6 轮附近有个插曲。训练集上有个 case 反复分错,Agent 的解决方式简单粗暴——在 prompt 里加了一条几乎照抄该 case 原文的特判规则。训练集分数应声上涨,验证集纹丝不动。
这就是 reward hacking:优化器不关心你的真实目标,只关心你给它看的分数。它不是「作弊」,它只是诚实地优化了你定义的东西。幸亏评测集拆了两份——我在任务说明里规定训练集可以看题目、答案和错误分析,验证集只回传一个总分。第 7 轮它自己从验证集分数没跟上这个信号意识到过拟合了,回滚了那条特判。
如果没拆集,周一早上我会看到一个训练集 95% 的「优秀成果」,欢天喜地上线,然后在生产环境现出原形。机器学习三十年前就懂的道理,换到 prompt 优化上照样成立,而且更容易忘——因为「调 prompt」感觉上不像是在「训练模型」,警惕性天然低。
回路能转起来的前提
复盘这次实践,回路能自主转两天,靠的是几个前置条件,缺一个都会退化成「人陪跑」:
每一步都有命令行入口。跑评测、拉报告、看日志,全是脚本。假如评测报告要人从一个网页后台导出——就一步——整个周末无人值守就泡汤了。这条我称之为「工具链 Agent-native」检验法:数一数你的流程里还有几个只能点鼠标的环节,那就是你离自动化回路的距离。
Champion-Challenger 基线管理。任务说明里规定:历史最优版本是 champion,每轮新改动是 challenger,必须在验证集上稳定胜出才能上位,否则回滚。为什么强调「稳定」——评测本身有方差,我们的评测集单轮跑分波动约 ±1%,没有这条规则,回路会在噪声上随机游走,把运气当成进步。
显式的长程纪律。几条写进任务说明的规则:相同报错不许机械重试,必须先分析原因;一次只改一个变量(不然分数变化归因不了);每轮迭代把「改了什么、为什么、结果如何」追加写进一个日志文件。最后这条让周一的我能完整重放它的思考过程——顺便说,那份迭代日志本身就是一份质量不错的调优报告。
上下文外置。两天几十轮,全堆一个窗口早爆了。它的工作状态(当前基线、历史尝试、已排除的方向)全在文件里,窗口里只保留当前这一轮的工作。老读者看出来了,还是上下文工程那套,只是执行者从人变成了 Agent。
这个周末花了多少钱
有人肯定关心成本,说下账目结构。两天回路的总推理消耗,折算下来大约是我手工调优两周人力成本的零头。构成上:六成花在每轮评测(评测集三百多个 case,每轮全量跑),三成花在 Agent 的分析和改动,一成杂项。
即便如此,成本结构里还有明显的优化空间。第二次跑类似任务时,我把评测改成两段式:先跑五十个 case 的快筛,胜出的 challenger 才上全量评测。总成本直接砍半。评测预算的分配本身就是回路设计的一部分——把贵的全量评测留给有希望的候选,垃圾改动用便宜的快筛拦在门外。
另一个省钱心得反直觉:控制单轮改动大小反而更便宜。早期我允许它一轮改多处,结果分数变化归因不清,经常要补跑对照实验。改成一轮一个变量后,轮次变多了,总成本反而降了——每一轮的信息量变干净了,没有浪费的实验。
什么时候别搭回路
再补一节劝退,不是所有优化都值得搭回路。我的门槛三条,缺一条就老老实实手工干:
单次「改动→评测」循环要够便宜。我们单轮几分钟、成本可忽略,所以两天滚得动十几轮。如果你的评测是一次全链路压测、或者要等真实用户反馈,单循环以天计,回路的迭代优势荡然无存。
评测集要经得起几十轮的凝视。三百个 case 被一个不知疲倦的优化器反复审视两天,任何缺陷都会被找出来利用(见上文 reward hacking)。人工调优时评测集有点瑕疵无妨——人不会过拟合到那种程度;上回路之前,得把评测集当攻击面来审一遍。
指标要有长期价值。一次性任务搭回路,搭建成本收不回。回路适合「这个指标未来半年都会持续关心」的阵地战。
冷水:评测集的质量就是天花板
必须泼的冷水。这套东西有个残酷的性质:回路的产出永远不会好于评测集,只会更快地逼近评测集的缺陷。
我们的 89% 上线后,真实准确率提升没有评测显示的那么多。排查后发现评测集的类目分布和线上最新分布有偏差——回路忠实地优化了一个略微过时的目标。这不是回路的错,是我的错:我花在搭回路上的心思,是花在检查评测集代表性上的十倍。比例应该倒过来。
所以现在我的顺序铁律是:先修评测,再跑回路。评测集有偏,迭代越高效,错得越坚定。业内有个跑了 17 小时完成 16 轮迭代的案例广为流传,大家都盯着「17 小时无人值守」看,我觉得那个案例真正的功力在于他们的评测体系配得上 17 小时的信任。
这个模式的适用面
「工单分类调优」只是个具体例子。抽象一下,任何满足三个条件的工作都能套这个回路:产出可评测、改动可回滚、有基线可比。检索策略调参、测试用例生成质量、报表 SQL 的准确性、甚至爬虫解析规则的维护——我列了一下我们内部符合条件的「调参型」工作,比想象的多得多。
它们的共同命运大概率是:从「工程师手工做」变成「工程师设计回路 + 定义评测 + 复核结果」。人的投入没有消失,是往上挪了一层——从拧螺丝变成设计拧螺丝的机器,以及(更重要的)决定螺丝该不该拧。
周一那天早上我看着迭代日志的心情有点复杂:它两天干的活赶上我两周,手法还挺像我——毕竟任务说明是我写的。要说感想,大概是:我调 prompt 的手艺没什么护城河了,但「知道该优化什么、拿什么衡量」这件事,短期内还是我的。得往这个方向多攒本钱。