30 秒判断:同一段规则在作者看来可能只有一种含义,具体模型却可能按另一套语言经验解释。提示词是否有效,不能靠反复润色自证,必须观察模型采用了什么判断依据,再用行为回归确认双方是否真正对齐。
适合谁读:正在设计 LLM 分类器、门禁、判官、结构化抽取,或正在为 N 次运行的结果波动寻找根因的工程师,以及调提示词调得要崩溃无语的兄弟们。
范围说明:本文假设分类目标、类别、金标准和 N/K 验收已经确认。本文只讨论“如何让模型稳定执行这个目标”,不讨论目标本身是否合理,也不讨论应该拆分还是保留这个分类器。
关联设计:02 · 如何做一个 Agent 的“提示词语义对齐”方法;
证据标记:✅ 真实模型实测;🧪 可回归;🤔 当前判断。
1. “模型没按要求做”不是根因
我们曾为 RAG 引用流程设计一个来源元描述门禁。它接收答案 span,判断该 span 是否属于来源覆盖、来源结构或答案自身过程,决定它是否进入后续引用标注。
最初的提示词已经把规则写得很清楚,但模型仍会稳定误判:
文档称这一改动对安全影响很小,因为 VM 依然对 agent 执行的代码施加文件系统与网络控制。
这句话的主语是“文档”,陈述的是 VM 的安全效果,应该进入正文引用。但模型把它排除了。
进入可复现实验时,第一版冻结基线如下。它已经写明了职责边界、类别定义和默认 fallback,但只允许返回固定 reason 枚举,没有解释性 reason:
<role>
你是引用标注流程中的来源元描述门禁。你不选择证据,也不判断引用是否成立。
你只拦截普通内容 block 无法直接支持、且命题对象是来源或答案过程的 span。
</role>
<input>
你会收到 question、完整 answer,以及已通过结构过滤的 spans。
span.text 是唯一判断对象;answer 只用于解释指代、范围和角色。
</input>
<source_meta_categories>
source_coverage:
对来源的覆盖范围作统计或否定判断,例如是否出现、出现次数、是否遗漏及覆盖范围。
转述来源中的具体事实或观点不属于此类。
source_structure:
命题对象是来源的章节、段落、目录、先后位置或其他组织方式。
answer_provenance:
命题对象是本次答案如何生成、归纳、推断、综合,或本次证据是否充分。
</source_meta_categories>
<rules>
1. 必须为每个输入 span_id 返回且只返回一次结果,不得增加、遗漏或重复。
2. 按 span 的核心语义判断,不按单个词或句式匹配。
3. 执行支持性检验:如果普通内容 block 能直接支持该命题,返回 false。
只有普通内容 block 无法直接支持,且命题属于上述来源或答案过程信息时,才返回 true。
4. `source_meta=true` 时必须给出上述固定原因之一。
5. `source_meta=false` 时 reason 必须为空字符串。
6. 上下文只用于解释指代和范围,不能把其他 span 的内容算入当前 span。
7. 不能确定是否属于来源元描述时,返回 false,让该 span 进入引用标注。
</rules>
<output>
只输出一个 JSON 对象,不得输出 Markdown、代码围栏或额外说明:
{"decisions":[{"span_id":"span_0001","source_meta":false,"reason":""}]}
</output>
即使有“主语是文档”“转述具体事实不属于覆盖类”“不能确定时默认进入正文”这些约束,模型仍会把“文档称 X”折算成答案依据。问题因此不在缺少一句强调,而在于我们看不到模型到底采用了哪条判断依据。
看到结果后,很容易继续写:
- “不是所有带来源词的句子都要排除”;
- “必须严格按主语判断”;
- “只有 answer 自己的过程才算 answer provenance”;
- “不要误伤普通事实”。
这些句子看似越来越明确,实际却可能只是把同一层意思换了几个说法。
真正的问题不是“强调得不够”,而是我们不知道模型把任务的哪个词、哪种类别和哪条规则关联成了什么。
1.1 分类提示词其实是一份自然语言契约
提示词不是程序代码。代码里的函数名、类型和分支会按确定的语义执行;提示词里的“来源”“答案”“归纳”“综合”“支持”却都依赖模型已有的语言经验和使用习惯来解释。
这带来一个根本问题:
作者写下的语义
≠
模型实际采用的语义
同一个“文档称 X”中的“文档”,在我们看来是来源主体;模型却可能把它理解成“回答的可信度依据”。同一个“综合”,在验收标准里指来源内容之间的关系,模型却可能把它理解成“answer 的组织方式”。
这不是简单换一个更准确的近义词就能解决。自然语言提示本身是欠定的:一段规则可以同时容纳多种合理但不同的解释,而且新增一句强调,也可能给模型增加新的关联线索。
因此,提示词工程的核心不是“我有没有把规则写清楚”,而是:
模型实际采用的解释,是否与验收标准所要求的解释对齐?
提示词在这里不是一组命令,而是一份需要持续校准的自然语言契约。写作者只能定义自己期望的语义;模型是否把同一组词映射到同一判断过程,必须通过可观察信号验证。
一个稳定的分类提示词至少有四层:
| 层 | 要回答的问题 | 常见失败 |
|---|---|---|
| 任务边界 | 模型负责什么、不负责什么? | 把分类、证据选择和答案生成混在一起 |
| 类别契约 | 每个类别的命题对象和边界是什么? | 两个类别在自然语言上天然重叠 |
| 决策程序 | 先看主语、命题还是证据?冲突时怎样回退? | 模型根据关键词或表面句式猜 |
| 输出语义 | 如何表达决定、依据、不确定性和协议失败? | 输出稳定,但依据错误 |
如果只改第四层措辞,而问题在前三层,就会不断出现“明明写清楚了,却还是错”。
2. 自然语言无法自证对齐,所以需要 reason
既然提示词的文字本身不能证明模型采用了哪种解释,我们就不能只看作者的意图或提示词的表面清晰度,而要看模型对当前输入实际依据了什么规则。
最直接的可观察信号,就是让模型在给出分类结果时,同时返回一条简短的判定依据。
这里必须区分两版提示词:
- 第一版:前一节展示的冻结基线,只输出
source_meta和固定 reason 枚举; - 诊断版:在二分类决定不变的前提下,把输出拆成
source_meta + category + reason,并进一步明确各类别的命题对象。
诊断版不是最终候选,而是为了让模型的理解过程变成可比较的数据。相关输出和类别定义如下,为便于阅读,只展示发生变化的部分:
{
"span_id": "span_0001",
"source_meta": true,
"category": "answer_provenance",
"reason": "以“文档称”说明该判断的来源与可信度。"
}
source_coverage_stat:对来源的覆盖范围作统计,例如出现次数;
source_coverage_not_appear:对来源的覆盖范围做否定判断,例如没有出现。
source_structure:说明来源的章节、段落、目录、先后位置或其他组织方式。
answer_provenance:说明 **answer 本身**是如何组织、推断或 **answer 本身**的
边界、范围、可信度的,注意 **文档** 是指来源的某个文档。
这是一次诊断性的组合修改:输出 schema、类别拆分和 answer 的命题对象同时发生了变化。因此它只用于观察 reason,不能直接拿旧基线的单变量结论解释所有差异。后续每一轮再把语义修改拆开验证。
这里最重要的不是多了一个 reason 字段,而是 reason 必须简短说明为什么命中当前 category。
2.1 reason 不是隐藏思维链
reason 不能证明模型的真实内部计算过程,模型也可能事后合理化自己的决定。它更适合被看作:
模型对当前输出所引用的一条可观察分类依据
所以使用方法应是:
- 收集 reason 的多次分布;
- 找出模型反复使用的错误分类依据;
- 形成可证伪的语义假设;
- 用修改前后的行为结果验证假设。
不能因为一句 reason 看起来合理,就认定模型理解正确。
2.2 诊断版里的第一组关键 reason
前面的例子在诊断版中出现了这样的判断依据:
以“文档称”说明该安全影响判断的来源与可信度。
这暴露的不是“模型没看到主语”,而是它把“来源归因”理解成了“answer 的可信度”。即使表面主语是文档,它的决策路径仍然落到了答案自身。
另一个典型误判是:
Cowork 的“关进虚拟机”不是一次成型,而是四步演进……
模型给出的 reason 是:
对 answer 整体演进脉络作概括与边界总结。
这说明它把“回答中对事实的多步综合”理解成了“answer 自身的组织方式”。
两条 reason 指向同一类问题:类别名称虽然不同,但模型对它们指向的命题对象发生了混淆。
3. 提示词语义对齐闭环
有了 reason 之后,调优不再靠“改一句看看”,而是走一个受控循环。
冻结目标与金标准
↓
运行基线,得到错误和 reason
↓
聚类 reason,提出一个语义根因假设
↓
只修改对应的提示词契约
↓
先跑定向探针,再跑全量回归
↓
保留、否决或形成下一假设
3.1 先冻结目标
调优过程中必须固定:
- 输入字段;
- 类别集合;
- 金标准;
- 输出 schema;
- 模型和采样参数;
- N/K 定义;
- 产品解析和重试语义。
如果中途改变“这个类别到底要不要”“是不是拆成两个模块”,那就不是在验证当前提示词,而是在更换任务。目标层可以做,但必须另开一轮决策,不能和当前调优结果混在一起。
3.2 用 reason 聚类,而不是逐条救火
不要看到 10 个错误就写 10 条例外。先问:
- 这些错误是否由同一种概念混淆产生?
- 模型反复引用的依据是什么?
- 它把哪个类别映射成了另一个类别?
- 是类别重叠、决策程序缺失,还是输出协议不稳定?
043 中,多个表面不同的错误最后收敛成两个语义根因:
- “来源归因”被折算成“答案可信度”;
- “对来源内容的综合”被折算成“答案组织方式”。
这时修改类别命题对象,比继续追加否定句更接近根因。
3.3 一轮只验证一个主要假设
一个可执行的假设应该写成这样:
假设:
answer_provenance当前定义让“来源中的具体事实”和“本次 answer 的生成过程”共享同一判断路径。
而不是:
这一轮要再写得更严格、更明确、更符合要求。
后者无法被证伪,也无法解释修改为什么有效。
3.4 定向样本通过只是必要条件
曾经有一版提示词把三个已知误判都稳定修成 body,三条均达到 10/10。但全量回归后,另外一些样本明显退化,并出现协议错误。
这证明:
定向反例 100% 修复
≠
提示词达到整体稳定目标
每次定向修复都必须跟随全量回归。否则只是把错误从样本 A 推到了样本 B。
3.5 回放必须和产品等价
实验期间还暴露了两个容易误判的差异:
- 模型在
source_meta=false时经常省略空category字段; - 实验脚本起初没有模拟产品的一次重试。
如果不修正这两个差异,实验会把“可恢复的格式波动”当成“最终协议失败”,或者反过来掩盖产品中的真实问题。
用于决定是否达到 N/K 目标的回放,必须复用产品的解析、重试和错误语义。
4. 一次真实迭代的收敛过程
下面是去掉中间无效尝试后的关键路径。
第一步:只有标签,没有解释
早期输出只有 source_meta=true/false 和固定枚举 reason。模型错了,但只能看到错在哪条样本,无法知道它使用了什么分类依据。
结果是提示词修改主要依靠猜测。
第二步:加入 reason,发现类别被重新解释
结构化 reason 出现后,才看到模型会把“文档称 X”解释为“answer 的来源与可信度”。
这一步没有修复结果,却找到了真正的调试对象。
第三步:修正类别命题对象
把 answer_provenance 从宽泛的“生成、归纳、综合”收窄为:
主语或根据上下文推断的隐含主语是 answer 整体。
三个定向误判随即都能判回正文,说明假设方向成立。
第四步:全量回归否决局部最优
虽然定向样本全部通过,但全量重复运行出现了新的退化。于是该版本被否决,不能因为“我已经找到了三个例子的正确答案”就停止。
第五步:继续拆分自然语言中混合的类别
后续迭代把原来的来源覆盖拆成两种更明确的判断:
- 覆盖统计,例如出现次数;
- 覆盖缺失,例如文档中不存在某说法。
同时继续固定“默认进入正文”的 fallback,避免不确定时扩大排除。
候选最终在一次产品等价回放中达到:
| 数据集 | 调用数 | 最终协议错误 | 10/10 一致 | K=9 稳定 |
|---|---|---|---|---|
| 单用例 10 个冻结答案 | 100 | 0 | 293/301 | 295/301 |
| 18-case | 180 | 0 | 519/528 | 524/528 |
这组数据说明方法正在收敛,不等于整个产品已经验收。它只对应当前分类目标下的门禁回放,后续还要重新走完整切片和端到端验证。
5. 四个可复用判断
5.1 reason 是诊断接口,不是判决依据
reason 最大的价值是让“模型如何理解类别”变得可观察。但它不是真值,也不是隐藏思维链。最终必须回到固定金标准上的行为结果。
5.2 K 值只描述稳定性
N=10、K=9 应该定义为:
在固定金标准下,同一分类单元重复 10 次,至少 9 次得到正确结果。
如果 9 次都给出同一种错误答案,那不是稳定通过,而是稳定失败。
5.3 定向通过必须经过全量回归
提示词修改最容易制造“局部修复、全局回退”。定向样本用来验证假设,全量样本用来确认没有把错误转移到别处。
5.4 不收敛时先检查哪一层被改变了
如果调优过程中不断改类别、改目标、改职责拆分,实验结果就不可归因。
正确做法是:
- 当前任务目标保持不变;
- 只研究提示词是否准确表达了这个目标;
- 如果目标本身需要重审,结束当前实验,另开目标决策;
- 不把“目标不对”混进“提示词没稳定”的实验结论。
6. 一份可执行清单
- 固定输入、输出、类别、金标准和 N/K。
- 让分类输出包含简短、可验证的 reason。
- 先跑基线并聚类 reason,不直接追加规则。
- 把根因写成可证伪的语义假设。
- 每轮只修改一个主要语义变量。
- 先跑定向正反例,再跑全量回归。
- 用产品相同的解析、重试和预算语义回放。
- 保留每个版本的失败分布和被否决原因。
- 只有完整目标达到 K 值,才进入产品实现。
- 不在调优中途悄悄更换目标或评价口径。
7. 边界
这套方法解决的是“固定 LLM 分类目标下,提示词如何逐步收敛”。
它不解决:
- 类别目标本身是否正确;
- 金标准是否可靠;
- 标注数据是否覆盖真实分布;
- 模型服务是否稳定;
- 这个分类步骤是否值得存在。
这些问题必须分别决策。把它们混进同一次提示词实验,会让结果看起来在变好,实际却失去可解释性。
8. 一页速查
固定目标
→ 收集决定 + reason
→ 从 reason 聚类理解偏差
→ 提出一个语义假设
→ 修改一个主要契约
→ 定向通过
→ 全量回归
→ 产品等价复核
→ 达到 N/K 才进入产品
核心判断:
不要问“这句话还能怎么强调”,要问“模型把哪个概念理解成了什么,证据在哪里”。