AI 评测集为什么会被提示词污染:固定模板、变量隔离与回归验收
来源:17golang原创
时间:2026-08-24 12:33:42 496浏览 收藏
评测集分数突然上涨,未必是模型真的变好了。更常见的原因是上一轮提示词、答案示例或调试字段被写回了样本,模型在测试时提前看到了本不该出现的线索。排查这类污染,要把“样本原文、渲染后的提示词、模型输出”分开留存,再用固定快照做回归。
先把评测输入冻结成只读快照,再检查变量是否跨样本复用;只看最终分数,通常定位不到提示词污染。
- 评测样本只保存任务事实,不保存上一轮的提示词和模型输出。
- 模板渲染必须使用一次性上下文,调试信息与正式输入分离。
- 回归验收同时比对输入快照、渲染结果和输出分布。
先确认分数上涨发生在哪一层
把一次评测拆成三份可追溯的证据:case.jsonl 是原始样本,rendered.jsonl 是送入模型的最终文本,result.jsonl 是模型响应。三者都绑定同一个 case_id,绝对不能互相覆盖。若原始样本没有任何改动,渲染文本里却多出上一轮参考答案或者之前的调试标记,问题就出在模板渲染环节。
case_id=qa-017
input: 用户要求解释一个超时错误
expected: 能指出超时发生在连接建立阶段
rendered: system + task + input
output: 模型最终回答
先统计每个 case_id 对应渲染文本的哈希值。同一份样本在不同轮次渲染得到不同哈希值,不一定是错误;模板版本调整、系统提示词改动或者变量值更新都可能造成差异。但如果变化来源是另一个样本的答案、人工批注或者调试日志,就得立刻停止单纯的分数对比排查。

最容易串入的三个变量
第一类是循环外的可变字符串。代码把上一条样本内容拼进 prompt 后没有做清空处理,下一条样本自然就继承了前面的内容。第二类是全局共享的字典或者列表,渲染函数修改了传入的公共对象,后续样本读取到的就是被改写后的副本。第三类是重试记录:第一次请求失败时写入的错误说明,被误当成下一次请求的上下文带入。
变量隔离没必要依赖复杂框架,核心规则是让渲染函数只接收只读的样本数据,最后返回全新的字符串。下面的写法把历史输出放进独立的观测对象,正式提示词完全不会引用到这部分内容:
def render_case(case, template):
values = {
"question": case["question"],
"constraints": tuple(case.get("constraints", ()))
}
prompt = template.format(**values)
return {"case_id": case["case_id"], "prompt": prompt}
def record_result(rendered, response, trace):
trace.append({"case_id": rendered["case_id"], "output": response})
这里的核心不是函数命名,而是明确边界:render_case 不读取 trace 模块里的历史数据,record_result 也不会往回改写 prompt 内容。如果评测场景必须加入检索资料或者少量示例,要为每个样本单独创建新列表,同时在日志里记录资料来源的唯一标识。
用哈希和抽样复核抓住污染证据
每次评测启动前,先为原始样本和当前模板生成 SHA-256 快照;每条渲染结果再单独记录 template_version、case_id 和 input_sha256。验收时先核对元数据,再校验文本内容,这比从长篇大段的模型输出里人工找线索效率高很多。
抽样复核至少覆盖三类样本:队列第一条、触发过重试的样本,以及上一轮得分波动最大的样本。检查内容里有没有出现其他 case_id、内部人工评语、参考答案或者“只输出 JSON”这类不属于当前样本的字段。如果是包含用户隐私的评测集,日志里只保留哈希和脱敏片段,不要把完整输入同步到公共看板。

回归验收不要只看平均分
修复相关问题后,重新跑一遍同一份冻结的快照,至少比对四项内容:渲染文本哈希是否稳定、污染关键词命中数是否归零、各类别样本数量是否完全一致、之前的失败样本是否还能稳定复现。平均分可以作为最终结果指标,但绝对不能代替输入层的证据校验。
一个实用的门禁规则是:输入快照哈希不变,模板版本明确,污染扫描结果为零,同时重点样本的输出差异有人工可解释的依据。如果修复后分数回落,别为了拉高数字就把旧输出重新塞回提示词;先确认模型行为变化确实来自完全干净的输入。
常见问题
提示词里放少量上一轮输出一定算污染吗?
不一定。如果这是评测设计明确要求的多轮上下文内容,并且归属到当前样本的输入范畴,就应该写进样本定义里同时参与快照校验。没有提前声明、跨样本引用、无法追溯来源的上一轮输出,才是需要阻断的污染。
为什么单元测试通过,批量评测仍会串数据?
单元测试通常每次只会渲染一个样本,没办法暴露循环复用可变对象的问题。补一组顺序测试用例:先渲染包含长答案的样本,再渲染空答案样本,然后断言第二条提示词里不包含第一条的任何内容。
只保存最终提示词够不够?
不够。还要同步保存原始样本哈希、模板版本和变量来源信息,不然你只能看到最终渲染结果,没法判断差异是来自样本改动、模板调整,还是渲染阶段串入了多余数据。
发布前检查清单
- 原始样本设为只读快照,
case_id唯一且样本总数稳定。 - 渲染函数不读取历史输出,重试记录和正式输入分开存储。
- 三份证据都记录哈希、模板版本和样本标识。
- 首条、重试条目和分数变化最大条目完成抽样复核。
- 污染关键词命中数为零,平均分之外的分布变化有明确解释。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习