上个季度,一家金融科技初创公司的安全审核员在系统提示词(system prompt)中添加了四行内容。这次修改包含一条拒绝规则,旨在防止助手为公司未获得运营许可的司法管辖区提供具体的税务建议。这听起来很合理、范围明确且符合审计要求。该规则在周二上线。到周五时,评估套件显示在与税务完全无关的客户入职流程中出现了 7 个点的下降——模型开始对任何提及国家的提问都模棱两可,甚至包括“这个账户持有哪种货币”。产品团队撤回了修改。安全团队在下周以略有不同的措辞重新发布了它。三周后,同样的退化以不同的形式再次出现,而接下来的安全修改又破坏了另一个无关的流程。
这里的 bug 不在于措辞,而在于拒绝规则放错了位置。它被挤进了一个 2,400 token 的构件中,该构件还包含助手的对话语气、格式契约、任务指令以及其他六项策略条款——对其中任何一项的修改都是对所有内容的行为修改,因为模型无法分辨哪句话是策略,哪句话是风格。生产环境中的系统提示词之所以变成了一坨乱麻的单体,是因为三个正交的关注点伪装成了一个整体。没有将它们解耦的团队在每次修改时都在支付“集成税”。
三种关注点,三类审核员,三种频率
打开任何足够成熟的 LLM 产品的系统提示词,你会发现三类文本挤在一起,除了空行之外没有任何有意义的分隔。
第一种是对话指令 ——助手的语气、人格、默认基调、如何询问澄清问题、如何 handle 歧义。(“你是一家电子商务商店的得力助手。表现得热情且简洁。当用户不高兴时,先表示同理心。”)这是产品文案的关注点。审核员是产品负责人或设计师。当品牌调性改变时它才会改变,而这很少见。
第二种是输出格式 ——对响应的结构化契约。Markdown 还是纯文本、代码块格式、列表规则、除非要求否则不包含表情符号。(“使用 Markdown 回复。产品类别使用 H3 标题。引用价格时带上本地货币符号。”)这是工程关注点。审核员是负责模型下游渲染器的任何人。当渲染器更改时它才会更改,这也很少见,但原因完全不同。
第三种是策略 ——拒绝规则、司法管辖限制、禁止提及竞争对手、升级触发条件,以及无论用户如何表述,模型必须做或不能做的任何事情。(“绝不直接点名推荐竞争对手的产品。拒绝提供医疗或法律建议。如果用户提到自残,请引导至危机资源流程。”)这是合规与信任安全(T&S)的关注点。审核员是法务、合规或 T&S 团队。每当监管或风险环境发生变化时它都会改变,而这种情况经常 发生——有时甚至是为了应对单一恶性事件而紧急修改。
三种关注点,三类不同的审核员,三种截然不同的修改理由。但在大多数生产系统中,这三者都存在于同一个字符串中,由同一个工具对比差异,由同一个人审核,并在同一个发布周期中上线。团队会在第一次“单行策略修改导致无关功能出现行为退化”时学到这个教训,然后一遍又一遍地重复教训,直到终于有人提出进行解耦。
为什么单体架构总是会退化
单体之所以失败,并不是因为单次修改有误。它失败是因为修改之间会产生交互作用 ,而这些交互在修改时是不可见的。
长系统提示词存在位置偏差 (position bias) ——靠近顶部和底部的指令比中间的指令权重更高。放在前面的拒绝规则被解读为身份(“你是那种不做 X 的助手”);放在后面的规则被解读为模型看到的最新指令。同样的文字,不同的行为。因此,当安全团队为了整洁而将第五个拒绝条款与现有的四个放在一起时,他们改变了其他每个条款的相对位置——导致在没人触碰的任务上出现了行为波动。
更糟糕的是,拒绝性语言具有生成性。告诉模型“不要对美国以外的司法管辖区提供税务建议”不仅仅是拦截了税务建议。它还改变了涉及非美国司法管辖区的每个回复的条件分布 ,因为模型现在在那个语义邻近区域被启动了“谨慎”模式。这种回避会蔓延。模型开始在货币转换、时区问题、原产地查询中添加免责声明——任何触及到该激活概念的内容都未能幸免。
这就是为什么进行量化衡量的团队会看到同样的模式:一个干净、精确、初衷良好的策略修改,在无关的评估中产生了弥散且难以归因的退化 。修复的方法不是更好的措辞,而是从一开始就不应该将策略拼接到提示词中。它应该是一个独立的构件,拥有自己的评估器、自己的分类法和自己的编译时注入点。
拆分后的形态
拆分包含三个部分,每个部分对应一个关注点,并成为你代码库中不同类型的对象。
对话指令保持为散文体(Prose)。 这是唯一真正需要自由文本的部分,因为语调很难模式化。它存在于一个由产品部门拥有、评审并受版本控制的文件中,且仅在产品部门确实需要修改的罕见情况下才会变动。工程团队仅在更新占位符时才会触碰它。
格式约束转化为 Schema。 大多数输出格式规则都是结构性的,可以用响应 Schema、JSON 模式契约或一个简单的 Pydantic/Zod 模型来表达。如果响应是通过一个在构建时就输出 Markdown 的结构化输出路径进行的,那么模型就不需要被告知“以带有 H3 标题的 Markdown 形式响应”。那些真正需要散文体描述的约束(例如“在列出产品时,按类别分组”)则变成一个简短的格式化块,由工程团队负责,与渲染代码一起评审,其规模小到一口气就能读完。
策略转化为数据。 这是最能体现价值的部分。拒绝规则、升级触发器、司法管辖禁令、竞争对手提及规则——所有这些都有相同的形状:触发条件、类别、处理方式。(“触发条件:请求税务建议。类别:拒绝提供许可咨询。处理方式:拒绝并提供寻找持证专业人士的建议。”)一旦你将它们写成结构化记录,三件事会同时发生:合规团队可以编辑它们而无需触及对话核心;评估集可以按类别而非按行进行处理;运行时可以在请求时将它们编译成提示词片段,仅注入与请求领域匹配的规则。
编译步骤是大多数团队所低估的。你不需要在每个请求中发送每一个策略条款。策略文件可以有 200 条目;而最终进入 LLM 调用的提示词片段可能只是与请求意图分类相匹配的 4 条。这缩小了提示词规模,减少了位置偏见(position-bias)的干扰,而且——至关重要的是——意味着策略编辑仅影响该策略领域内的请求。金融科技初创公司的税务建议规则不会触及引导流程(onboarding flow),因为引导流程的意图分类器不会选中它。
运行时:作为编译片段的策略 机械层面的图景非常直接。在请求时,一个编排层 会对输入请求进行分类,查找标记为该意图的策略,将它们渲染成提示词片段,并在调用模型之前将它们与(很少变动的)对话块和格式块拼接在一起。LLM 看到的提示词是针对每个请求从三个独立版本化的来源组装而成的。
这种模式已经有几种开源实现。NVIDIA NeMo Guardrails 将用 Colang(一种用于输入/输出护栏的微型 DSL)编写的策略流编译到运行时中,该运行时拦截请求、运行护栏,并在到达主模型之前进行重写或拦截。策略即提示词(Policy-as-prompt)框架 则更进一步:它们将自然语言策略文档解析为可验证的策略树,然后将该树编译为基于提示词的分类器,在运行时审计模型的输出。其他团队则完全跳过 LLM 评审层,将 YAML 护栏定义编译成 OPA 捆绑包 ,让现有的策略引擎基础设施像强制执行栈中其他策略一样强制执行 LLM 输出规则。
具体的工具选择不如架构转变重要。模型看到的系统提示词不再是一个手动编辑的字符串;它是一个构建产物(build artifact),由策略文件、格式 Schema 和语调块组装而成,所有这些都有独立的归属和独立的评审。其中任何一个的变动都可以与其同级文件进行 diff 比较,针对特定类别的测试用例进行评估,并按其自身的节奏发布。合规团队可以在一小时内落地一项紧急的司法管辖规则,而无需等待产品发布。产品团队可以调整助手的语调,而无需合规团队重新审核策略表。工程团队可以收紧格式 Schema 而无需触动另外两者。
从 4,000 Token 单体架构迁移的路径 大多数读到这篇文章的团队并没有一个整洁的三文件系统。他们拥有的是一个被所有人编辑过 200 次的 4,000 Token 产物,问题在于如何在不花费一个季度时间的情况下对其进行拆分。
成本最低的第一步是不改变运行时的分类提取 。在不修改运行时的前提下,遍历现有的提示词,并将每个子句标记为三个类别之一。你可能会发现 60% 是策略,25% 是对话,15% 是格式。策略部分将是编辑最频繁的区域。标记完成后,将其拆分为三个同级文件,在构建时进行拼接。模型看到的仍然是相同的字符串;但 diff 工具现在知道该提醒哪个评审人员。
第二步是按关注点划分评估集(Eval suite) 。为每个类别构建一个小型的评估集。语调评估在温和的请求中检查语气和亲和力。格式评估在代表性输出中检查结构。策略评估检查拒绝的正确性——既包括合法的拒绝是否触发(真阳性),也包括它们是否没有泛化到无关请求(在无用但安全(unhelpful-but-safe)维度 上的假阳性)。当单一产物是唯一事实来源时,每次编辑都要运行所有三项评估;当策略文件独立时,策略编辑只需运行策略评估,这样速度更快,并强制形成更清晰的思维模型。
第三步——也是真正释放架构潜力的一步——是按请求进行的策略选择 。在 LLM 调用上游添加一个意图分类器。为每个策略条目标记其适用的意图。在请求时,仅注入匹配的子集。这是位置偏见和跨领域泄漏问题开始从你的评估报告中消失的时候。这也是需要真正工程投入的一步,因此大多数团队在完成前两步后就停滞了,并永远支付着这种扩散性衰退(diffuse-regression)的税收。
你的系统提示词其实是伪装成一体的三个配置文件 大多数团队最终都会意识到,系统提示词(system prompt)从来都不是单一的整体。它一直由三部分组成——语气(voice)、模式(schema)和策略表(policy table)——由于早期实现为了方便,且模型接受字符串输入,才将它们黏合在一起。这种“黏合”的决定逐渐演变成了架构层面的束缚,现在每一次策略修改都会波及语气和格式,因为这个产物内部没有清晰的界限。
解耦(Factoring)并不是一种审美偏好。这决定了合规部门能否按照其所需的节奏发布策略,还是必须等待整个产品周期,只因为他们那两行的拒绝规则需要进行全面的回归测试。这决定了你拥有的是一个带有特定类别评估的 200 行策略文件,还是一个谁也无法完全理解的 4,000 token 的长字符串。这决定了你是将提示词视为模型的使用手册,还是将其视为模型的编译镜像——由源码构建,由源码所有者持有,并根据源码的契约进行评估。
没有进行解耦的团队并没有在编写更简单的代码。他们只是在编写一个巨大的字符串,并在每次修改时承担其不可读性带来的成本。当某次策略更新没有破坏不相关的流程时,解耦的价值就体现出来了——如果现有的提示词是一个单体(monolith),这种破坏几乎每周二都会发生。
会员专享
余下内容仅对会员开放。 会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
— 完整文章,包含未公开存档的部分 — 可落地的工作框架,附带权衡与决策依据 — 新文章抢先看,先于公开发布 登录以继续阅读→ 随时取消 · 一次订阅,畅读全部