提示词弃用合约:为什么措辞清理是一项破坏性更新
系统提示词(system prompt)上一个四个词的修改——用 "respond using clean JSON"(使用干净的 JSON 响应)替换 "output strictly valid JSON"(输出严格有效的 JSON)——在评估(eval)中一度没有引起任何波动。它在周四发布,却在周五凌晨 4 点被回滚,因为结构化输出的错误率从 0.3% 飙升到了 11%。提示词并没有变糟。它只是变得“不同”了,而下游解析器在无人察觉的情况下,已经固化(pinned)在了 "strictly valid" 这个词组上。
这是大多数提示词工程(prompt-engineering)团队尚未建立工具来应对的失效模式:提示词被视为作者拥有的文本,而实际上它是与作者从未见过的消费者之间的一份合约。这些消费者中,有些是逐字引用原句的其他提示词;有些是 JSON 模式(JSON schema)字段锚定在特定形容词上的工具描述;有些是其评分标准(rubrics)要求裁判(judge)检查“严格有效格式”的评估(evals);还有一些是解析器——最脆弱的一类——其正则表达式是根据模型输出的精确前导语(preamble)进行校准的。
一次“ 小小的措辞清理”会悄无声息地破坏解析器、导致裁判校准偏移,并使数周的评估运行失效。这些失败都不会在 PR(拉取请求)中显示出来,而是在一周后作为“偏移”(drift)出现在仪表盘上。
提示词有消费者,且消费者已被固化
当你发布一个 REST 端点时,消费者是“大声”的。他们会编写集成测试,如果你更改了某个字段,他们会出现在你的错误日志中,如果你将 userID 重命名为 user_id,他们不出一小时就会提交一个 Jira 工单。而当你发布一个提示词时,消费者是沉默的——而且他们的数量比你想象的要多。
梳理一个典型的 AI 功能并数数看:
- 其他引用你的提示词。 一个检索感知的系统提示词说“遵循规划器使用的格式”,这依赖于规划器格式的稳定性;一个聊天模式提示词逐字粘贴智能体的指令,这依赖于智能体措辞的稳定性。这些引用通常是不可见的——在集成时通过复制粘贴完成,而非链接。
- 工具描述。 函数调用工具的自然语言描述(“当用户想要按助手被指示的措辞方式查找订单时调用此工具”)继承了系统提示词的假设。修改系统提示词的词汇,工具描述现在描述的就是模型不再产生的行为了。
- 评估和裁判标准。 一个评分标准为“模型是否在严格有效的 JSON 信封中响应”的 LLM-as-judge 裁判,已经针对数千个过去的输出进行了校准。将系统提示词改为 "clean parseable JSON",模型输出的内容相同,但由于锚定在 "strictly valid" 这个词组上,裁判开始将其标记为模棱两可。校准偏移(Calibration drift)是基于裁判评估的已知失败,而提示词修改是其最可靠的诱因之一。
- 解析器。 正则提取器、JSON 形状验证器和思维链提取器都依赖于稳定的前导语。将 "Sure, here's the response:" 替换为 "Here you go:",对作者来说是一个字符的差异,而对消费者来说则是解析失败。
- 链式智能体。 当智能体 A 的输出是智能体 B 的输入时,第二个智能体的提示词已经过调整,以期望从第一个智能体那里获得特定的形状。对智能体 A 进行的“润色”变成了智能体 B 的回归(regression),且由于评估是按智能体进行的,没人能发现这一点。
每一个这样的消费者都是你在不经意间交付的一份合约。措辞就是 API。措辞就是下一个系统要解析、评分或引用的内容。
为什么“评估通过”不代表可以安全发布
大多数团队发布时的直觉——“如果评估套件全绿,那么提示词更改就是安全的”——是错误的,而且在事故发生之前很难察觉。
评估针对的是输出(output),而消费者固化的是措辞(wording)。这两者是不同的层面。
提示词更改可以使评估集上的输出分布保持基本不变(因此得分不变),但 同时又改变了表面形式,足以导致下游解析器停止匹配。裁判看到的答案仍然正确;解析器看到的文本却无法再从中提取字段。评估报告显示绿色,而生产环境则报告来自消费服务的 4xx 错误峰值。
这与不破坏 API 行为(behavior)、仅破坏其接口(interface)的向后不兼容 API 更改的形式相同。REST 团队绝不会将 created_at 重命名为 creationTime 并称之为补丁发布(patch release)。而提示词团队每周都在发布类似的东西,并称之为“小小的清理”。
解决方法不是更大规模的评估,而是意识到提示词有两份合约:一份是评估可以衡量的行为合约,另一份是评估无法衡量的措辞合约。两者都需要进行版本管理。
提示词弃用合约长什么样
直接借用 API 管理规范:
带有语义化版本(semver)分类的提示词版本注册表。 每个提示词都有一个版本。修改在 PR 时进行分类:
- 补丁(Patch) —— 拼写错误修复、仅限注释的更改、空格。不能更改可观察的措辞。
- 次版本(Minor) —— 添加部分、新约束、不替换现有示例的新示例。不能删除或重命名其他工件可能引用的短语。
- 主版本(Major) —— 任何删除、重命名或重构已被引用、解析、评审或链式调用的措辞的操作。需要填写弃用分录(deprecation entry)。
这种分类属于 PR 模板的一部分,就像数据库迁移声明它是扩展还是收缩一样。
为每个提示词建立消费者索引。 这是一份与提示词存放在同一个代码库中的列表,记录了每一个固化在其中某个短语上的工件。引用系统提示词的工具描述、锚定在特定形容词上的裁判标准、正则表达式包含字面前导语的解析器,以及复制了某个片段的其他提示词。消费者索引是作者在合并之前需要看到的“爆炸半径”。该索引通过在消费者端添加回溯链接来维护(例如,“此正则依赖于提示词 X v3.2 中的 'strictly valid'”),并通过工具进行反向索引。
重大更改的弃用窗口。 当你删除或重命名消费者依赖的措辞时,旧措辞应与新措辞并存一个定义的周期——长到足以让每个消费者完成迁移。模型会同时获得两种措辞,消费者会收到通知,只有在消费者索引报告剩余固化数为零后,旧措辞才会退役。这与在客户端更新期间同时保留 created_at 和 creationTime 字段一个季度的模式相同。
在未声明的破坏性变更上报错的 CI 门禁。 如果一个 PR 删除了一段出现在消费者索引中的短语,但没有提升主版本号并添加弃用分录,则 PR 失败。不是警告——是失败。这是承重部分,因为其余的规范都是自愿的,而在发布压力下,人类会跳过自愿的规范。
这一切并不稀奇。这几乎是逐行复刻了一个成熟的后端团队处理公共 REST 端点的方式。
最难的部分是消费者索引
注册表和 CI 门禁是机械化的。消费者索引则是需要组织协调的部分,因 为消费者通常是投机性地自行添加,而作者往往没有动力去注册。
使其变得可处理的三种模式:
消费者端的反向链接,而非提示词端。 依赖于“严格有效的 JSON”的评审准则(judge rubric)会获得一个头部注释:# depends on system_prompt v3.x phrase "strictly valid"。正则表达式提取器也是如此。消费者携带依赖声明,因为消费者才是会因变更而崩溃的一方。然后工具遍历代码库,并将这些声明反向索引到提示词的消费者视图中。
短语级指纹识别。 对提示词中起关键支撑作用的短语进行哈希处理,并检测版本之间哈希值的变化。随后 CI 门禁可以询问:“短语 X 已更改;消费者索引列出了三个绑定到短语 X 的产物;弃用条目是否存在?”这与公共资产的内容哈希(content-hash)思路一致 —— 你不需要枚举所有消费者来检测破坏性变更,只需检测契约界面(contract surface)发生了移动。
针对新消费者的“禁止引用”规则。 想要依赖提示词用词的新消费者必须通过命名且带版本的摘录(excerpt)来进行,而不是直接复制粘贴。摘录成为了 API。提示词作者可以自由更改摘录周围的所有内容;而摘录本身遵循弃用规则。这在结构上等同于强制 API 消费者依赖类型化的客户端,而不是对 JSON 结构进行逆向工程。
做对这件事的团队会将消费者索引视为代码库的一等公民,在 PR 中进行评审,就像对待 CODEOWNERS 文件或 OpenAPI 规范一样。
