跳到主要内容

系统提示词蔓延:当你的 AI 指令变成 Bug 的源头

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数团队都是通过惨痛的教训才发现系统提示词蔓延(System Prompt Sprawl)问题的。AI 功能发布了,用户发现了边缘情况,而修复方案总是如出一辙:增加另一条指令。六个月后,你就有了一个 4,000 token 的系统提示词,没人能完全记在脑子里。模型开始执行一些并非初衷的任务——不是因为它坏了,而是因为你写的指令之间存在细微的矛盾,而模型正悄悄地代表你处理这些矛盾。

蔓延并不是一种灾难性的故障。这正是它的危险之处。当你的指令发生冲突时,模型不会崩溃或抛出错误。它会做出选择,通常很流利,通常看起来很合理,而且通常错误得刚好足以成为真正的支持负担。

系统提示词是如何变大的

系统提示词并不是一上来就有 4,000 token。它始于 150 token。“你是 Acme Corp 的一名得力助手。请回答有关我们产品的问题。要简洁专业。”干净、聚焦、有效。

接着,现实接踵而至。用户向助手询问竞争对手的情况。你增加了一条指令,要求拒绝竞争对手的对比。用户收到了刻薄的回复。你增加了一条语气指令。法务部门进行了审查,并要求添加免责声明。支持团队注意到模型忽略了他们的升级脚本。你逐字逐句地粘贴了脚本。一个新功能发布了,你注入了该功能的操作文档块。安全审查又增加了三段拒绝指南。

十二个月后,你得到了一个既是工作说明、又是政策手册、既是常见问题解答、又是法律条款的系统提示词。它可能运行得很好——也可能包含一句来自第三个月、却与第九个月添加的内容直接冲突的话,而且没人知道模型在任何给定的查询中究竟遵循哪一句。

关于大语言模型(LLM)技术债务的研究发现,LLM 项目中超过 54% 的自认技术债务源于提示词设计问题。其根本机制与传统软件类似:你通过增加代码库来解决症状,而不是重构它。对于系统提示词,这种债务的成本在模型行为真正变得不可预测之前是隐形的。

矛盾导致破坏的具体方式

大型系统提示词在三种不同的模式下会失败,而将它们混为一谈会导致错误的修复方案。

指令屏蔽(Instruction shadowing)。 LLM 具有位置偏差:它们更关注上下文窗口开头和结尾附近的指令,而对中间信息的关注度显著降低。这有时被称为“迷失在中间”(lost in the middle)效应——研究表明,埋藏在长上下文中心的信息被正确检索的概率比放置在边缘的同等信息低 13–85%。在实际操作中,你早期关于语气和角色的指令可能会占主导地位,而你上个月添加(并为了逻辑连贯而放在文档中部)的关键行为约束则会被系统性地降低权重。

竞争目标(Competing objectives)。 当模型收到两个相互冲突的指令时,它不会选择其中一个并丢弃另一个。它会尝试同时满足两者,这通常意味着两者都无法干净利落地完成。“始终保持极其简洁”和“始终逐步解释你的推理过程”可以并存于系统提示词中数周,直到用户发现了一个迫使模型做出直接选择的查询。当这种情况发生时,模型的处理结果是不一致的——有时它选择简洁,有时选择透彻,有时则会产生一种奇怪的混合体。从用户的角度来看,该功能只是“有时表现得很奇怪”。

精准度-流利度反转(Precision-fluency inversion)。 这是最危险的失败模式。现代模型擅长撰写连贯、流利的散文,即使其底层的推理是不连贯的。一个正在解决指令矛盾的模型,会产生一个语法通顺、听起来自信的答案,但其基础却是错误的内部推理。旧的、较弱的模型会表现出明显的困惑。目前的模型则会掩盖矛盾,产出在日常检查中看起来不错、只有在大规模应用、用户反馈或对抗性测试中才会显露裂痕的输出。

阈值在哪里

系统提示词的长度本身并不是一个 Bug。如果结构合理,一个 5,000 token 的提示词可以非常连贯。问题在于大多数提示词并非结构化的——它们是“只增不减”的文档。

推理性能基准测试显示,在遵循指令的任务中,即使没有明显的矛盾,性能下降在 3,000 token 左右也会变得可衡量。超过这个阈值,庞大的指令量会产生足够的潜在歧义,从而损害一致性。这个阈值并不是硬性规定——模型的生成和上下文窗口大小各不相同——但它是一个有用的工程启发式方法:如果你超过了 3,000 token,请像对待需要重构的代码库一样对待提示词,而不是将其视为需要编辑的文档。

此外还有成本维度。长系统提示词会减慢首字生成时间(TTFT),因为预填充(prefill)阶段与序列长度成平方关系。对话中的每一条消息都会重新处理整个系统提示词。对于高流量产品来说,附加 10,000 token 的系统提示词会带来显著的延迟和基础设施成本,而不仅仅是工程美学问题。在现实工作负载下,从 2,000 token 增加到 10,000 token,每个 token 的能耗大约会增加 3 倍。

模块化组合:结构化修复

对于大型系统提示词(System Prompt),正确的心理模型不是文档 —— 而是一个配置系统。你不会通过向单个源文件不断追加内容来维护复杂的应用程序。同样的原则也适用于此。

模块化的系统提示词将关注点分离到命名的各个部分中,每一部分负责模型行为的一个特定方面:

  • 身份和角色: 模型是谁以及它的用途
  • 行为约束: 它必须做什么以及绝对不能做什么
  • 领域知识: 它需要的特定事实、术语或上下文
  • 格式指令: 回答应该如何结构化
  • 升级逻辑: 当模型无法或不应回答时该怎么做

这种分离有两个直接的好处。首先,它使冲突变得可定位 —— 当行为出现偏差时,你可以查看相关的部分,而不是扫描数千个 token。其次,它为所有权创造了自然的界限:法务团队编辑约束部分,产品团队编辑领域知识部分,双方互不干扰。

基于插槽(Slot-based)的模板化更进一步。你不再维护一个庞大的提示词,而是维护一个带有命名占位符(如 {user_context}{active_feature_flags}{domain_knowledge})的模板,并在运行时填充相关内容。这将静态指令(模型是谁,绝对不能做什么)与动态上下文(用户在做什么,启用了哪些功能)分离开来。静态内容可以被缓存,从而大幅降低延迟和成本;提示词缓存(Prompt Caching)的实现已证明,当静态系统提示词内容在请求间复用时,成本可降低高达 90%,延迟可改善 85%。

发布前的冲突检测

虽然目前还没有用于检测系统提示词逻辑冲突的成熟自动化工具,但缺乏工具并不意味着缺乏方法。

对抗性配对测试(Adversarial pair testing)。 针对涉及同一行为维度(语气、简洁度、拒绝逻辑、人格设定)的任何两条指令,编写强制在两者之间做出直接选择的测试查询。如果模型在五次运行中的输出不一致,那么你就遇到了实际冲突。这比尝试阅读提示词来寻找矛盾更有效,因为模型实际的解析逻辑通常很难仅从文本中看出来。

行为回归日志(Behavioral regression logging)。 在对系统提示词进行任何重大更改之前,对一组规范查询及其预期输出进行快照。更改后,运行相同的查询并对比输出。这虽然无法捕获由于你未建模的用户行为而出现的问题,但它能捕捉最常见的情况:一个初衷良好的补充却无意中改变了该功能中不相关部分的行为。

部分所有权与审查(Section ownership and review)。 像对待生产代码更改一样对待系统提示词的更改 —— 它们需要经过审查,有负责人,并包含关于预期改变什么行为以及原因的简要说明。在你在凌晨 2 点调试回归问题,却找不到何时添加了 200 个 token 的块或它原本要修复什么的记录之前,这听起来像是流程开销。

提示词版本管理平台 —— LangSmith、Braintrust、Langfuse、PromptLayer —— 为跟踪随时间变化的更改以及针对评估基准运行 A/B 测试提供了基础设施。如果你正在迭代驱动真实产品的系统提示词,那么带有评估流水线的版本控制提示词就相当于代码的单元测试。它们不能防止所有问题,但能让调试变得可控。

重构决策

决定何时进行重构(而不仅仅是追加或编辑)是一种判断,但有一些具体的信号:

  • 如果不重新阅读,你无法解释提示词的某个部分在做什么。 如果提示词大到无法保存在工作记忆中,那么它就大到无法可靠地维护。
  • 你已经遇到两次或更多次因为提示词更改导致其他地方出现意外行为的事件。 这是耦合的证据 —— 应当独立的部分实际上是相互依赖的。
  • 最近五次更改都是增加,而不是编辑。 一个只增不减的提示词正在不断累积范围。每条指令都应该有其替换的对应指令,或者有增加新范围的正当理由。
  • 指令内容的 token 数量持续超过 3,000 个(不包括注入的数据和对话历史,这些内容随使用规模而变化)。

重构并不意味着推倒重来。它意味着审计现有提示词中的重复意图,将正交的关注点提取到命名的部分中,并删除那些最初的正当理由已不复存在的指令。大多数系统提示词在经过结构化审计时,都会包含两到三条过时的指令,这些指令原本是为了解决在其他地方已经修复的 Bug —— 而没有人移除这些权宜之计。

与复杂性共存

系统提示词会不断增长。产品在进化,边界情况会出现,法律和政策要求会累积。目标不是保持提示词短小,而是在它们增长时保持其清晰易读和可维护。

管理得好的团队会像对待代码一样对待他们的系统提示词:拥有权、版本历史、自动化测试和更改的结构化审查。而挣扎的团队通常把系统提示词当作任何人都可以编辑的共享文档,没有审计追踪,没有评估基准,当行为倒退时也没有明确的负责人。

底层的失败模式并不是系统提示词变大了。而是它们在缺乏使“庞大”变得可控的基础设施的情况下变大了。修复基础设施,复杂性就会变得可控。如果不这样做,模型就会变成一个不可靠的黑盒 —— 不是因为模型改变了,而是因为没有人记录你对它说了什么。

References:Let's stay in touch and Follow me for more thoughts and updates