先亮旧稿。前阵子跑代码生成,第一版 system prompt 是这么写的:
你是一名资深软件工程师,必须严格遵守以下要求:仔细阅读函数签名和注释,务必理解全部需求,然后生成完整、准确、可直接运行的代码,不得遗漏任何边界情况。请注意,本任务非常重要,请认真对待。
四十多个字,字字都觉得自己有道理。问题就出在有道理上。
【务必】【必须】【请注意】是客套字,不解决任何歧义,只把气氛搞紧张。模型接不住态度,它接得住的是步骤。【务必理解全部需求】最虚——“全部需求”是个筐,模型永远没法确认自己理解全了,于是只能堆防御性检查来表忠心,真正的实现逻辑被淹了。
类似的效果,一篇叫 ECLAIR 的论文用案例研究验证过。它测了指令式、更长少样本、签名增强三种提示设计对两个模型代码生成准确性的影响,结论是三种都有小幅负面因果效应。
三种人人都爱用的“增强”,全在帮倒忙。我拆开讲。
指令式。旧稿:务必理解全部需求,生成完整、准确、可直接运行的代码(25字)。新稿:按函数签名和注释逐条处理输入,列出所有边界情况再写实现(24字)。
字数没变多少,分量换了。旧稿的诗眼是【务必】——只有态度没有内容的词,模型收到的是重音,不是路径。新稿的诗眼是【逐条】——可执行的动作序列:“一条一条来,别跳”。同样的字重,一个喊口号,一个画路线。
再说少样本。第一版放五个示例,按“简单到复杂”排。跑十几条,模型在第三个示例之后开始往复杂风格上靠,简单输入也输出一大堆没必要的分支。V2 倒过来,复杂到简单。跑偏没了,但模型对第一条锚得太死,后面四条白放。V3 才想明白:位置不是重点,“最后一条离输出最近”才是。模型对结尾处的示例天然敏感——放在最后的那条,等于在告诉它“这就是本次任务该有的风格”。把风格最贴目标那条放最后,其余垫场,三个比五个管用。
ECLAIR 测出来的“更长少样本”负效应,说的就是这件事。你以为加的是信息量,实际上加的是干扰项。模型不需要你展示五种写法,它需要你告诉它哪一种是“对的”。
再来说签名增强。旧稿在 prompt 末尾补了半截函数签名,让模型接着写:
请生成 JavaScript 函数,处理输入并返回结果。 旧稿补充:function process(input) {
这个技巧我一度推得最凶,直到一次跑递归逻辑,模型的整个排序逻辑被塞进一个 return 里——签名把思路钉死了。它以为你给的是终态,它只需要填空;填得越暴力越好,因为“形状已经定了”。
签名增强的本质是 prefill。开头定得越具体,模型越懒得想后面——不是它偷懒,是你把思考责任提前收缴了。签名只定了形状、没定逻辑,等于把模型变成填空机器。ECLAIR 说它有小幅负面因果效应,我认为原因就是这个虚假的终局感。
改到第三版,定稿放这:
任务:按函数签名实现该函数。
约束:
1) 先列出输入可能的类型和取值范围;
2) 再逐条确定每种类型的输出;
3) 实现里每个分支都要有对应注释,说明它应对的是哪种输入。
示例:{输入:null,输出:异常——"输入不能为空"}
和最初那版比:第一,没有任何“务必”“必须”,指令本身把动作写清了,不需要重音;第二,示例只有一条,但恰好示范了“先判断输入类型,再决定怎么做”的结构;第三,删掉签名那半截,让模型自己决定函数体。
但我不敢说这是终版。ECLAIR 的结论是结构性的:这些增强的效应依条件而变,没有一种写法天然得宠。我改到第三版,也只敢说“在当下这个任务里能用”。以前有一条 system prompt 被我改了七八版才敢用,隔三周回头看又觉得扎眼。
为一个字纠结一下午,说出去有点丢人,但真的有用。这版先用着,哪天被条件推翻了,回来再改就是。
