指出 Prompt 修改与代码修改的本质差异:Prompt 效果是分布式的、影响范围不可见、微小调整可能产生大幅行为变化。提出从效果可测性、影响范围声明、位置敏感性三个角度建立审查框架。
一次提示词变更,就是对所有使用它的请求的行为变更——它通过一套本为代码设计的审查流程发布,因为代码的行为可以从 diff 中直接读出。审查者面临的问题是:六行字的编辑可能同时影响准确率、成本、延迟和输出格式,而这些在补丁中全都不可见。
普通代码审查之所以有效,是因为 diff 和效果非常接近。改一个比较操作符,审查者可以追溯发生了什么。提示词编辑在三个方面打破了这个关联。
效果是分布式的。 加上"请简洁"并不会让输出变得简洁;它只是把输出的分布往某个方向移动了。这有没有帮助,取决于大量样本,没人能靠阅读文本回答这个问题。
波及范围未声明。 一个共享的系统提示词可能服务于六个功能。diff 显示的是一个文件;但变更会影响到所有导入它的地方,包括那些依赖于被这次编辑放松了格式的下游解析器。
小编辑不等于小改动。 重排指令、换一个例子、或者把一个约束从末尾移到中间,对行为的影响可能远大于加一段话。提示词中的位置不是中性的——参见提示词敏感性。
所以审查不能是"这段文字看起来合理吗"。它必须是对审查者无法自行推导出的证据的检验。
如果变更显示为 Python 或 TypeScript 字符串字面量中的一行修改,先停下来,要求把提示词移到一个独立文件。你没法逐词审查你看不到的东西。这事值得做一次,一劳永逸——把提示词存为文件可以永久解决未来所有 PR 的这个问题。
描述中应该列出读取此提示词的每一个功能和每一条代码路径。如果作者不知道,这就是发现的问题:一个使用者未知的提示词无法被安全地修改。
不是"测试通过"——单元测试反正都会通过的。你要的是黄金数据集的运行结果、修改前后的通过率,以及在任一方向上改变了判决结果的任何用例的标识符。一个开始通过的用例和开始失败的用例一样值得关注,因为它可能因为错误的原因开始通过了。
如果下游有任何东西在解析响应,schema 断言必须仍然成立。添加自然语言指令的编辑往往会在副作用中放松格式合规性。
新文本中的每个占位符都必须由调用代码提供,每个提供的变量也应该仍然被使用。一个未被替换的占位符到达模型是一只静默的质量 bug,而不是一个错误。
用提供商文档中指定的分词器,在一个有代表性的渲染后提示词上测量出一个数字。参见下一节了解如何处理它。
如果你在响应上记录了提示词哈希——你应该这么做,这样支持工单就可以追溯到生成它的提示词——那么这个 PR 必须产生一个新的哈希,而且不需要手动更新任何其他东西就能实现。
问一下如何在凌晨两点用两分钟把它关掉。如果答案是"回滚 PR 并重新部署",那就要权衡这个风险和变更的规模。
拒绝行为、PII 处理,以及因为过去的事故而存在的任何指令。这些在"为了清晰而重写"的过程中被意外删除的频率远高于故意删除,所以要专门检查是否有被移除的内容。
系统提示词上的 token 增量会乘以每个请求,这使得从 diff 上很容易低估它。要明确地计算它,每个输入都要命名。
以一个将系统提示词增加 180 个 token 的变更为例, endpoint 每月服务 400,000 次请求,假设输入价格是每百万 token 3 美元。那么 180 × 400,000 = 72,000,000 每月额外输入 token,按每百万 3 美元计算就是每月 216 美元。公式中的每个数字都是使用它的那个句子中声明的假设:替换成你自己的 token 数量、你自己的量,和你读这篇文章那天提供商列出的价格。算术过程是重点,而不是总数。
通常有两个调整。如果添加的文本位于缓存前缀内部,而且你的提供商对缓存输入按折扣价计费,有效成本会更低——但这只对命中缓存的请求生效,所以你需要知道命中率才能说出具体低多少。而且如果编辑改变了输出长度,输出增量通常占主导地位,因为输出 token 的定价通常是输入的数倍。要测量回归运行中的平均输出长度,而不是靠猜。
每个 token 的价格和缓存折扣率会随时变动。PR 描述中的任何成本数字都应该带上计算日期,否则六个月后会被人当作还是正确的数字来引用。
把这个做成模板,这样每次就不用谈判了。一次提示词变更 PR 应该包含:一个真实输入渲染前后的提示词;回归运行标识符及两端的通过率和翻转用例列表;token 增量及其成本计算;使用者列表;以及回滚机制。五项内容,所有这些作者在开 PR 之前就已经有了或者应该已经获取到了。
渲染后的提示词比听起来更重要。审查者读的是模板;模型读的是渲染结果,包括检索步骤注入的内容和模板引擎产生的任何空白。存在于这个间隙中的 bug——一个杂散的分隔符、一个把指令和它的例子分开的双换行——在模板 diff 中是不可见的,但在渲染结果中一目了然。
阻止一个提示词变更直到被证明正确,是阻止任何人改进提示词的好方法,因为证明成本高昂且不完整。更可行的做法是:看证据拦截,而不是看结果拦截。
以下情况应该拦截:PR 完全没有回归证据、schema 断言发生退化、安全指令被移除而没有提及、或者没有比部署更快的回滚路径。当证据存在但模糊不清时放行——在 flag 后面、以部分流量——当你的测试套件的噪声范围内通过率有小幅度移动时,正是灰度发布能解决的问题,而审查者无法判断。决定什么比例和什么对比,是另一个问题,参见选择灰度百分比。
最后一个值得培养的审查习惯:在看结果之前,先问作者期望发生什么。有明确假设的提示词变更是可以审查的。"这看起来更好"这样的变更没有失败条件,意味着跟随它的灰度发布没有什么可以失败的。
Storing Prompts as Files Instead of Strings in Code, for Better Diffs
Versioning Prompts Like Code
Detecting Quality Regressions in Production