Articles
一场被指标带偏的 LLM 业务实验
这不是一篇调 prompt 的经验贴,而是一篇关于我如何和 Codex 一起,把一个本应服务业务的实验,逐步做成了一个奖励错误目标的系统的复盘。
这不是一篇调 prompt 的经验贴。更准确地说,这是一篇关于我如何和 Codex 一起,把一个本应服务业务的实验,逐步做成了一个奖励错误目标的系统的复盘。那几天我在高强度优化一个法律文书自动填写功能,目标原本很朴素:在成本、质量、效率之间找到一个真正可用的平衡点。我几乎把所有可用时间都投进去了,也让 Codex 深度参与,从搭回归框架、跑模型对比、整理结果,到继续提出下一轮实验假设。最后真正暴露出来的,却不是某个模型强不强,而是我和助手一起,把一个应该不断贴近业务的问题,慢慢做成了一个越来越自洽、越来越像科学实验、也越来越偏离真实目标的闭环。
我最初以为自己在做一件相当正常的事。自动填写这种功能天生很难靠主观印象做判断,所以我想把它尽量放到一个可以比较、可以复现、可以迭代的框架里。我的初衷并不复杂:先找一些真实样本,尽量走真实链路,用统一的输出和统一的标准去比较不同模型和不同提示策略,看谁更便宜、谁更稳、谁更像真正能上线的候选。Codex 在这个过程中很自然地成了加速器。它擅长把模糊的想法改写成可执行的任务,把零散的观察整理成结构化结论,也擅长在我提出“再试几轮”“换个角度比”“把这套评测再收紧一点”的时候,迅速把这些要求变成一轮轮具体实验。站在起点看,这一切都很合理,甚至很像我一直希望建立起来的那种工作方式:不是凭感觉做 LLM,而是让 LLM 优化工作进入某种有证据、有节奏、有积累的状态。
问题出在接下来的几步,它们每一步都不荒谬,但连起来之后,事情就开始变形了。第一步是 baseline 和回归框架。为了避免每次都凭印象说“这次好像更好”,我先把样本固定下来,把期望输出固定下来,把测试入口固定下来。这样做的好处非常明显:模型一换、提示一改、得分就会变,实验终于从聊天变成了某种可以比较的对象。第二步是引入更细的评估。原始的“有没有填上”太粗,我开始加入更细的比较方式,例如某些字段按精确值比,某些长文本再额外交给 judge 去看语义是不是更接近 gold,于是结果看起来更有分辨率,也更像是在做严肃评测。第三步是实验纪律不断升级。轮次从随手试几版,变成至少十轮;流程从并排放一堆候选,变成上一轮分析驱动下一轮生成;判断从“哪版看起来更好”,变成 challenger、复跑、稳定性验证、跨模型迁移。第四步是整套系统开始收口。它不仅能给分,还能解释为什么给分;不仅能挑 winner,还能总结某类错误该如何通过提示或规则压下去。到这一步时,整个过程已经非常像一套科学实验了。危险恰恰也在这里:问题不是我做得不够严谨,而是我越来越严谨地在优化一个代理目标。
真正的失真,就是从这里开始发生的。先是古德哈特定律。我的原始问题明明是“这个功能能不能更可信地完成自动填写”,但实验系统很快把它改写成了“哪个模型在某个评分函数上更高”。一旦分数变成中心,系统就会自动奖励那些更容易拉高分数的行为,而不一定奖励那些更贴近真实业务的行为。比如某一轮里,长文本字段的 judge 更偏好“语义上更像 gold”的回答,那么更擅长组织语言、生成看起来更完整文本的模型就会占优。可自动填写这件事真正需要的,很多时候并不是“写得更像参考答案”,而是“更克制、更忠于材料、更少做不该做的解释”。从业务角度看,漂亮的表达未必比保守的搬运更有价值,甚至可能更危险。
然后是过早形式化收敛。当时我的样本其实很少,我对真实用户的需求理解也并不深。更具体一点说,我知道自己在做“法律文书自动填写”,但并没有真正进入到一个足够清楚的用户视角里去回答:法务或录入人员到底最怕什么错误,什么错误可以容忍,什么字段宁可空着也不能猜,什么看起来相近的表达其实在业务上不可替代。按理说,在这种理解还没有扎实之前,评测体系应该保持松动,允许不断返工和修正。但我和 Codex 的协作模式天然会推动形式化。因为一旦一个问题被说成“请固定样本、固定 gold、固定 judge、跑十轮、给排名”,它就立刻变成一个可以执行的工程任务。Codex 很擅长做这件事,而我当时也迫切需要这种推进感。于是 gold 更明确了,judge 更明确了,轮次要求更明确了,排名规则更明确了。形式上看,实验越来越严谨;本质上看,是在需求理解仍然模糊时,过早把一套暂时性的判断冻结成了评测制度。
再往后,就是自洽闭环。这里的问题不只是“样本少”,而是同一批样本被拿来做了太多事:用它们发现问题,用它们定义标准,用它们提炼失败模式,再用它们验证改进。于是系统越来越会解释自己,也越来越会说服我。某个字段总是错,那就把这个错误命名;某种扩写总出现,那就把它写成负例;某轮 prompt 压住了某类错误,那就让下一轮继续沿这个方向强化。每一步都顺理成章,但合起来之后,实验已经不再只是观察系统,而是在同一套材料上不断重写“什么叫好”。最危险的地方在于,这种闭环非常容易给人一种成熟感。你会觉得自己不仅找到了问题,还找到了问题的结构;不仅能修错误,还能解释错误是如何被修掉的。可一旦“发现问题”“定义标准”“验证改进”都在同一小块地盘里完成,系统就会越来越自圆其说,而不是越来越接近外部世界。
这里还有两个更朴素、也更让我后知后觉的问题。一个是需求陌生。那几天我不断和模型、指标、输出打交道,却并没有同等强度地和真实用户需求打交道。我当然知道这是一个文书自动填写场景,但“知道场景”与“真正理解使用者如何判断结果是否可信”之间,差得很远。很多时候我其实是在让评测体系替代用户。只要一个输出更像 gold,只要一轮结果更可比较,只要一份报告更会总结,我就容易下意识地把它当作离用户更近。另一个是样本过少。高强度实验会制造一种错觉,好像自己已经看到了足够多的模式。实际上不是。两三天里做很多轮试验,并不等于见到了足够多的现实。它更可能意味着:我在一小批样本上看见了越来越清晰的结构,然后误以为自己看见了问题本身。
如果只把这些问题归到我身上,其实也不完整。因为 Codex 在这个过程中并不是一个被动记录者,而是机制的一部分。它擅长把目标形式化,擅长把模糊问题收束成可执行任务,也擅长在当前目标被定义之后,把整个系统往更清晰、更整齐、更高效的方向推。可它不会天然替我对抗错误目标。如果我没有主动保留反证、没有主动扩大样本、没有主动问“这是不是已经在奖励错误行为”,它就会顺着当下的评测框架,把体系做得越来越漂亮。某种意义上,这正是它的强项,也是它的风险。对一个还在找问题边界的人来说,这种强项很容易把推进速度错认成认识质量。我负责设定目标与边界,它负责把当前目标推到极致。一旦目标偏了,我们就不是一方纠正另一方,而是会一起把偏差工程化。
也正因为这样,我当时没有及时停下来,其实并不奇怪。陷阱之所以难以察觉,是因为局部改进都是真的。每一次实验收紧,都会解决上一轮里某个具体的不满;每一次评估细化,都会减少一点“只能靠印象判断”的不安;每一次报告生成,都会让结果显得更完整、更可比、更有依据。Codex 的帮助又把这种感觉进一步放大了。它让推进速度快得惊人,也让每一步都更容易留下痕迹。你会看到更清楚的对比表、更像样的 round 命名、更完整的结论摘要,于是很自然地产生一种感觉:我不是在乱试,我正在逐步逼近正确答案。可事后回看,真正的问题恰恰是这种逼近感本身。因为它不是来自对用户需求更深的理解,也不是来自更丰富的样本和更强的外部验证,而是来自内部系统越来越会解释自己。更麻烦的是,Codex 也没有主动提醒我样本不足、需求理解不足、指标替代目标的问题。但这件事同样不能简化成“助手失职”。我当时并没有明确要求它扮演一个持续唱反调、持续拉回业务目标的角色,我更多是在要求它推进、整理、比较、收敛。于是它就很好地完成了我交给它的任务,只是这个任务本身并不够对。
所以回头看,这次实验真正留下来的,不是某个模型应不应该被选中,也不是哪种提示策略暂时赢了几轮,而是几个我现在还没有完全回答的问题。面对真实业务,什么时候应该先扩样本,什么时候才值得先做精细评测?当我对需求理解还浅的时候,到底应该允许什么程度的形式化,才不会把临时判断过早冻结成制度?在人机协作的实验里,能不能有意识地设计一种“反证角色”,让助手不只是沿着当前目标加速,还会不断追问这个目标本身是不是错的?更根本一点,对 LLM 业务优化来说,什么才算真正可信的改进?是某个评分函数更高,是某类错误被压下去,是一套回归框架已经建好,还是只有当一个系统在更大的样本、更陌生的情境、更贴近真实用户的判断下仍然稳住时,我们才配说自己真的前进了一步。那几天我和 Codex 一起做出来的,不是一个已经解决的问题,而是一个被暴露得更清楚的问题。它还没有答案,这反而是它最有价值的地方。