
上个月我们负责的内部知识问答系统走完了最后一轮测试项目组在验收单上签了字。但我清楚所谓测试收官只是把可以穷举的部分全部穷举完了剩下那些测不完、说不清、偶尔还翻车的部分才刚刚进入长期观察期。如果你用传统软件测试的思路来测一个基于大语言模型的AI系统头两周你会觉得这不就是接口测试加了一点规则吗第三周心态就会崩——同一个问题上午和下午的回答不一样加了一个偏移词整个回答的立场就变了线上跑了三千条用例全过用户随口一句你女朋友呢就能把系统带进沟里。这篇文章就把我们这一趟AI测试的完整旅程写下来怎么重新定义测试对象怎么设计五层验证体系踩了哪些让团队集体沉默的坑以及最后凭什么判断可以结束了。如果你是第一次负责AI系统的测试或者已经在AI测试里被badcase折磨得怀疑人生这篇应该能给你一些可以直接用的东西。1. 当被测对象从确定性代码变成概率性行为1.1 传统测试的第一性假设为什么崩塌传统软件测试的核心假设是给定同样的输入经过同样的逻辑必然产生同样的输出。基于这个假设我们才能谈通过/失败、谈回归、谈自动化。但基于大模型的AI系统不是这样模型推理时的采样过程本身带随机性同样的输入在不同时间、不同采样参数下可能给出不同回答。我印象最深的一次争论是项目组质疑我们你们是不是没等模型加载完就跑了为什么同一个问题两次结果不一样我只能打开日志把两次输出的token分布、采样seed、温度参数摆出来。这不是测试执行的问题而是被测对象的属性变了——从确定性逻辑变成了分布性行为。你没法用断言一个精确字符串的方式去验证一个概率模型就像你不能要求一个真人每次都用一模一样的措辞回答你。这个认识是后面所有工作的起点。我们跟研发达成了一个共识AI测试的本质不是检验一次结果是否正确而是评估大量样本下行为的整体可信度。传统测试追求的是零缺陷AI测试追求的是缺陷在可控范围内且可被持续观测。1.2 测试模型的重构从判对错到量偏差既然输出是概率性的那测试就不能只回答对不对而应该回答偏不偏偏了多少能不能接受。我们做了一件事把原先的测试用例分类从功能点改成行为维度。具体拆成了五类语义一致性用户意图是否被正确理解、观点立场一致性回答是否越界、偏航、被带偏、内容安全合规是否触碰禁区、任务成功率是否能完成知识查询、信息抽取等具体任务、极端输入容忍度乱序、错别字、恶意引导时是否崩溃。每个维度都定义了可量化的观测指标而不是笼统地说回答质量差。比如任务成功率我们定义成给定一百个标准知识检索请求系统能在规定时间内返回且答案与知识库原文的语义相似度超过阈值的比例。极端输入容忍度则用一组包含错别字、口语噪音、中英混排的对抗样本来评估看系统答非所问的比例是否超过5%。这些指标虽然不完美但至少让团队有了一把共同的尺子。1.3 用例设计方式的变化原来写用例是输入 → 期望输出 → 断言现在写用例是输入 → 基准回答 → 容忍区间 → 多轮采样。比如同一个用户问题我们会让系统回答5次统计语义相似度分布低于某个阈值才标记为异常。这个问题听起来简单实际上一开始我们的脚本写得很粗糙循环调用接口五次然后直接比对字符串结果误报率高得吓人。后来我们把多轮采样设计成三个层级同一参数下采样、不同温度参数下采样、不同prompt模板下采样。只有同一参数下结果出现显著漂移才判定是模型不稳定不同参数下的差异属于预期行为只做记录不做判断。这个区分帮我们省掉了大量无效排查。2. 五层验证体系把AI系统拆成看得见的地方2.1 输入解析层考验的是鲁棒性不是正确性整个系统不是一个裸模型直接对外提供服务它前面有意图识别、实体抽取、检索召回、规则拦截等一堆环节。我们按调用链路拆了五层每一层分别设计测试策略。第一层是输入解析层包括ASR文本转写如果有语音入口、错别字纠正、中英文混排处理等。这一层的测试重点不是解析得对不对而是面对各种畸形输入还能不能继续往下走。我们造了一批离谱的输入比如全角半角混用、emoji夹杂、连续多个标点、拼音和汉字混写观察系统是报错、乱答还是给出合理兜底。有一个很典型的badcase用户把帮我查一下明天的天气写成帮我查一下明天滴天气系统在前端纠错环节把滴正常识别为的但到了下游意图识别时却把整句判定为闲聊直接返回了一句俏皮话。你说它错了吧它确实识别出了意图说它对了吧任务完全没完成。这类问题的根子不在模型而在管道环节的置信度互传机制只有分层测试才能暴露出来。2.2 知识召回层向量检索返回的是候选不是答案第二层是知识召回层系统会先把用户问题转成向量在知识库做相似度检索再决定从哪几篇资料里提取答案。这里最容易踩的坑是把召回结果直接当成答案来断言。我们的做法是单独评估召回准确率和顶k命中率。也就是说故意构造一批只与知识库某一条记录语义相关、但措辞完全不同的提问看系统能否从海量文档里捞出正确的那篇。这一层不需要看最终回答是否漂亮只看候选列表里有没有正确答案。有一次我们查一个为什么我的申请被驳回的问题系统捞回来的文档全是关于驳回申诉流程的跟用户想要的驳回原因分类完全不沾边最后生成阶段再努力也答不到点上。这种问题在端到端测试里很难定位但在分层测试里一目了然。2.3 生成策略层温度参数不是随便调着玩的第三层是生成策略层也就是把召回结果和用户问题组装成最终回复的那一步。这一层的变量最多因为prompt模板、温度参数、最大token数、停止词都会影响输出形态。我们专门做了一组参数敏感性测试固定所有输入只调温度参数从0.1到0.9观察输出的语义漂移程度。结果发现温度超过0.7之后回答开始出现大量口语化填充词虽然读起来更自然但知识性内容开始漏温度低于0.2回答又变得极其机械甚至出现复读机现象。最后我们把业务场景做了拆分——知识问答类强制用低温闲聊寒暄类可以适当提高温度。这个经验后来被写进了系统配置规范每个接入的业务线都按这个原则去调参。2.4 多轮对话状态层上下文记忆的过期与串味第四层是多轮对话状态层也是最容易出隐蔽问题的地方。系统需要记住用户前几轮说了什么才能给出连贯回答。但与人类对话一样记忆是有期限和边界的。我们发现两个典型故障模式。一是上下文过期用户在第3轮修正了需求系统到第5轮还在按老需求回答因为对话状态管理器没有正确更新槽位。二是上下文串味两段完全不相干的对话被粘在同一个session里模型把前一段话题的信息错误地引用到后一段。比如用户先问推荐几部科幻电影又突然问明天有什么会议安排系统会把电影名当成会议议题来回答。这类问题用单轮接口测试永远发现不了必须设计一系列多轮场景而且要在中间故意变更用户意图验证系统能否遗忘掉已经过时的信息。2.5 业务规则层对齐约束是否真实生效第五层是业务规则层包括内容安全拦截、敏感话题回避、品牌黑话管理等规则。这一层测试起来有点像传统的规则引擎测试但难点在于规则与模型的优先级。我们遇到过一种情况安全规则库明明拦截了包含某个敏感词的问题但模型在回答时还是顺着语境输出了一段擦边内容。原因是安全模块只做了关键词匹配而模型生成阶段没有接入相同的约束。后来我们调整了验证策略不再只看规则有没有生效而是看规则在每一条生成结果里是否都生效。做法是把安全规则做成了生成阶段的post-check和pre-check双重校验测试也分两步走先验证入口拦截再验证生成结果端的合规性。这五层不是割裂的一个端到端问题往往同时在两层里都有影子。但把它们拆开之后至少每次出问题我们都能快速定位而不是对着一个黑盒瞎猜。3. 那些让测试团队集体沉默的AI异常现场3.1 同一条问题上午测通过、下午测翻车我要说一件让团队集体沉默的事。我们有一组核心回归用例在早上跑全绿下午发布新版本后跑了同样的用例居然有十几个直接失败。研发第一反应是新版本引入回归了赶紧回滚。但仔细看了日志之后发现失败的原因不是模型权重变了而是我们把测试环境的并发数提到二十之后部分请求走了不同的GPU节点节点的量化精度设置不一样导致输出分布发生偏移。这不是偶发个案。大模型服务通常部署在多节点集群上不同节点的推理引擎版本、量化方式、显存状态都可能不一样于是同一版本也会出现节点差异。从那以后我们把多节点一致性列入了回归项每次跑用例之前先记录请求落在哪个节点上如果结果异常先做节点维度聚类分析而不是武断地归因到模型更新。3.2 换个称呼就全盘失守的口令漂移我们的系统里设置了一个终止话题的功能用户说换个话题或者不聊这个了时系统应该礼貌地结束当前话题。测试用例里的换个话题、聊点别的都通过了结果上线当天就被打脸——用户说的是咱们换个话题吧这个没意思系统完全没识别出来还在继续输出上一个话题的内容。这就是典型的口令漂移同一个意图有无数种表达方式测试样本只覆盖了其中一小部分。我们后来做了一套语义等价扩写工具用大模型本身把每一条测试集中的口令类用例扩写成五十个不同说法再拿扩写后的集合去跑测试。实测下来召回率从原来的68%提到了89%但仍然没有到100%。这件事让我彻底明白了一个道理AI测试的样本覆盖率永远追不上真实世界的表达多样性能做的是不断用线上badcase回灌测试集把这个覆盖率的缺口越缩越小。3.3 一本正经胡说八道的置信度陷阱我们的系统会在回答后面附带一个置信度分数设计初衷是让用户自己判断结果可信不可信。测试时我们发现模型对某些冷门知识点的回答明明已经错到离谱了置信度居然还显示0.95。研发解释说这个置信度来自解码概率的归一化只能反映模型对生成内容的内在确定性不能反映事实正确性。这个发现非常要命。如果用户看到高置信度就自然信任了错误答案的传播影响会被放大。所以我们调整了产品交互不再展示一个孤立的数字而是把置信度拆成三个标志——是否有知识库依据、检索结果与问题的相关性、生成内容的语义连贯性。只有三项都满足才显示推荐采纳否则直接标注仅供参考请核查来源。这个改动本质上是用工程手段对抗模型的内在不确定性也是测试逼出来的产品改良。3.4 复现不了的问题要怎么记录AI测试最让人抓狂的是badcase不可复现。我们跨部门联合排查一个多轮对话异常业务方反馈用户遇到的僵硬回答我们拿着日志里的原始输入去复现结果连续三次都是正常回答直到第四十八次才终于出现一次预期内的错误。后来我们形成了一套现场快照的规范但凡发现异常行为第一时间抓取session ID、请求体、响应体、模型版本、参数配置、时间戳、节点编号并强制保存一个上下文切片——特别是多轮对话前几轮的完整记录。没有这些信息badcase基本等同于不存在。另外我们不再追求每次都能复现而是用在什么分布条件下出现概率更高来描述问题比如当轮次超过5轮且用户连续两次修改了槽位时出错率约12%。这种描述比偶发故障有价值得多研发也更容易定位到真正的根因。4. 测试终点的真实含义通了不等于用得住4.1 用三个硬指标定义可以收官项目上线前产品负责人连着问了三次到底测完没有。这个问题让我想了很久最后我们定下了三个硬指标全部满足才允许签署测试通过结论。第一个是场景覆盖率核心业务场景的用例覆盖率达到95%以上且这些用例由业务方、测试方、研发方三方共同评审确认。第二个是语义漂移容忍度在固定样本集上连续运行一周每日输出与基准版本的语义相似度波动不超过设定阈值这个阈值按业务场景不同而不同知识问答类控制在3%以内开放闲聊类控制在8%以内。第三个是badcase闭环率近两个迭代周期内发现的所有高优badcase必须全部有明确的处置结论要么修复验证通过要么确认在已知风险清单里并有对应降级方案。有意思的是这三个指标全部满足之后我反而觉得测试结束这个说法不准确。准确的说法是这一阶段的测试目标已经达成可以进入运维期的持续监控。所谓终点其实是一个阶段性的验收点不是一个可以一劳永逸的句号。4.2 灰度流量与线上哨兵策略测试通过了并不意味着就可以把所有监控都撤掉。我们的做法是让测试体系在线上以另一种形态继续活着对真实流量做抽样的自动标注、自动比对、自动告警。具体来说我们在线上搭建了一个哨兵通道对进到系统的请求按1%的比例做无侵入的副作用记录然后把模型输出发给一个独立的评测模型打标签标签维度包括回应相关性、安全性、任务完成度。一旦某类标签的异常率超过历史基线两倍就自动触发告警并把样本回灌到下个版本的测试集里。这套机制上线后帮我们抓到了好几个线下测不出来的问题其中最典型的是长尾用户问法导致的回答质量劣化——只有真实流量大了这些才会浮现。4.3 环境清理与长期观测机制的接管在宣布测试收官之前我们还做了一件很琐碎但必须做的事把测试环境与生产环境彻底隔离测试数据不再参与线上模型的任何训练或评测流程。听起来简单实际执行中很容易出差错因为团队的调试脚本偶尔还会指到旧环境。清完之后我们把长期观测责任正式交给了运维侧测试团队只保留每个迭代的波动提醒。线上监控面板上挂了三个核心指标用户反馈差评率、回答超时率、内容安全拦截率。这三个指标任何一个出现连续下跌值班人员就会拉一个临时测试专项。从那一刻开始项目的测试阶段才算真正画上句号。5. 走完这趟旅程后我想分享的五条实战经验5.1 测试数据集要当成产品来维护这是我这趟旅程最大的教训。最初测试集是开发临时攒的按各自理解随手丢进去几十条结果不同版本的测试结果之间没法对比——不是模型变好了而是样本被换掉了。后来我们专门建了一套测试集管理流程所有人提的新用例必须过评审每个用例标注业务来源、优先级、创建时间、最近一次有效时间。每个月做一次样本体检去掉过时或重复的用例补充新发现的badcase。只有把测试集当成一个独立的交付物测试结论才是可信的。5.2 badcase报告要带上下文切片初期的badcase描述都是用户问了一个关于A的问题系统回答了很多关于B的内容。研发拿到这种问题描述根本无法定位是意图识别错了、检索错了还是生成错了。后来我们统一了badcase报告模板必须包含四个部分原始输入的完整上下文特别是多轮历史、实际输出、期望行为说明、问题发生的链路层推断。人话说就是不仅要说发生了什么还要说是在哪一步开始错的。这个改变把badcase的处理效率提升了不止一倍。5.3 用大模型生成对抗样本是一把最锋利的矛研发最烦测试说这里可能有问题但我想不出来怎么构造这个输入。我们的解决方案是让测试人员和研发用大模型自己做语义等价扩写和对抗输入生成。把原生用例喂给模型让它改写成不同语气、不同句式、不同干扰程度的变体再人工筛选后加入测试集。这样做的好处非常明显人工设计用例时受思维定势影响写来写去都是正常问法模型生成的变体则能覆盖很多让人意想不到的表达。当然生成出来的样本一定要人工复核否则容易混进去本身标注错误的脏数据。5.4 人机协同回归比全自动回归更可靠我们一开始追求全自动回归脚本跑完直接出红绿报告。后来发现全自动脚本在AI测试里有一个致命缺陷它只能检查机器能定义的规则比如超时时间、关键词、长度上限而真正的语义质量它判断不了。于是我们把回归改成两段式第一段全自动跑出所有结果第二段由测试人员抽检10%到20%的样本做人工语义审核同时用评测模型给所有样本打预标签人工只复核评测模型标出的疑似异常。这套模式兼顾了速度和准确度也让人工从海量重复劳动里解放出来。5.5 AI测试工程师的核心能力是翻译最后一条经验可能有点务虚但我觉得是最重要的。做AI测试技术手段只占一半另一半是沟通能力。你要能把用户的模糊反馈翻译成测试工程师能执行的验证场景把测试发现的问题翻译成研发能定位的技术语言把测试风险翻译成产品能理解的业务语言。很多时候三方讨论陷入僵局不是问题本身多复杂而是各说各话。测试人员一旦能把这些翻译工作做好你会发现排查问题的效率能再上一个台阶。现在每当我被问到AI测试什么时候能结束我的回答依然不是测完就结束而是你需要在哪些指标上建立稳定信心在哪些风险上保留可监督的容忍空间。这些想清楚了终点自然就到了。