<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>评估 on Chico's Tech Blog</title><link>https://realtime-ai.chat/tags/%E8%AF%84%E4%BC%B0/</link><description>Recent content in 评估 on Chico's Tech Blog</description><image><title>Chico's Tech Blog</title><url>https://github.com/chicogong.png</url><link>https://github.com/chicogong.png</link></image><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sat, 16 May 2026 11:00:00 +0800</lastBuildDate><atom:link href="https://realtime-ai.chat/tags/%E8%AF%84%E4%BC%B0/index.xml" rel="self" type="application/rss+xml"/><item><title>Agent 上线之后:怎么评估和监控</title><link>https://realtime-ai.chat/posts/agent-evals/</link><pubDate>Sat, 16 May 2026 11:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/agent-evals/</guid><description>Agent 难的不是搭出来,是上线后知道它好不好。讲清楚 Agent 该看哪些指标、怎么做离线 eval、在线 trace、人审和 LLM-as-judge 的取舍,以及回归怎么防。</description><content:encoded><![CDATA[<p>用一个下午就能搭出一个像样的 Agent demo。接个大模型、写几个工具、调通 ReAct 循环,跑十条 case,全过。截图发群里,大家鼓掌。</p>
<p>两周后,一个客户在工单里贴出对话记录:你的 Agent 把退款金额算成了原价的三倍,还信誓旦旦地说&quot;已为您处理&quot;。你翻监控面板——CPU 正常、接口 P99 40ms、错误率 0.02%,一片绿。</p>
<p>这就是 Agent 工程里最反直觉的地方:<strong>搭出来是最简单的一步,知道它到底好不好,才是真正的工程</strong>。传统软件你写完测试、跑通 CI,基本就放心了;Agent 不行——它每次的输出都不一样,它&quot;出错&quot;的方式根本不会触发任何异常。这篇讲讲上线之后那部分:看什么指标、怎么评、怎么防回归。</p>
<h2 id="为什么你那套监控不管用">为什么你那套监控不管用</h2>
<p>先说清楚传统监控为什么在这里失灵。</p>
<p>传统软件的故障是<strong>二值</strong>的:要么 200,要么 500;要么返回了,要么超时了。你的告警系统盯着这些信号,出事就响。Agent 的故障是<strong>语义</strong>的:HTTP 200,JSON 合法,字段齐全,延迟正常——内容是错的。Agent 自信地编了一个不存在的退货政策,调了正确的工具但传错了参数,绕了七步才完成一件三步能干完的事。这些在传统监控眼里全是&quot;成功请求&quot;。</p>
<p>更麻烦的是 Agent 是<strong>非确定性</strong>的。同样一句&quot;帮我查下上个月的账单&quot;,今天它走两步给出答案,明天可能走五步还问你要确认。你没法用&quot;输入 X 必然输出 Y&quot;来断言。所以 Agent 的评估,本质上是在做<strong>概率系统的质量管理</strong>——你管的不是单次对错,是一个分布。</p>
<p>还有一层:Agent 是<strong>多步</strong>的。一次任务里,规划器把目标拆成子步骤,工具选择器挑了几个工具,检索器拉了上下文,模型可能还重试了两次,最后才有一个回答。出了问题,你得知道是哪一步坏的。只盯着最终输出,等于只看考试总分不看错题——你知道它考砸了,但不知道为什么。</p>
<pre class="mermaid">flowchart TD
  A[用户请求] --> B[规划<br/>拆解子任务]
  B --> C[工具选择]
  C --> D[工具调用]
  D --> E{结果够了吗}
  E -->|不够| B
  E -->|够了| F[生成回答]
  F --> G[返回用户]
  style B fill:#fde7c2,stroke:#e8b23c
  style C fill:#fde7c2,stroke:#e8b23c
  style D fill:#fde7c2,stroke:#e8b23c
</pre><p>橙色那三块——规划、选工具、调工具——是 Agent 区别于&quot;一次 LLM 调用&quot;的地方,也是大多数故障的发生地。你的可观测性必须能看进这三块,而不只是看进出。</p>
<h2 id="agent-该盯哪几个指标">Agent 该盯哪几个指标</h2>
<p>把指标分成两类:<strong>业务结果</strong>和<strong>过程健康</strong>。前者回答&quot;它有没有把事办成&quot;,后者回答&quot;它办事的姿势对不对&quot;。</p>
<table>
  <thead>
      <tr>
          <th>指标</th>
          <th>它在说什么</th>
          <th>不正常时意味着</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>任务成功率</td>
          <td>用户的目标到底达成了没</td>
          <td>这是北极星,其他指标都为它服务</td>
      </tr>
      <tr>
          <td>步数 / 轮次</td>
          <td>完成一个任务走了几步</td>
          <td>步数飙升 = 规划在打转或工具在失败重试</td>
      </tr>
      <tr>
          <td>工具调用错误率</td>
          <td>工具调用里失败的比例</td>
          <td>区分&quot;参数错&quot;和&quot;工具本身挂了&quot;</td>
      </tr>
      <tr>
          <td>Token 消耗</td>
          <td>单次任务烧掉多少 token</td>
          <td>直接对应成本,也是绕路的信号</td>
      </tr>
      <tr>
          <td>端到端延迟</td>
          <td>用户从发问到拿到结果等了多久</td>
          <td>多步 Agent 的延迟是各步之和,会累</td>
      </tr>
      <tr>
          <td>工具选择准确率</td>
          <td>该用 A 工具时它是不是用了 A</td>
          <td>选错工具,后面全错</td>
      </tr>
  </tbody>
</table>
<p>几个容易踩的点。</p>
<p><strong>任务成功率不能自己定义。</strong> &ldquo;成功&quot;必须从用户视角定:用户想退款,Agent 走完全流程、退款到账才算成功;它礼貌地回了一大段话但没退成,是失败。很多团队把&quot;流程跑完没报错&quot;当成功,这是自欺。</p>
<p><strong>步数和 token 是一对孪生信号。</strong> 它俩一起涨,通常是 Agent 陷进了&quot;调工具—结果不满意—再调&quot;的循环。我习惯给每个任务设一个步数上限(比如 15 步)做硬熔断,然后把&quot;步数分布&quot;画成直方图——你要看的不是平均值,是那条长尾。平均 4 步很健康,但如果有 5% 的任务走到 20 步,那 5% 就是你的成本黑洞和体验灾难。</p>
<p><strong>工具调用错误率要拆开看。</strong> &ldquo;模型给工具传了非法参数&quot;和&quot;工具后端 500 了&quot;是两种完全不同的病:前者是模型的问题,要改 prompt 或工具描述;后者是依赖的问题,要改基础设施。混在一个数字里,你永远不知道该修哪。OpenTelemetry 的 GenAI 语义约定(2026 年仍是 experimental,但已经是事实标准)专门为 <code>execute_tool</code> span 和 <code>error.type</code> 留了字段,就是为了让你能这样拆。</p>
<h2 id="离线评估上线前的单元测试">离线评估:上线前的&quot;单元测试&rdquo;</h2>
<p>离线评估,就是给 Agent 写单元测试。核心是一个 <strong>eval 集</strong>:一批输入,配上你认可的&quot;理想行为&rdquo;。每次改了 prompt、换了模型、调了工具描述,先拿这批 case 跑一遍,看分数有没有掉。</p>
<p>eval 集怎么来,决定了它有没有用。<strong>别凭空想象 case,要从真实流量里捞。</strong> 一个我反复验证的做法:每周翻线上 trace,把失败的、用户追问的、绕路的对话挑出来,清洗成 eval case。你的 eval 集应该是你<strong>踩过的坑的合集</strong>,而不是产品经理拍脑袋写的&quot;理想用户故事&quot;。理想故事永远通过,真实的坑才暴露问题。</p>
<p>Agent 的离线评估比纯 LLM 难,难在要评<strong>轨迹(trajectory)</strong>,不只是评最终答案。Google 的 ADK 把这件事说得很直白:一个 golden case 要同时记两样东西——<strong>理想的工具调用序列</strong>和<strong>理想的最终回答</strong>。于是你能分别打两类分:</p>
<ul>
<li><strong>轨迹分</strong>:它选的工具对不对、顺序合不合理、有没有多余的步骤。轨迹可以严格比对(必须和 golden 完全一致),也可以宽松比对(关键工具调到就行)。</li>
<li><strong>结果分</strong>:最终回答对不对、全不全。</li>
</ul>
<p>为什么要分开?因为一个 Agent 可能&quot;答对了但过程很糟&quot;——瞎试了八个工具碰巧蒙对。这种 case 结果分满分,轨迹分很低。你要是只看结果分,就会把一个脆弱的、纯靠运气的 Agent 当成好 Agent 放上线。</p>
<p>一条实用纪律:<strong>如果你的 eval 集通过率是 100%,那不是你的 Agent 完美,是你的 eval 太简单了。</strong> 健康的 eval 集应该一直留着几条过不了的 case,逼着你持续改进。通过率到顶的那天,就是该往里加硬 case 的那天。</p>
<h2 id="在线观测用-trace-还原现场">在线观测:用 trace 还原现场</h2>
<p>离线评估管&quot;上线前&quot;,在线观测管&quot;上线后&quot;。核心工具是 <strong>trace</strong>——把一次完整任务里的每一步都记下来:每次 LLM 调用的输入输出和 token,每次工具调用的参数和返回,每一步的耗时。出了问题,你能像看录像回放一样把现场还原出来。</p>
<p>观测的粒度分三层,这个分层很关键:</p>
<ul>
<li><strong>Span 级</strong>:单个步骤。定位&quot;哪一步坏了&quot;——是第三次工具调用传错了参数。</li>
<li><strong>Trace 级</strong>:一次完整任务。判断&quot;整件事办成了没&quot;。</li>
<li><strong>Session 级</strong>:跨多轮对话的一整个会话。评估&quot;这个用户这一次来,体验到底如何&quot;。</li>
</ul>
<p>值得提醒的一点:早期那批 observability 工具(Langfuse、LangSmith、Braintrust、W&amp;B Weave)最初都是为&quot;监控 LLM 调用&quot;设计的,后来才扩展去支持 Agent——而它们处理 Agent 的方式,常常是把 Agent 当成&quot;一串 LLM 调用&quot;,而不是当成&quot;一个有目标、有结果的会话&quot;。这个出身决定了你用它们时要多留个心眼:<strong>别让工具默认的视角把你带偏到只看单次调用,你真正要回答的是 trace 级和 session 级的问题。</strong></p>
<p>2026 年这个领域的工具已经分化得比较清楚,选型可以这么看:</p>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>适合谁</th>
          <th>特点</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Langfuse</td>
          <td>想自托管、要开源、在意数据主权</td>
          <td>开源标杆,无按席位收费;2026 年 1 月被 ClickHouse 收购</td>
      </tr>
      <tr>
          <td>LangSmith</td>
          <td>技术栈是 LangChain / LangGraph</td>
          <td>和自家框架咬合最紧,接入几乎零开销</td>
      </tr>
      <tr>
          <td>Braintrust</td>
          <td>重视 eval 工程、要把 eval 卡进 CI</td>
          <td>免费额度大方,CI 门禁工作流最成熟</td>
      </tr>
      <tr>
          <td>Arize Phoenix</td>
          <td>想要开源 + 偏 ML 团队习惯</td>
          <td>基于 OpenTelemetry,可观测性血统正</td>
      </tr>
      <tr>
          <td>AgentOps</td>
          <td>多框架混用、重在调试多 Agent</td>
          <td>多框架 Agent 调试能力强</td>
      </tr>
  </tbody>
</table>
<p>不用纠结选哪个&quot;最好&quot;。务实的选法:<strong>先确认它原生支持 OpenTelemetry GenAI 语义约定</strong>,这样你不会被锁死,以后换工具数据能带走。然后看它的出身和你的技术栈合不合。能自托管、数据敏感就 Langfuse;深度用 LangChain 就 LangSmith;eval 是核心工作流就 Braintrust。</p>
<h2 id="谁来打分人审还是-llm-as-judge">谁来打分:人审还是 LLM-as-judge</h2>
<p>trace 有了,你还得给每条 trace 打分,才知道质量是涨是跌。打分有三种人:规则、人、和另一个大模型。</p>
<p><strong>能用规则就用规则。</strong> 凡是确定性的检查——延迟有没有超标、JSON schema 合不合法、token 有没有爆预算、有没有调到那个必须调的工具——全用代码硬判。规则评估快、不要钱、结果稳定,能用规则的地方绝不要上模型。这是省钱省心的第一原则。</p>
<p><strong>剩下的&quot;质量&quot;问题,人审最准但最贵。</strong> 回答的语气专不专业、有没有答非所问、逻辑通不通——这些目前只有人能可靠地判断。人审是你所有评估的<strong>真相来源(ground truth)</strong>,但你不可能让人审每天几十万条对话。所以人审的正确用法是<strong>抽样</strong>:每天抽一两百条,尤其抽那些自动评估打了低分或者落在边界上的。</p>
<p><strong>规模化只能靠 LLM-as-judge</strong>——用一个大模型当裁判,按 rubric 给另一个 Agent 的输出打分。但这东西用不好就是自我安慰,几条铁律:</p>
<ol>
<li><strong>先校准,再信任。</strong> 上线一个 judge 前,拿它跑那批人审过的 golden case,看它和人的判断一致率。业界经验是要做到 <strong>75%–90% 一致</strong>才能用。没校准过的 judge,它给的分只是&quot;看起来很科学的噪声&quot;。</li>
<li><strong>rubric 要具体到能打钩。</strong> 别问 judge&quot;这个回答好不好&quot;,要给明确标准:&ldquo;是否引用了知识库里的真实政策?是否直接回答了用户的问题?有没有编造金额?&ldquo;评判标准越像一张检查清单,judge 越稳。</li>
<li><strong>judge 喂的输入要对。</strong> 评轨迹就把完整 trace 给它,评回答质量就只给它问题和回答。喂错了上下文,分数就废了。</li>
<li><strong>警惕 judge 被骗。</strong> 2026 年初已经有研究(arXiv 上《Gaming the Judge》)指出:Agent 可以生成一段&quot;看起来很有道理但其实不忠实&quot;的推理,把 LLM judge 哄过去。所以高风险场景下,judge 的结论仍然要被人审抽查兜底。</li>
</ol>
<p>我的分工建议很简单:<strong>规则做体检(确定性指标),LLM-as-judge 做日常巡检(规模化、覆盖全量),人审做权威诊断(抽样、校准 judge、定真相)。</strong> 三层各管各的,谁也别越位。</p>
<h2 id="回归别让今天的修复变成明天的故障">回归:别让今天的修复变成明天的故障</h2>
<p>Agent 最阴险的回归是这样发生的:用户报了个 bug,你改了 prompt 把它修好了,上线。三周后另一类对话开始出问题——你那次改 prompt,顺手把另一种场景搞坏了。Prompt 是全局生效的,改一个字,影响面没人说得清。</p>
<p>防回归的办法,是把 eval 集变成 Agent 的<strong>回归测试套件,并且卡进 CI</strong>。</p>
<p>具体做法:每次提交改动(改 prompt、换模型、调工具),CI 自动跑全套 eval 集,把分数和主干基线逐条对比。Braintrust 的 GitHub Action、Promptfoo 这类工具已经把这条路铺好了——它会在 PR 里直接贴一张表,哪个 case 的哪个评分项涨了(🟢)、哪个跌了(🔴),一目了然。</p>
<p>关键是<strong>门禁(quality gate)</strong>:设一条线,核心 case 的成功率掉破阈值,这个 PR 就不许合。这一步把&quot;上线后被用户发现回归&quot;前移成了&quot;提 PR 时就被 CI 拦下&rdquo;。从一次线上事故,变成一次代码评审里的红叉——成本差着好几个数量级。</p>
<pre class="mermaid">flowchart LR
  A[改 prompt/模型/工具] --> B[提交 PR]
  B --> C[CI 跑全套 eval]
  C --> D{核心成功率<br/>过线了吗}
  D -->|过线| E[允许合并]
  D -->|没过| F[阻断 + PR 里标红]
  F --> A
  E --> G[上线]
  G -.线上失败 case.-> H[回灌进 eval 集]
  H --> C
  style D fill:#fde7c2,stroke:#e8b23c
  style H fill:#fde7c2,stroke:#e8b23c
</pre><p>注意图里那条虚线:<strong>线上抓到的新失败,要回灌进 eval 集。</strong> 这是整个闭环里最容易被偷懒省掉、但最值钱的一步。每修一个线上 bug,顺手把它变成一条 eval case——这样同一个坑,你这辈子只会踩一次。eval 集不是写一次就完的资产,它是跟着你的线上事故一起长大的。</p>
<h2 id="最后评估投入排个序">最后:评估投入排个序</h2>
<p>如果你正在做 Agent,评估和监控这块的投入,我建议这个顺序:</p>
<ol>
<li><strong>先上 trace。</strong> 一个看不见内部的 Agent,你连它怎么坏的都不知道,谈何优化。这是地基,而且接入成本很低。</li>
<li><strong>再攒 eval 集。</strong> 从线上 trace 里捞真实失败 case,哪怕只有 30 条也比没有强。它会马上开始帮你。</li>
<li><strong>然后卡进 CI。</strong> 把 eval 集变成回归门禁,从此改 prompt 不再是闭眼下注。</li>
<li><strong>最后才上 LLM-as-judge,而且必须先用人审校准。</strong> 校准跳不得。</li>
</ol>
<p>很多团队的顺序是反的——demo 一通就急着上线,出了事再回头补监控。但 Agent 这东西,<strong>你对它的可观测性有多深,你能把它做多好就有多高的上限</strong>。先让自己看得见,再谈让它变得更好。</p>
]]></content:encoded></item><item><title>LLM 评估怎么做才靠谱</title><link>https://realtime-ai.chat/posts/llm-evals/</link><pubDate>Sun, 10 May 2026 11:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/llm-evals/</guid><description>公开 benchmark 为什么不能直接信、怎么建自己的 eval 集、LLM-as-judge 有哪些偏差、如何防止过拟合 eval,以及 A/B 与线上指标的取舍。</description><content:encoded><![CDATA[<p>你把 prompt 改了一版,在三个例子上试了试,看着比之前顺眼,于是上线。</p>
<p>第二天客服群里有人说 AI 答得不对劲。你回头去看,发现那三个例子确实变好了,但另外二十种你没试的情况里,有五种悄悄变差了。</p>
<p>这是做 LLM 应用最常见的窘境:<strong>你没法靠&quot;看几个例子&quot;判断一次改动是涨还是跌</strong>。模型是个高维的黑盒,你改 prompt、换模型、调温度,影响面是发散的——在你盯着的地方变好,在你没盯着的地方变坏。评估(eval)要解决的就是这件事:把&quot;我觉得变好了&quot;换成&quot;我有证据说变好了&quot;。</p>
<p>这篇讲怎么把这套证据系统搭起来,以及一路上的坑。</p>
<h2 id="公开-benchmark能看排名不能信分数">公开 benchmark:能看排名,不能信分数</h2>
<p>打开任何一个模型发布页,都有一排 benchmark 分数:MMLU 多少、GPQA 多少、SWE-bench 多少。这些数字有用,但对你的应用,它的参考价值比你以为的小得多。</p>
<p>第一个问题是<strong>饱和</strong>。2026 年的前沿模型在 MMLU 上普遍是 92–94%,彼此之间的差距已经掉进噪声里了。一个 93%、一个 94%,你没法据此说后者更强——重跑一次,排名可能就反过来。MMLU 这种榜单现在只能告诉你&quot;这是不是个能用的模型&quot;,没法在头部模型之间分高下。后来的 MMLU-Pro 想救场,到 2026 年初头部模型也挤到了 90% 附近,同样在走向饱和。</p>
<p>第二个问题更麻烦:<strong>污染</strong>。Benchmark 的题目是公开的,公开就意味着它们大概率被爬进了下一代模型的训练数据。模型可能不是&quot;做对了&quot;题,而是&quot;背过&quot;答案。已经被记录的案例不少:MMLU 的题目在 Common Crawl 里能找到原文;HumanEval 的题和 LeetCode 题高度重合;SWE-bench 的 issue 在公开 git 历史里能翻到现成的修复 commit。</p>
<p>污染有多严重?Scale AI 做过一个对照实验:他们照着小学数学题 GSM8K 的风格,重新出了 1250 道全新的题。结果模型在新题上系统性掉分,最差的那个掉了 13 个百分点。同一个模型,题目换成没见过的,能力就缩水一成多——这说明原来那个高分里,有相当一部分是&quot;背&quot;出来的。</p>
<p>所以 2026 年大家转向<strong>抗污染的 benchmark</strong>:LiveCodeBench、LiveBench 这类按时间切片,只用某个日期之后才出现的新题;FrontierMath 把题目压在手里不公开。这些比静态榜单可信。但即便如此,它们衡量的还是&quot;通用能力&quot;,不是&quot;你的任务&quot;。</p>
<p><strong>结论很直接:公开 benchmark 用来粗筛候选模型——把明显不行的排除掉。但&quot;这个模型在我的客服场景里好不好用&quot;,它一个字都没回答。这个问题只能你自己回答。</strong></p>
<h2 id="自己的-eval-集这才是真正的资产">自己的 eval 集:这才是真正的资产</h2>
<p>你的应用有一个公开 benchmark 永远覆盖不到的东西:<strong>你的真实输入分布</strong>。你的用户怎么提问、问什么、用什么语气、夹杂什么错别字和行业黑话,这是你独有的。eval 集就是把这个分布固定下来。</p>
<p>怎么建,有三个我认为不能省的原则。</p>
<p><strong>第一,例子来自真实流量,不要凭空编。</strong> 你坐在工位上想象的用户提问,和用户真实打出来的,分布不一样。最好的来源是线上日志:把真实请求捞出来,尤其是那些用户追问、重述、明显不满意的——失败案例的信息密度最高。每修一个线上 bug,就把那个 case 沉淀进 eval 集,它就再也不会悄悄复发。</p>
<p><strong>第二,先覆盖,再追数量。</strong> 一个有 50 条、覆盖 15 种场景的 eval 集,比一个有 500 条、全是&quot;查订单状态&quot;的 eval 集有用得多。你要的是把<strong>输入空间的不同角落</strong>都摸到:正常请求、边界请求(超长输入、空输入、多意图混在一句)、对抗请求(prompt 注入、诱导越权)、还有那些你修过的历史 bug。每加一条都先问:它覆盖了一个新角落,还是只是重复?</p>
<p><strong>第三,每条例子都要能判对错。</strong> 一条 eval 数据 = 输入 + 判断标准。判断标准可以是标准答案,可以是一组必须满足的规则(&ldquo;回复里必须包含订单号&rdquo;、&ldquo;不能承诺退款&rdquo;),也可以是一段评分 rubric。没有判断标准的例子不是 eval,是 demo。</p>
<p>eval 集建起来之后,它会变成你团队最值钱的资产之一——比某一版 prompt 值钱。Prompt 会被改无数次,模型会换代,但 eval 集是持续累积的、关于&quot;什么叫做对&quot;的集体知识。</p>
<h2 id="三种判分方式以及各自的脾气">三种判分方式,以及各自的脾气</h2>
<p>有了例子,接下来是怎么自动判分。三种方式,从硬到软排:</p>
<table>
  <thead>
      <tr>
          <th>判分方式</th>
          <th>适用场景</th>
          <th>优点</th>
          <th>坑</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>精确匹配 / 结构校验</td>
          <td>分类、抽取、JSON 输出、函数调用</td>
          <td>客观、零成本、可复现</td>
          <td>只能判有唯一答案的任务</td>
      </tr>
      <tr>
          <td>规则 / 断言</td>
          <td>「必须含 X」「不得出现 Y」、格式、长度</td>
          <td>快、便宜、覆盖硬约束</td>
          <td>写不出复杂语义判断</td>
      </tr>
      <tr>
          <td>LLM-as-judge</td>
          <td>开放式回答、摘要、对话质量</td>
          <td>能评主观质量</td>
          <td>自带偏差,本身需要被评估</td>
      </tr>
  </tbody>
</table>
<p>优先用硬的。能用精确匹配解决的,绝不上 LLM 判分——它客观、免费、每次结果一样。能拆成规则断言的也尽量拆:&ldquo;回复里有没有订单号&quot;用一个正则就够了,没必要请一个大模型来读。</p>
<p>真正绕不开的是开放式任务——&ldquo;这个摘要写得好不好&rdquo;、&ldquo;这个客服回复够不够得体&rdquo;。这种没有唯一答案,只能上 LLM-as-judge:让另一个模型按 rubric 给被测输出打分。这是 2026 年的主流做法,但你得知道它的脾气。</p>
<h2 id="llm-as-judge-会骗你而且骗得很有规律">LLM-as-judge 会骗你,而且骗得很有规律</h2>
<p>LLM 当裁判的最大问题是:<strong>它的偏差不是随机噪声,是系统性的</strong>。随机噪声多跑几次能平掉,系统性偏差不会——它会朝一个固定方向把你的判断带偏。</p>
<p>有几个偏差已经被反复测出来,几乎跑不掉:</p>
<ul>
<li><strong>位置偏差。</strong> 做两个回答的对比评分时,排在前面的那个赢面更大,跟它质量无关。一篇系统研究跨 15 个裁判模型、约 15 万次评测,确认这个偏差稳定存在,而且两个回答质量越接近,偏差越明显。</li>
<li><strong>长度偏差。</strong> 更长、更啰嗦的回答倾向于拿更高分,哪怕信息量没多。</li>
<li><strong>自我偏好。</strong> 裁判模型会偏爱&quot;长得像自己输出&quot;的回答。用 GPT 当裁判,它会高看 GPT 系的生成。</li>
</ul>
<p>这些偏差有多严重?2026 年 RAND 的一项研究发现,没有任何一个裁判模型在所有 benchmark 上都可靠,前沿模型在高难度的偏差测试上错误率超过 50%。换句话说,<strong>你直接拿一个模型当裁判,它的判断有可能跟抛硬币差不多</strong>。</p>
<p>但 LLM-as-judge 不是不能用,是要带着纪律用:</p>
<ol>
<li><strong>位置偏差用双向取平均。</strong> 每对回答评两次,A 在前评一次、B 在前评一次,结果平均。一次都不能省。</li>
<li><strong>自我偏好用跨家族裁判。</strong> 别用同一家的模型既当选手又当裁判。被测是 GPT,就用 Claude 或 Gemini 当裁判。</li>
<li><strong>长度偏差写进 rubric。</strong> 在评分标准里明说&quot;长度不是加分项,只看信息是否准确、完整、相关&rdquo;。</li>
<li><strong>裁判本身也要被评估。</strong> 这步最常被跳过,但最关键:你得人工标一批&quot;金标准&quot;数据——比如 100 条人类专家打过分的样本——然后看你的 LLM 裁判跟人类标注的一致率有多高。一致率太低,这个裁判就不能用。<strong>裁判是被测系统的一部分,它没经过验证,它给的所有分数都是空的。</strong></li>
<li><strong>让它做选择题,别做作文题。</strong> LLM 判断&quot;A 和 B 哪个好&quot;比直接打&quot;7.5 分&quot;靠谱得多。能转成两两对比或分类的,就别让它打绝对分。</li>
</ol>
<p>整套流程串起来大概是这样:</p>
<pre class="mermaid">flowchart TD
  A[线上真实流量] --> B[沉淀为 eval 集<br/>输入 + 判断标准]
  B --> C{任务类型}
  C -->|有唯一答案| D[精确匹配 / 规则断言]
  C -->|开放式| E[LLM-as-judge<br/>双向 + 跨家族 + rubric]
  E --> F[用人类金标准<br/>校准裁判一致率]
  D --> G[聚合分数]
  F --> G
  G --> H[CI 里设阈值<br/>低于线就拦住]
</pre><h2 id="eval-也会被过拟合">eval 也会被过拟合</h2>
<p>这是个反直觉但很真实的陷阱:<strong>你太频繁地拿同一个 eval 集调东西,迟早会过拟合它</strong>。</p>
<p>机制和模型训练里的过拟合一模一样。你改 prompt → 看 eval 分 → 没涨 → 再改 → 再看分……重复几十次之后,你其实是在用 eval 集当训练信号,手动地把 prompt&quot;拟合&quot;到这 50 条例子上。最后 eval 分很漂亮,线上没动静——你优化的是分数,不是真实质量。判分用 LLM 的时候更隐蔽:你可能在不知不觉中专门迎合那个裁判的偏好。</p>
<p>防过拟合有几个具体做法:</p>
<p><strong>留一个 holdout 集,平时锁起来。</strong> 把 eval 集切成两份:开发集天天用、随便看;holdout 集藏好,只在准备上线前、或重大版本节点跑一次。如果开发集涨了、holdout 没涨,说明你过拟合了开发集,这次改动是假涨。</p>
<p><strong>让 eval 集持续流动。</strong> eval 集不是建一次就定死的。每周从最新线上流量补新例子进去,旧的、已经被反复优化过的逐步轮换出主力集。一个会更新的 eval 集,你很难持续过拟合它——因为标准在动。</p>
<p><strong>盯波动幅度,别盯小数点。</strong> eval 分从 86% 变成 87%,在大多数 eval 集规模下都落在统计噪声里,不代表任何东西。先估算一下你这个 eval 集的噪声范围(同一个配置跑几次,看分数抖多大),只有改动幅度明显超过噪声,才算数。</p>
<h2 id="eval-过了不等于线上变好">eval 过了,不等于线上变好</h2>
<p>最后这点是态度问题:<strong>离线 eval 永远是真实世界的近似,不是真实世界本身</strong>。</p>
<p>eval 集再好,也只是你<strong>当下能想到</strong>的输入。用户永远会问出你没预料的问题,真实分布永远在漂移。所以离线 eval 全绿,不等于上线就好。真正的裁判是线上。</p>
<p>成熟的做法是把离线和线上接成一条链:</p>
<ul>
<li><strong>离线 eval 当守门员。</strong> 接进 CI:每次改 prompt、换模型、动检索,自动跑一遍 eval,分数低于阈值的 PR 直接拦住,不让合。这一步拦的是<strong>明确的退步</strong>——已知该做对的事别做错了。</li>
<li><strong>A/B 测线上真实效果。</strong> 离线绿灯只是&quot;准你上&quot;,不是&quot;它一定好&quot;。新版本上线要灰度,拿一小部分真实流量跑 A/B,比的是真实业务指标:任务完成率、人工转接率、用户重述率、负反馈率。</li>
<li><strong>线上当 eval 集的源头。</strong> A/B 里跑出来的新失败 case,回流进 eval 集。这样下次同样的问题就被离线 eval 挡住了。</li>
</ul>
<p>这是个闭环:线上发现问题 → 进 eval 集 → CI 里防复发 → 新版本 A/B → 再发现新问题。eval 集就在这个循环里越长越厚,你的&quot;证据系统&quot;越来越能覆盖真实世界。</p>
<pre class="mermaid">flowchart LR
  A[改动:prompt/模型/检索] --> B[CI 跑离线 eval]
  B -->|低于阈值| A
  B -->|通过| C[灰度 A/B]
  C --> D[看线上指标<br/>完成率/转接率/负反馈]
  D -->|发现新失败| E[回流进 eval 集]
  E --> B
</pre><h2 id="写在最后">写在最后</h2>
<p>把 LLM 评估这件事压成几句:</p>
<p>公开 benchmark 只能粗筛模型,饱和加污染让它的分数当不得真。真正靠谱的是<strong>你自己的 eval 集</strong>,例子要来自真实流量、先求覆盖、每条都能判对错——这是你团队最该攒的资产。判分能用硬规则就别用 LLM,绕不开 LLM-as-judge 时,位置、长度、自我偏好三个偏差必须主动治,裁判本身要拿人类标注校准过才算数。别在同一个 eval 集上反复磨,留 holdout、让 eval 集持续更新。最后记住离线 eval 只是近似,线上 A/B 和真实指标才是终审。</p>
<p>很多团队做 LLM 应用,功能上得飞快,却始终说不清每次改动是涨是跌——因为他们一直在&quot;看几个例子拍脑袋&quot;。先把这套证据系统搭起来,你才算真的在迭代,而不是在赌博。</p>
<hr>
<p>参考资料:</p>
<ul>
<li><a href="https://newsletter.pragmaticengineer.com/p/evals">A pragmatic guide to LLM evals for devs — The Pragmatic Engineer</a></li>
<li><a href="https://developers.openai.com/api/docs/guides/evaluation-best-practices">Evaluation best practices — OpenAI API</a></li>
<li><a href="https://arxiv.org/abs/2406.07791">Judging the Judges: A Systematic Study of Position Bias in LLM-as-a-Judge — arXiv</a></li>
<li><a href="https://www.adaline.ai/blog/llm-as-a-judge-reliability-bias">LLM-as-a-Judge: Why Frontier Models Fail 50%+ Bias Tests — Adaline</a></li>
<li><a href="https://llm-stats.com/blog/research/what-is-a-contaminated-llm">What Is a Contaminated LLM? Detection, Famous Cases, 2026 Guide — llm-stats.com</a></li>
<li><a href="https://benchmarkingagents.com/what-these-benchmarks-miss/">What LLM Benchmarks Don&rsquo;t Measure — benchmarkingagents.com</a></li>
<li><a href="https://www.braintrust.dev/articles/llm-evaluation-guide">What is LLM evaluation? A practical guide — Braintrust</a></li>
</ul>
]]></content:encoded></item></channel></rss>