Lecture 10 · 智能体需要什么数据 · What Data Do Agents Need?

Engineering AI Agents · Lecture 10。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:Stanford CS329Z Engineering AI Agents(Fall 2026),Lecture 10 · Wed Oct 28 · What Data Do Agents Need?(原课 10/26 的客座讲座本讲义不覆盖)。阅读材料:Shankar, Data Flywheels for LLM Applications(2024)/ Tan et al., Large Language Models for Data Annotation and Synthesis: A Survey(EMNLP 2024)。 依据说明:写作时(2026-10-16)这一讲的 slides 还没有公布。本讲依据课表上的主题描述(轨迹、示范与反馈;用于优化的数据 vs 用于评估的数据;数据飞轮;合成数据生成;从人与智能体的交互中收集数据)和两篇阅读材料来写。等 slides 公布后,侧重点可能和这里不同。全部实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:code/lecture10/(只用 Python 标准库;5 个脚本 + 4 个模块 + 1 个可选脚本;不需要 API key;最慢的脚本约 20 秒) 预计阅读时间:3 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲你应该能够:

  1. 列出智能体系统里几种数据——轨迹、示范、偏好对、反馈信号、评估用例——各从哪来、用来干什么、用之前要先确认什么。
  2. 分析一个上线系统的反馈信号:显式和隐式信号各覆盖哪些失败、漏掉哪些失败;为什么”用户没抱怨”不等于成功;为什么”找问题”和”估计水平”要用两种抽样。
  3. 设计一个数据飞轮(评估 → 监控 → 持续改进):挑哪些轨迹去标注、错误分析怎样驱动修复、评估集和判分标准怎样跟上变化(标准漂移)。
  4. 用 LLM 生成和标注数据时,知道它常见的偏差(重复、过于干净、分布不对、漏报),会去重、会比较合成数据和真实数据的分布,会把人放在 LLM 最可能错的地方。
  5. 说清为什么用于优化的数据必须和用于评估的数据分开,识别四种常见的污染(在测试集上优化、反复看评估集、随机切分遇上漂移、近似重复泄漏)。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
第 9 讲:提示词优化、蒸馏、DPO 各需要什么数据;赢家诅咒从数据里挑最有信息量的部分、标注一致性、IRT(第 11 讲)
第 5 讲 §5.4:追踪(trace)与日志;第 7 讲:记忆投毒、来源标记评估用例的 4 元组和 benchmark 的有效性(第 12 讲)
第 8 讲 §6:失败分类、Cohen’s κ、LLM 评审LLM 评审的偏差与校准(第 13 讲)

0.3 本讲地图 Map

§0.6 开场:上线之后,数据才真正开始
§1  智能体需要什么数据:轨迹、示范、偏好对、反馈、评估用例                        ← 代码 01
§2  从人和智能体的交互中收集数据:显式与隐式信号、看不见的失败、谁在说话             ← 代码 02
§3  数据飞轮:评估 → 监控 → 持续改进;评估集会过时;标准漂移                        ← 代码 03
§4  合成数据与 LLM 标注:生成、去重、分布差异、LLM 当标注者                         ← 代码 04
§5  用于优化的数据 vs 用于评估的数据:四种污染                                     ← 代码 05
§6  用真实模型试一试                                                            ← 代码 06(可选)
§7  一份数据计划
§8 小结   §9 常见误区   §10 练习   §11 延伸阅读   §12 下一讲预告

0.4 术语 Terms

术语本讲里的意思
轨迹(trace / trajectory)一次运行的完整记录:输入、每一步的思考 / 工具调用 / 观察、输出、元数据
示范(demonstration)“在这个上下文里应该做这个动作”的例子;可以做 SFT 数据或少样本示范
偏好对(preference pair)同一个输入的两个输出,加上”哪个更好”的判断
显式 / 隐式反馈用户主动给的评价(点赞 / 点踩、评分)/ 从用户行为里推断的信号(换说法、转人工、回头再找)
审核(audit)人(或 LLM)读一条轨迹、按标准判断对错和原因
数据飞轮(data flywheel)用线上数据持续改进系统的循环:评估 → 监控 → 改进 → 再评估
标准漂移(criteria drift)判断”好”的标准随着看到的输出、业务的变化而改变
合成数据(synthetic data)由模型生成的输入(或标注),而不是来自真实用户
污染 / 泄漏(contamination / leakage)评估用的数据(或它的近似重复)进入了优化过程

0.5 本讲的代码

代码模拟一个上线 12 周的客服智能体(Orrin Grid,第 3、4 讲的虚构能源公司):

  • 请求(support_world.py):7 类——改期、取消、停电补偿、改地址、账单疑问、要求转人工、(第 5 周起)太阳能计划;每周 400 个,有 15% 的用户说话含糊、带错别字。
  • 政策:先查客户、只能改到工作日、日期含糊要问清、取消前要确认、有停电记录才补偿、补偿有上限(第 8 周起从 50 降到 30)、改地址前验证 PIN、要转人工就转、太阳能先查资格。
  • 智能体(support_agent.py):读系统提示里写的规则办事,没写的凭”常识”(有的常识对,有的完全不知道)。第 1 周的提示词写了当时的全部政策——之后没人改它。
  • 用户的反应:每类失败让用户”看得见”的程度不同:不知道太阳能计划,用户会困惑、换说法、要求转人工;补偿给多了,用户只会高兴。

提醒:遵守规则的概率、用户反应的概率、标注者的准确率、合成生成器的偏差都是旋钮(各模块开头);轨迹的结构、抽取规则、信号的统计、抽样估计、错误日志与修复的时机、MinHash、最近邻分类都是真的计算。

0.6 开场:上线之后,数据才真正开始

前九讲大部分时候,我们手里有一个固定的数据集:第 3 讲的 96 道题、第 9 讲的 850 张报销单。真实的智能体不是这样:它上线以后,每天产生成百上千条对话;用户的需求在变(新产品)、公司的规定在变(新政策)、“什么算做得好”本身也在变。

第 9 讲的每一种优化方法都在消费数据:GEPA 要带反馈的例子,蒸馏要老师的标签,BetterTogether 要正确的轨迹,DPO 要偏好对,所有方法都要一个没碰过的测试集。这一讲问它们从哪来。Shankar 的文章给了一个框架:数据飞轮——用线上数据持续评估、监控、改进系统;Tan et al. 的综述则系统地整理了用 LLM 来生成和标注数据的做法。


1. 智能体需要什么数据 · What data do agents need

1.1 轨迹:一切数据的原材料

代码 01 让第 1 周的提示词跑第 9 周(太阳能已上线、补偿上限已下调)的 400 条对话。一条轨迹的日志长这样(一张补偿单:用户要 100 美元,智能体按提示词里的旧上限给了 50,而新上限是 30):

{"rid": "R09-0009", "week": 9, "prompt_version": "v1", "signals": {"thumbs": null, "rephrase": false, ...}, "confidence": 0.823, "tokens": 572}
   user   : Hi, this is Kai Moreno. The power was out for hours. Please credit my account 100 dollars.
   agent  → get_account(fields="outage_logged")
   agent  → issue_credit(amount=50)
   agent  : I've added a 50 dollar credit.

一周 400 条对话的 JSONL 日志约 296 KB、23.6 万个 token。日志里有:用户说了什么、调用了哪些工具和参数、回了什么、用户有什么反应、用了哪个版本的提示词。日志里没有:这次对话对不对、违反了哪条规定、用户真正想要什么。这一周的真实成功率是 68.0%,但光看日志不知道——这些要靠标注。

记日志的几条工程要点(第 5 讲 §5.4 的追踪):记下提示词和模型的版本(之后才能比较)、工具的参数和结果、用户的后续行为;写入前脱敏;用 JSONL 这样可以逐行追加、逐行读的格式,坏行要能跳过。

1.2 从轨迹里能拿到什么

示范(SFT 数据):成功轨迹里的每一个”上下文 → 动作”都是一个样本。关键是”成功”怎么判断:

选择方法轨迹(上下文 → 动作) 样本其中真失败的轨迹其中”用户不会抱怨”的违规
全部轨迹4001,261128(32%)46
用户没有任何负面信号3161,08157(18%)40
用户点了赞10340(0%)0
人工审核判成功(随机抽 40 条审核)311081(3%)1

“用户没抱怨”的 316 条里有 57 条其实失败了,其中 40 条是用户根本不会抱怨的那几类:补偿超过上限、没有停电记录也给了补偿、没验证 PIN 就改了地址。拿它们做示范,就是在教模型违反政策。点赞的轨迹很干净,但只有 10 条;人工审核过的干净得多,但贵、少。

偏好对:两个版本的提示词(第 1 周的 v1、按第 9 周政策更新的 v2)跑同样的请求,再判断哪个好:

谁来判断哪个更好得到的偏好对方向对的方向反的其实一样好 / 一样差
真实结果(理想情况)13813800
用户没有负面信号12068844
人工审核139126013

用”没有负面信号”当裁判,120 对里只有 68 对方向对:8 对把一个失败了、但用户没吭声的回答当成了更好的,44 对两个回答其实一样好或一样差——是信号的噪声造出来的”偏好”。第 9 讲的 DPO 就是用这样的数据训练的:偏好数据的质量取决于裁判。

1.3 四种数据,四种要求

数据从哪来用来先要确认什么
示范(轨迹 → SFT 样本)成功的轨迹微调、少样本示范、蒸馏真的成功了(包括用户不会抱怨的那些规则)
偏好对同一请求的两个回答DPO / RLHF、比较两个版本谁更好的判断是可靠的;两个回答来自同样的输入
反馈(显式 / 隐式信号)用户的行为监控、挑选要审核的轨迹信号覆盖哪些失败、漏掉哪些失败
评估用例(4 元组)标注过的请求 + 环境 + 停止条件 + 判分器衡量系统、比较版本和优化用的数据分开;跟得上流量和政策的变化

(“请求、环境、停止条件、判分器”的 4 元组来自 Press 的 benchmark 写作建议,第 12 讲细讲。)


2. 从人和智能体的交互中收集数据 · Collecting data from human–agent interaction

2.1 显式信号和隐式信号

代码 02:第 9 周 400 条对话,真实失败 128 条。每种信号能抓住多少失败?

信号出现次数覆盖了多少失败(召回)出现时真是失败(精确)
点踩97%100%
换个说法再问3724%84%
要求转人工2419%100%
7 天内回头再找4127%83%
任何一种负面信号8455%85%
置信度 < 0.75642%96%

显式反馈极其稀疏:点踩 9 次,只覆盖 7% 的失败。隐式信号多得多,但每个都有噪声(成功的对话里也有人换个说法、过几天又来问别的事)。所有负面信号合起来覆盖 55%——信号适合用来挑要看的轨迹,不适合直接当标签。

2.2 看不见的失败

按失败的类型看,用户看得见吗?

失败的类型(违反的规则)次数有任何负面信号
solar(不知道太阳能计划)4783%
credit_cap(补偿超过上限)4012%用户不会抱怨
lookup(没先查客户)2572%
misunderstood(听错了)1984%
credit_outage(没停电也给补偿)520%用户不会抱怨
verify_pin(没验证 PIN)40%用户不会抱怨

(credit_cap 的 12% 来自同一对话里的其他失败。)最贵的失败——钱、安全、合规——恰恰是用户不会告诉你的。它们只能靠主动审核发现:这是为什么任何只靠用户反馈的改进流程,都会系统性地漏掉一类问题。

2.3 谁在说话

12 周合计,按用户类型看显式反馈:

用户类型对话点赞点踩给了反馈的比例
普通(calm)2,91076574.6%
话多(vocal)718492510.3%
沉默(silent)1,172080.7%

“话多”的用户只占 15%,给反馈的比例却是普通用户的两倍多;“沉默”的用户几乎不给。点赞 / (点赞 + 点踩) = 58%,而 12 周的真实成功率是 80%——反馈代表的是愿意说话的那些人,它的比例不是成功率。

2.4 估计 vs 发现:两种抽样

估计第 9 周的真实成功率(68.0%):

估计方法看了多少花费(美元)估计的成功率
1 − 负面信号比例全部 400 条079.0%
点赞 / (点赞 + 点踩)19 次反馈052.6%
随机抽 40 条人工审核40 条8065.0% [49.5, 77.9]
按信号挑 40 条人工审核40 条8010.0%
LLM 评审看全部(提示词里是第 1 周的政策)全部 400 条481.8%
LLM 评审看全部(提示词更新到当前政策)全部 400 条472.5%
  • “1 − 负面信号比例”漏掉了看不见的失败,偏高;点赞比例偏得没有方向。
  • 随机抽查是无偏的,但 40 条的置信区间有 28 个点宽(第 12 讲会讲需要多少样本)。
  • 按信号挑着查严重偏低:挑的就是可疑的——它是找问题的好办法,却不能用来估计水平。
  • LLM 评审便宜,但它的判断标准是它提示词里的政策;政策变了没人告诉它,它就看不出新上限下的违规(§3.4 的标准漂移)。

第一条经验:找问题用”按信号挑”(富集失败),量水平用”随机抽”(无偏)。两件事、两种抽样,不要混。


3. 数据飞轮 · Data flywheels

3.1 Shankar 的三步

Shankar 的 Data Flywheels for LLM Applications 的出发点:人的偏好会变、LLM 不一定照指令办事,所以评估不能只做一次,要变成一个持续转动的循环:

  1. 评估:定义成功的指标。指标要从数据里来,而不是凭空想出来——先读大量真实输出,再决定检查什么(文中的例子:发现输出里总有”delve”这样一看就是 AI 写的词);能用代码检查的用代码,主观的用 LLM 评审,并给评审少量好坏示例来对齐;优先用二元的指标(对 / 错),比 1–5 分更容易对齐、标注更一致;多步的流水线要在每个节点设检查点(分类节点看准确率,写作节点看质量,写代码的节点跑测试);输入也要检查(话题是否支持、是否含敏感信息、是否异常)。
  2. 监控:让指标跑起来。定期抽样、标注线上数据,标签带时间戳;标准会漂移——新的失败模式出现、模型 API 变了,指标本身要定期复审;让 LLM 评审”动态”起来:检索相关的已标注例子当少样本示范,优先使用人和评审意见不一致的例子(主动学习),近期的标签权重更高。
  3. 持续改进:闭环。记录输出和指标分数;手动迭代(看低分的簇、分析输入的模式、A/B 测试提示词);自动修复(把低分输出改好、记录理由,改好的轨迹在运行时作为最相似的少样本示范);把”质量”拆成多个指标,标注更一致、评审更容易对齐、也更容易定位是哪一项坏了。

3.2 一个每周转一圈的飞轮

代码 03(flywheel.py)把它写成每周一圈:用当前提示词跑这周的 400 个请求 → 按某种策略挑一些去标注 → 失败按原因记进错误日志(跨周累积)→ 某个原因累计 3 次 → 工程师查政策、把规则写进提示词,下周生效 → 标注过的加进评估集。比较六种策略:

策略第1周第5周第8周第9周第12周第 8–12 周平均12 周标注花费(美元)修好太阳能修好补偿上限
不转飞轮91%86%71%70%70%71.4%0没修没修
只审核点踩的对话89%87%83%79%82%81.5%128第 5 周没修
每周随机抽 40 条89%84%78%89%89%86.8%960第 6 周第 8 周
按信号优先挑 40 条92%84%80%80%82%81.8%960第 5 周没修
30 条按信号 + 10 条随机90%88%84%89%88%86.9%960第 5 周第 8 周
LLM 评审看全部 + 10 条人工抽查89%86%82%81%86%85.4%287第 5 周第 9 周

(“修好”指那一周的错误日志里攒够了证据;修改下一周生效。)

  • 不转飞轮:91% → 70%。没有人改提示词,世界却变了。上线不是终点,而是飞轮的起点。
  • 只看点踩、按信号挑:能发现用户看得见的问题(太阳能,第 5 周就攒够了证据),但永远发现不了补偿超过上限——用户只会高兴。
  • 加上随机抽查(mixed、纯随机)才能发现看不见的失败;mixed 两者兼顾:既能快速找到看得见的问题,又不漏掉看不见的。
  • LLM 评审全量便宜(287 美元),但它的政策是团队提示词里写的旧政策,看不出补偿上限的问题;最后靠每周 10 条人工抽查慢慢攒够证据,第 9 周才修好。

3.3 估计也要用对的样本

各策略用自己标注的数据估计成功率(估计 / 真实):

策略第 3 周第 6 周第 9 周第 12 周
每周随机抽 40 条90% / 91%80% / 85%85% / 89%90% / 89%
按信号优先挑 40 条57% / 90%55% / 92%50% / 80%52% / 82%
30 条按信号 + 10 条随机60% / 89%60% / 90%68% / 89%55% / 88%
LLM 评审看全部 + 10 条人工抽查86% / 90%88% / 89%88% / 81%84% / 86%

按信号挑出来的样本估出来的成功率只有真实的一半多——§2.4 说过,它是用来找问题的。mixed 策略如果要报告整体水平,应该只用那 10 条随机样本(或者按抽样概率加权)。

3.4 评估集会过时;标准会漂移

评估集会过时。让一直不改的智能体(第 1 周的提示词)每周在三种评估集上各报告一个数:

第几周线上真实第 1 周的请求 + 第 1 周的标准本周的请求 + 第 1 周的标准本周的请求 + 本周的标准
193.8%91%86%94%
585.5%87%89%87%
872.0%93%87%75%
1268.8%93%90%68%

第 12 周线上只有 69%,第 1 周建的评估集还报告 93%。就算换成本周的请求,用第 1 周的标准判分也报告 90%——请求要跟上流量,判分标准也要跟上政策。

标准漂移(criteria drift)。Shankar 和合作者在 Who Validates the Validators?(第 11 讲的阅读材料)里观察到:人在给输出打分的过程中,才逐渐明确自己的标准;有些标准依赖于看到的具体输出,没法事先定死。在我们的飞轮里,它表现为 LLM 评审的”政策”有没有更新:

LLM 评审修好补偿上限第 8–12 周平均第 9 周 估计 / 真实
评审的政策 = 团队提示词里写的(政策变了没人告诉它)第 9 周85.4%88% / 81%
评审的政策 = 公司当前的政策第 8 周87.3%88% / 90%

评审本身也是要维护的数据:它的提示词、它的少样本示例、它对照的政策,都要和业务一起更新。

3.5 标注预算

mixed 策略(3/4 按信号、1/4 随机),每周审核多少条:

每周审核几条第 8–12 周平均12 周花费(美元)修好太阳能修好补偿上限
882.8%192第 6 周没修
2085.0%480第 5 周第 9 周
4086.9%960第 5 周第 8 周
8086.9%1,920第 5 周第 8 周

预算决定问题被发现得多快;超过某个量之后,多审核只是在重复确认已知的问题。剩下的 10% 左右是”听错了”之类改提示词修不好的失败——那是第 9 讲权重或推理算力的事。


4. 合成数据与 LLM 标注 · Synthetic data and LLM annotation

4.1 用 LLM 生成和标注数据

Tan et al. 的综述把”用 LLM 做数据”分成三个方面:用 LLM 生成标注(让 LLM 给数据打标签、写理由、生成指令和回答、生成成对的偏好)、评估 LLM 生成的标注(怎样判断这些标签和数据的质量)、利用 LLM 生成的标注(拿它们做监督学习、对齐、推理训练等);并讨论了它的局限:偏差、幻觉、和真实分布的差距、以及评估这些数据本身的困难。

为什么要合成数据?真实数据少(新产品刚上线,太阳能请求一共没几条)、贵(人工标注每条 2 美元)、来得慢(要等用户来问)、可能有隐私问题。代码 04 用一个模拟的生成器(data_lab.SyntheticGenerator)演示它的典型问题——它的偏差是我们设定的;06_real_llm.py 可以用真实的 Claude 检验这些偏差是否真的存在。

4.2 重复

直接生成 1,000 条请求:

去重方法去掉剩下
完全相同(字符串相等)604396
MinHash 相似度 ≥ 0.9 算重复604396
MinHash 相似度 ≥ 0.7 算重复628372
MinHash 相似度 ≥ 0.5 算重复856144
(对照)1,000 条真实请求,相似度 ≥ 0.7397603

生成器反复写同一个模板、只换名字和日期——数量多不等于信息多。

MinHash 是近似去重的标准工具:把一段文本切成”词的 3-gram”集合;用 k 个哈希函数,每个函数下取集合里的最小哈希值,得到长度 k 的签名。两个集合的签名里”同一位置相等”的比例,是它们 Jaccard 相似度(交集 / 并集)的无偏估计。签名越长越准:300 对文本上平均绝对误差 k=16 时 0.057,k=64 时 0.027,k=256 时 0.013。签名短、可以分桶(LSH)只比较可能相似的那些,所以能处理几百万条文本。

4.3 分布:难的情形被”洗干净”了

特征真实流量直接让 LLM 生成照着真实日志生成
意图:改期 / 补偿 / 转人工23% / 19% / 6%14% / 14% / 14%24% / 18% / 7%
说话含糊 / 有错别字13%0%15%
改期请求里日期含糊22%0%23%
改期请求里要求周末23%0%23%
补偿请求里没有停电记录34%0%29%
补偿请求里金额 > 5036%0%32%

直接生成的数据意图均匀、语言干净、情形”标准”——最容易出错的那些情形恰恰被洗掉了。“照着真实日志生成”(给生成模型几条真实对话当示范、指定用户画像和场景)的比例和真实流量接近得多。

4.4 在合成数据上评估会高估多少

(判分用第 12 周的政策。)

智能体真实流量直接生成的合成数据照着日志生成的合成数据
只有任务说明、没写任何政策41.8%48.1%43.3%
第 1 周的提示词68.8%71.4%71.3%
按第 12 周政策更新的提示词88.5%90.8%90.2%

高估多少取决于智能体弱在哪:没写任何政策的智能体在周末、含糊日期、没有停电记录这些情形上更容易错,而这些情形在直接生成的数据里被洗掉了,所以高估了 6 个点;第 1 周的提示词剩下的失败(太阳能、补偿上限)在合成数据里也有,只高估了 2.6 个点。合成数据的盲区和智能体的弱点重合得越多,评估就偏得越多——而你事先不知道它们重不重合。

第二条经验:合成数据最适合补覆盖(新意图、罕见情形、对抗样本),不适合单独拿来评估。要评估,就让它的分布照着真实日志,并且和真实数据一起报告。

4.5 LLM 当标注者

第 12 周、第 1 周提示词的 400 条对话:

标注方式和真实结果一致漏掉的失败花费(美元)
人工审核全部97.0%6800
LLM 评审全部89.0%304
LLM 评审全部 + 人工复查它判失败的和随机 20 条(共 124 条)91.8%33252

LLM 便宜两百倍,但漏报多。混合方案的一致率升了,升的部分来自纠正 LLM 的误报;LLM 判”成功”的那些失败人根本没看到,漏掉的失败没有减少(人复查时也会看漏几个)。人要放在 LLM 最可能错的地方——而 LLM 的漏报恰恰藏在它很有把握的”成功”里。更好的做法是在 LLM 判成功的样本里也随机抽查,估计它的漏报率(第 11、13 讲)。


5. 用于优化的数据 vs 用于评估的数据 · Data for optimization vs. evaluation

同一批数据,拿来”改系统”和拿来”量系统”,会互相污染。代码 05 演示四种常见的方式。

5.1 在测试集上优化

把第 9 讲的 GEPA 跑两遍(3 个种子):一遍在验证集上挑候选、在测试集上报告;一遍直接把测试集当成挑候选的集合:

做法报告的数字全新数据(1,000 张)高估
正确:在验证集上挑,在测试集上报告89.8%89.3%+0.5%
污染:把测试集当成挑候选的验证集92.3%84.9%+7.4%

优化器在哪个集合上挑,哪个集合的分数就不能再当作”没见过的数据”。污染的那一组在全新数据上反而更差:100 张测试单子太少,挑出来的是”恰好在这 100 张上好”的候选。

5.2 反复看同一个评估集

团队一版一版地改提示词,每次在同一个 100 张的评估集上看一眼,留下最好的:

试了几个版本挑中的版本在评估集上同一个版本在全新数据上高估
164.0%58.9%+5.1%
567.0%70.2%−3.2%
2086.0%75.0%+11.0%
8087.0%75.1%+11.9%

(1 个、5 个版本时的差别主要是 100 张评估集本身的抽样误差。)版本越多,评估集上的最高分里运气越多——第 5、9 讲的赢家诅咒。每一次”看一眼评估集再决定”,都在把评估集变成训练集。要留一个只在最后看一次的测试集;常用的评估集要定期更换。

5.3 时间漂移:随机切分 vs 按时间切分

一个按第 4 周政策写的提示词(不知道太阳能),用两种评估集预测第 9–12 周的表现:

评估集其中太阳能请求报告的成功率
第 1–8 周里随机抽 200 条6%81.0%
最近一周(第 8 周)抽 200 条12%70.5%
(真实)第 9–12 周的全部流量13%69.8%

流量在变时,评估集要按时间切(用最近的数据),随机切分会把过去平均进来。同样的道理也适用于训练 / 测试的切分:用过去训练、用未来测试,才模拟得了上线后的情形。

5.4 近似重复泄漏

把评估用例”改写”一下(换个商家名、换个说法)混进训练数据或少样本的检索池,是最隐蔽的污染。代码 05 用一个最近邻分类器(“记忆”的极端情形,相当于动态少样本检索:找最像的已标注例子、抄它的答案)在报销审核任务上演示:

检索池条数评估集(150 张)全新数据(500 张)高估
600 张独立的标注单子60076.7%73.2%+3.5%
再加上评估用例的改写(每张改写 2 次,+300 条)90096.7%73.0%+23.7%

评估集上的 96.7% 是”抄”来的。和评估集去重能修好它,但去重本身有讲究:

和评估集去重:怎样比较去掉的改写(共 300)误伤的独立单子(共 600)评估集全新数据
整张单子,阈值 0.630038764.0%65.4%
去掉模板文字,阈值 0.6120090.0%73.2%
去掉模板文字,阈值 0.42761677.3%73.2%
去掉模板文字,阈值 0.32987275.3%71.8%
  • 直接比较整张单子:每张都有的字段名和汇率行让所有单子都”相似”,误伤了 387 张好数据——比较之前先去掉模板。
  • 阈值要在”漏掉泄漏”和”误删好数据”之间取舍:0.6 只抓到 120 条改写(评估集仍虚高到 90%),0.4 抓到 276 条、误伤 16 张,0.3 几乎全抓到、误伤 72 张。

第三条经验:合成数据、数据增强、从网上抓来的数据、动态少样本的检索池——进训练(或进提示词)之前,都要和评估集去重。大模型的”测试集污染”(benchmark 的题目出现在预训练数据里)是同一个问题的放大版。


6. 用真实模型试一试 · Try it on a real model

06_real_llm.py(可选,需要 pip install anthropic 和 ANTHROPIC_API_KEY,2 次调用)让真实的 Claude 用两种方式各生成 40 条客服请求——只说要求 / 给 6 条真实的请求当示范——然后用 MinHash 去重、用关键词粗略统计意图、含糊日期、周末、错别字的比例,和真实流量比。

python3 06_real_llm.py

不联网检查脚本本身:python3 06_real_llm.py --toy(用模拟的生成器)。

读结果时想一想:真实模型生成的请求会不会也”过于干净”?给了真实示范之后,错别字和含糊日期出现了吗?意图的比例像不像真实流量(关键词分类很粗糙,只看大的差别)?40 条里有多少近似重复?编写时没有用真实 API 跑过这个脚本,这里不报告数字。


7. 一份数据计划 · A data plan

给一个要上线的智能体写数据计划时,逐条回答:

  1. 记什么:每条轨迹的输入、每一步(工具和参数)、输出、提示词和模型版本、用户的后续行为;写入前脱敏;保留多久。
  2. 标什么、谁来标:成功与否 + 失败原因(二元、按规则拆开);人工审核员拿的是当前的政策手册;LLM 评审的提示词和政策一起更新,并定期用人工标注验证它(第 13 讲)。
  3. 挑什么去标:按信号挑一部分(找问题),随机抽一部分(量水平、发现看不见的失败),两部分分开统计。
  4. 错误日志:失败按原因累积;够证据就修;修了之后看那一类失败是否真的消失。
  5. 评估集:和优化用的数据分开;按时间更新(最近的流量);判分标准随政策更新;留一个只在发布前看一次的测试集。
  6. 合成数据:用来补覆盖(新意图、罕见和对抗情形),照着真实日志生成;进训练或检索池之前和评估集去重。
  7. 示范和偏好数据:只用确认过的成功轨迹;偏好对的裁判要可靠(审核过的,而不是”用户没抱怨”)。

8. 小结 · Summary

  1. 轨迹是原材料:日志能记下输入、步骤、输出和用户反应,记不下”对不对”——那要靠标注。示范、偏好对、反馈信号、评估用例各有用途,也各有要求:示范要确认真的成功,偏好对要可靠的裁判,信号要知道它漏掉了什么,评估用例要和优化数据分开、跟得上变化。
  2. 用户反馈有盲区:显式反馈稀疏、偏向愿意说话的人;隐式信号多但有噪声;最贵的失败(钱、安全、合规)用户不会告诉你。找问题用按信号挑,量水平用随机抽。
  3. 数据飞轮:评估 → 监控 → 改进,每周转一圈。只靠用户信号的飞轮发现不了看不见的失败;加上随机抽查才行。评估集会过时,判分标准会漂移——评审本身也是要维护的数据。
  4. 合成数据与 LLM 标注:生成的数据会重复、过于干净、分布不对;照着真实日志生成能缩小差距;在合成数据上评估会高估,高估多少取决于它的盲区和智能体的弱点重不重合。LLM 标注便宜但漏报多,人要放在它最可能错的地方。
  5. 优化数据和评估数据要分开:在测试集上优化、反复看同一个评估集、随机切分遇上漂移、近似重复泄漏,都会让报告的数字虚高;去重要先去掉模板、再在漏报和误删之间选阈值。

9. 常见误区 · Common pitfalls

  • “日志全记下来了,数据就有了。” 日志里没有”对不对”;没有标注的轨迹只是原材料。
  • “用户没抱怨,就是成功。” 第 9 周”没有负面信号”的轨迹里 18% 其实失败了,大多是用户不会抱怨的违规(多给钱、没验证身份)。
  • “点赞率就是满意度、就是成功率。” 点赞 / (点赞 + 点踩) = 58%,真实成功率 80%;给反馈的主要是话多的那部分用户。
  • “把可疑的对话挑出来审核,顺便就知道整体水平了。” 按信号挑的样本估出来的成功率只有真实的一半多。
  • “评估集建好了就能一直用。” 第 1 周的评估集在第 12 周报告 93%,线上只有 69%。
  • “换上最新的请求,评估集就不会过时。” 判分标准也要更新:用旧政策判新请求还报告 90%。
  • “LLM 评审全量标注,又便宜又全面。” 它只认识它提示词里的政策;它的漏报藏在它很有把握的”成功”里。
  • “合成数据越多越好。” 1,000 条里 60% 是完全重复;它还把最难的情形洗掉了。
  • “在合成数据上测过了,上线也差不多。” 高估多少取决于合成数据的盲区和智能体弱点的重合,你事先不知道。
  • “数据增强是好习惯。” 把评估用例改写一下混进检索池,评估集准确率从 76.7% 变成 96.7%,全新数据上一点没涨。

10. 练习 · Exercises

练习 1(选示范):代码 01 里,“用户没有任何负面信号”的轨迹有 316 条,其中 57 条失败。(a) 如果拿这 316 条做 SFT,模型会学到什么坏习惯?(b) 只用人工审核过的 31 条又有什么问题?(c) 设计一个折中方案。

参考答案 (a) 40 条是"用户不会抱怨"的违规:补偿超过上限(按旧上限给 50)、没有停电记录也给补偿、没验证 PIN 就改地址——模型会学到"多给钱、跳过验证"是正常做法;另外 17 条是其他失败(例如不认识太阳能计划时的含糊回复)。(b) 太少,而且随机抽的 31 条大多是简单的请求,覆盖不了罕见情形。(c) 例如:用"没有负面信号"做初筛,再用**程序检查**看得见的规则(issue_credit 的金额是否 ≤ 当前上限、update_address 之前是否有 verify_pin、太阳能请求是否调用了 check_solar_eligibility)过滤掉违规;剩下的再按意图分层抽一部分人工审核,估计残留的错误率;高风险意图(补偿、改地址)只用人工确认过的。

练习 2(信号的召回和精确):代码 02 里”任何一种负面信号”出现 84 次、精确 85%、召回 55%,真实失败 128 条。(a) 验证这几个数互相一致。(b) 如果每周只能审核 40 条,全部从有信号的对话里挑,期望能找到多少个失败?随机挑呢?

参考答案 (a) 有信号且真失败 = 84 × 0.85 ≈ 71;71 / 128 ≈ 55%,一致。(b) 从有信号的里挑 40 条,期望 40 × 0.85 = 34 个失败;随机挑 40 条,期望 40 × 128/400 ≈ 12.8 个。按信号挑找到的失败多将近 3 倍——但找到的都是"看得见"的那类,而且不能拿来估计整体成功率。

练习 3(估计的置信区间):随机抽 40 条审核,32 条成功。(a) 用正态近似算 95% 置信区间。(b) 要把区间半宽缩到 ±5 个点,大约要抽多少条?(c) 这和每周 400 条的流量比,意味着什么?

参考答案 (a) p̂ = 0.8,标准误 = √(0.8 × 0.2 / 40) ≈ 0.063,95% 区间 ≈ 0.8 ± 0.124,即 [67.6%, 92.4%](代码里用 Wilson 区间,形状稍有不同)。(b) 1.96 × √(0.8 × 0.2 / n) = 0.05 ⇒ n ≈ 246。(c) 要把每周的成功率估到 ±5 个点,几乎要审核一半的流量;实际做法是按月汇总、或者用 LLM 评审全量估计再用少量人工样本校正它的偏差(第 13 讲)。

练习 4(为什么按信号挑会偏):用贝叶斯公式解释:按信号挑出来的 40 条里成功率约 50%,而整体成功率 80% 左右。

参考答案 P(成功 | 有信号) = P(有信号 | 成功) · P(成功) / P(有信号)。成功的对话也有少量"误报"信号(例如 3% 换个说法、4% 回头再找),失败的对话有信号的概率高得多(看得见的失败 50% 以上)。整体 80% 成功时,P(有信号) 主要由失败贡献,所以有信号的对话里成功的比例远低于 80%。按信号挑,就是在条件 P(·| 有信号) 下抽样——它回答的是"有信号的对话里有多少失败",不是"所有对话里有多少失败"。如果非要用这批样本估计整体,要按抽样概率加权(逆概率加权),这需要知道每条对话被挑中的概率。

练习 5(设计飞轮):代码 03 的飞轮假设”错误日志里一个原因攒够 3 条,工程师就能把规则写对”。(a) 现实中这一步可能怎样出错?(b) 怎样验证一次修复真的生效了?(c) 什么情况下修复会引入新的问题?

参考答案 (a) 3 个例子可能来自同一个特殊情形,归纳出的规则过窄或过宽;工程师不知道政策的细节(例如新上限是否对老客户也适用);修复写进了提示词,但和已有规则冲突,或者让提示词变长、其他规则被遵守得更差(第 9 讲 §1.3)。(b) 在修复之后的流量里,专门统计那一类失败的比例(需要随机样本),并在评估集上回归测试所有其他类别;最好先在一小部分流量上 A/B 测试。(c) 修复过宽(例如为了修补偿上限,写成"拒绝所有补偿请求")、改变了其他意图的行为;或者修复针对的是错误的原因(第 9 讲 §3.3 的归因问题)。所以修复之后要看**所有**类别,而不只是被修的那一类。

练习 6(标准漂移):举出你熟悉的一个场景里”判分标准需要随时间更新”的三个原因,并说明每种情况下谁应该负责更新评估。

参考答案(之一) 以客服为例:(1) 政策变了(补偿上限、退货期限)——政策团队变更时同步通知评估的维护者,评估集的判分器版本号跟政策版本绑定;(2) 产品变了(新功能、新套餐)——产品上线流程里加一步"补充评估用例";(3) 用户期望变了(例如过去可以接受的"请稍候"现在被视为差体验),或者团队在看输出时发现了新的失败模式(Shankar 的观察:标准是在看输出的过程中形成的)——由做错误分析的人提出、经评审后加进评分细则。共同点:评估是一份要版本管理、要有人负责的资产。

练习 7(合成数据的覆盖):太阳能计划刚上线时,真实请求只有十几条。设计一个用 LLM 生成太阳能相关测试用例的流程,使它尽量覆盖真实会遇到的情形,并说明怎样检查生成的数据。

参考答案(之一) 1) 先列出情形清单(不是让 LLM 自由发挥):有资格 / 没资格、地址不在服务区、已经在计划里、想退出、问价格、说话含糊或有错别字、夹带别的请求("顺便改个地址")、不认识"solar"这个词的说法;2) 每个情形给 LLM 几条真实的请求当示范、指定用户画像(年长用户、着急的用户、非母语用户),各生成若干条;3) 去重(先去掉模板、再 MinHash),并和评估集去重;4) 检查分布:每个情形的数量、错别字和含糊表达的比例、和真实请求的相似度;5) 人工读一个样本,确认情形标签对、请求自然;6) 生成的用例用于**覆盖测试**,报告时和真实请求上的结果分开。

练习 8(LLM 标注者的漏报):代码 04 里 LLM 评审漏掉 30 个失败,混合方案还漏掉 33 个。设计一个更好的人机分工,并说明怎样估计最终标签里还剩多少漏报。

参考答案(之一) 在 LLM 判"成功"的样本里也随机抽一部分人工复查(例如 10%),用它估计 LLM 的漏报率 r;对已知 LLM 容易漏的类别(例如需要知道最新政策的补偿上限、需要看工具调用顺序的 PIN 验证)用程序检查或者全部人工复查;人和 LLM 不一致的例子拿去更新 LLM 评审的提示词(少样本示例、政策)。最终的漏报数 ≈ LLM 判成功的条数 × r(只在没被人工复查的那部分上),给出置信区间。这本质上是第 13 讲"用少量人工标签校准 LLM 评审"的做法。

练习 9(反复看评估集):代码 05 里,试 80 个版本后评估集高估了 11.9 个点。(a) 解释为什么版本越多高估越多。(b) 列出三种减轻它的做法。

参考答案 (a) 每个版本在评估集上的分数 = 真实水平 + 抽样噪声(100 张时标准差约 4–5 个点)。挑最高分时,挑中的往往是噪声恰好为正的那个;版本越多,最大的噪声越大(大约随 √(2 ln K) 增长)。(b) ① 留一个只在最后看一次的测试集;② 增大评估集(噪声随 1/√n 下降)或者用配对比较(两个版本在同一批例子上比,噪声小得多,第 12 讲);③ 定期更换评估集、限制每个评估集被查看的次数;④ 对"最好的版本"在全新的数据上复测再上线。

练习 10(开放题:给你的智能体写一份数据计划):选一个你熟悉或者想做的智能体(例如帮研究生找文献的智能体),按 §7 的七条写一份数据计划,并特别说明:它的”看不见的失败”可能是什么、你准备怎样发现它们。

参考答案(之一) 以文献助手为例:看不见的失败包括引用了不存在的论文(用户不一定去查)、漏掉了最重要的相关工作(用户不知道自己不知道)、把论文的结论说反了(用户相信了)。发现它们:① 程序检查——每个引用都去 DOI / arXiv 查是否存在、标题作者是否匹配;② 随机抽查——每周抽 20 条对话,请领域内的人检查结论是否准确、是否漏了关键文献;③ 构造覆盖测试——对一些有公认综述的问题,检查回答是否覆盖了综述里的核心文献。其余几条:记录检索词、检索结果、引用和用户是否点开了引用;评估集按月更新(新论文不断出现),判分标准里"重要文献"的清单要随领域更新;合成问题用于覆盖不同领域和不同表述,进检索池之前和评估问题去重。

11. 延伸阅读 · Further reading

本讲的阅读材料

  • S. Shankar, Data Flywheels for LLM Applications, 2024(sh-reya.com 博客)。
  • Z. Tan et al., Large Language Models for Data Annotation and Synthesis: A Survey, EMNLP 2024.

相关

  • S. Shankar et al., Who Validates the Validators? Aligning LLM-Assisted Evaluation of LLM Outputs with Human Preferences, UIST 2024(EvalGen 与标准漂移;第 11 讲的阅读材料)。
  • O. Press, How to Build Good Language Modeling Benchmarks(博客;请求、环境、停止条件、判分器的 4 元组;第 12 讲)。
  • A. Z. Broder, On the Resemblance and Containment of Documents, 1997(MinHash 的原始论文)。
  • L. Ouyang et al., Training Language Models to Follow Instructions with Human Feedback, NeurIPS 2022(示范数据和偏好数据怎样用于对齐)。

12. 下一讲预告 · Next lecture

第 11 讲 数据选择与质量(11/2)。这一讲说的是”需要什么数据、从哪来”;下一讲问”有了一大堆数据,哪些值得用、怎样保证它们是好的”:怎样找出信息量最大的数据(tinyBenchmarks 用 100 道题估计整个 MMLU 的分数)、过滤与选择的策略、小而精的数据为什么够用(LIMA 的 1,000 条)、标注的实践与一致性、从智能体轨迹里大规模构建训练数据(SWE-smith 从 128 个代码仓库里造出 5 万个任务),以及”谁来验证验证者”(EvalGen)。配套代码会用 IRT 模型挑出最有信息量的评估题、比较几种数据过滤与选择的方法、模拟标注者之间的一致性,并在一个小代码仓库上照着 SWE-smith 的做法自动造出”能让测试失败的 bug”任务。

← 返回课程目录