跳到主要内容

Prompt Sprawl:当系统提示词演变成难以维护的遗留代码

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的系统提示词(system prompt)起初只有 200 个 token。一个清晰的角色定义,几条格式规则,一两个约束条件。六个月后,它变成了 4,000 个 token 的指令堆砌,其中一半互相矛盾,团队里也没人能解释为什么会出现关于 JSON 格式化的第三段内容。欢迎来到提示词膨胀(prompt sprawl)—— 这种生产环境中的问题会在每个人都认为提示词“没问题”的情况下,悄悄削弱你的 LLM 应用。

提示词膨胀发生在你把提示词当作“只增不减”(append-only)的配置时。每一个 bug 都会换来一条新指令。每一个边缘案例都会换来一条新规则。每一个利益相关者(stakeholder)都会换来一段新文字。提示词不断增长,却没人删掉任何东西,因为没人知道哪些是起到支撑作用的(load-bearing)。

这就是遗留代码 —— 甚至更糟。没有编译器来捕捉矛盾。没有类型系统来强制执行结构。没有测试套件能验证第 47 条指令是否否定了第 12 条。而且,与乱作一团的代码库不同,你无法安全地进行重构,因为没有依赖图(dependency graph)来引导你。

没人衡量的退化曲线

在你达到宣称的上下文窗口上限之前,LLM 的指令遵循能力就已经开始退化了。研究表明,一旦系统提示词超过大约 2,500–3,000 个 token,准确率就会出现可衡量的下降 —— 这不是一个突然跌落的悬崖,而是一个随着提示词长度增加、准确率逐渐被侵蚀的斜坡。

其机制非常简单。Transformer 的注意力机制表现出首因效应(primacy bias)和近因效应(recency bias),对提示词开头和结尾的权重分配比中间部分更高。超过 3,000 个 token 后,中间部分的指令获得的关注最少。你那些最针对具体任务的规则 —— 那些精心编写的边缘案例处理 —— 恰好落在模型最容易忽略的区域。

这种情况会隐蔽地累积。每增加一条新指令,都会稍微降低对现有指令的遵循程度。新增的指令在隔离状态下“有效” —— 它能通过快速测试。但整体质量会下降一小部分。重复五十次之后,你就积累了可衡量的退化,而这种退化并不是由任何单一变更引起的。

死于千次追加。

还有一个更隐蔽的陷阱。语义相似但存在重叠的指令 —— 这种指令通常是在多人独立添加规则时积累起来的 —— 极具破坏性。模型会以不可预测的方式解决歧义,而且这种解决方式在不同请求之间是不固定的。

膨胀提示词的剖析

提示词膨胀遵循一个可辨识的模式。以下是积累的内容:

矛盾的指令。 “始终以 JSON 响应”出现在“对于错误情况,请以纯文本解释响应”的三段话之上。两位作者都不知道对方的指令。模型会随机选择一个,且选择结果取决于输入。

冗余的护栏(guardrails)。 同一个安全约束被以三种不同的方式陈述,因为三次不同的事件促使不同的人都去“添加一条规则”。模型将每一条都视为独立的指令,在同一个约束上浪费了注意力容量。

作废指令。 针对已不存在的功能的规则。针对几个月前就被重写的下游消费者的格式化要求。针对你已经升级掉的模型版本的约束。没人移除它们,因为没人记得为什么要添加它们。

隐式依赖。 指令 7 只有在指令 3 的背景下才有意义,但它们被 800 个 token 的无关规则隔开了。模型无法可靠地将它们连接起来,因此指令 7 在指令 3 不适用的语境下也会被错误触发。

利益相关者的妥协。 法务加了一段。产品加了语气指南。机器学习团队加了输出格式。支持团队加了错误处理规则。每一次添加在当时都是合理的。加在一起,它们构成了一份 4,000 token 的文档,没有连贯的作者,也没有一个人能理解其全貌。

财务成本也在悄悄累积。系统提示词每增加 500 个 token,就会增加延迟和每个请求的比例成本。在规模化运行下 —— 每天数百万次请求 —— 臃肿的提示词每月可能在浪费的 token 上花费数万美元。多轮对话会放大这一点:系统提示词会随着每次 API 调用发送,因此浪费会随着每一轮对话成倍增加。

为什么“直接清理掉”行不通

显而易见的解决办法 —— 裁剪提示词 —— 遇到了一个根本性问题:没人知道哪些指令是起到支撑作用的。

与代码不同(在代码中你可以通过 grep 搜索调用者并运行测试),提示词指令没有依赖图。删除一句话可能会破坏一个每千次请求才发生一次的边缘案例。你在测试中看不见这种失败,因为你的测试集没有覆盖到它。三周后,当客户针对离奇的回复提交工单时,你才会发现它。

这产生了一种棘轮效应(ratchet effect)。添加指令是低风险且可以立即测试的。移除指令是高风险的,且只能通过生产环境监控来检测。团队理性地选择了增加而不是移除,于是提示词只会不断增长。

版本控制问题放大了这一点。长的提示词在每次变更时都会产生巨大的 diff。审查一段 200 行的提示词 diff 需要理解整个提示词的交互动态,而不仅仅是修改的那几行。大多数审查者只是例行公事地批准(rubber-stamp),原本应该在生产前捕捉矛盾的质量关卡从未真正发挥作用。

模块化提示词架构

解决方法不是更强的自律,而是更好的架构。防止代码蔓延的原则同样适用于提示词,但需要根据 LLM 实际处理指令的方式进行调整。

将关注点分离为可组合的片段。 不要使用单一的单体系统提示词,而应从离散模块构建:角色定义模块、输出格式模块、领域知识模块和约束模块。每个模块都独立编写、版本化且可测试。组装后的提示词在请求时通过仅组合相关模块生成。

通过共享提示词库应用 DRY 原则。 如果三个不同的提示词需要相同的 JSON 格式规则,该规则应存在于一个地方,并通过引用包含。当格式要求变化时,它会在所有地方同步更改。当它过时时,从一个位置移除即可从所有使用者中移除。

路由到专门的提示词,而不是培养一个全才。 提示词路由器对传入的请求进行分类,并将其分发到专注的、特定任务的提示词,而不是维护一个处理所有可能输入类型的巨型提示词。每个专门的提示词都保持精简 —— 500–800 个 Token,而不是 4,000 个 —— 且由于模型仅处理相关指令,指令遵循准确率会保持在较高水平。

路由可以简单到关键词匹配,也可以复杂到使用轻量级分类器 LLM 调用。路由开销通常为 20–50ms —— 这通常低于分发较短的专门提示词(而非臃肿的全才提示词)所节省的延迟。

像对待基础设施一样对待提示词版本,而不是像配置文件。 每个提示词版本都有一个不可变的标识符。变更产生新版本,而非直接修改。通过环境(开发 → 测试 → 生产)的晋升作为带有评估门控的显式步骤进行。回滚是瞬时的,因为之前的版本仍然原封不动地存在。

提示词审计流程

对于已经在处理扩张提示词的团队,这里有一种系统化的分解方法:

盘点每一条指令。 逐行检查系统提示词,并将每条指令归入以下四类之一:角色定义、输出格式、领域约束或行为护栏。如果某条指令不属于任何类别,它可能已经失效了。

测试承重指令。 分别移除每条指令并运行你的评估套件。如果评估分数没有变化,说明该指令没有起作用。如果分数在意外维度上发生变化(不仅是该指令针对的维度),你就发现了一个需要明确化的隐式依赖。

识别矛盾。 映射引用同一输出维度(格式、语气、长度、内容)的指令。任何具有多条指令的维度都有冲突风险。将每个维度合并为一条单一且明确的指令。

衡量 Token 预算。 清理后,对于专注的任务,你的系统提示词理想情况下应在 1,500 个 Token 以下;对于复杂的、具备多种能力的系统,应在 2,500 个 Token 以下。如果你超过了 3,000 个 Token,你就进入了性能退化区,应该将其分解为路由式的专门提示词。

建立所有权。 每个提示词模块都有一个负责人 —— 负责审查变更、在合并前运行评估,并对该模块的行为负责。无人负责的提示词会野蛮扩张,这与无人负责的代码动态一致。

预防优于治疗

避免提示词扩张的团队通常共享以下几种实践:

他们像对待代码变更一样对待提示词变更。 每次修改都要经过版本控制、接受审查,并在进入生产环境前通过自动化评估套件。评估套件专门测试指令遵循情况 —— 不仅仅是黄金示例的输出质量,还包括模型是否在各种输入中始终遵循每条指令。

他们强制执行 Token 预算。 对系统提示词长度的硬性限制会迫使团队尽早做出架构决策。当你因为超出预算而无法添加另一条指令时,你将被迫移除某些内容或分解为路由架构。这种约束驱动了更好的设计。

他们将稳定指令与易变指令分离。 角色定义和输出格式很少更改。领域知识和行为约束频繁更改。将它们保存在不同的模块中意味着高频变动的部分会得到最多的审查关注,而稳定的基础不会在差异噪声中被意外修改。

他们衡量每条指令的遵循率,而不只是总体的输出质量。当添加新指令时,他们会跟踪模型是否遵循了它 —— 以及对现有指令的遵循率是否下降。这使得退化在发生的那一刻就清晰可见,而不是三周后在客户工单中才被发现。

更深层的模式

提示词扩张是一个更广泛的组织问题的症状:团队将提示词视为非正式的人造产物,而不是生产基础设施。防止代码蔓延的工程纪律 —— 模块化、版本化、测试、所有权和代码审查 —— 同样适用于提示词管理。

区别在于成熟度。大多数工程组织用了几十年时间学习这些代码实践。提示词工程还很年轻,许多团队仍处于“一个文件包罗万象”的阶段 —— 相当于一个每个人都害怕重构的 5,000 行 utils.js

在生产环境中交付可靠 LLM 应用的团队已经完成了这一转变。他们的提示词是模块化、版本化、经过测试且有负责人维护的。他们的系统提示词 Token 计数是一个带有警报阈值的跟踪指标。当有人提议添加新指令时,第一个问题总是:“为了腾出空间,我们要移除什么?”

那个被一致提出的简单问题,比你能买到的任何提示词管理平台都更有价值。

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