
agno 数据标注质量度量用 Fleiss kappa、Krippendorffs alpha 与 Cohens kappa 校验 Inter-Annotator Agreement【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno本文讲解 agno 数据标注 cookbook 中_19_inter_annotator_agreement模块的核心思路把同一 judge 模型的多种指令措辞当作独立标注者annotator用纯标准库实现的四项一致性指标——原始一致率raw agreement、Fleiss kappa、Krippendorffs alphanominal与两两 Cohens kappa——度量标注管线是否真正可复现。读完本文你将掌握判断标注者之间的共识有多少是真实信号、多少只是偶然一致的完整方法并可直接运行两个示例情感标注与 DPO 偏好陪审团投票把低一致条目自动路由到人工复核。为什么需要度量标注者一致性任何标注管线只要有两个以上标注者模型、指令措辞或人工接触同一批样本就必须回答一个问题他们的共识里有多少是真实信号原始一致率很容易虚高——当标签分布本身偏斜比如 83% 的投票都是a时即使标注者完全靠猜也会因为都倾向于多数标签而表现出很高的原始一致率。因此标准做法是使用**经过偶然一致校正chance-corrected**的指标。在本模块中标注者被刻意设计为同一个 judge 模型在 temperature0 下的三种不同指令措辞。因为温度为零采样噪声被消除所有分歧都只能追溯到指令措辞本身而不是模型的随机性。这使度量结果具有极强的归因价值如果三种措辞对某条样本产生分歧几乎可以肯定是指南措辞存在歧义而非模型发挥失常。模块实现的核心约定见 basic.py 与 jury_votes.py 的源码注释数据组织为items × raters 矩阵单元格可能为None缺失评分只有krippendorff_alpha和raw_agreement能处理缺失单元格fleiss_kappa要求完整行无缺失遇到缺失必须先在完整行子集上计算四项指标全部用纯标准库实现仅依赖itertools与collections每个文件在发起任何模型调用之前先用手工推导的基准值对实现做self_check()断言。两个示例文件基本一致性校验与陪审团投票模块包含两个可独立运行的文件文件任务标注者样本特殊设计basic.py情感标注positive / negative / neutral三条指令措辞简洁版、详细评分细则rubric、标注者人设persona12 条文本其中 4 条被设计为真正有歧义所有非一致条目路由到 review 列表jury_votes.pydpo_jury 形状的偏好投票a / b / tie三种陪审员措辞简洁版、反冗长评分细则、助教人设8 个刻意偏斜的偏好对一名陪审员在 1 个对上弃权制造缺失单元格运行方式需要GOOGLE_API_KEY默认使用 Geminipython cookbook/data_labeling/_19_inter_annotator_agreement/basic.py python cookbook/data_labeling/_19_inter_annotator_agreement/jury_votes.py一、basic.py情感标注的三措辞实验1. 结构化输出 Schema 与三个标注 Agent三个标注 Agent 共享同一个 Pydantic 输出 Schema保证输出一定是合法标签之一class SentimentLabel(BaseModel): label: Literal[positive, negative, neutral] Field( ..., descriptionThe assigned sentiment label )三个 Agent 均使用agno.agent.Agent构建模型为Gemini(idgemini-3.5-flash, temperature0)唯一的区别是指令措辞basic.py简洁版terseLabel the sentiment of the text: positive, negative, or neutral.——只有一句最简指令不做任何细化详细评分细则rubric显式规则例如讽刺与反语按真实意图而非字面词义标注正负混杂时标 neutral各方面相互抵消fine, I guess 这类勉强夸奖算 neutral 而非 positive纯事实性描述为 neutral标注者人设persona把自己想象成众包平台上的商品评论情感标注员从是否促使消费者下单角度判断纯事实无购买信号才标 neutral。这正是 agno Agent 的典型用法同一个模型、同一个输出 schema仅通过instructions参数注入不同策略就能得到三个行为可区分的标注者。2. 样本设计8 条清晰 4 条刻意歧义12 条文本ITEMS中 8 条是意图明确的清晰案例4 条被刻意设计为真正有歧义basic.py歧义类型示例难点反讽sarcasmOh great, another update that wipes all my settings. Just what I always wanted.字面全是正面词意图是负面正负均衡混合Gorgeous screen and superb speakers, but the battery dies by lunch and the hinge already creaks.两个正面 两个负面是否抵消勉强夸奖faint praiseHonestly, better than I expected. I would not buy it again, but it does the job.轻微正面措辞无真实背书摇摆不定ambivalenceThree stars. Some days I love it, some days I want to throw it out the window.作者本人态度两难歧义样本的价值在于它们是把措辞分歧逼出来的探针。如果三种指令对歧义样本产生分歧说明指南没有覆盖该场景正是需要改进指南措辞的信号。3. 四项一致性指标公式、实现与自检四项指标全部以公式注释 纯标准库实现的形式写在同一文件中basic.py任何指标都可以直接复制到自己的标注管线上使用。原始一致率 raw agreement——每个 item 上标注者配对一致的比例再对全部 item 取平均P_o (1/N) * sum_i [ agreeing_pairs_i / total_pairs_i ]少于两个评分的 item 被跳过。这是最直觉的指标但也是被偏斜分布欺骗最严重的指标。Fleiss kappa每个 item 标注者数相等、无缺失单元格——推广到多个标注者的 kappan_ik 给 item i 标为类别 k 的标注者数 P_i (sum_k n_ik^2 - n) / (n * (n - 1)) 每个 item 的一致率 P_bar (1/N) * sum_i P_i 观测一致率 p_k sum_i n_ik / (N * n) 类别比例 P_e sum_k p_k^2 偶然一致率 kappa (P_bar - P_e) / (1 - P_e)源码中若矩阵存在任何None单元格fleiss_kappa直接抛出ValueError要求调用方传入完整行子集。Krippendorffs alphanominal——唯一在声明层面原生支持缺失单元格的多标注者指标只保留至少有 2 个可配对非缺失值的单元item构建共现矩阵coincidence matrix在每个含 m_u 个值的单元内来自不同标注者的每个有序值对 (c, k) 贡献1/(m_u - 1)到 o_ck计算边际 n_c 与总数 nnominal 分歧度量c ≠ k 时 delta 1alpha 1 - D_o / D_e其中D_o sum_{c≠k} o_ckD_e sum_{c≠k} n_c * n_k / (n - 1)。Cohens kappa——仅用于两两标注者在双方都评过的 item 上计算kappa (p_o - p_e) / (1 - p_e)其中p_e sum_k p_a(k) * p_b(k)是两个标注者各自边际分布的乘积。自检self_checkself_check()在发起任何模型调用前断言实现正确包含两组手工可推导的案例basic.py完美一致矩阵混合类别→ 四项指标全部为 1.02 标注者 × 4 item 矩阵rater A: pos pos neg negrater B: pos neg neg pos→ 原始一致率 0.5、Cohen 0.0、Fleiss 0.0、alpha 0.125。注释中完整推导了每个数字p_o 0.5双方边际均为 0.5/0.5故 p_e 0.5kappa 0alpha 的 D_o 4D_e 32/7alpha 1 − 7/8 0.125。4. 运行流程与 review 路由主流程basic.py为self_check()→ 每个文本 × 每个标注者跑一次构建 item × rater 矩阵 → 打印矩阵与四项指标 → 将所有非全票一致len(set(row)) 1的条目路由到 review 列表并打印各标注者投票。label_text()对每个标注结果做最多 3 次重试只有run.content是合法的SentimentLabel实例时才接受解析失败就重试绝不强转never coerce保证了矩阵中每个单元格都是模型真正输出的结构化标签。根据 TEST_LOG.md 中的一次真实运行记录self_check passed指标为 raw_agreement 0.833、fleiss_kappa 0.742、krippendorff_alpha 0.749、cohen_kappa terse_vs_rubric 0.874、terse_vs_persona 0.739、rubric_vs_persona 0.629。恰好是 3 个被设计为歧义的条目产生分歧并被路由到 review其中反讽条目标为一致 negative混合、勉强夸奖与摇摆条目各标注者意见不一。最终统计12 items × 3 raters9 个全票一致3 个进入复核。由于 temperature0两次运行的输出完全一致但标签仍可能随模型更新在原则上发生变化。二、jury_votes.py把一致性指标应用到 DPO 偏好投票1. dpo_jury 形状的投票矩阵jury_votes.py将同样的四项指标应用到dpo_jury形状的偏好投票上dpo_jury模式定义于 cookbook/data_labeling/_05_text_pairwise_preference/dpo_jury.py给定 prompt 与两个候选回答判断 a、b 哪个更好或平局。class Vote(BaseModel): winner: Literal[a, b, tie] Field( ..., descriptionWhich answer better addresses the prompt, or tie )三名陪审员terse / rubric / persona以 temperature0 运行指令措辞被刻意做成互相冲突的决胜规则简洁版只要求选更好的答案反冗长细则版rubric两个答案都正确时永远选更短的更长的背景、警示、教学内容不得取胜助教人设版persona正确性优先但两个都正确时永远选更有教学性的。这保证了接近的候选对上两个细则会给出相反方向的裁决从而制造有信息量的分歧。2. 偏斜分布与缺失单元格两个关键实验设计标签偏斜是刻意的8 个偏好对中有 6 个构造为a明显更优含正确的 fib 实现、Python 3 bankers rounding、TCP 字节流语义等见 jury_votes.py另外 2 个HTTP 404 与0.1 0.2两个答案都正确恰好让 rubric 的选更短与 persona 的选更有教学性走向相反。偏斜正是原始一致率会粉饰陪审团的场景——多数标签上的偶然一致本来就很高。缺失单元格是模拟出来的真实dpo_jury中陪审员会对自己模型家族生成的候选对弃权self-preference recusal。此处三个措辞共享同一个底层模型因此用硬编码集合RECUSALS {(persona, fib)}让 persona 陪审员在 fib 对上确定性弃权jury_votes.py复现出投票矩阵中的缺失单元格形状。3. 缺失单元格alpha 原生处理Fleiss 只能退而求其次这是本文件最重要的教学点同一份投票矩阵中Krippendorffs alpha 原生处理缺失——它只统计可配对的值被弃权的单元格不贡献任何配对Fleiss kappa 没有原生的缺失数据处理机制实现上直接抛错只能退而在 7/8 个完整行子集上计算。jury_votes.py的self_check()同样在模型调用前断言且专门加入了含缺失单元格的手工案例jury_votes.py完美一致矩阵 → 四项指标全为 1.03 陪审员 × 3 item、含一个缺失单元格的矩阵[a,a,None] / [a,b,b] / [b,b,b]→ 原始一致率 7/9、alpha 8/15对完整行子集第 2、3 行计算 Fleiss 得−0.2——一个低于偶然一致的负值案例注释给出了完整推导。4. 运行结果解读0.833 的原始一致率是如何坍缩成 0.421 的根据 TEST_LOG.md 的真实运行记录投票分布为{a: 19, b: 4}83% 是 a6 个偏斜对原始一致率 1.0002 个接近对404、float上 terse 与 persona 投 b、rubric 投 a总体raw agreement 0.833 坍缩为 krippendorff alpha 0.421fleiss kappa7/8 完整行0.382两两 Cohenterse_vs_persona 1.000但terse_vs_rubric 0.000、rubric_vs_persona 0.000——rubric 陪审员在全部 8 对上投 a这个退化到全投多数标签的边际导致 kappa 恰好为 0尽管它与 terse 有 75% 的原始一致率。这个案例是原始一致率 vs 偶然校正指标差异的教科书演示一个始终投票多数标签的陪审员可以与别人保持很高的原始一致率而机会校正后的一致率为零。脚本结尾会打印提醒——通过 raw agreement ≥ 0.75 过滤的陪审团其超出偶然的信号可能远低于原始数字所暗示的请在报告 raw agreement 的同时报告 alphajury_votes.py。三、什么时候使用这个模块根据 README.md只要多个标注者——模型、指令措辞或人工——接触同一批样本且你需要知道共识中有多少是信号就用它审计指南重写是否真的改变了标注对比改版前后的一致性指标若一致率显著变化说明措辞确实在起作用决定单模型标注者是否可以独立上线若一种措辞与其它措辞的 Cohens kappa 高到足以信赖可以放心让其单独运行审查陪审团投票过滤器当标签分布偏斜时高原始一致率阈值可能放过大量偶然一致而一个总是投多数标签的陪审员可以表现出高原始一致率、零机会校正一致率——正是jury_votes.py演示的场景。四、在数据标注工作流中的上下游衔接本模块不是孤立的它在 agno 数据标注 cookbookcookbook/data_labeling/README.md中处于组合模式composed patterns层位于各模态标注原语之上上游——生成被度量的偏好投票本模块测量的偏好投票由_05_text_pairwise_preference/的dpo_jury.py模式生成见 cookbook/data_labeling/_05_text_pairwise_preference/README.md5 个模型族组成的陪审团输出训练就绪的 DPO 记录含位置消偏、自偏好弃权、金对校准与分歧路由下游——处理被标记的分歧对本模块路由出的非一致条目可接入_18_quality_review/的 reviewer/adjudicator 复核管线cookbook/data_labeling/_18_quality_review/README.md两个不同提供商的标注者并行抽取 → reviewer 逐字段比对 → 仅在有分歧时条件触发仲裁者全程落库 SQLite同源——被压力测试的单裁判打分这些指标所检验的单裁判打分范式本身见_17_llm_as_judge/cookbook/data_labeling/_17_llm_as_judge/README.md对 (prompt, response) 对按评分细则打分同一套标注机制用于评估而非产标签。五、环境准备与运行在 agno 仓库根目录执行./scripts/demo_setup.sh # 创建并激活 demo venv source .venvs/demo/bin/activate export GOOGLE_API_KEY... # 本模块只依赖 Gemini python cookbook/data_labeling/_19_inter_annotator_agreement/basic.py python cookbook/data_labeling/_19_inter_annotator_agreement/jury_votes.py按 TEST_LOG.md 的约定本模块在 agno 2.7.4 gemini-3.5-flash上验证通过。需要说明的边界标签在原则上会随模型更新与服务的非确定性漂移即使 temperature0 也不能保证长期可复现——这正是每次运行都应保留一致性指标而非只看少数几条样本的原因。总结_19_inter_annotator_agreement用最小的代码体量给出了标注质量审计的完整范式以指令措辞构造可归因的标注者、以纯标准库实现四项一致性指标、以手工推导的自检保证指标实现可信、以偏斜分布与缺失单元格两个刻意设计演示原始一致率的盲区最后把分歧条目路由到复核管线。无论你是要审计指南重写效果、决定单模型标注者能否独立上线还是审查陪审团投票过滤器的可靠性这套raw agreement Fleiss Krippendorff Cohen的组合都是判断标注共识里有多少真实信号的标准答案。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考