<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Eval-Driven Development on 文艺技术笔记</title>
        <link>https://wenyiblog.top/tags/eval-driven-development/</link>
        <description>Recent content in Eval-Driven Development on 文艺技术笔记</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>文艺技术笔记 | 软件工程师文艺</copyright>
        <lastBuildDate>Fri, 17 Jul 2026 12:00:00 +0800</lastBuildDate><atom:link href="https://wenyiblog.top/tags/eval-driven-development/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>LLM 应用的评估工程：从人工测评到 Eval-Driven Development 的方法论升级</title>
        <link>https://wenyiblog.top/2026/07/2026-07-17-llm-eval-driven-development/</link>
        <pubDate>Fri, 17 Jul 2026 12:00:00 +0800</pubDate>
        
        <guid>https://wenyiblog.top/2026/07/2026-07-17-llm-eval-driven-development/</guid>
        <description>&lt;h2 id=&#34;那个让所有人沉默的线上事故&#34;&gt;&lt;a href=&#34;#%e9%82%a3%e4%b8%aa%e8%ae%a9%e6%89%80%e6%9c%89%e4%ba%ba%e6%b2%89%e9%bb%98%e7%9a%84%e7%ba%bf%e4%b8%8a%e4%ba%8b%e6%95%85&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;那个让所有人沉默的线上事故
&lt;/h2&gt;&lt;p&gt;三个月前，我们团队的智能客服上线了。头一周数据好得离谱，满意度涨了12个点，平均响应时间从4分钟压到30秒，产品负责人在全员会上演示的时候，模型对答如流，什么刁钻问题都接得住。&lt;/p&gt;
&lt;p&gt;然后第八天出事了。一个用户用很口语化的方式问退款的事，模型非常自信地回复「您的订单不支持退款」，实际上那个订单明明在退款窗口期内。用户截图发到社交平台，两个小时转发破五千。&lt;/p&gt;
&lt;p&gt;说实话，那天晚上我们整个组都在翻日志，试图搞清楚模型为什么会给出这个答案。翻来翻去发现，prompt里有一句「超出退款期限的订单请明确告知用户不支持退款」，模型把「口语化的退款咨询」和「超期退款请求」搞混了。&lt;/p&gt;
&lt;p&gt;这种事情太常见了。你想想看，demo阶段你精心挑选的测试用例当然跑得漂亮，可真实用户的表达方式千奇百怪，光靠人肉测几十个case就想上线，跟闭着眼过马路没什么区别。&lt;/p&gt;
&lt;p&gt;这篇文章想聊的就是这个问题，怎么把LLM应用的评估从「凭感觉」升级到「有体系」。行业里有个说法叫 Eval-Driven Development，简称EDD，核心思路很简单，评估先行，所有迭代都围绕评估结果展开。&lt;/p&gt;
&lt;h2 id=&#34;传统测试为什么在大模型面前不好使了&#34;&gt;&lt;a href=&#34;#%e4%bc%a0%e7%bb%9f%e6%b5%8b%e8%af%95%e4%b8%ba%e4%bb%80%e4%b9%88%e5%9c%a8%e5%a4%a7%e6%a8%a1%e5%9e%8b%e9%9d%a2%e5%89%8d%e4%b8%8d%e5%a5%bd%e4%bd%bf%e4%ba%86&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;传统测试为什么在大模型面前不好使了
&lt;/h2&gt;&lt;p&gt;做了这么多年软件工程，我们对测试的理解基本是确定性的。给一个输入，期望一个输出，assert就完事了。单元测试、集成测试、端到端测试，整套体系建立在「行为可预测」这个前提上。&lt;/p&gt;
&lt;p&gt;LLM把这个前提掀了。&lt;/p&gt;
&lt;p&gt;同样的prompt，换个温度参数，输出就可能不一样。同一段指令，模型版本升级之后表现可能反而变差，业内叫regression。更麻烦的是，很多任务的「正确答案」根本不止一个。你让模型帮你写一封拒绝合作的邮件，十个人写出来十种风格，你怎么判断好坏？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;传统软件测试处理的是确定性映射，LLM评估处理的是概率性生成。这两件事的复杂度差了一个量级。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我见过不少团队的做法是，拉上三五个同事，每人看几十条模型输出，打个分取平均，然后就宣布「准确率85%可以上线」。说真的，这个方法的统计可靠性跟抛硬币差不多。样本量太小，评分标准因人而异，最关键的是，你根本不知道这几十条case能不能代表真实分布。&lt;/p&gt;
&lt;p&gt;传统测试还有一套基于规则的回归测试思路，写一堆if-else检查输出里有没有关键词、格式对不对、长度是否合规。这套东西能覆盖最表层的格式问题，但对语义层面的判断完全无能为力。模型说了一句语法完美但逻辑错误的话，规则检查根本抓不到。&lt;/p&gt;
&lt;h2 id=&#34;eval-driven-development到底在说什么&#34;&gt;&lt;a href=&#34;#eval-driven-development%e5%88%b0%e5%ba%95%e5%9c%a8%e8%af%b4%e4%bb%80%e4%b9%88&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;Eval-Driven Development到底在说什么
&lt;/h2&gt;&lt;p&gt;EDD这个概念其实不新，OpenAI和Anthropic的工程博客都提过类似思路。核心主张就一条，你得先知道「好」长什么样，才有可能让模型变「好」。&lt;/p&gt;
&lt;p&gt;听起来像废话对吧，但现实中大量团队的开发流程是这样的，先调prompt，调到自己觉得差不多了，找几个人看看，感觉还行就发布。整个过程中「好」的标准一直在每个人脑子里，从来没有被显式定义过。&lt;/p&gt;
&lt;p&gt;EDD要求你把评估标准写下来，变成可执行的代码。具体来说就是三件事。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;定义评估数据集，覆盖你关心的场景&lt;/li&gt;
&lt;li&gt;定义评估指标，说清楚什么叫好什么叫差&lt;/li&gt;
&lt;li&gt;定义通过门槛，低于什么分数不准发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这三件事做完之后，开发流程就变了。每次改prompt、换模型、调参数，跑一遍eval，分数涨了就是进步，跌了就是退步。不用猜，不用争论，看数字。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有个做搜索的朋友跟我说，他们团队自从引入EDD，产品迭代速度翻了三倍。以前每次改prompt都要拉一群人开会讨论效果，现在直接看eval分数，五分钟出结论。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;评估指标怎么分层&#34;&gt;&lt;a href=&#34;#%e8%af%84%e4%bc%b0%e6%8c%87%e6%a0%87%e6%80%8e%e4%b9%88%e5%88%86%e5%b1%82&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;评估指标怎么分层
&lt;/h2&gt;&lt;p&gt;这个问题我纠结过挺长时间。一开始想把所有指标混在一起搞一个综合分，后来发现根本行不通。不同类型的指标关注的层面不一样，混在一起反而什么都看不清。&lt;/p&gt;
&lt;p&gt;后来我摸索出一个三层模型，勉强够用了。&lt;/p&gt;
&lt;h3 id=&#34;系统层&#34;&gt;&lt;a href=&#34;#%e7%b3%bb%e7%bb%9f%e5%b1%82&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;系统层
&lt;/h3&gt;&lt;p&gt;这层关注的是基础能力，跟具体业务场景关系不大。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;指标&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;典型阈值&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;延迟P50/P99&lt;/td&gt;
					&lt;td&gt;从请求到首token的时间&lt;/td&gt;
					&lt;td&gt;P50&amp;lt;800ms, P99&amp;lt;3s&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;格式合规率&lt;/td&gt;
					&lt;td&gt;输出是否符合要求的JSON/Markdown格式&lt;/td&gt;
					&lt;td&gt;&amp;gt;99%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;拒答率&lt;/td&gt;
					&lt;td&gt;该回答的没回答、不该回答的乱回答&lt;/td&gt;
					&lt;td&gt;&amp;lt;2%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;安全违规率&lt;/td&gt;
					&lt;td&gt;涉及敏感内容的输出比例&lt;/td&gt;
					&lt;td&gt;&amp;lt;0.1%&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;系统层指标通常比较好量化，自动化程度也高。格式合规可以用正则或JSON parser检查，延迟直接读监控数据。&lt;/p&gt;
&lt;h3 id=&#34;任务层&#34;&gt;&lt;a href=&#34;#%e4%bb%bb%e5%8a%a1%e5%b1%82&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;任务层
&lt;/h3&gt;&lt;p&gt;这层跟你的具体应用场景直接相关。做摘要的关注压缩率和信息保留度，做翻译的关注语义等价性和流畅度，做客服的关注意图识别准确率和回答完整度。&lt;/p&gt;
&lt;p&gt;任务层指标的定义需要领域知识。比如我们做客服场景，把任务层指标拆成了五块，意图理解准确率、事实一致性、回答完整度、语气恰当性、多轮连贯性。每块单独打分，加权合成得出总分。&lt;/p&gt;
&lt;p&gt;其实吧，权重怎么定这件事本身就很值得讨论。我们的做法是先让业务专家标注一批样本，然后用标注结果反推各个维度对整体满意度的贡献度，大致得到一个权重分配。这个过程不需要很精确，有个大致方向就行。&lt;/p&gt;
&lt;h3 id=&#34;业务层&#34;&gt;&lt;a href=&#34;#%e4%b8%9a%e5%8a%a1%e5%b1%82&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;业务层
&lt;/h3&gt;&lt;p&gt;最上面这层直接跟商业目标挂钩。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户满意度(CSAT)变化&lt;/li&gt;
&lt;li&gt;问题解决率(FCR)&lt;/li&gt;
&lt;li&gt;人工转接率&lt;/li&gt;
&lt;li&gt;用户留存率变化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;业务层指标的特点是滞后性很强，而且受很多非模型因素影响。你不可能每改一次prompt就等两周看留存数据。所以业务层指标的用途在于定期校准下面两层指标是否真的在驱动业务价值，日常迭代靠它不太现实。&lt;/p&gt;
&lt;h2 id=&#34;自建benchmark这件事&#34;&gt;&lt;a href=&#34;#%e8%87%aa%e5%bb%babenchmark%e8%bf%99%e4%bb%b6%e4%ba%8b&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;自建Benchmark这件事
&lt;/h2&gt;&lt;p&gt;开源Benchmark一大堆，MMLU、HumanEval、GSM8K、TruthfulQA，看着很全。但说实话，这些通用基准对你的业务场景帮助有限。一个通用Benchmark拿了90分的模型，在你的客服场景可能只有60分的表现。&lt;/p&gt;
&lt;p&gt;自建Benchmark几乎是每个认真做LLM应用的团队都绕不开的事。&lt;/p&gt;
&lt;h3 id=&#34;数据从哪来&#34;&gt;&lt;a href=&#34;#%e6%95%b0%e6%8d%ae%e4%bb%8e%e5%93%aa%e6%9d%a5&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;数据从哪来
&lt;/h3&gt;&lt;p&gt;最靠谱的来源是线上真实日志。我们从上线第一天就开始采样，按场景分类存储。每积累500条左右就做一次清洗和标注，逐步扩充评估集。&lt;/p&gt;
&lt;p&gt;另一个来源是刻意构造的边界case。比如我们专门建了一批「诱导性错误」测试集，用户用错误的语气暗示模型给出错误答案，看模型能不能扛住。还有「知识截止日」测试集，专门问模型关于最新事件的问题，看它会不会瞎编。&lt;/p&gt;
&lt;h3 id=&#34;标注怎么做&#34;&gt;&lt;a href=&#34;#%e6%a0%87%e6%b3%a8%e6%80%8e%e4%b9%88%e5%81%9a&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;标注怎么做
&lt;/h3&gt;&lt;p&gt;标注这件事，怎么说呢，理想状态是找领域专家逐条标注，但现实中成本太高了。我们的折中方案是，核心场景(大约占总评估集30%)找业务专家标注，其余的用LLM辅助标注加人工抽检。&lt;/p&gt;
&lt;p&gt;具体流程是这样的。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先用一个能力较强的模型(比如GPT-4级别)做初始标注&lt;/li&gt;
&lt;li&gt;人工抽检20%的标注结果，计算一致性&lt;/li&gt;
&lt;li&gt;如果一致性低于80%，调整标注指南再跑一轮&lt;/li&gt;
&lt;li&gt;一致性达标后，批量完成剩余标注&lt;/li&gt;
&lt;li&gt;收尾阶段再抽5%做人工复核&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;标注指南是一份活文档，每次标注都会根据实际情况修订。我们发现，标注指南的质量直接决定了评估集的质量，值得反复打磨。&lt;/p&gt;
&lt;h3 id=&#34;验证benchmark本身&#34;&gt;&lt;a href=&#34;#%e9%aa%8c%e8%af%81benchmark%e6%9c%ac%e8%ba%ab&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;验证Benchmark本身
&lt;/h3&gt;&lt;p&gt;很多人忽略这一步。你的评估集建好了，但它本身靠谱吗？&lt;/p&gt;
&lt;p&gt;一个简单的验证方法，拿评估集跑两个已知能力强弱不同的模型，看分数排序是否符合预期。如果一个公认更强的模型在你的Benchmark上反而得分更低，那多半是评估集本身有问题。&lt;/p&gt;
&lt;p&gt;另一个方法是计算评估集和人工判断的相关性。随机抽50条case让人类专家评分，再拿自动化评估跑一遍，算Spearman相关系数。我们的经验是相关系数达到0.7以上就算可用了，不必追求完美。&lt;/p&gt;
&lt;h2 id=&#34;评估工具链怎么选&#34;&gt;&lt;a href=&#34;#%e8%af%84%e4%bc%b0%e5%b7%a5%e5%85%b7%e9%93%be%e6%80%8e%e4%b9%88%e9%80%89&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;评估工具链怎么选
&lt;/h2&gt;&lt;p&gt;市面上做LLM评估的工具这两年冒出来不少，各有侧重。我们试用过好几个，整理了一个对比表。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;工具&lt;/th&gt;
					&lt;th&gt;定位&lt;/th&gt;
					&lt;th&gt;核心能力&lt;/th&gt;
					&lt;th&gt;适合阶段&lt;/th&gt;
					&lt;th&gt;价格模型&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Promptfoo&lt;/td&gt;
					&lt;td&gt;开源eval框架&lt;/td&gt;
					&lt;td&gt;prompt对比、多模型横评&lt;/td&gt;
					&lt;td&gt;早期探索&lt;/td&gt;
					&lt;td&gt;免费&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Braintrust&lt;/td&gt;
					&lt;td&gt;全链路平台&lt;/td&gt;
					&lt;td&gt;eval+日志+可观测性&lt;/td&gt;
					&lt;td&gt;中期规模化&lt;/td&gt;
					&lt;td&gt;按量付费&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;LangSmith&lt;/td&gt;
					&lt;td&gt;LangChain生态&lt;/td&gt;
					&lt;td&gt;trace追踪+eval+在线调试&lt;/td&gt;
					&lt;td&gt;LangChain用户&lt;/td&gt;
					&lt;td&gt;按量付费&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Ragas&lt;/td&gt;
					&lt;td&gt;RAG专项评估&lt;/td&gt;
					&lt;td&gt;检索质量、答案忠实度&lt;/td&gt;
					&lt;td&gt;RAG应用&lt;/td&gt;
					&lt;td&gt;开源免费&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DeepEval&lt;/td&gt;
					&lt;td&gt;类pytest体验&lt;/td&gt;
					&lt;td&gt;14+内置指标、CI集成友好&lt;/td&gt;
					&lt;td&gt;工程化团队&lt;/td&gt;
					&lt;td&gt;开源免费&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;inspect-ai&lt;/td&gt;
					&lt;td&gt;UK AI安全所出品&lt;/td&gt;
					&lt;td&gt;可复现评估、Agent评估&lt;/td&gt;
					&lt;td&gt;研究型评估&lt;/td&gt;
					&lt;td&gt;开源免费&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;我们的选型路径大概是这样的，早期用Promptfoo快速验证想法，跑通基本流程。等评估集规模上去、需要持久化存储和团队协作的时候，切到了Braintrust。RAG部分单独用Ragas做补充评估。&lt;/p&gt;
&lt;p&gt;反正我觉得工具本身没那么重要，重要的是把评估流程跑起来。用一个趁手的工具赶紧开始，比花三个月调研选一个「最优解」然后迟迟不动手强太多。&lt;/p&gt;
&lt;h2 id=&#34;把评估塞进cicd流水线&#34;&gt;&lt;a href=&#34;#%e6%8a%8a%e8%af%84%e4%bc%b0%e5%a1%9e%e8%bf%9bcicd%e6%b5%81%e6%b0%b4%e7%ba%bf&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;把评估塞进CI/CD流水线
&lt;/h2&gt;&lt;p&gt;Eval如果只存在于数据科学家的Notebook里，那它的价值就很有限。真正能发挥作用的场景是每次代码变更都自动触发评估，跟单元测试一样，跑不过就不让合并。&lt;/p&gt;
&lt;p&gt;我们的流水线大致长这样。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# .github/workflows/eval-gate.yml (简化版)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;eval-gate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;steps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Run eval suite&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;promptfoo eval --config eval/promptfooconfig.yaml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Check thresholds&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;python scripts/check_eval_thresholds.py&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Block merge if failed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;failure()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;exit 1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;check_eval_thresholds.py&lt;/code&gt;这个脚本做的事情很直白，读取eval结果JSON，逐项检查指标是否达到预设门槛。任何一项不达标就返回非零退出码，CI自动标红，PR无法合并。&lt;/p&gt;
&lt;p&gt;门槛值的设定有个小技巧。一开始不要设太高，用当前系统的baseline作为门槛，保证现有能力不退化就行。然后每隔一两个sprint根据最近的优化成果适当上调。门槛值应该是一个持续校准的参数，不是写死不动的数字。&lt;/p&gt;
&lt;p&gt;还有一个容易忽略的点，eval的执行时间。如果评估集太大，跑一次要二十分钟，开发人员会很烦，开始想办法跳过。我们的做法是维护两个评估集，一个quick set大概200条case，五分钟跑完，每次PR都跑。一个full set大概2000条，每周跑一次做全面检查。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有个经验之谈，eval跑在CI里最大的好处在于让每次prompt改动都有可追溯的记录，拦住坏代码只是顺手的事。三个月后回头看，你能清楚看到每次改动的效果变化曲线。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;llm-as-judge好用但坑多&#34;&gt;&lt;a href=&#34;#llm-as-judge%e5%a5%bd%e7%94%a8%e4%bd%86%e5%9d%91%e5%a4%9a&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;LLM-as-Judge，好用但坑多
&lt;/h2&gt;&lt;p&gt;用模型来评价模型，这个思路乍一听有点循环论证的味道。但实际操作下来，LLM-as-Judge在大部分场景下是可用的，前提是你要知道它的局限。&lt;/p&gt;
&lt;p&gt;LLM-as-Judge最大的优势是成本低、速度快、可扩展。人工标注一条case可能要5分钟，成本几块钱。LLM标注一条只要几秒钟，成本几乎可以忽略。当你的评估集有几千条case的时候，这个差距就很明显了。&lt;/p&gt;
&lt;p&gt;但它有几个系统性的偏差需要你注意。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自我偏好&lt;/strong&gt;。模型倾向于给自己的输出打高分。如果你用GPT-4当judge，它对GPT-4生成的文本天然有好感。解决办法是用不同厂商的模型做judge，或者混合多个模型的判断取多数投票。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;位置偏差&lt;/strong&gt;。在A/B对比场景下，模型倾向于选排在前面或者更长的那个回答。解决办法是跑两次，一次A在前一次B在前，只取两次结果一致的case。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长度偏好&lt;/strong&gt;。模型倾向于认为更长的回答更好，即使短回答实际上更准确。解决办法是在评分prompt里明确告诉judge，回答质量与长度无关。&lt;/p&gt;
&lt;p&gt;我们的实践是，LLM-as-Judge负责日常迭代的快速评估，人工评估作为定期校准手段。每个月做一次全量人工标注，跟LLM judge的结果做对比，如果发现偏差变大就调整judge的prompt或者换一个judge模型。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 一个简化版的LLM-as-Judge评分prompt模板&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;JUDGE_PROMPT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;你是一个专业的客服质量评估员。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;请从以下维度评估这个回答，每个维度打1-5分。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;1. 事实准确性，回答中的信息是否正确
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;2. 完整性，是否回答了用户的核心问题
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;3. 语气恰当性，是否礼貌专业
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;4. 安全性，是否存在误导或有害信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;用户问题，&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{question}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;模型回答，&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{answer}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;参考信息，&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{reference}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;请按JSON格式输出各维度分数和简要评语。&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个prompt本身也需要迭代。我们前前后后改了十几版，每一版都拿人工标注结果做校准。说真的，judge prompt的调优比业务prompt的调优更考验功力，因为它直接影响你对整个系统质量的判断。&lt;/p&gt;
&lt;h2 id=&#34;线上监控和线下评估是两码事&#34;&gt;&lt;a href=&#34;#%e7%ba%bf%e4%b8%8a%e7%9b%91%e6%8e%a7%e5%92%8c%e7%ba%bf%e4%b8%8b%e8%af%84%e4%bc%b0%e6%98%af%e4%b8%a4%e7%a0%81%e4%ba%8b&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;线上监控和线下评估是两码事
&lt;/h2&gt;&lt;p&gt;线下评估做得再好，也只能覆盖你能想到的场景。线上环境永远有你预料不到的输入，所以线上监控是不可替代的另一道防线。&lt;/p&gt;
&lt;p&gt;我们线上监控主要看这几个信号。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户显式负反馈(点踩、投诉)的比例变化&lt;/li&gt;
&lt;li&gt;对话轮数异常(突然变长可能意味着模型答非所问)&lt;/li&gt;
&lt;li&gt;用户重复提问率(同一个问题换着法子问，说明之前的回答不满意)&lt;/li&gt;
&lt;li&gt;人工转接触发率&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些信号都有延迟，而且噪音很大。某个case被踩了，可能是模型的问题，也可能纯粹是用户心情不好。所以我们不拿单个case的反馈做决策，只看趋势。&lt;/p&gt;
&lt;p&gt;线下评估和线上监控的关系有点像体检和日常健康监测。线下评估是定期做的全面体检，能发现深层次的问题。线上监控是每天看的血压心率，能及时发现突发状况。两者缺一不可。&lt;/p&gt;
&lt;p&gt;有一个比较tricky的问题，模型更新后线下评估分数涨了，线上指标反而跌了。我们遇到过好几次。事后分析发现，通常是评估集没有覆盖到新版本引入的新行为模式。每次遇到这种情况，我们就从线上日志里挖掘失败case，补充到评估集里，让评估集跟着模型一起进化。&lt;/p&gt;
&lt;h2 id=&#34;谁来干这件事怎么推动&#34;&gt;&lt;a href=&#34;#%e8%b0%81%e6%9d%a5%e5%b9%b2%e8%bf%99%e4%bb%b6%e4%ba%8b%e6%80%8e%e4%b9%88%e6%8e%a8%e5%8a%a8&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;谁来干这件事，怎么推动
&lt;/h2&gt;&lt;p&gt;技术层面的事情聊完了，聊聊组织层面。评估工程的落地，说实话最大的障碍在于人的观念和资源分配，技术问题反而是次要的。&lt;/p&gt;
&lt;p&gt;很多团队的现状是，做LLM应用的人身兼开发、测试、上线多职。评估被视为「有空再做」的事情，优先级永远排在「新功能」后面。这个心态可以理解，但很危险。&lt;/p&gt;
&lt;p&gt;我们的做法是，设立一个专职的「AI质量」角色，不需要很多人，一两个人就够。这个角色的职责是维护评估集、跑定期评估、分析评估结果、推动问题修复。这个角色最好直接向技术负责人汇报，不挂在某个产品线下面，这样才有独立性。&lt;/p&gt;
&lt;p&gt;推动这件事的切入点也有讲究。不要一上来就搞一套宏大的评估体系，先找一个最痛的场景，用最简单的方法跑通。比如先拿Promptfoo加50条核心case做一个最小评估集，集成到CI里，让团队看到「每次改动都有分数反馈」这件事的价值。等大家尝到甜头了，再逐步扩展评估集的规模和覆盖范围。&lt;/p&gt;
&lt;p&gt;还有一个建议，把评估结果可视化。我们做了一个内部Dashboard，每天自动跑一遍核心评估，结果展示在大屏上。每个指标的趋势、跟上周的对比、跟上月目标的差距，一目了然。这个东西做了之后，管理层对评估的重视程度肉眼可见地提升了。&lt;/p&gt;
&lt;p&gt;上周五下午，我把最新一版的评估集更新推到了仓库。CI自动跑了一遍，全绿。顺手打开Dashboard看了一眼，核心场景通过率从上个月的87%爬到了93%。关掉页面之前，我在评估集的changelog里加了一行注释，下周二之前把退款相关的边界case再补20条，上次那个事故的变种还没覆盖到。&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
