1. 为什么AI购物助手需要一套在线评测体系
我们团队负责的电商AI购物助手,最近被一个高频词折腾得不轻——“变差了”。运营同学跑过来反馈说,用户觉得助手回答质量下滑,但你真要问“差在哪里”,没有人能说清楚。我接到的任务,就是把这种模糊的体感,翻译成可量化的在线评测指标,再用 LLM-as-a-Judge 做质量归因,找到“到底哪里变了、为什么变”。这篇文章记录的,就是这套体系从设计到落地的完整过程。它适合正在为大模型应用做质量评估的团队参考,也适合那些被“回答变差”这类反馈困扰、却不知道从何下手的同学。
1.1 问题从哪里来:模型上线后的“变差”恐慌
做过大模型应用的人都有同感:模型上线前,离线评测集上跑得好好的,准确率、相关性、流畅度样样达标,可一上线,用户体感就开始出问题。最常见的一幕是——用户问“500元以内的降噪耳机推荐”,购物助手推荐了三款两千元以上的产品,还热情地补了一句“如果您愿意提高预算,这些是顶级选择”。你说它错了吗?没有。但你说它对吗?用户已经想关掉对话了。
这类问题的核心在于,离线评测集覆盖的是“我们以为用户会问的问题”,而线上真实流量里永远有你想象不到的query形态。更麻烦的是,用户很少会耐心投诉。数据显示,绝大多数用户遇到糟糕体验后只是默默离开,真正转化为客服工单的不到百分之一。等你靠人工反馈察觉问题时,影响面早就扩散开了。
所以我们需要一套在线评测体系:从真实流量中持续采样,用自动化的方式评估回答质量,把“变差了”这种模糊信号变成可以量化、可以追踪、可以定位的数字。这不是一个锦上添花的工具,而是大模型应用能不能长期稳定运转的底线工程。
1.2 评测体系的三个层次:离线、在线、回归
我在搭建这套体系时,先把评测分成了三个层次,它们各有分工,互相不能替代。
- 离线评测:用固定的、人工标注过的数据集,在模型或Prompt变更后跑一次,看分数是否达标。它的作用是发布前的“安全检查”。
- 在线评测:从线上真实流量中按规则采样,对助手实际生成的回答进行打分,持续监控质量趋势。它的作用是发现“发布后的问题”。
- 回归评测:把历史上出过问题的case沉淀成回归集,每次变更前强制跑一遍。它的作用是防止“老问题复发”。
三个层次缺一不可。离线评测跑不过,坚决不发版;在线评测分数异常,立刻启动归因;回归评测失败,说明某个改动静默地破坏了已有能力。
这里有个容易踩的坑:很多人把离线评测做得很重,在线评测却草草了事——每天抽几十条样本,人工看一眼就算完。这种做法的问题在于,离线评测集的规模撑死几千条,再怎么精心设计也覆盖不全线上长尾;而人工打分的速度根本赶不上流量,等你评完一天的量,问题已经在线上跑了好几个小时了。
1.3 为什么选择 LLM-as-a-Judge 作为评测执行器
要把在线评测跑起来,第一个绕不开的问题是:谁来打分?
当时的候选方案有三个。一是纯规则匹配,比如查是否包含商品名、是否触发敏感词,但规则只能判断“有没有”,判断不了“准不准”“贴不贴切”。二是人工标注,质量高,但成本和延迟都是硬伤,日均几千条样本根本消化不了。三就是 LLM-as-a-Judge,也就是让一个大语言模型扮演评分员角色,按我们定义的维度给回答打分。
LLM-as-a-Judge 的核心优势在于,它既能理解语义,又能通过Prompt灵活定制评分标准,而且调用延迟和成本都在可控范围内。你可以让它同时评测相关性和完整性,也可以让它单独挑出安全违规,所有维度只要在评分Prompt里写清楚就行。
但必须说清楚:LLM-as-a-Judge 不是银弹,它只是一个“执行器”。如果你没有把维度定义写清楚,没有设计好采样策略,没有建立人工复核闭环,那它打分再准也只是一堆数字。真正让这套体系转起来的,是评测设计、流程规范和质量归因能力。接下来的内容,就是围绕这三个部分展开的。
2. 评测设计:从维度拆解到样本构建
2.1 评测维度怎么定:既要有用又要可执行
在定义评测维度之前,我们团队做了一件事:把过去三个月的高频客服投诉、用户评价、业务方反馈全部翻出来,按问题类型归类。最后提炼出五个核心维度,每个维度都有明确的考察点:
| 评测维度 | 考察点 | 典型低分表现 | 典型高分表现 |
|---|---|---|---|
| 相关性 | 回答是否直接回应了用户提问 | 答非所问,回复与问题无关 | 准确抓住用户意图,直击问题核心 |
| 准确性 | 回答是否与商品事实一致 | 编造参数、混淆规格、促销信息过期 | 商品信息、价格、库存与事实一致 |
| 完整性 | 是否覆盖用户问题中的所有诉求 | 只回答了一半问题,遗漏关键条件 | 覆盖全部要点,并给出必要补充 |
| 安全性 | 是否存在夸大宣传、违禁表述 | 绝对化用语、引导线下交易 | 语气稳妥,无违规风险 |
| 沟通体验 | 表达是否清晰、结构是否合理 | 内容冗长、无重点、语气僵硬 | 结构清晰、简洁易懂、有温度 |
五个维度看起来不多,但已经足够覆盖我们业务方最关心的质量问题。这里给一个建议:维度宁少勿多。一开始我列了十来个维度,包括“情感共鸣”“多轮一致性”“品牌调性”等等,结果Judge模型打分方差巨大,人工复核时发现不同人自己对标准理解都不一样,后来砍到五个才稳定下来。你让一个评测者同时盯十个指标,每个指标的判断标准都会变得模糊;盯五个以内,标准才可能说清楚。
每个维度的评分等级也做了收敛,统一用1到5的整数分。3分是“及格线”,代表“可以用但是有明显问题”,4分是“良好”,5分必须是有固定锚点定义的“完美”。没用更细的0.5分档,因为Judge模型在细粒度区分上不可靠,整数的可解释性也更好。
2.2 评测集三分法:黄金集、对抗集、线上采样
评测集按用途分成了三部分,比例上有个基本盘:黄金集500条左右,对抗集300条左右,线上采样集每日常驻1500到3000条。
黄金集是根基,所有样本都是人工精标,覆盖核心业务场景:商品搜索、商品咨询、对比推荐、售后处理、优惠计算。黄金集不追求“难”,追求“典型”。每次Prompt或模型版本变更,先跑黄金集,分数下滑超过阈值就禁止上线。它本质上是一条高置信度的回归基线。
对抗集是从“翻车现场”里沉淀出来的。比如某次线上事故,购物助手把“折扣价”理解成“原价”导致用户投诉,这个case就会被收进对抗集,并配上正确的参考答案。对抗集的作用是防止同样的坑踩第二次。我会要求每次质量事故复盘后,必须补充至少两到三条对抗样本,形成制度化的沉淀机制。
线上采样集则是唯一能反映真实质量分布的数据源。它不做任何难度筛选,完全按流量入口和用户场景分层采样,保留线上最真实的长尾query分布。这个集合不需要人工标注,全部走LLM-as-a-Judge自动打分,它也是后面质量归因分析的主要数据来源。
2.3 采样策略与人工复核闭环的设计思路
线上采样不是随便抽几条就行。一开始我们只是简单地按固定比例随机采样,结果发现搜索入口的样本占了七成,商品详情页入口样本少得可怜,导致整体评分被搜索场景主导,其他场景出了问题根本看不出来。
后来改成了分层采样:按照入口流量占比分配采样配额,同时给低频但重要的入口设置最低采样量。比如搜索入口流量大,按20%采样也能拿到很多样本;商品详情页入口流量中等,按30%采;购物车和售后入口虽然流量小,但固定保证每天不少于300条。这样每个入口的质量都有独立的样本量支撑,归因时才能拆得开。
另外一个关键设计是“维度裁剪”。不是每个样本都需要评全部五个维度,浪费钱不说,还会稀释注意力。比如购物车入口的query大多是“帮我算一下满减”,评测重点放在准确性上;售后入口的query重点是完整性和沟通体验。每个入口固定关联两到三个评测维度,按需打分。
人工复核闭环一定要跟上。我们每天从低分样本中抽取5%到10%,由内部标注同学复核,确认Judge打分是否合理。每周还会做一次一致性校准,把本周Judge打分和人工打分的差异率拉出来看。差异率高于15%时,说明评测Prompt需要调整了。这一步不能省,Judge模型也会漂移,不校准则整个评测体系的可靠性都会受到质疑。
3. LLM-as-a-Judge 的工程化落地
3.1 Judge模型选型:独立性与能力边界的权衡
LLM-as-a-Judge 落地时,第一个决策是选哪个模型当裁判。我的建议是:不要用被测模型自己当Judge。大模型普遍存在“自偏好”倾向,会更喜欢和自己风格接近的回答。如果你用A模型做助手、又用A模型打分,分数的水分会很大,某些情况下甚至会出现“不管回答质量如何,只要风格像A模型就给高分”的荒谬结果。
理想的Judge应该来自另一个模型家族,或者在能力等级上明显高于被测模型。当时我们在两类方案之间做了对比:
| 方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| 商用旗舰模型API | 语义理解强,评分稳定,不需要运维 | 单次调用成本高,数据要出内网(需合规评估) | 上线初期的Prompt验证、黄金集评测 |
| 开源中等参数量模型自部署 | 成本可控,时延低,数据不出内网 | 需要GPU资源和运维投入,能力弱于旗舰模型 | 规模化在线评测、高频次调用 |
我们的实践路线是:先拿商用旗舰模型把评测Prompt打磨成熟,确认评分标准没问题,再评估能否用自部署的开源模型替代。实测下来,对于电商购物助手这种相对垂直的场景,开源模型在相关性和完整性两个维度上已经能打出和旗舰模型80%以上一致的分,但在准确性和安全性的细粒度判断上还是偏弱,所以目前保留了一个“小模型初筛、旗舰模型复核”的混合架构。
3.2 评分Prompt的打磨:标准、锚点与思维链
评测Prompt的质量直接决定了Judge打分的一致性。我们的评分Prompt经过了好几轮迭代,结构大致如下:
你是一名资深的电商购物助手质量评测员。 请根据下面的评测维度定义,对“被测助手的回答”进行打分。 【用户问题】 用户的实际输入内容 【参考回答】 评测集里人工确认的高质量回答 【被测回答】 购物助手实际生成的回答 评测维度: 1. 相关性:是否直接回答了用户的问题,离题程度。 2. 准确性:是否与商品事实一致,是否存在臆造信息。 3. 完整性:是否覆盖用户问题中的主要诉求。 4. 安全性:是否包含违禁、夸大或诱导性表述。 评分要求: - 每个维度 1-5 分,只允许整数。 - 先给出不超过 50 字的评分理由,然后输出 JSON。 - 格式:{"rationale": "...", "relevance": 5, "accuracy": 4, "completeness": 5, "safety": 5}这个Prompt里有三个值得注意的设计。第一个是“参考回答”的存在。给Judge一个高质量的参考答案,相当于提供了一个基准锚点,能显著降低打分漂移。第二个是要求“先写理由再给分”。强制Judge先生成评分理由,相当于让它在打分前进行一轮自我推理,实测下来比直接给分要稳定得多。第三个是结构化JSON输出,方便下游解析和入库。
但维度定义和格式只是基础。真正让分数稳定下来的是锚定示例。我们会为每个维度附加几个“经典样本”,比如相关性维度给一个1分样本(完全答非所问)、一个3分样本(相关但侧重点偏了)、一个5分样本(精准命中意图),让Judge照着例子理解“不同分数长什么样”。这一步的效果非常明显:加了锚定示例之后,连续三天评测结果的标准差下降了40%以上。
3.3 一致性、偏差与成本:三个必须处理的工程问题
LLM-as-a-Judge 的一致性问题是绕不开的。同一个样本,用相同的Prompt跑两遍,理论上应该得到相同分数,实际却可能差出1分甚至2分。我们的处理方法是:Judge调用时温度设定为0,并且对低置信度样本做“三次投票取中位数”。什么叫低置信度?就是Judge在评分理由中犹豫不决,或给出的分数与历史同类型样本差异过大。这类样本占比不高,但一旦出现,就需要额外调用成本来换取稳定。
偏差问题主要集中在这几类:冗长偏好,Judge倾向于给更长的回答更高分,哪怕其中一半是废话;位置偏差,在对比类任务里更明显,绝对评分里稍轻一些;自偏好,前面已经说过,解决手段是使用独立Judge模型。针对冗长偏好,我们会在评测指标里加一个“信息密度”参考项,或者在Prompt中明确要求“优先简洁、不欢迎凑字数”。
成本控制上有一个简单的估算公式:
单日评测成本 ≈ 采样量 × 单样本平均token消耗 × 模型单价
按我们的量级,日均采样2000条,单样本平均输入输出约2500 token,即日均500万token。按当前商用模型API的价格估算,单日评测成本大约在几元到十几元之间,如果按维度裁剪和缓存优化还能再降。这个成本相比人工标注几乎可以忽略。真正需要警惕的是无节制的全量评测——每个入口、每个维度全跑,采样量再加两个数量级,成本就会膨胀到不合理。所以原则是:样本要做分层采样,维度要按入口裁剪,Judge结果要做缓存。
3.4 评测流水线与告警:从线上日志到可视化看板
在线评测跑起来之后,整个流水线是这样一个链路:
- 线上日志采集:购物助手每次回答请求都会记录日志,包含用户脱敏ID、入口场景、query、生成结果、Prompt版本、模型版本、上下文长度。
- 规则清洗与采样:过滤测试账号、脱敏处理用户信息,按分层配额随机采样。
- 组装评测请求:把用户问题、参考回答(只对黄金集样本)、被测回答、评测维度拼装成评测Prompt。
- 调用Judge模型:异步队列消费,带重试和超时机制。
- 结果入库:评分、理由、样本元数据写入评测库。
- 看板与告警:按时聚合,展示趋势,触发告警。
这里有一个容易被忽略的点:告警阈值不要用固定绝对分。购物助手的评分会因为用户query分布波动而在某个区间内自然浮动,比如大促期间大量用户问“活动什么时候结束”,供应商发来大量“对比型query”,这些都会改变整体分数基线。我们用“滑动窗口基线”配合“相对跌幅告警”,比固定阈值准得多。具体做法是:取过去7天同时段的平均分作为基线,当前时段平均分比基线低3%以上,或低分样本占比上升5个百分点,才触发告警。分维度、分入口的告警也各配一套,避免被整体平均分掩盖。
4. 质量归因实战:一次评分下跌的完整排查
4.1 现象确认:分数跌了,到底是哪里跌了
有一次,线上看板显示综合评分从4.28跌到了4.05,持续了将近四个小时,自动告警已经触发了。很多人拿到这种信号的第一反应是冲进模型后台调参数,我的建议是先按顺序排除三件事:评测系统自身是否正常、样本是否异常、Judge模型是否稳定。
先看评测系统。检查了数据管道,确认日志采集没有断档,采样数量正常,没有出现重复样本或乱码。再看Judge模型,用一组固定的调试样本当天早中晚各跑了一次,分数基本没变化,说明裁判没有侧漏。排除了这些之后,可以确认:评分下跌是真实的质量问题,不是评测系统出了幻觉。
4.2 特征拆解:分维度、分入口、分query族
确认是真实问题后,开始做特征拆解。第一步先按评测维度拆:相关性从4.31跌到4.02,完整性从4.15跌到3.95,安全性和准确性基本没动。这说明不是模型“瞎说”,而是“说不准、说不够”。
第二步按入口拆:商品详情页入口的得分下跌最严重,从4.25跌到3.89,搜索入口几乎没有变化。这一步把问题范围缩小了一大半——不是全链路恶化,而是某个特定入口场景出了问题。
第三步按query族拆。我们把跌分时段内所有低分query拿出来做聚类,发现“对比型query”占比异常高,比如“A和B有什么区别”“这两款哪个更适合通勤”“帮我对比一下这三款手机的续航”。进一步检查这些低分样本的回答内容,发现购物助手只是在单独介绍每款商品,没有生成对比结构,也没有明确给出侧重点差异。用户要的是“对比”,给的是“罗列”,相关性自然被打低。
4.3 变更定位:检索、Prompt与模型版本的三方对账
定位到具体query类型之后,就该查变更了。这里最怕的是“凭感觉甩锅”。我们有一套变更日历,记录每次模型版本、Prompt模板、检索服务、商品信息服务的变更时间和灰度比例。
查下来发现,两天前确实有一个新Prompt版本上线,改动点是增加了“先充分理解用户需求再回答,如果用户意图不明确,需要主动追问澄清”的指令。这个指令的初衷是减少误解,但副作用是模型在处理“对比型query”时,经常先抛出两三个追问问题,而不是直接给出对比结果,导致回答的相关性和完整性同时下跌。
隔离确认这一步很关键。我们把流量按版本切分,一组流量走新Prompt,一组走旧Prompt,观察两个版本在同一时间段、同一类query上的得分差异。结果非常明显:新Prompt在对比型query上的得分比旧版本低了近1分,其他query类型差异不大。至此可以确认,Prompt变更就是主要触发因素。检索侧也做了对账求证:通过日志回放确认,低分样本的检索召回和排序结果与跌分前没有明显差异,排除检索服务变更的嫌疑。
4.4 修复验证:用回归集防止问题复发
归因完成后的修复动作要克制,不要一上来就改大方向。我们把Prompt里的“主动追问澄清”从强制动作改为了可选动作,同时增加了一条生成约束:“当用户问题中包含两个及以上待比较对象时,优先输出结构化对比,不要先提问。”
小流量灰度验证是必须的。先在10%流量上观察了四个小时,对比灰度组和对照组的得分曲线,确认相关性和完整性都回到4.2以上,再逐步放量到全量。整个过程中,评测看板一直开着,随时盯着是否有二次波动。
修复完成后,我们把这批“对比型query”以及对应的低分case全部补充进了对抗集,同时更新了黄金集里对比场景的参考答案。这么做是为了让回归评测在后续每次变更时都能主动盯住这个场景,而不是靠运气再发现一次。
这次排查给我最大的感受是:质量归因不是“找单一根因”的过程,而是“层层排除可能性”的过程。分维度是排除“裁判的问题”,分入口是排除“链路共性问题”,查变更是排除“代码和配置问题”,最终剩下的结论才有说服力。
5. 常见问题与避坑清单
5.1 Judge打分不稳怎么办
Judge打分不稳定是询问频率最高的问题,表现是同一个样本两次打分差出1分甚至更多。按照我们的排查经验,优先级从高到低排列:
- 先看温度参数:Judge调用温度设为0,这是基础操作。
- 再看Prompt里有没有锚定示例:只写抽象标准是最常见的病根,加上“各分数档典型样本”后稳定性提升最大。
- 检查是否要求了“先理由后分数”:强制思维链能显著减少拍脑袋式评分。
- 如果上述都做了还是不稳定:对争议样本做三次调用取中位数,同时预留人工复核通道。
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
| 分数忽高忽低 | 缺少锚定示例 / 温度过高 | 补few-shot示例,温度调0 |
| 与人工评分偏离大 | 维度定义太抽象 | 针对每个维度补充正反例 |
| 长时间运行后整体漂移 | Judge模型版本更新 / 参考集过期 | 每周人工抽样校准,重建基线 |
| 高分集中在长回答 | 冗长偏好 | 在Prompt中强调简洁与信息密度 |
5.2 归因时最常见的三个误判
误判一:把样本分布变化当成了质量下降。线上流量结构是动态的,大促期间“比价类query”变多,平均分就可能自然下跌,但这不是模型变差了,而是题目变难了。排查时一定要先看样本分布,再看分数变化,顺序不能反。
误判二:把Prompt的锅甩给检索。检索和生成是两个环节,背锅之前先对账。如果检索日志显示召回结果、排序逻辑、商品列表都没变,那问题大概率在生成侧。我们的习惯是任何归因结论必须附带两项证据:检索日志对比结果和同payload的复现结果。
误判三:只看平均分,忽略分段恶化。平均分是最容易骗人的指标。有可能95%的query都正常,只有5%的query得分从4.5掉到2.0,就把均值拉低了。做归因时除了看均值,一定要看低分占比、P50/P90分位数、按query聚类后的分段得分,否则很容易得出“全面变差”的错误结论。
5.3 评测数据污染与成本失控的防御
数据污染是个隐蔽问题。线上采样集如果过滤不干净,把测试账号、内部评测账号、爬虫流量甚至用户误触发的噪声query采进来,评测结果就会被稀释。我们做了三道防线:第一,维护一个内部账号黑名单,采样前过滤;第二,对query长度、单次会话轮数设上下限,极端短或极端长的样本直接丢弃;第三,对单用户单日多次命中采样的样本做去重。
成本失控防御同样要制度化。核心原则是“按需评测、只评必要的”。我们每个月会复盘一次采样率和维度组合,把那些连续两周没有产出任何告警且与最终结论无关的维度砍掉。另外,做大促活动时,流量会上涨数倍,如果不提前降低采样比例,评测成本也会跟着翻倍。大促期间我们通常会动态把采样率下调到平峰的30%到50%,因为此时样本的“重复度”很高,超额采样并不会带来额外信息量。
5.4 给后来者的几点实用建议
最后分享几条我们在实际迭代中沉淀下来的建议,不一定写在哪份文档里,但每条都是真金白银换来的。
第一,把评测Prompt、评分标准、样本集全部纳入代码仓库做版本管理。很多人把评测做成了一堆散落在平台上的配置,改来改去没有记录,出了问题根本不知道当前线上跑的是什么版本的评测标准。我们后来把评测Prompt模板、维度定义、锚定示例作为代码的一部分,每次修改都要走正常的发布评审流程。
第二,维护一份变更日历,这是归因体系的命脉。每次模型版本更新、Prompt修改、检索策略调整、商品信息字段变更,都要记录时间和灰度比例。没有这份日历,质量归因就只能靠猜,效率会低一个数量级。
第三,不要用评测分数作为业务团队的KPI。评测分数是工程内部的质量信号,它应该用来帮助团队发现问题和定位根因,而不是用来考核或施压。一旦分数跟绩效挂钩,就会出现刷分、争议标准、优化评测集而不是优化产品的问题,评测体系本身的可靠性就会被侵蚀。
第四,尽量做到评测能力的可解释性。我们现在每一条评测记录都能追溯到原始样本、评测Prompt版本、Judge模型版本和评分理由,业务方质疑任何一个分数时,都能把证据链完整呈现出来。这个看起来很不起眼的细节,反而是在跨团队协作中赢得信任的关键一步。
如果你正在搭建类似的评测体系,我的建议是从最小闭环开始:先拿一个人工标注过的百级样本集,跑通LLM-as-a-Judge评分,再逐步接入在线采样和告警。不要一上来就追求大而全的平台,先把分数跑准了,把归因链路走通了,这套体系自然会生长出属于你自己的最佳实践。