1. 从提示词到系统
  2. 第二篇 管理模型看见的世界
  3. 第 5 章 什么时候提示词已经够了

第 5 章 什么时候提示词已经够了

前四章一直在往上走:从契约到示例,从示例到推理,每一步都在增加系统的复杂度。这一章往回拉一把。

因为读完前面几章,最容易产生的一个念头是:“这个系统好像也该上状态机了。”这个念头往往是错的,而且错了的代价,比很多人预期的要大。


一、一个分类器,真的需要状态机吗

回到第 2 章的场景一。

一个工单自动分类系统:用户提交一段问题描述,系统判断它属于哪一类,转给对应的处理队列。单轮、无状态、结果可以直接和人工标注比对。当时它的困扰是分类准确率上不去,几个相邻类别老是混。

现在假设这个团队读完了前四章,开了个会。会上很自然地出现了这样的提议:

  • “是不是应该把用户描述里的字段抽出来,做成槽位?”
  • “要不要加一个闸门,判断这条工单够不够格自动分类?”
  • “既然分类不准,是不是该拆成两次调用,一次抽取一次判断?”
  • “长远看,做成工作流是不是更规范?”

每一条听起来都有道理,也都不便宜。而这些提议有一个共同点:它们都没有回答“现在这个准确率问题,是哪一层造成的”。

按第 4 章的诊断表,分类不准的常见原因是:标签体系有重叠、判断标准缺失、示例没覆盖到语言变体。这三种原因,槽位解决不了,闸门解决不了,拆成两次调用也解决不了。加上去之后最可能的结果是:准确率没什么变化,系统复杂度却明显上升,而且现在更难查出问题出在哪。

这一章要回答的就是这个判断:什么时候该往上走,什么时候该停下来把手头这层做扎实。

二、过度工程的代价

“复杂一点总没坏处”——这个想法之所以危险,是因为代价大多不是立刻显现的。

上下文与成本。 每一层机制都要占提示词篇幅、占 token 预算。拆成多次调用通常会进一步增加消耗、延迟和故障点,串行链路尤其明显。这一条是最直观的,也往往是最小的一条。

维护面积。 每加一个机制,就多一样需要有人懂、有人改、有人测的东西。槽位要维护状态定义,闸门要维护判定条件,状态机要维护每一条转换。一段时间后人员流动,这些东西会变成没人敢动的地方。

调试成本。 链路越长,定位越贵。一个单轮分类器出了错,你看输入和输出就知道大概;一个五段管线出了错,你得先判断是抽取错了、状态错了、判定错了,还是表达错了。第 20 章会专门处理这种分层定位问题。层次是有代价的,不能白加。

变更速度。 简单系统一次变更涉及的链路更短、回归范围更小;复杂系统改一处,可能牵动多份契约和多个阶段。这在早期尤其致命——当你还在摸索业务规则的时候,最需要的是快速试错的能力。

还有一条最隐蔽的:

生产观察 额外的机制会掩盖真正的问题。 一个分类不准的系统,加上槽位和闸门之后,多半还是不准——但现在你有了一堆新的可疑对象,排查会先从新加的机制查起,而真正的原因(标签重叠)反而更不容易被发现。复杂度不只是成本,它还会降低你诊断问题的能力。

三、最小复杂度原则

把上面这些合起来,就是本书的一条基本主张:

用能可靠解决问题的最小复杂度。升级由证据触发,不由架构计划触发。

有三点需要说清楚。

第一,这不是“越简单越好”,而是“匹配”。 第 1 章那个系统的问题在另一个方向:它面对的是 L4 的问题(多轮状态与流程控制),却一直在用 L2 的手法(改措辞、加禁令)解决。那同样是不匹配,同样代价惨重。

工程不足和过度工程,是同一种失败的两面——复杂度与问题不匹配。判断的依据不是“系统应该有多先进”,而是“当前遇到的问题出在哪一层”。

第二,升级要有依据。 依据可以是一个已经发生的、可复现的失败,也可以是明确的业务要求、安全约束、合规要求、成本目标或已知的规模边界。

这里要把话说准:不要因为“以后也许会需要”而升级,但也不要非等一次线上事故,才去处理一个已经确定存在的风险。 一个即将开始自动发消息、写数据库或提交订单的系统,权限、幂等和结果确认应当在第一次事故之前就位——那不是预感,那是已知的风险。

证据驱动,不是事故驱动。 这两者的差别很大。

第三,停下来不等于不做工程。 这一点最容易被误解,第六节会展开。

四、复杂度诊断树

下面这张图是本书的导航图。它和第 2 章那把成熟度尺子分工不同:

第 2 章的六级,描述一个系统可能发展到哪里;这张诊断树,决定这一次到底要不要往那里走。

图 5-1 为了便于总览,把相近判断合并成六组,并标出三个停靠点;图后的文字版再把其中几组合并项拆开,一共列成九个具体问题。两者是“总览”和“展开”的关系,不是两套不同判据。

从输出契约到职责外置的复杂度诊断树

图 5-1 复杂度诊断树与三个停靠点

下面是展开后的逐项文字版:

每一层的左边是触发信号,右边是对应的章节

你的任务是什么样的?

  输出会被程序或他人依赖吗?
      是 → 写输出契约、定义失败出口            〔第 3 章〕
      │
  边界能靠文字描述清楚吗?
      否 → 用示例演示边界                      〔第 4 章〕
      │
  任务需要展开几步才能想清楚吗?
      是 → 给推理空间 / 任务分解                〔第 4 章〕
      │
  ─────────── 停靠点 A:到这里够用的任务 ───────────
      │
  需要模型本身不掌握的知识吗?
      是 → 接入检索,约束证据与引用             〔第 7 章〕
      │
  需要真正去办事、产生外部影响吗?
      是 → 接入工具;执行、权限与回执由代码保证,
           不能由模型自行宣称已完成               〔第 9 章〕
      │
  ─────────── 停靠点 B:到这里够用的任务 ───────────
      │
  正确性依赖"前几轮的哪些事实现在仍然有效"吗?
      是 → 显式状态:槽位、证据、归并            〔第 10–12 章〕
      │
  关键动作有前置条件,且必须每次都满足吗?
      是 → 闸门与决策表                         〔第 13 章〕
      │
  系统存在明确的流程阶段吗?
      是 → 状态机与不变量                       〔第 14–15 章〕
      │
  确定性规则是否正在膨胀?状态、计数、格式校验
  这类工作是不是越来越多地挤进了提示词?
      是 → 把确定性职责系统性外置到代码         〔第 16 章〕
      │
  ─────────── 停靠点 C:完整体 ───────────

关于这张图,有三件事必须说明。

它是路线图,不是操作手册。 这里给的是“往哪走”,不是“怎么走”。真正动手改造一个已有系统时,还需要判据、成本估算和退出条件——那是第 25 章的操作版。

每一个“是”都需要依据。 不是“以后可能会需要多轮”,而是“上周有 17 个会话因为重复追问被用户中断”,或者“这个动作会真的把订单提交出去”。前者是故障,后者是已知风险,两种都算依据;“感觉迟早用得上”不算。

它是诊断顺序,不是强制的施工顺序。 这张图建议你从复杂度较低的一端开始排查,因为很多故障在更低的一层就能解决。但如果业务本身已经明确需要检索、工具、持久状态或流程控制,没有必要为了“按级升级”先把前面的机制统统实现一遍——直接查订单状态的助手不需要先接知识库,纯多轮的需求收集也可能一个工具都不调。不能跳过的是问题诊断,不是架构层级。

需要警惕的只有一种情况:在基础的任务定义本身还混乱时就增加更复杂的机制。那往往只是把混乱组织得更整齐一些。

五、别被假信号骗了

在真实团队里,推动升级的往往不是故障,而是别的东西。四个最常见的假信号:

表 5-1 复杂度升级的四类假信号

假信号 实际情况
“以后可能会用到” 以后再加通常更便宜,因为那时你已经知道到底需要什么
“别人都是这么做的” 别人的约束条件和你的不一样,尤其是团队规模和容错要求
“这样显得更专业” 架构复杂度不是专业度,能说清楚为什么不加,才是
“模型不够聪明” 这只是一个待验证的假设。先分清任务定义、数据质量、上下文和模型能力哪个才是真正的瓶颈——模型能力确实可能是瓶颈,但那应该由对比实验得出,而不是凭感觉

真信号的形态是这样的:

一个具体的、可复现的失败,或者一项明确的业务、安全与合规要求;并且你能说明为什么它在当前这一层解决不了。

后半句比前半句更重要。“用户说过的东西它又问了一遍”是一个具体失败,但如果原因是提示词里压根没让它回看历史,那就还不是状态层的问题。

判断的标准不是“当前层的技巧有没有被用尽”——那样会把人重新带回第 1 章那种“再补一条试试”的循环。标准应该是:

这个问题在当前这一层,还能不能以可接受的可靠性、成本和维护复杂度解决。

不能了,就该往上走;还能,就先把这一层做扎实。

六、停靠点 A:一个到此为止的系统

停靠点 如果你的任务符合下面四个条件,本书的第一篇就已经够用了。再往下读是有价值的——但主要是为了知道自己不需要什么。

四个条件:

  1. 单轮或近似单轮——这一轮的正确性不依赖前几轮的事实;
  2. 无外部副作用——不写数据库、不发消息、不触发流程;
  3. 知识自足——所需信息都在输入里,不需要检索模型不掌握的内容;
  4. 结果可评测——存在明确的标签、规则、参考答案,或者一套稳定的质量判据。

意图分类、信息抽取、格式转换,以及有明确输出标准的内容改写、基于给定材料的单轮问答,大多符合这四条。

这样一个系统需要什么:

一份契约          任务、类别定义、裁决规则、失败出口、输出结构
必要时一组示例    典型正例 + 常见变体 + 边界题 + 反例
一张回归集        每条包含:输入、期望结果、判定条件
一套可重复的判分  判定规则固定,不随评审者和版本改变

以工单分类为例,它的回归用例可以简单到这个程度:

id: TC07
输入: 收到的杯子有个缺口,但颜色和图片是一样的
期望: {"reason": "质量问题"}
判定: reason 字段严格等于期望值
备注: 边界题——外观损坏但描述相符,用于检验标签边界

这个例子里,判分完全可以由代码完成:字段是否存在、取值是否在枚举内、是否等于期望值。

但这一点不能推广成通则。分类、抽取这类结构化任务应当尽量用代码判分;开放生成类任务则需要明确的评分标准、人工标注,或者经过校验的模型评审。 关键不在于用什么方式判,而在于同一份用例反复跑得出的结论是否一致——第 19 章会展开。

它不需要什么: 槽位、闸门、状态机,通常也不需要复杂的多阶段执行链。这些机制解决的问题,它一个都没有。

但有一样东西不能省:最基本的可观测记录。 至少要能追溯到用的是哪个提示词版本、哪个模型、什么时候执行、耗时多久、结果状态如何、有没有报错。至于输入输出是否原样完整保存,则要服从数据最小化、脱敏和留存周期的要求——真实输入里可能有手机号、姓名和客户信息,不是所有内容都适合长期留着(第 23 章会讨论这条边界)。

它不需要第 20 章那种完整的执行追踪,但也不该什么都不记。

七、停下来之后,力气花在哪

这是最容易被误解的一点:停在停靠点 A,不等于不做工程。

它只是把工程的重心放在了别处:

标签体系与任务定义。 前面反复出现的那个教训——分类不准,多半是分类本身没分开。这件事没有任何架构能替你做,它需要你和业务方坐下来,把每一个边界情况的归属定清楚。

数据质量。 示例从哪来、怎么脱敏、覆盖到了哪些变体、有没有把罕见但重要的情况纳入。

回归集与评测。 这是投入产出比最高的一项。一个有稳定回归集的简单分类器,往往比一个没有测试的复杂管线更可控、也更容易维护。第 19 章会讲怎么建这套东西。

监控。 线上真实分布会漂移——新的产品类型、新的用户表述习惯、季节性问题。分类器不会自己知道这些,需要有人定期看。

换句话说:停靠点 A 的系统,工程重点在数据和评测,不在架构。 把本该花在标签体系上的时间花去搭状态机,是这一章想拦住的典型错误。

八、什么时候真的该往前走

前面讲了这么多“别急着升级”,最后要说清楚另一面:真到了该走的时候不走,就是第 1 章那个故事。

判断标准回到第四节那张图。当你能指出一个具体的、可复现的失败,或者一项已经确定的业务、安全与合规要求,并且确认当前这一层无法以可接受的可靠性和成本处理它时,就该引入下一层机制了。

值得注意的是,大多数任务遇到的第一个真正的缺口,并不是状态。按那张图的顺序,更早出现的通常是另外两件事:

  • 模型“不知道”——更准确地说:回答所依赖的信息不在这一轮的输入里,而系统又不能可靠地只依赖模型参数中的记忆——那些记忆可能缺失、可能过时,也可能这些信息本来就属于你的私有数据;
  • 模型看不见——该看的信息没被送进上下文,或者送进去的是错的。

第二种尤其容易被误诊。它表现出来的样子往往是“模型答错了”“模型在编”,于是团队开始改提示词、加示例、换模型——而真正的问题在更前面一步:这一轮,模型到底看见了什么。

这是下一篇的主题。

读到不对的地方?

勘误、疑问,或者你在自己项目里的验证与反例,都欢迎交流。

微信联系
微信二维码

扫码添加,备注「从提示词到系统」