提示词考古:从无文档遗留提示词中还原设计意图
你加入了一个团队,他们已经在生产环境中运行某个 LLM 功能十八个月了。这个功能运作正常——用户喜欢它,业务也在乎它——但没有人能确切解释这个提示词做了什么,或者为何要这样写。编写它的工程师已经离职。当时讨论它的 Slack 消息埋在某个不复存在的频道里。提示词躺在数据库记录中,长达 900 个 token,没有注释,提交信息除了"更新提示词"什么都没有。
而现在,你被要求去修改它。
这种情况比业界承认的要普遍得多。提示词被当成配置值来对待:写起来很快,代码审查中看不到,一旦跑通就被遗忘。区别在于,配置错误的 feature flag 会立即暴露问题,而配置错误的提示词会在数周内悄悄地降低某些边缘情况的处理质量,直到有人注意到。
从无文档的生产提示词中还原意图是一项考古工作。你在试图从遗留的痕迹中重建某人当初的想法。本文讲的正是系统化地完成这项工作的方法,以及能防止下一位工程师面临同样问题的文档格式。
提示词为何失去文档
根本原因不是懒惰,而是提示词不在代码的工作流程中。
工程师写代码时,会在版本控制中打开文件,写提交信息,经过代码审查,合并 pull request。每一步都是留下上下文的机会。工程师写提示词时,通常是在 playground 里反复迭代,把结果复制到数据库或配置文件,然后继续下一件事。没有 diff,没有审查,往往也没有任何记录表明有东西改变了。
对 1200 多个 LLM 生产部署的分析显示,提示词更新是生产事故的最大单一触发因素——比代码部署和基础设施变更都多。为了改善对话语气而添加的三个词,在数小时内导致结构化输出错误率飙升,中断了一个创收工作流,直到工程师手动回滚才恢复。提示词没有文档,出错的行为没有文档,回滚花了数小时,因为没人知道"正确"应该是什么样子。
这就是团队悄悄积累的提示词文档债务。每一个无文档的提示词都是一个计时器——不是在倒计时何时会出错,而是在计算出错时调试的难度。
开始挖掘:阅读文物
当你接手一个无文档的提示词时,第一反应可能是仔细阅读它,试图从文本中推断意图。对简单的提示词这行得通。对复杂的生产提示词,这并不可靠。
长提示词会积累多个层次。原始意图可能埋在后续的修补之下。一个看似冗余的片段可能是在处理九个月前有人发现的某个边缘情况。删掉它会在某个周二因为没人想到要测试的输入而导致生产故障。
从可观察的输出入手,而不是文本本身。抽取一批真实的生产请求及其对应的输出。几百个比几个要好。观察:
- 输出格式一致性:提示词是否总是产生相同结构,还是格式有变化?变化往往是输出约束规格不足的信号。
- 长度分布:异常短的输出通常意味着拒绝、格式化失败或输出被截断。异常长的输出通常意味着缺少长度约束。
- 语言模式:提示词是否有独特的语气?是否总是带有修饰?是否总会加上警告?这些行为特征通常是有意为之的。
- 失败特征:是否有某些输出模式出现在模型明显感到困惑的时候——比如模糊措辞、承认不确定、话题转移?这些告诉你提示词的薄弱之处以及它试图处理的内容。
这次输出审计会让你在动提示词之前先有一个行为画像。
行为探测:绘制边界地图
从生产输出中得到行为画像之后,下一步是系统性探测——专门设计输入来揭示提示词在极限情况下的行为。
把它想象成对未知系统的诊断测试套件。你还不是在测试正确性(你还不知道什么是正确的),而是在绘制响应曲面。
沿输入维度探测。 如果提示词处理客服查询,就用短查询与长查询、简单词汇与技术词汇、礼貌语气与沮丧语气、英文与其他语言、规范问题与杂乱描述来测试。记录哪些维度产生 干净的输出,哪些产生变化。
探测生产系统常见的边缘情况。 以下是值得专门测试的类别:
- 空的或接近空的输入
- 包含与系统提示词相同关键词的输入
- 提示词显然不是为其设计的语言输入
- 包含冲突信号的输入(礼貌措辞,敌意意图)
- 技术上在范围内但不寻常的输入(一个针对产品推荐设计的提示词收到了关于退货的问题)
测试对微小变化的敏感度。 用十几种方式改写同一个输入。如果输出因措辞而非含义发生显著变化,这个提示词是脆弱的。如果输出保持一致,它是健壮的。当你决定哪些可以安全修改时,这一区别很重要。
测试温度稳定性。 在多个温度设置下运行同一输入。在温度为 0 时出现高方差是不寻常的——如果看到了,往往意味着提示词依赖幸运采样来产生好的输出,而不是可靠的指令遵循。
每次探测产生一个数据点。合在一起,它们给出了提示词被设计用来处理什么,以及它在哪里会失效的地图。
从证据中重建意图
经过行为画像和探测之后,你应该有足够的证据来形成关于提示词试图完成什么的假设。
寻找负空间:提示词明确禁止什么(通常是特定事件遗留的痕迹),它在哪些方面推诿给人类,它拒绝参与哪些话题。这些都是生产故障留下的伤疤。每一个都代表着某人在某个时间点出于某种原因做出的决定,而你现在需要推断那个原因。
与周围系统交叉参考。 谁在消费这个提示词的输出?如果输出被下游服务解析,它期望的模式告诉你提示词试图产生什么。如果输出直接展示给用户,查看用户行为指标——用户在哪里采纳输出,在哪里忽略它或追问?这些行为数据包含了提示词文本所没有的意图。
与最接近这个功能历史的人交谈。不是为了得到"正确"答案——记忆是不可靠的,尤其是关于提示词变更的——而是为了验证你的假设。"我认为这个部分是为了处理用户询问竞争对手的情况——这和你记得的有吻合吗?"是一个有用的问题。"这个提示词做什么?"则不是。
还有一个有用的技巧:以受控方式故意破坏提示词。删除一个部分,测试输出是否改变。如果删掉一段没有可测量的影响,它可能是死代码——为生产流量中不出现的情况而添加,或者被后来的改动变得多余了。如果删掉它导致失败,你现在就知道那个部分在保护什么了。
记录你的发现
所有这些挖掘工作的目标不仅仅是让你自己理解提示词——而是防止下一位工程师不得不重复这项工作。
文档格式不需要复杂。一个 Markdown 文件放在提示词旁边(或者作为元数据存储在提示词所在的任何地方),包含以下字段,就能覆盖 90% 重要的内容:
用途:一到三句话。这个提示词在执行什么任务?预期的输出是什么?这听起来显而易见,但几乎从未被写下来。
关键行为:提示词刻意实现的行为的列表——它总是做的事,它总是避免的事,它以特定方式处理的事。这些是你通过探测发现的、从提示词文本中看不出来的东西。
输入假设:这个提示词为什么样的输入设计的?预期的长度范围、语言、领域、格式是什么?什么输入明确超出范围?
输出格式规格:这是缺失时导致最多生产事故的字段。精确记录输出结构应该是什么——字段名称、类型、输出是 Markdown 还是纯文本还是 JSON,适用什么长度限制。如果输出被下游解析,记录模式。
已知边缘情况:测试过程中行为异常的特定输入或输入模式列表,以及正确行为是(或应该是)什么的注释。这是伤疤地图。
版本历史:日期、作者、一行说明改变了什么以及为什么。这个字段能防止"改了三个词,生产崩了"的场景——不是因为你能阻止改变,而是因为你在调试时能立即找到它。
文档不需要完美。70% 准确的文档比没有文档有用无数倍。写下你知道的。标注你不确定的。让它比你发现时更好。
深层的组织问题
个人的文档习惯只能走这么远。更深层的问题是大多数组织没有强制提示词文档化的工作流程。
如果提示词存在数据库里,代码审查就发现不了提示词变更。如果不存在测试,CI/CD 流水线就不会运行提示词测试。事后分析将事故归因于"提示词变更",却没有记录变更是什么,或者为什么对原始提示词的理解不足以预测失败。
处理这个问题做得好的团队,用和对待代码变更相同的严格程度来对待提示词变更。他们将提示词存在版本控制中。他们在任何生产提示词变更前运行测试套件。他们要求任何超出修正错别字的变更都要有书面理由。他们为每个生产提示词维护一个行为测试语料库——一组规范的输入和预期输出,任何提示词变更在部署前都必须通过。
这听起来很繁重。对单个提示词而言,确实如此。在拥有数十个提示词驱动不同功能的生产系统规模下,这是防止考古问题无限复合的唯一方法。
现在就开始审计
如果你今天有在生产中运行的提示词,而你无法在五分钟内自信地向新工程师解释,你就有无文档的提示词。记录它们的时机不是在你需要修改它们的时候——而是现在,趁行为稳定,你可以用生产流量来验证你的理解。
挑出你系统中风险最高的提示词。运行行为画像。做探测测试。写文档。然后处理下一个。
第一次考古是痛苦的。系统化地做,它也会产生文档基础设施,让每次未来的变更更快,让每次未来的事故更快调试。目标是成为最后一个必须挖掘的团队——并确保你留下更好的东西。
