系列第 6 篇讲 judge 校准时留了个尾巴:金标集从哪来?答案是人。这件事值得用一整篇展开——自动评测的每一层,judge、断言、回归门禁,合法性最终都锚定在人的判断上;而线上用户随手点的一个"踩",可能是整套体系里最便宜也最真实的数据源。人工不是评测体系建成前的过渡形态,是不可拆除的结构件。
本篇系统讲人工的位置与规模化方法:先摆清人工在评测体系里的三重角色,再看用户反馈入口的产品设计、反馈数据的清洗治理、三种人工数据源的选型,然后是标注一致性的日常运营、从用户踩到修复回归的完整链路,最后谈激励与可持续。本文按"角色 → 产品化 → 质量治理 → 数据源选型 → 标注运营 → 改进链路 → 可持续 → 总结"组织全文。
1、人工的三重角色
人工在 EDD 体系里同时扮演三个角色,每个角色回答一个自动化回答不了的问题。
| 角色 | 回答的问题 | 典型产出 |
|---|---|---|
| 地面真值生产者 | "好"的标准到底是什么 | 金标集、锚定样例、rubric |
| 最终裁决者 | 机器拿不准的 case 谁说了算 | 疑难 case 的裁定 |
| 持续监督者 | 指标还代表真实体验吗 | 线上抽样审查报告 |
地面真值生产者是体系的地基。第 6 篇的结论在这里生效:judge 的 kappa 是对着人工金标算出来的,没有金标,judge 分数只是模型的主观意见。金标必须由人产出,且不能由被测模型家族代劳——用模型生成"金标"再校准 judge,等于拿被测系统校准自己,误差闭环放大。InstructGPT 走的 RLHF 路线是同一个逻辑:偏好数据必须真人标,才有资格定义奖励函数。
最终裁决者的出手范围要刻意收窄:judge 换位判后结论漂移的、两个跨厂 judge 分歧大的、置信度低于阈值的,只有这些进人工队列。人贵且慢,让机器先消化 95% 的确定部分,人只裁 5% 的模糊地带,成本才守得住。
持续监督者是唯一面向"现在"的角色。评测集是静态快照,线上分布一漂移,自动指标可能全线绿灯而体验正在变差。每周从线上流量分层抽样一百条人眼看一遍,监控的是"指标与体验的相关性"本身——这是任何自动指标的定义盲区:指标测不出自己与现实的脱钩。
三个角色的共同点:都站在自动化的逻辑边界之外。不是模型不够强,而是交给模型就构成循环论证。
2、用户反馈的产品化
第二个数据源不在标注间里,在产品界面上。反馈入口的设计直接决定数据质量,这里的坑也最密。
2.1、赞踩按钮的陷阱
赞/踩是成本最低的反馈,但两个系统性偏差让它不能直接当质量指标读。
负向偏差:点踩的动机远强于点赞——满意的用户关页走人,不满的才停下来按按钮,赞踩比天然偏离真实满意度,当 KPI 读会系统性高估问题严重度。位置偏差:按钮放答案末尾还是开头、赞在左还是右,都影响点击分布;把"赞"排在"踩"前面,踩率通常会降一截。按钮位置上线前做一轮 A/B,之后就不要再动——位置一变,历史数据就断了口径。
还有一个更根本的短板:一个"踩"的信息量太少。不知道是错了还是不合口味,不知道该修提示词还是修检索——打分采集容易,下游几乎不可用。
2.2、纠错框的设计
更有价值的做法是点踩后展开一个纠错框:几个结构化选项,加一个可选文本框。枚举把"不满"翻译成可归因的类别,自由文本留给真正想说的人。上报的 payload 直接决定下游好不好处理,参考结构如下:
{
"verdict": "down",
"reasons": ["factual_error", "not_answered"],
"comment": "给的 API 参数名不存在,应该是 maxTokens",
"case_id": "sess_8f3a2c",
"user_hash": "u_7742",
"client_ts": "2026-10-25T09:14:03+08:00"
}
解读:reasons 用受控枚举做主渠道,保证下游能按类别聚合;comment 是补充而非必填,降低反馈门槛;case_id 指向完整会话快照,处理的人能还原现场;user_hash 为第 3 节的清洗和第 7 节的闭环告知留钩子。枚举清单本身要随运营迭代——某类问题在文本框里反复出现,就升格为正式选项。
2.3、沉默大多数问题
最深的坑是:会点按钮的用户本来就是极少数。Nielsen 2006 年的经典文章参与度不均等给出 90-9-1 法则——约 90% 的用户只看不反馈,9% 偶尔反馈,1% 贡献了大部分内容。落到赞踩上更极端,而且沉默不等于满意,多数只是懒得说。
对策是把"等反馈"换成"主动测":行为代理指标(重试率、答案复制率、会话中途放弃率)覆盖全部流量,弥补反馈样本的稀疏;每季度一轮小样本用户访谈,专门去问沉默用户。反馈按钮测的是愿意说话的人,代理指标测的是所有人,两套数据对着看才完整。
3、反馈数据的质量治理
反馈进 backlog 之前先过清洗。三类噪声要分开治理:误点(手滑、没看清就点)、恶意点(刷踩、脚本)、无意识点(心情不好迁怒于产品)。治理思路是置信度加权加模式识别,清洗骨架如下:
# clean_feedback.py —— 反馈置信度加权与异常模式过滤
def user_weight(user):
w = 1.0
if not user.get("logged_in"):
w *= 0.4 # 未登录降权
if user.get("history_agree_rate", 1.0) < 0.6:
w *= 0.5 # 历史确认误报率高
if user["age_days"] < 3:
w *= 0.6 # 新注册账号
return w
def is_burst(events):
"""同一来源 10 分钟内对同一目标集中反馈 5 条以上,疑似刷量"""
by_key = {}
for e in events:
k = (e["src"], e["case_id"]) # 来源指纹 + 目标
by_key.setdefault(k, []).append(e["client_ts"])
return any(len(ts) >= 5 for ts in by_key.values())
def score(events):
out = []
burst = is_burst(events)
for e in events:
s = user_weight(e) * (0.1 if burst else 1.0)
if e.get("comment") and len(e["comment"]) > 20:
s *= 1.5 # 认真写了说明的反馈更可信
out.append({**e, "confidence": round(s, 3)})
return out
解读:权重不是给反馈"定罪",决定的是处理优先级——高置信度的进待审队列前排,低置信度的攒批抽检。is_burst 抓的是集中刷量的粗模式,实际还要叠加文本相似度聚类,识别换账号复读同一句话的灌水。清洗规则必须有兜底:被过滤的数据留档不删,每周人工抽看过滤结果——真出了坏版本,集中负反馈是正常现象,别当攻击挡掉。
4、三种人工数据源对比
专家标注、众包、用户反馈是三种人工数据,成本结构与适用场景完全不同。
| 维度 | 专家标注 | 众包 | 用户反馈 |
|---|---|---|---|
| 单条成本 | 高 | 中 | 近乎零 |
| 一致性 | 高,kappa 0.8 可达 | 中,依赖质控 | 低,噪声大 |
| 规模 | 百级 | 千到万级 | 随流量 |
| 覆盖 | 按设计走 | 按任务走 | 真实分布 |
| 时效 | 慢 | 中 | 实时 |
选型判断三句话。定义标准用专家:金标集、rubric、边界 case 裁决,量小但每条都要对,背景知识不可替代。扩容用众包:judge 校准集从 50 条扩到 500 条、偏好对采集,众包加三件套质控(金标题、抽检、按质量结算)够用,Label Studio 这类开源平台可以自己搭。发现问题用用户反馈:只有真实用户能把系统推到你没想到的角落,它是新 bad case 的雷达,但信号脏,必须接第 3 节的清洗和第 6 节的人工确认才可用。
三者最好的用法是接力:用户反馈负责发现,专家确认与归因,确认后的 case 沉淀成金标,众包再照金标口径扩容周边数据。
5、标注一致性的运营
第 6 篇讲过 kappa 怎么算、验收线在哪,这里补运营视角——一致性不是验收时算一次的数字,是每周要看的心跳。
指南迭代是运营的核心动作。双人标注的不一致条目不是废料,是金矿:每个歧义 case 仲裁定案后,把结论写回标注指南——要么补一条可核对的判定规则,要么加一个边界样例。指南因此是活文档,要带版本号;大版本更新后,已标数据抽 10% 回标,检查旧数据在新口径下是否仍成立。
kappa 监控要按人和按类别切开看,每周一张报表,实现如下:
# weekly_kappa.py —— 按标注员组合与类别的周级 kappa 报表
import json
from itertools import combinations
from collections import defaultdict
rows = json.load(open("labels_week.json", encoding="utf-8"))
# 结构:[{case_id, category, labels: {标注员: verdict}}, ...]
def kappa(pairs):
n = len(pairs)
po = sum(a == b for a, b in pairs) / n
cats = {x for p in pairs for x in p}
pe = sum(sum(a == c for a, _ in pairs) / n *
sum(b == c for _, b in pairs) / n for c in cats)
return (po - pe) / (1 - pe) if pe < 1 else 1.0
grid = defaultdict(list)
for r in rows:
for a, b in combinations(sorted(r["labels"]), 2):
grid[(a, b, r["category"])].append(
(r["labels"][a], r["labels"][b]))
for (a, b, cat), pairs in sorted(grid.items()):
print(f"{a} × {b} [{cat}] n={len(pairs)} kappa={kappa(pairs):.2f}")
解读:报表的价值在"分开看"。总体 kappa 达标但某个标注员对某类 case 持续偏低,多半是疲劳或该类别定义有洞;某类别所有组合集体走低,是指南问题不是人的问题,回去修指南。两两组合之外,标注员多于两个时换 Krippendorff's alpha 一次算全组,Cohen's kappa 只适合两两。
仲裁流程要事先写死:两人不一致进第三人仲裁,仍分歧升级资深专家定案,所有仲裁结论当天回写指南。仲裁不是纠纷解决,是指南的采集管道。
6、反馈到改进的链路
采集只是上半场,反馈的全部价值在于闭环。全链路如下:
解读:链路的关键不在节点数,而在两个人工卡点。人工确认:没有这一环,清洗漏掉的误报会直接变成 backlog 里的伪需求,工程师追查半天发现"用户其实想点的是赞"——确认环节每周花几个小时,省下的是成倍的无效排期。黄金集回归:确认过的真实 case 必须进回归集,"踩过的地方不再踩"是体系能给出的硬承诺。Hamel Husain 的评估实践反复强调:真实失败样本是评测集里价值密度最高的部分。
用户踩出来的 case 免费、真实、且已被验证值得修——不进回归集就是浪费。
链路健康度盯两个指标:反馈到修复的平均时长,决定用户是否感知"报了有用";重复反馈率,同一问题修复前被反复踩的比例,偏高说明修复太慢或归因错了。
7、激励与倦怠治理
链路是机器的部分,链条两端都是人,人的可持续性要单独设计。
内部标注最大的敌人是倦怠:全职标注两三个月后,对 case 的敏感度肉眼可见地钝化,kappa 悄悄下滑。轮值制比专职制健康——每人每周固定半天标注,配每周半小时标注例会,分享本周最有意思的分歧 case。例会既是质控(歧义 case 当场过),也是激励(标注从流水线变成集体侦探)。预警信号就藏在第 5 节的周报里:某人 kappa 连续三周走低,先谈话减量,别等出错。
用户侧的激励是闭环告知:反馈被确认、被修复时,通知当初反馈的人。2.2 的 payload 里留的 user_hash,就是为了这一刻能把消息送回去。技术上给反馈挂状态机——received → confirmed → fixing → fixed,翻到 fixed 时触发告知;联系方式选填,留了的才通知,别把纠错框做成注册墙。闭环告知对反馈率的提升实打实:用户确认"报了有用",才会继续报。再配一份公开的"已修复"清单,潜在反馈者看到声音有回音,沉默的成本就低一分。
8、总结
人工在评测体系里是结构件不是脚手架:作为地面真值生产者定义"好",作为最终裁决者接管机器的模糊地带,作为持续监督者盯着指标与体验的脱钩。反馈入口要避开赞踩的负向与位置偏差,用纠错框把不满翻译成结构化信号;牢记 90-9-1 法则,沉默是大多数,用代理指标和主动访谈补盲区。反馈数据必须清洗,置信度加权、刷量识别、留档兜底三件缺一不可。三种数据源各就其位:专家定标准、众包扩规模、用户反馈当雷达,最好的用法是接力。标注运营盯三件事:歧义 case 收进指南持续迭代、kappa 周报按人按类别切着看、仲裁结论当天回写。从踩到修复走完整链路,确认环节防伪需求,黄金集回归守住"踩过不再踩";轮值制防倦怠,闭环告知养反馈意愿。
留两个练习:
- 给数据分析 Agent 设计三层反馈采集,写出各层枚举与 payload,并画出完整闭环图
- 为纠错框的
reasons枚举设计清洗规则,说明误点、恶意点、无意识点各自的识别信号
对于已经在收集用户反馈的团队,建议本周做一件事:把最近 50 条踩拉出来人工过一遍——确认率低于一半的话,问题多半不在用户,在反馈入口的设计。

