做提示工程架构师这几年,被人问得最多的一个问题就是:你改过的这套AI提示系统,凭什么说比上一个版本好?过去我也跟很多人一样,攒几个精心挑选的对比用例,截图发群里,大家看看说不错就上线。直到有一次在客服场景里,因为改了一个全局提示词,整个话术风格集体跑偏,用户投诉量翻倍,我们花了整整两天才定位到原因——没有基线、没有回归、没有监控,全靠人肉翻聊天记录。
从那次之后,我彻底把提示系统测试当成跟业务代码测试同等重要的事情来对待。这篇文章就拿我实际踩过的坑和沉淀下来的方法,聊聊AI提示系统的测试方法和工具,内容包括测试维度怎么拆、指标怎么定、数据集怎么建、工具怎么选、流程怎么落,以及一堆常规文档里不会写的避坑经验。适合正在从提示词手艺人往提示工程架构师方向进阶的同学,也适合所有不想“上线即翻车”的AI应用团队参考。
1. 为什么提示系统是最需要测试的线上系统
先说清楚一件事:提示词不是文档,它是在生产环境里运行的一段“自然语言代码”。 有了这个认知,后面的测试方法才顺理成章。很多团队把提示词当成可读的文本,写完人肉测几个case就上线。但提示词和传统代码最大的区别在于,它的执行结果不受你完全控制,而且改动一个词,影响的可能不是单条路径,而是整个行为分布。
1.1 提示词的本质是一段可运行的自然语言代码
传统代码有编译期检查、有单元测试、有断言。提示词完全不一样,你写的东西模型不一定按字面执行,输出的结果还带随机性。同一个输入,就算把温度调到0,输出也未必完全一致,更别说还有模型版本、上下文窗口、缓存、服务端负载这些变量。所以很多人第一次给提示词写测试,会碰上一个非常尴尬的卡点:不知道断言该写什么。
我建议先完成一个思维转换:把提示系统当成一个“行为不太稳定的组件”来测,而不要把它当成一段确定性的函数。这就好比你在带一个新人员工,你不能断言他“今天一定用某种语气说话”,只能给他设定“语气必须包含的要素”“禁止出现的表达”“必须返回的结构”,然后通过一批样本观察他的行为分布是否符合预期。一旦习惯了这种“分布思维”,提示系统测试的整个逻辑就顺了:你不是在证明某一次输出是对的,而是在证明一个提示版本在足够多样本上的表现足够稳定。
这里还有一个很多人忽略的点:提示词修改是上游变更。传统代码里,一个函数改了,编译错误能拦住大部分问题;提示词改了,没有编译期,没有类型系统,所有问题都会直接暴露在真实用户面前。而且提示词往往存在全局和局部叠加的作用,一个全局指令微调,可能把局部场景里的拒答语气、致歉话术全部带偏。所以它比普通代码更需要测试,因为它几乎没有“中间层”帮你兜底。
1.2 没有测试基线,改一版就翻一次车
我自己就翻过一次车。那次在客服系统里给全局系统提示词加了一句“请用热情的语气回复”,本意是让售前话术更亲切,结果拒答文案、售后致歉、甚至面对用户发泄情绪时的安抚话术全部变成热情风格。有用户直接投诉“客服在笑呵呵地拒绝我”。这个问题的根因就是全局提示词的放大效应,而当时我们压根没有测试基线,没有数据集,不知道改动前到底什么水平,也不知道改动后哪些场景退化、哪些场景进步,排查和回退全靠肉眼。
没有测试基线,线上事故通常长这样,我当时整理过三类高发问题:
- 格式事故:模型返回的JSON里突然多了注释、markdown标记或多余字段,下游解析器直接抛异常。这种问题在提示词里加一句“只返回JSON”并不能百分百解决,必须靠断言持续盯。
- 语义漂移:模型升级或切换备用型号后,同样的提示词,输出风格、信息密度、语气全变了,你如果没有历史基线,根本说不清是“变好了还是变坏了”。
- 安全与合规事故:提示注入、越狱词、有害内容漏过,这种事一旦发生就是舆情级别的,而没测试基线意味着你没法提前发现哪个样本组合让防线失效。
所谓测试基线,说起来就三样东西:一个覆盖典型场景的数据集、一套可量化的评估指标、一组历史运行记录。有了这三样,任何提示词改动都变成一次可比较的变更:跑同一套测试集,算同一套指标,和基线对比,通过就合并,不通过就打回。这本质上就是把软件开发里的“回归测试”思路搬到了自然语言代码上。别再靠“我觉得差不多”来上线了,真的会翻车。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 提示系统测试的核心维度与指标设计
测试维度怎么拆,决定了你测试体系的天花板。如果只测“回答好不好看”,那这套体系撑不起生产级提示系统。我习惯把提示系统测试切成六个维度,每个维度都有对应的测试手段和评估方式。
2.1 六个测试维度一张表拉通
| 测试维度 | 测什么 | 典型用例 | 评估方式 |
|---|---|---|---|
| 功能正确性 | 输出结构、字段完整性、内容约束 | JSON字段是否齐全、是否返回指定格式 | 规则断言、schema校验 |
| 输出质量 | 相关性、忠实度、信息密度、语气 | 回答是否针对问题、是否基于上下文 | LLM裁判、人工抽检 |
| 稳定性一致性 | 同输入多次调用结果方差 | 同一问题跑10次,语气和结构漂移多大 | 多次采样、计算方差 |
| 性能 | 首字延迟、总延迟、并发表现 | 低峰和高峰下延迟分位数 | 链路追踪、服务监控 |
| 成本 | Token消耗、每请求成本 | 提示词膨胀导致的Token超标 | 用量统计 |
| 安全对抗 | 提示注入、越狱、有害内容 | 攻击样本能否绕过系统限制 | 攻击库遍历、安全扫描 |
功能正确性是最容易自动化的一层,本质就是验证“输出的形状对不对”。比如要求模型输出一个包含退款路径、预计处理时间、售后入口三个字段的JSON,那就写一个schema校验断言,缺字段、多字段、类型不对都算失败。这一层建议做成全量自动,每个提示词版本都跑,成本低且价值极高。
输出质量是最难的一层,因为“好”和“不好”本身是主观判断。我常用的做法是:把质量拆成可评价的子属性,比如相关性、忠实度、可操作性、语气一致性,每个子属性单独打分,而不是笼统问“这个回答好不好”。拆开打分的好处是问题定位准——你知道是语气偏了,还是信息缺失,而不是只知道“这版效果不太好”。
稳定性和一致性往往被新团队忽略,但这类问题上线后最让用户困惑。同一句话这次有礼貌用语、下次干巴巴,用户会明显觉得“这系统不太靠谱”。我在生产里会定期抽一批固定用例做重复采样测试,比如每条跑5到10次,看语义层面的方差。如果方差过大,通常不是提示词的问题,而是温度参数、模型切换或上下文拼接不稳定导致的。性能和成本这层很实在:提示词越长、需要推理的步骤越多,延迟和成本就越高。我见过团队为了“让回答更严谨”把提示词越堆越长,结果成本翻了四倍、首字延迟直接超预期,最后不得不砍掉一半内容重写。安全对抗测试平时看起来“没用”,但真的出一次事就够你受的。这里不需要搞得多复杂,维护一个攻击样本清单,每次发版前跑一遍就行。
2.2 客观指标自动化,主观指标交给裁判
指标设计上,一条核心原则:能客观的坚决客观,不能客观的再上主观。 客观指标包括JSON schema校验通过率、必答字段完整率、禁词命中率、输出长度范围、Token消耗量、延迟分位数。这些指标不需要任何解释,脚本跑完就是结论,适合放进CI里做硬性门禁。我见过有些团队连“回答里有没有包含订单号”这种能正则匹配的断言都要靠人肉看,这是测试成本的大头浪费。
主观指标包括相关性、忠实度、语气、可操作性、有害性。这类指标有两种评估路径:人工评估和LLM裁判。人工评估准但贵,LLM裁判便宜但有偏差,实操中我推荐混合模式:每条生产变更先跑一组100到200条的小样本,用LLM裁判全量打分,同时抽20到30条交给两名评估员盲评,最后对比两者的结论。如果LLM裁判和人工评估的一致性达到90%以上,那这次变更就主要参考LLM结论;如果一致性掉到80%以下,说明这版提示词的评估本身有争议,需要扩大人工抽检比例。
这里补充一个实操细节:主观评估的采样不要用均匀随机,要用分层采样。先把业务场景分层,比如客服、导购、售后、投诉,每层随机抽固定比例,保证每个场景都被覆盖到。均匀随机采样的最大问题是,如果某个场景请求量特别大,抽到的样本会集中在那个场景,其他冷门场景成了评估盲区。我踩过这个坑,当时客服场景占了七成请求,评估指标一路绿灯,结果售后的一个语气问题上线三天没人发现。
2.3 LLM裁判的三大偏差与规避方法
用大模型给大模型的输出打分,听起来省事,里面坑不少。最常遇到的三种偏差:
- 位置偏差:做A/B对比时,LLM裁判明显偏好排在前面的回答,哪怕两条只有细微差别。
- 自我偏好偏差:裁判模型往往给自己同源或同风格的回答打高分,换一个风格的优秀回答反而被低分。
- 冗长偏好:回答越长越容易被判定为更详细、更认真,即使其中有大量废话。
规避手段我实验下来比较有效的是这几个。第一,A/B比较时把两份回答的顺序交换各跑一轮,只有两轮结论一致的样本才算有效结论。第二,给裁判提供明确的评分量表,比如“从1到5,5表示包含明确下一步动作”,而不是让它自由发挥写评价。第三,增加一个“不确定”选项,让裁判在无法判断时不要硬选,这个选项能显著降低随机性。第四,定期做人工校准,拿一批人工标注好的样本去测裁判的一致性,发现一致性跌破阈值就换裁判模型或调整评分提示词。
还有一个选型经验:裁判模型不一定越大越好。某个在特定领域对齐良好的中小参数模型,在格式遵循和打分稳定性上可能超过通用大模型,而且推理成本低,能支撑更大的评估样本量。我们后来就把裁判模型换成了一款专门做过指令对齐的开源小模型,准确率没降,评估成本下降了六成。
3. 高质量测试数据集怎么构建和维护
测试集才是提示系统测试体系的地基。没有好的测试集,工具再强、指标再科学都是空转。我见过不少团队“借用”别人开源的测试集来评估自己的业务提示词,结果那些通用测试集跟实际业务场景差太远,测出来的分数毫无参考意义。测试集必须从你真实业务里长出来,这是绕不开的一步。
3.1 测试用例的三个来源:线上、构造、合成
我构建测试集主要用三个来源,按比例大概6:3:1。
第一个来源是生产日志采样,这是最高价值的用例来源。把线上真实用户输入按场景分层随机抽样,脱敏后作为测试用例。生产样本的价值在于真实——用户不会按你预想的问法提问,他们会有错别字、口语化表达、指代不明、夹杂情绪,这些都是在会议室里编不出来的。注意两点:一是脱敏要做干净,该替换的实体信息必须替换;二是要去重和去噪,比如把完全一样的问法合并,把纯表情、纯乱码这种噪声过滤掉。
第二个来源是人工构造的badcase,针对边界情况和对抗场景。我会专门维护一份边界用例清单:空输入、超长输入、多轮对话截断、非中文输入、全大写输入、包含特殊符号、明显诱导性提问、重复提问、自相矛盾的问题。这些边界样本的价值在于,它们是提示系统最容易出问题的地方,而且往往能暴露提示词里的隐性假设。比如有的提示词假设“用户输入一定有明确诉求”,但真实用户会说一堆废话最后问一句“你看着办吧”,这种场景人工构造特别管用。
第三个来源是合成数据扩展,用已有用例做变形。比如把一个退款咨询改成不同商品类目、不同金额范围、不同用户情绪强度,再换几种问法,一条用例就能扩成十条。合成数据的比例我控制在10%左右,主要用来扩大覆盖度,不会把它当成主要来源,因为纯合成数据容易产生模式固化,测出来的指标“看起来挺好”,线上还是漏。
这里有个心得:测试集不是一次性建完就完事。生产在变、用户问法在变、业务规则在变,测试集必须定期从生产日志里补充新样本,同步淘汰过时的样本。我一般每个月做一次样本回流,把本月新增的高价值badcase合入测试集,同时检查有没有已经不符合业务现状的老用例,该删就删。这个动作不复杂,但坚持下来,测试集才不会和你真实场景脱节。
3.2 黄金数据集的版本管理与标注质检
稳定的测试集要叫它黄金数据集,英文社区一般叫golden set。黄金数据集的特点是有“标准答案”或者“标准属性”,模型的输出拿过来可以跟标准作比较。我会给每一条测试用例设计统一结构,大概是这样的:
json复制{
"id": "case-0001",
"type": "regression",
"source": "production_2025_06",
"input": {
"user_query": "订单一直不发货,怎么办?",
"session_context": "来自售后入口"
},
"expected": {
"attributes": ["包含明确下一步动作", "不承诺具体发货时间"],
"json_schema": {"need_refund_path": "boolean"},
"tone": "neutral_positive"
}
}
注意,“expected”字段我写的是属性标签,不是完整标准答案。为什么不用标准答案?因为提示词输出天然有多样性,适合“包含什么属性、具备什么语气、满足什么结构”这种约束式标注,而不是要求逐字一致。这样标注的核心思路,是让测试用例可复用:提示词改了,期望属性不变,模型输出的表达方式千变万化,只要属性命中就算通过。
标注质检上,我坚持双人标注加仲裁机制。每个用例至少要两个人各自标注,标注结果一致才合并进测试集,不一致的由经验丰富的人仲裁。一开始这样做有点慢,但后面会发现,很多线上问题就出在“评估者和标注者对标准的理解不一致”,双人标注能提前把这种偏差摁掉。每周我会随机抽20条已标注用例做一致性复核,如果标注一致性低于95%,说明用例定义或者业务理解出问题了,需要回头修标准。
黄金数据集的版本管理要跟提示词版本绑定。数据集文件和提示词文件一起纳入版本管理,同一个发布版本用同一个标签。这样以后查问题,可以精确回放到“当时这个提示词版本是配着哪份测试集评估的”。我们曾经因为数据集单独更新、没跟提示词同步,导致某次对比里一个历史版本的分数据说是它本身就差,实际是数据集已经换过了,那次之后我就强制两者同仓同标签。
4. 主流测试工具选型与实测对比
工具这块比较容易走偏。很多团队上来就问“哪个工具最好”,实际应该先问“我现在处在哪个阶段”。不同阶段的测试需求完全不一样,工具选型自然也不同。我的经验是:先分场景,再选工具,最后考虑要不要自研。
4.1 先分场景再选工具
我把提示系统测试拆成三类场景:单点提示实验、批量回归测试、线上持续监控,三类场景对应的工具路径差异很大:
| 场景 | 核心诉求 | 推荐路径 |
|---|---|---|
| 单点提示实验 | 快速看效果、多版本对比 | 在线调试平台、批量对比工具 |
| 批量回归测试 | 可重复、可脚本化、能接CI | 开源框架如promptfoo、DeepEval |
| 线上持续监控 | 真实流量采样、告警 | 商业追踪评测平台或自研采集评估链路 |
单点实验阶段,核心是速度。你还在琢磨这个提示词怎么写的时候,不需要复杂的评估体系,在线调试平台或者简单的批量对比脚本就够用。这个阶段最常见的错误是“把实验当测试”——手工试了几条觉得不错,就当测试通过了。实验是探索,测试是验证,两者不能互相替代。
真正进入测试体系,一定要落在可重复的、脚本化的回归测试上。工具必须满足三个条件:配置文件能版本管理、执行结果能自动断言、能接入CI流程。开源框架里我实测下来用得最多的是promptfoo和DeepEval,各有所长,下面细说。
4.2 开源框架实测:批量回归与断言
promptfoo是我最早稳定使用的工具,它的设计思路是用声明式配置文件把提示词、模型、测试用例、断言全部描述出来,跑一次就能看到多条用例在不同提示版本下的对比结果。一个典型的配置长这样:
yaml复制prompts:
- file://prompts/support_agent.txt
- file://prompts/support_agent_v2.txt
providers:
- id: chat:your-model
config:
temperature: 0.3
max_tokens: 512
tests:
- vars:
user_query: "订单一直不发货,怎么办?"
assert:
- type: contains
value: "退款"
- type: is-json
- type: llm-rubric
value: "回复中必须包含一个用户可以立即执行的下一步动作"
读法很简单:“prompts”定义两个提示词版本,“providers”指定模型和采样参数,“tests”定义用例数组,每条用例带一组断言。跑完它会生成对比表,两版提示词在同一条输入下的输出并排显示,断言通过或不通过一目了然。这个工具最适合做“批量对比+基础断言”,上手成本低,适合作为团队的第一套回归测试工具。
DeepEval是另一个路子,它更贴近测试工程习惯,把评估指标封装成和pytest兼容的断言函数。下面是一个我用过的示例:
python复制from deepeval.test_case import LLMTestCase
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.run_test import assert_test
test_case = LLMTestCase(
input="订单一直不发货,怎么办?",
actual_output=generate_response(...),
retrieval_context=["你可以通过订单详情页申请退款"],
)
assert_test(test_case, [AnswerRelevancyMetric(threshold=0.8)])
和promptfoo的区别在于,DeepEval的核心是“指标断言”——回答相关性、忠实度、幻觉检测这些指标都能以模块化方式加进来,阈值一设,跑不过就是跑不过。它的优势是能写复杂的测试逻辑,适合团队里已经有测试工程习惯、希望用Python代码组织评估的人。我在做RAG类项目时,还会用Ragas这类专注检索增强评估的工具,它内置了上下文相关性、答案忠实度、上下文利用度等RAG专属指标,能省掉很多自研评估逻辑。
实测下来我的结论是:promptfoo适合快速批量对比和格式类断言,DeepEval适合写指标级断言和融入pytest体系,Ragas适合RAG场景专项评估。工具不必贪多,一两个能解决问题就够了。真正重要的不是工具本身,而是你有没有把测试集、指标、断言逻辑沉淀下来,形成可复用的资产。
4.3 什么时候值得自研一套测试基座
开源工具用顺手之后,会有一种“不够用”的感觉,比如:测试数据不能出内网、指标需要完全定制、要和内部发布系统深度打通、需要把评估结果同步到内部看板。这个阶段就可以考虑自研,但我不建议一上来就搞平台,先做成命令行脚本就够了。
自研测试基座的最小闭环,我拆成四个组件。数据集管理负责读取测试集文件、按场景分层、支持样本回流。批处理执行器负责任务调度:读取提示词版本、调用模型、采集输出。评估器负责跑各种断言和指标,包括规则断言、schema校验、LLM裁判。报告器负责输出对比表、走势图、变更结论,能对接消息通知。这四个组件串起来,本质就是promptfoo做的事情,只是换成了你完全可控的代码。
值得提醒的是,工具这部分最大的坑是“过早自研”。我见过有团队还没建立测试集,就花三周时间自研评估平台,最后平台建好了,发现没有数据可跑。自研的前提是流程已经跑通、数据已经沉淀,工具只是把流程自动化。如果还在摸索阶段,先用开源工具把跑起来再说,自研永远是最后一步,不是第一步。
5. 完整测试流程从零到上线落地
工具和指标都清楚了,接下来是整套流程怎么从零落地。我走过几轮从零搭建的流程,这里给出一套可以照抄的六步法。
5.1 六步搭好提示系统测试基线
第一步,收集历史问题样本。 把线上反馈、客服工单、badcase日志都翻出来,整理出过去踩过的坑:哪些输入导致输出异常、哪些场景用户表达强烈不满、哪些格式问题造成过系统错误。这是测试集的种子,价值远超拍脑袋构造的用例。
第二步,构建种子测试集。 按照前面说的比例,从生产日志采样一部分真实输入,加上构造的边界样本和部分合成变体,先建一批100到200条的小测试集。这个数量不用太大,关键是覆盖度要够:每个业务场景至少20条,每条要带预期属性和来源标记。
第三步,定义指标和初始阈值。 先搭好客观指标清单,再选两三个主观指标作为核心质量门禁。阈值怎么定?我的做法是先在当前生产提示词上跑一轮,收集数据,取平均值再加减一个容忍区间。比如回答相关性基线是0.85,那就设0.8作为门禁,比基线低就必须人工确认。阈值不要拍脑袋写死在配置里,后面要按实际变化持续校准。
第四步,跑基准并记录。 用当前生产环境的提示词跑一遍测试集,把结果记录成基线文件,纳入版本管理。这一步相当于给当前系统拍了张体检照,以后所有改动都跟这张照片对比。
第五步,写自动化脚本并接入CI。 把测试执行脚本固化下来,接入CI的指定分支或PR流程。建议拆成两个档位:PR阶段跑一个50条左右的快测集,控制在几分钟内;合并后跑全量回归集,通常在几百条规模。快测集挡明显问题,全量回归集兜底。
第六步,上线后持续监控采样。 线上系统跑起来之后,对真实流量做低比例采样,比如3%到5%,异步进入离线评估队列,每天产出一份质量报告。监控不是为了回测,而是为了发现测试集没覆盖到的漂移。
这六步走完,提示系统才算真正进入了可管理的轨道。后面每一次提示词优化,都会自然变成一个标准流程:改提示词、跑测试集、对比基线、通过了就上,不通过就继续调。
5.2 配置化测试用例长什么样
测试用例一定要配置化,不要写在业务代码里硬编码。配置化的好处前面提到过:可版本管理、可审计、可回放。我用promptfoo风格的YAML写个更完整的实际示例,大致是这样:
yaml复制prompts:
- file://prompts/support_agent_v3.txt
providers:
- id: chat:your-model
config:
temperature: 0.2
max_tokens: 400
tests:
- vars:
user_query: "订单一直不发货,怎么办?"
assert:
- type: is-json
- type: json-schema
value: |
{
"type": "object",
"properties": {
"reply": {"type": "string"},
"need_refund_path": {"type": "boolean"}
},
"required": ["reply"]
}
- type: contains-any
values: ["退款", "取消订单", "联系人工"]
- type: llm-rubric
value: "内容必须针对收货时间问题,不能泛泛而谈,必须包含能执行的下一步"
- vars:
user_query: "你就是个傻X,我要投诉你"
assert:
- type: not-contains
value: "对不起"
- type: llm-rubric
value: "面对发泄型用户,不能道歉过度,也不能冷漠,要保持稳定和克制"
这个配置里能看出几个设计思路。第一条用例用json-schema验证结构,contains-any验证关键信息,llm-rubric验证语义层面的质量。第二条用例针对对抗性输入,用not-contains挡掉“无脑道歉”这种典型错误,再用llm-rubric卡语气。断言类型可以组合,同一条用例能用多条规则从不同角度约束输出。测试配置就像提示词本身的“说明书”,每次改提示词时同步改配置,下一次跑测试才有意义。
5.3 接进CI/CD与上线后监控
流程落地的关键是CI/CD集成和监控告警。CI/CD这块,我强烈建议在PR阶段做“快测集+非阻塞提示”。也就是说,快测集跑出问题先给开发者提示,但不强制阻断合并,等全量回归集跑完再决定阻断还是不阻断。原因很实际:模型输出非确定性高,单次跑失败不一定是真失败,如果PR阶段就硬性阻断,团队会被频繁误报搞到麻木,后面真的出问题反而不敏感了。
阈值策略我推荐“连续两次失败才算失败”。理由很简单,大模型输出有不稳定性,一条用例跑一次失败,重跑一次可能就过了。连续两次失败再判定失败,误报率能降一个量级。我自己实测下来,单次断言误报率大约在3%到5%左右,用二次连续失败判断后几乎可以忽略。
上线后监控这块,除了前面说的采样评估,还要建三项指标看板:质量分趋势、Token成本趋势、延迟分位数趋势。质量分下滑要告警,成本突增要告警,延迟超标要告警。另外我特别提醒一个场景:模型版本升级或供应商切换。这种变更不是提示词变更,但对提示系统的影响是全方位的,必须提前在测试集上跑一轮兼容性验证,再用小流量灰度方式上线。我见过有团队直接把模型换了一个新版本,没跑回归,结果整套输出的格式和语气全变,线上出了问题才意识到。
6. 高频问题排查与避坑手册
最后这部分,我把平时被问到最多的几个问题整理成速查表,再展开说几条独家的排查心得。
6.1 测试结果不稳定怎么办
测试本身不稳定,是刚搭建测试体系时最让人头大的问题。主要表现是:同一份提示词,同一套测试集,昨天跑全过,今天跑挂一片。这个现象有两个根因:一是模型输出的非确定性,二是测试环境的不稳定。
排查顺序我建议这样来:先检查测试环境变量,比如温度参数是否被改、模型是否被路由到不同实例;再检查用例本身,有的用例设计得太严苛,比如要求contains某个词但模型用了近义表达;最后才是接受“非确定性不可消除”这个现实,改用统计策略。统计策略的意思是,一条用例跑5次,4次以上通过才算通过;或者一个维度的指标取多次结果的平均分。这样做的代价是测试成本上升,但稳定性换来了,值得。
6.2 LLM裁判与人工不一致怎么办
裁判结论和人工结论不一致,本质上说明评估标准还没统一。我一般按这个流程处理:先出分歧报告,把“LLM打高分但人工打低分”和“LLM打低分但人工打高分”的样本分别列出来;然后看分歧模式。如果分歧集中在某个场景,说明这个场景的主观标准没定义清楚,需要细化评分量表;如果分歧是全面性的,说明裁判模型本身不合适,换一个试试。
这里还有一个技巧:给LLM裁判用的评分提示词,本身也需要版本管理。我们曾经调整过裁判提示词,结果整体打分偏好变了,基线全得重跑。建议把裁判提示词当成代码来对待,改动了必须回归验证一致性。
6.3 测试成本失控和模型升级引发的集体翻车
测试成本问题是跑全量回归时常碰到的痛点。500条测试集,每条跑2到5次,还要加上裁判模型,一个月跑下来token费用不低。我的解决办法是分层测试:冒烟集50条,每次PR都跑;回归集200到300条,合并后跑;周期评估集1000到2000条,每隔一段时间跑一次。成本敏感时期,CI里还可以对回归集做随机子采样,比如每次随机抽70%,两周内覆盖完全集。
模型升级引发的集体翻车,可以说是我最不想处理但最常遇到的问题。换版本后测试集一片飘红,这时候第一件事不是改提示词,而是确认“是不是所有失败指向同一个原因”。常见原因有三种:模型输出格式风格改变、模型能力变化导致回答风格漂移、裁判模型打分标准在换版本后不通用。定位到原因后再决定是调提示词、调测试阈值、还是换裁判模型。我最后的建议是:把模型版本也纳入基线管理,每次换版本都记录一份独立基线,不要拿旧版模型的测试结果直接对比新版,否则会产生大量伪回归。
| 高频问题 | 核心原因 | 排查与解法 |
|---|---|---|
| 测试结果忽好忽坏 | 模型非确定性、环境参数变化 | 多次采样取聚合、连续两次判定 |
| LLM裁判与人工不一致 | 评分标准未统一、裁判模型偏差 | 出分歧报告、细化量表、换裁判 |
| 测试成本飙升 | 用例量级过大、重复执行太多 | 分层测试、随机子采样、缓存答案 |
| 模型升级后全挂 | 输出风格漂移、阈值不匹配 | 独立基线、小流量灰度、重校准阈值 |
| 对抗输入覆盖不足 | 测试集缺少攻击样本 | 攻击库定期补充、生产恶意样本回流 |
再补一条我的实际体会:提示系统测试体系的建设,本质是在跟“不确定性”对抗。你不可能让模型完全确定,但你可以让你对它的判断非常确定。早期多花时间在数据集和基线上,后期每一条提示词优化都能用数据说话,这比我见过的大多数“手感优化”要靠谱得多。
最后分享一个我自己一直坚持的小技巧:把最近一次线上事故的复盘样本永远保留在测试集里,哪怕问题已经解决。这些事故样本是测试体系里最宝贵的资产,它们代表的是系统真正破裂过的时刻。每次新提示词或者新模型版本上线之前,先看看这些样本有没有通过,通过的版本才能谈下一步优化。这套体系做得越久,你会越清楚它保住的并不只是某个提示词版本的质量,而是整个团队对AI系统可靠性的信心。
