第25题:如何诊断 Prompt 模板导致的效果下降?
1. 核心回答
诊断 Prompt 模板导致的效果下降,我会采用一条严格的因果定位流程:
确认真实回退 → 固定其他变量 → 旧/新 Prompt 配对回放 → 定位 Prompt 差异 → 单变量消融 → 错误分类 → 修复 → 全量回归测试
核心原则是:
只有在模型、数据、采样参数、工具、检索结果和评分器保持一致时,旧 Prompt 与新 Prompt 之间稳定出现性能差异,才能把问题进一步归因到 Prompt。
因此第一步通常不是直接修改 Prompt,而是先证明:
$$
\Delta_{\text{prompt}}
Metric(P_{\text{new}})
Metric(P_{\text{old}})
<0
并且这个差异能够在同一批样本上稳定复现。 *** ** * ** *** ### 2. 第一步:先确认是否真的发生了 Prompt Regression 假设线上指标从: F1=0.86 F1=0.86 F1=0.86 下降到: F1=0.79 F1=0.79 F1=0.79 我首先会保存两个版本: * PoldP_{\\text{old}}Pold:性能正常的旧 Prompt; * PnewP_{\\text{new}}Pnew:出现下降的新 Prompt。 然后使用**完全相同的一组 Evaluation Dataset** 对两个 Prompt 做配对测试。 对每个样本 xix_ixi: yiold=M(Pold,xi) y_i\^{old}=M(P_{old},x_i) yiold=M(Pold,xi) yinew=M(Pnew,xi) y_i\^{new}=M(P_{new},x_i) yinew=M(Pnew,xi) 再使用相同 Grader 得到: siold=G(yiold) s_i\^{old}=G(y_i\^{old}) siold=G(yiold) sinew=G(yinew) s_i\^{new}=G(y_i\^{new}) sinew=G(yinew) 重点观察每一个样本的变化: Δi=sinew−siold \\Delta_i=s_i\^{new}-s_i\^{old} Δi=sinew−siold 这样可以直接找到: **哪些原来正确的样本,在新 Prompt 下变错了。** 比单独比较两个平均分更容易定位问题。 *** ** * ** *** ### 3. 第二步:固定所有 Prompt 之外的变量 进行 Prompt 因果诊断时,需要尽量固定: * Model 及具体版本; * System / Developer Prompt; * User Input; * Evaluation Dataset; * Temperature; * Top-p; * 最大输出长度; * Tool Definition; * Retrieval Result; * Context; * Output Parser; * Grader; * 推理配置。 可以把输出抽象为: Y=f(P,M,D,R,T,G,...) Y=f(P,M,D,R,T,G,\\ldots) Y=f(P,M,D,R,T,G,...) 其中: * PPP:Prompt; * MMM:Model; * DDD:Input Data; * RRR:Retrieval / Tool Context; * TTT:Sampling Configuration; * GGG:Evaluation Method。 本轮实验只改变: Pold→Pnew P_{old}\\rightarrow P_{new} Pold→Pnew 其他变量保持一致。 否则即使最终指标下降,也无法明确判断下降来自 Prompt、模型升级、检索变化还是评分器变化。 *** ** * ** *** ### 4. 第三步:对旧 Prompt 和新 Prompt 做结构化 Diff Prompt 模板通常可以拆成多个组件: P=\[I,C,E,F,S,T\] P= \[ I,C,E,F,S,T \] P=\[I,C,E,F,S,T\] 例如: * III:Instruction,任务指令; * CCC:Context,上下文; * EEE:Examples,Few-shot 示例; * FFF:Output Format,输出格式; * SSS:Safety / Constraint,约束; * TTT:Tool Instructions,工具说明。 先比较: `P_old vs P_new` 明确到底修改了什么。 常见变化包括: * 新增了一条规则; * 修改了指令措辞; * 调整了指令顺序; * 增加 Few-shot Example; * 删除 Example; * 修改输出 JSON Schema; * 增加背景材料; * 修改工具说明; * 改变上下文排列顺序; * Prompt 整体长度显著增加。 如果一次发布同时修改了十几个部分,直接阅读最终输出通常很难判断真正原因。 *** ** * ** *** ### 5. 第四步:使用单变量消融定位问题 假设新 Prompt 相比旧版本增加了三个组件: ##
P_{new}
P_{old}
A+B+C
$$
例如:
- AAA:新增角色说明;
- BBB:新增 Few-shot Example;
- CCC:新增 JSON 输出约束。
可以依次测试:
Pold+A P_{old}+A Pold+A
Pold+B P_{old}+B Pold+B
Pold+C P_{old}+C Pold+C
再测试必要的组合:
Pold+A+B P_{old}+A+B Pold+A+B
Pold+A+C P_{old}+A+C Pold+A+C
Pold+B+C P_{old}+B+C Pold+B+C
观察每一种配置相对于 Baseline 的变化。
如果发现:
Metric(Pold+A)≈Metric(Pold) Metric(P_{old}+A)\approx Metric(P_{old}) Metric(Pold+A)≈Metric(Pold)
Metric(Pold+B)≈Metric(Pold) Metric(P_{old}+B)\approx Metric(P_{old}) Metric(Pold+B)≈Metric(Pold)
但:
Metric(Pold+C)≪Metric(Pold) Metric(P_{old}+C)\ll Metric(P_{old}) Metric(Pold+C)≪Metric(Pold)
那么可以优先定位到 CCC。
当 Prompt 很长时,可以使用二分法。
例如 Prompt 新增了 20 条规则:
- 先移除前 10 条;
- 测试是否恢复;
- 根据结果继续对问题区间二分;
- 逐步缩小到一条或几条规则。
这种方法比凭感觉不断重写整个 Prompt 更容易建立因果证据。
6. 第五步:对失败样本进行错误分类
定位到某个 Prompt 组件后,还需要回答:
它为什么造成性能下降?
我会把回退样本按照错误机制分类。
6.1 Instruction Conflict
两个指令之间存在冲突。
例如前面要求:
必须给出完整解释
后面又要求:
答案只能包含一个词
模型需要在冲突要求之间进行取舍,输出可能发生明显变化。
检查:
- System、Developer、User 指令之间是否冲突;
- 同一 Prompt 内是否存在重复但不一致的要求;
- Few-shot Example 是否与文字规则冲突。
6.2 Instruction Dilution
Prompt 中加入大量低价值规则后,真正关键的任务要求变得不突出。
例如原 Prompt 只有:
判断代码是否包含 SQL Injection,并给出证据。
后来增加大量:
- 语气要求;
- 排版要求;
- 角色描述;
- 无关背景;
- 重复规则。
最终核心任务只占整个 Prompt 很小一部分。
此时可以测试:
删除非必要规则 → 重跑同一 Eval
如果性能恢复,则说明 Prompt 复杂度本身已经影响任务执行。
6.3 Context Truncation
Prompt 变长可能直接挤占有效输入空间。
假设上下文窗口允许的总 Token 数为:
Lmax L_{\max} Lmax
实际输入满足:
Lprompt+Lcontext+Loutput≤Lmax L_{prompt} + L_{context} + L_{output} \leq L_{\max} Lprompt+Lcontext+Loutput≤Lmax
如果:
Lprompt↑ L_{prompt}\uparrow Lprompt↑
可留给真实业务 Context 的空间就可能下降。
需要检查:
- 用户输入是否被截断;
- RAG 文档是否被截断;
- Few-shot Example 是否挤占有效上下文;
- 最重要的信息是否位于被裁剪区域;
- 最大输出长度是否导致生成提前终止。
6.4 Position / Ordering Effect
Prompt 中的信息顺序发生变化也可能改变结果。
例如原来:
任务定义 → 数据 → 输出要求
修改后:
大量示例 → 背景 → 输出要求 → 任务定义
可以分别测试:
- Instruction 放前面;
- Instruction 放后面;
- Context 在前;
- Example 在前;
- 关键约束靠近最终输入。
一次只改变排列顺序,然后重新运行相同 Eval。
6.5 Few-shot Example Pollution
Few-shot Example 可以帮助模型明确任务,也可能引入错误模式。
需要检查:
- Example 是否覆盖真实任务;
- Example 是否包含错误答案;
- Example 的输出格式是否与当前要求一致;
- Example 是否让模型学到表面模式;
- Example 是否集中于某一类别;
- Example 顺序是否造成类别偏置。
可以分别运行:
Zero-shot
1-shot
Few-shot
观察具体变化。
6.6 Output Schema / Parser Failure
这一类问题很容易被误判为模型能力下降。
例如旧版本输出:
{"label": "safe"}
新 Prompt 输出:
{"result": {"label": "safe"}}
语义结果仍然正确,但下游 Parser 只读取:
label
于是系统把新输出判定为失败。
因此必须把:
模型语义错误
和:
格式 / Parser 错误
分别统计。
可以分别定义:
SemanticAccuracy SemanticAccuracy SemanticAccuracy
和:
ParseSuccessRate ParseSuccessRate ParseSuccessRate
如果:
SemanticAccuracy≈原水平 SemanticAccuracy\approx\text{原水平} SemanticAccuracy≈原水平
但:
ParseSuccessRate↓ ParseSuccessRate\downarrow ParseSuccessRate↓
问题主要位于 Schema、Prompt 格式要求或解析程序。
7. 第六步:检查 Eval 本身有没有制造"假回退"
另一个重要风险来自评分方法。
例如标准答案是:
SQL Injection
模型输出:
The vulnerability is SQL injection.
如果评分器使用严格字符串匹配:
ExactMatch=0 ExactMatch=0 ExactMatch=0
但语义判断实际上正确。
Prompt 改变后,模型可能只改变表达形式:
旧 Prompt:
SQL Injection
新 Prompt:
This code contains an SQL injection vulnerability.
此时 Exact Match 指标下降,任务能力没有同步下降。
因此回退诊断需要同时检查:
- Exact Match;
- Structured Field Accuracy;
- Semantic Grader;
- 人工抽样;
- Parser Success Rate。
对于开放式任务,我会随机抽取新旧 Prompt 出现分歧的样本进行人工复核。
这样可以判断:
真实能力下降 \text{真实能力下降} 真实能力下降
和:
评测方式导致的表面下降 \text{评测方式导致的表面下降} 评测方式导致的表面下降
分别占多少。
8. 第七步:修复后必须做完整回归测试
定位问题并修复 Prompt 后,不能只重新测试几个失败案例。
需要重新运行完整 Eval Set。
定义:
Pfix P_{fix} Pfix
然后同时比较:
Pold P_{old} Pold
Pnew P_{new} Pnew
Pfix P_{fix} Pfix
理想情况应该满足:
Metric(Pfix)≥Metric(Pold) Metric(P_{fix}) \geq Metric(P_{old}) Metric(Pfix)≥Metric(Pold)
同时重点检查:
原来正常的样本有没有因为修复产生新的失败。
因此我会建立固定的 Prompt Regression Suite,包括:
- 高频正常样本;
- 历史失败样本;
- 边界样本;
- 长输入;
- 短输入;
- 特殊格式;
- Tool Calling;
- RAG 场景;
- 拒答场景。
每次 Prompt 发布前都运行一次。
9. 工程上如何长期避免 Prompt 回退
我会把 Prompt 当作正式的软件配置进行版本管理。
例如:
prompt_v1
prompt_v2
prompt_v3
每个版本记录:
- Prompt 内容;
- Model Version;
- Evaluation Dataset Version;
- Sampling Configuration;
- Eval Score;
- 修改原因;
- 失败案例;
- 发布时间。
整个发布流程可以设计成:
修改 Prompt
↓
运行固定 Eval
↓
逐样本 Diff
↓
人工抽查 Regression
↓
通过阈值
↓
灰度发布
↓
监控线上指标
↓
异常则回滚 Prompt Version
OpenAI 的 Prompt Management 也提供 Prompt Versioning,并建议 Prompt 发布后重新运行关联 Eval 来发现 Regression。
10. 面试时可以压缩成下面这段
诊断 Prompt 模板造成的效果下降,我首先会固定模型版本、测试数据、采样参数、工具、检索上下文和评分器,然后用旧 Prompt 和新 Prompt 对同一批样本做配对回放。
确认回退能够稳定复现以后,我会先做 Prompt Diff,把 Prompt 拆成 Instruction、Context、Few-shot Example、Output Schema 和 Tool Instruction 等组件,再采用单变量消融或二分法定位导致指标下降的部分。
定位以后,我会对失败样本分类,重点检查指令冲突、Prompt 过长导致的上下文截断、信息顺序变化、Few-shot Example 污染、输出 Schema 改变以及 Parser Failure。
同时我会检查 Eval 本身。尤其是开放式生成任务,严格 Exact Match 可能把语义正确但表达方式变化的答案判错,所以需要结合语义评分和人工抽样判断是真实能力回退还是评分方式造成的表面回退。
修复以后重新运行完整 Regression Suite,并对 Prompt 做版本管理。只有新版本在整体指标、历史失败案例和关键业务切片上都通过回归测试,才进入发布。
11. 来源
- OpenAI, Best practices for prompt engineering with the OpenAI API。
- OpenAI API Documentation, Model guidance --- Prompting best practices。
- OpenAI, Prompt management in Playground。
- OpenAI API, Evals 与 Graders 文档。
- Hua et al., Flaw or Artifact? Rethinking Prompt Sensitivity in Evaluating LLMs, 2025。
- He et al., Does Prompt Formatting Have Any Impact on LLM Performance?, 2024。
- Chatterjee et al., POSIX: A Prompt Sensitivity Index For Large Language Models, 2024。