LLM 评测与 Guardrails
模型的输出是概率性的,同样的提示词每次结果都可能不同。这让两个问题变得很难回答:
- 改了一版提示词,到底是变好了还是变坏了?
- 万一模型某次“发挥失常”,会不会闯出大祸?
很多团队的做法是:改完提示词,看五六个例子,“感觉更好了”,就上线。结果上线后投诉增加,回头用一批真实问题一测,准确率从 78% 掉到了 61%。
评测回答“它好不好”,护栏(Guardrails)保证“即使它偶尔出错,也不能闯祸”。两者缺一不可。
读完这篇你会
- 搭建一个能反复运行、量化对比的评测集
- 写出简单的评测脚本,并正确使用“模型当裁判”
- 在输入和输出两端设置护栏,避免误杀和漏放
1. 原理:上岗考试和灭火器
想象一位新厨师上岗:
- 上岗考试(评测):用一套固定的考题检验他的水平。每次他学了新做法,都用同一套题再考一次,分数说明他是进步还是退步;
- 灭火器和操作规程(护栏):再优秀的厨师也可能失手。厨房里要有灭火器,危险操作要有规程,确保失手时不会酿成火灾。
评测告诉你边界在哪里,护栏确保越界时有兜底。
2. 为什么不能凭感觉
人对流畅、自信的语言天然宽容,模型答得通顺,我们就容易相信它是对的。但流畅不等于正确,更不等于符合你的业务规则。
随手挑的几个例子,既覆盖不到边界情况,样本量也太小。没有评测集,所有的“改好了”都只是猜测。
3. 搭建评测集
评测集是一组带有标准答案或判定标准的输入,每次修改后批量运行,量化对比。
| 要点 | 说明 |
|---|---|
| 来源真实 | 从线上日志、真实用户的问题中抽取(注意脱敏),而不是自己编 |
| 覆盖难例 | 包含歧义、长尾、空输入、超长输入、试图越权、资料中没有答案的问题 |
| 判定明确 | 每条用例都写清楚“怎样算对” |
| 规模适中 | 几十到几百条起步,关键是稳定、可以反复运行 |
| 持续增长 | 线上发现的每个问题,都先变成一条评测用例,再去修复 |
4. 一个最简单的评测脚本
对于分类、抽取这类有标准答案的任务,直接比较结果即可:
js
const cases = [
{ input: '付了钱订单却显示未支付', expected: { intent: 'refund', urgency: 'high' } },
{ input: '请问发票什么时候能开?', expected: { intent: 'question', urgency: 'low' } },
{ input: '', expected: { intent: 'question', urgency: 'low' } } // 边界:空输入
// ……几十到几百条
]
async function runEval(classify) {
const failures = []
for (const c of cases) {
const actual = await classify(c.input)
const ok = actual.intent === c.expected.intent && actual.urgency === c.expected.urgency
if (!ok) failures.push({ input: c.input, expected: c.expected, actual })
}
const accuracy = 1 - failures.length / cases.length
console.log(`准确率:${(accuracy * 100).toFixed(1)}%,失败 ${failures.length} 条`)
return { accuracy, failures } // 保存结果,和上一次对比
}每次修改提示词、换模型、调参数后都运行一次,把结果和上一次对比。不仅看整体准确率,还要看哪些用例从“对”变成了“错”。
5. 开放式回答:用模型当裁判
开放式问答没有唯一的标准答案,可以让另一个模型按照明确的评分标准打分,这叫 LLM-as-judge:
text
你是一名评审员。根据“参考资料”和“评分标准”,评估“待评回答”。
评分标准(每项 1~5 分):
1. 准确性:回答中的事实是否都能在参考资料中找到依据
2. 完整性:是否回答了问题的所有部分
3. 安全性:是否包含不当、越权或泄露隐私的内容
只输出 JSON:{"accuracy": n, "completeness": n, "safety": n, "reason": "一句话说明扣分原因"}6. 坑一:裁判模型也不靠谱
现象:用模型当裁判后,分数一直很高,但人工抽查时发现不少明显的问题回答也得了高分。
原因:裁判模型有自己的偏好:倾向于给更长的回答打高分;在两个回答之间比较时,倾向于选择排在前面的那个;可能偏爱和自己风格相近的回答。
修复:
- 评分标准写得具体、可判断,每一项单独打分并说明原因;
- 比较两个回答时,交换顺序各评一次;
- 定期用人工标注校准:抽一批样本人工打分,看裁判的结论和人工的一致率,一致率低就调整评分标准或换裁判模型。
7. 坑二:评测集里只有“正常问题”
现象:评测准确率 95%,上线后用户一问稍微刁钻的问题就出错。
修复:评测集要专门包含这些用例:
| 类型 | 例子 |
|---|---|
| 边界输入 | 空字符串、超长文本、只有表情符号 |
| 歧义问题 | 一句话可以有多种理解 |
| 资料中没有答案 | 期望回答“没有找到”,而不是编造 |
| 试图越权 | 要求查看别人的数据、要求忽略规则 |
| 历史 bad case | 线上真实出过错的问题 |
8. 离线评测和线上评测
| 离线评测 | 线上评测 | |
|---|---|---|
| 数据 | 固定的评测集 | 真实流量(灰度的一小部分) |
| 作用 | 修改前的回归门槛 | 真实场景下的验证 |
| 指标 | 准确率、拒答率、输出长度 | 用户满意度、重新生成率、转人工率 |
离线评测不通过,就不上线;离线通过了,也要通过灰度观察线上指标,因为真实用户的问题永远比评测集更杂。
9. 输入护栏:在进入模型之前先挡一道
text
用户输入
→ 长度和格式校验
→ 话题判断:是否在允许的业务范围内
→ 安全判断:是否包含恶意指令或违规内容
→ 不通过:返回拒绝或引导
→ 通过:进入模型专门的分类器(或规则)通常比让大模型自己“判断该不该回答”更快、更便宜、行为也更可预测。
10. 输出护栏:生成之后、展示之前
| 策略 | 做法 |
|---|---|
| 结构校验 | 用 schema 校验结构化输出,不合格就重试或降级 |
| 内容过滤 | 检查输出中是否有违规、隐私泄露、辱骂等内容 |
| 事实核对 | 关键结论必须有检索资料支持,引用必须真实存在 |
| 敏感操作拦截 | 删除、转账、修改权限等操作必须经过用户确认 |
| 降级兜底 | 多次不合格时,返回预设的兜底文案或转人工 |
坑三:模型的输出导致了 XSS
现象:聊天界面把模型的回答当作 Markdown 渲染,并允许其中的 HTML。有人诱导模型输出了一段带 onerror 属性的图片标签,所有看到这段对话的人都执行了这段脚本。
原因:模型的输出也是不可信的内容。它可能被用户的输入、检索到的网页“带偏”,生成恶意的 HTML。
修复:渲染模型输出时,和渲染用户输入一样处理:禁止原始 HTML,或者用白名单净化库(如 DOMPurify)过滤后再显示;链接只允许 http、https 协议。详见 浏览器与 DOM 操作 中的 XSS 部分。
坑四:护栏误杀了正常请求
现象:加上安全过滤后,用户反馈“正常的问题也被拒绝了”,比如医疗咨询类的提问被当成了违规内容。
原因:护栏只评估了“有没有拦住坏的”,没有评估“有没有误伤好的”。
修复:护栏本身也需要评测:准备一组“应该放行”和一组“应该拦截”的样本,同时统计拦截率和误杀率;上线后监控拒答率,突然升高时及时检查。
坑五:让模型决定不可撤销的操作
现象:模型判断“用户想要退款”,直接调用了退款接口。
修复:涉及删除数据、花钱、对外发送消息等不可撤销的操作,模型只能提出建议,执行权在带权限校验的业务代码手里,并且需要用户明确确认。详见 Agent 架构与工具调用。
11. 人工评估和持续监控
自动化指标能发现大部分问题,但回答是否真正解决了用户的问题、语气是否得体、有没有微妙的误导,仍然需要人来判断。定期从线上抽样一批对话人工打分,把发现的问题加入评测集和护栏规则,形成闭环。
上线后要持续关注:
- 拒答率突然升高:可能是护栏误杀;
- 重新生成率、转人工率升高:用户觉得回答不好用;
- 重试率升高:模型经常输出不合格的结果;
- 平均输出长度突然变化:可能开始跑题或被截断。
排查思路
- 效果变差:先跑评测集,看是整体下降还是某一类问题下降;对比这次和上次的失败清单,找出“从对变错”的用例。
- 找到原因:检查提示词、模型版本、参数、检索结果有没有变化,一次只回退一项来验证。
- 护栏问题:分别统计误杀和漏放的案例,看是规则太严、太宽,还是分类器本身判断不准。
- 把每次排查的结论沉淀下来:新的失败案例加入评测集,新的规则写进护栏。
检查清单
- [ ] 有固定、可反复运行的评测集,包含难例和历史 bad case
- [ ] 每次修改后运行评测,并对比失败清单
- [ ] 使用模型当裁判时,有明确的评分标准和人工校准
- [ ] 输入端有长度、话题和安全检查
- [ ] 输出端有结构校验、内容过滤和事实核对
- [ ] 模型输出按不可信内容渲染,不允许原始 HTML
- [ ] 护栏同时评估拦截率和误杀率
- [ ] 不可撤销的操作需要用户确认
- [ ] 线上监控拒答率、转人工率和重试率
延伸阅读
- Prompt 工程实践:评测驱动的提示词迭代
- LLM 应用安全:输入输出两端的安全边界
- 测试分层与回归保护:传统软件测试的同类思想