基于 agno 的 Inter-Annotator Agreement 实践:用纯标准库实现评估 LLM 标注与陪审团投票的一致性

发布时间:2026/9/11 23:16:55
基于 agno 的 Inter-Annotator Agreement 实践:用纯标准库实现评估 LLM 标注与陪审团投票的一致性 基于 agno 的 Inter-Annotator Agreement 实践用纯标准库实现评估 LLM 标注与陪审团投票的一致性【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno本文基于 agno 数据标注系列 cookbook 中的_19_inter_annotator_agreement模块含 TEST_LOG.md 的实测记录、README.md 的用法说明及 basic.py、jury_votes.py 两个可运行示例讲解如何衡量多个标注者模型、指令框架或人类对同一批样本产出标签的一致程度。读完本文你将掌握 raw agreement、Cohens kappa、Fleiss kappa、Krippendorffs alpha 四种一致性指标的纯标准库实现与公式细节理解如何在 agno 中以同一基础模型的三种指令框架模拟独立标注者、构建 item × rater 矩阵、处理缺失单元格以及如何在标签分布倾斜时识别被原始一致性掩盖的陪审团投票信号。为什么需要一致性指标原始一致性会吹捧流水线任何标注流水线的标准可靠性检查都是检验独立标注者能否复现彼此的标签。在本模块中标注者并非多个不同模型而是同一个判断模型在不同指令框架instruction framings下以 temperature0 运行。这一设计非常关键既然采样噪声被 temperature0 消除那么每一次分歧都只能追溯到指南措辞guideline wording本身而不是随机性。正如 README.md 所指出的仅看 raw agreement 会美化一条标注流水线只有经过机会校正chance-corrected的指标才能告诉你指南是否真正可复现。该模块的适用场景来自 README 的 When to use审计一次指南重写是否真的改变了标签结果决定单一模型的标注器是否足够可靠、能否独立运行审查陪审团投票过滤器jury-vote filters当标签分布倾斜时高 raw agreement 阈值可能放行的只是大量偶然一致而一个永远投多数标签的陪审员即使与其他人有很高的原始一致性其机会校正后的一致性也可能为零。四种一致性指标的纯标准库实现与公式basic.py与jury_votes.py都以Matrix list[list[Optional[str]]]表示item行× rater列矩阵单元格None表示缺失评分。四个指标全部用纯标准库实现仅依赖itertools、collections、typing并把公式以注释形式写在函数内便于核对与教学。以下实现细节均可在 basic.py 中直接阅读。raw_agreement —— 原始一致性对每个 item统计评了同一标签的 rater 对占所有 rater 对的比例再对所有 item 取平均P_o (1/N) * sum_i [ agreeing_pairs_i / total_pairs_i ]少于两条评分的 item 被跳过。它不包含任何机会校正因此在标签倾斜场景下会给出虚高的数值。Cohens kappa —— 两两比较的机会校正适用于两两 rater 比较仅统计两者都评过的 itemp_o 标签完全一致的 item 占比 p_e sum_k p_a(k) * p_b(k) 两个 rater 各自边际分布的乘积和 kappa (p_o - p_e) / (1 - p_e)在basic.py主流程中三个 rater 两两组合产出cohen_kappa_terse_vs_rubric、cohen_kappa_terse_vs_persona、cohen_kappa_rubric_vs_persona三个成对指标。Fleiss kappa —— 多 rater 的机会校正适用于每个 item 的 rater 数相等且无缺失单元格的矩阵n_ik 类别 k 被分配给 item i 的 rater 数n 每 item 的 rater 数N item 数 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)实现中若检测到任何缺失单元格会直接抛出ValueError(fleiss_kappa requires complete rows (no missing cells))。Krippendorffs alphanominal—— 原生支持缺失单元格这是四个指标中唯一为缺失单元格提供原生处理的多 rater 机会校正指标对 nomin 类数据delta 1 when c ! k, else 0按以下步骤计算只保留含 ≥ 2 个可配对非缺失值的 item构建共现矩阵单元内有 m_u 个值来自不同 rater 的每个有序值对 (c, k) 贡献1/(m_u - 1)到 o_ck边际n_c sum_k o_ckn sum_c n_c名义不一致D_o sum_{c ! k} o_ck期望不一致 D_e sum_{c ! k} n_c * n_k / (n - 1)最终 alpha 1 - D_o / D_e。缺失单元格不贡献任何配对因此天然被正确处理而 Fleiss kappa 没有这种机制。实验一basic.py —— 三种情感指南框架标注 12 段文本实验设计basic.py用同一个Gemini(idgemini-3.5-flash, temperature0)基础模型以三种真实不同的指南措辞代码见 basic.py标注 12 段商品评论文本框架指令要点terse一句话Label the sentiment of the text: positive, negative, or neutral.rubric详细规则讽刺/反语按真实意图标注混合情绪因正负相抵标 neutral微弱或高度修饰的表扬如 fine, I guess标 neutral纯事实陈述标 neutralpersona购物者视角会推动购买标 positive让消费者犹豫标 negative无购买信号如纯事实标 neutral所有 Agent 均使用output_schemaSentimentLabel输出Literal[positive, negative, neutral]的 Pydantic 结构化结果并在label_text中最多重试 3 次解析 schema 失败绝不强转basic.py。12 条 item 中8 条为清晰的正/负/中性样本4 条被特意设计为真正模糊basic.py讽刺字面正向、意图负向的 Oh great, another update...、均衡混合情绪Gorgeous screen and superb speakers, but...、微弱表扬better than I expected. I would not buy it again...以及作者本人摇摆不定的矛盾文本Some days I love it, some days I want to throw it out the window.。自检先于任何模型调用验证指标实现self_check()在任何模型调用之前用两组手算案例断言四个实现basic.py完全一致矩阵mixed categories四个指标全部为 1.02 rater × 4 item 手工推导矩阵rater A 为pos pos neg negrater B 为pos neg neg pos。raw agreement 2/4 0.5Cohen 因双方边际均为 0.5/0.5kappa 0.0Fleiss 同样为 0.0Krippendorff 共现矩阵推导得 alpha 1 - 4/(32/7) 0.125。TEST_LOG.md 记录self_check passed即实现与手算值全部吻合通过后才发起模型请求。实测结果TEST_LOG.md 记录2026-07-18agno 2.7.4本次运行指标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 个被设计为模糊的 item 产生分歧并被路由到 review 列表其余 9 条一致混合情绪项tersenegative / rubricneutral / personanegative微弱表扬与矛盾文本项terseneutral / rubricneutral / personanegative讽刺项三个框架一致判 negative说明 rubric 的按真实意图标注规则与 persona 的购物者底线判断一致。最终汇总为12 items x 3 raters: 9 unanimous, 3 routed to review。两次运行temperature0输出完全一致但 TEST_LOG.md 同时提醒标签原则上仍可能随模型更新而漂移。实验二jury_votes.py —— 对 DPO 偏好对做陪审团投票一致性分析实验设计jury_votes.py将同一套指标应用到dpo_jury 形状的偏好投票上三个 juror 框架terse、反冗长 rubric、助教 persona对 8 对答案投a/b/tiejury_votes.py。8 对答案被刻意设计为倾斜其中 6 对明显是 a 更好如 fib、sum35、round、tcp、reset、sky2 对设计为接近的简明 vs 教学型对比http404、float此时 rubric 的永远选更短规则与 persona 的永远选更有教学价值规则指向相反方向jury_votes.py。此外persona juror 在 fib 对上确定性弃权recusal——这是对 dpo_jury 中自偏好弃权模型家族不评自己族生成的答案的模拟dpo_jury.py 中真实实现为if family ex[source_family]: recuse。三个框架共享同一基础模型因此这里通过RECUSALS: set {(persona, fib)}硬编码一次弃权在投票矩阵中留下一个缺失单元格。自检含缺失单元格与低于机会一致性案例self_check()除完全一致矩阵外还手算断言了两个关键案例jury_votes.py含缺失单元格的 3 juror × 3 item 矩阵[a, a, None] / [a, b, b] / [b, b, b]。raw agreement 7/9Krippendorffs alpha 8/15缺失单元格不贡献配对Fleiss 仅在完整行子集item 2、3上计算得 kappa -0.2即低于机会一致性的案例。这直接验证了 alpha 原生处理缺失、Fleiss 只算完整行 的差异。实测结果TEST_LOG.md 记录本次运行投票分布{a: 19, b: 4}即83% 的投票是 a倾斜正是实验目的。核心结果6 对倾斜对上 raw agreement 1.0002 对接近对上 terse 与 persona 投 b、rubric 投 a使整体 raw agreement 0.833但机会校正后急剧回落krippendorff alpha 0.421fleiss kappa 0.382在 7/8 完整行上计算——输出行醒目地指出 0.833 collapsing to 0.421 under 83% skew成对 Cohenterse_vs_persona 1.000terse_vs_rubric 0.000rubric_vs_persona 0.000。rubric juror 在全部 8 对上都投 a其退化的一致性边际全多数标签使得 kappa 在与 terse 有 75% raw agreement 的情况下恰好为 0最终汇总8 pairs x 3 jurors: 23 votes cast, 1 recused, 6 pairs unanimous among sitting jurors两次运行输出一致。这正是 README 强调的教训在 83% 的标签倾斜下raw agreement 0.833 一旦移除多数标签上的机会一致性就坍缩为 alpha 0.421一个永远投多数标签的 juror 可以同时拥有高 raw agreement 与零机会校正一致性。因此 jury_votes.py 结尾建议通过agreement 0.75过滤的陪审团其超机会信号可能远低于原始数值所暗示的水平应把 alpha 与 raw agreement 并列报告jury_votes.py。与相邻 cookbook 的关系从投票生成到裁决闭环该模块不是孤立存在的它位于 agno 数据标注体系cookbook/data_labeling中与上下游用例衔接偏好投票的产生本模块评测的 dpo_jury 形状投票来自 cookbook/data_labeling/_05_text_pairwise_preference 的dpo_jury.py模式——5 个模型家族OpenAI、Anthropic、Google、Groq、Mistral构成陪审团带置信度、双向交换消解顺序敏感、自偏好弃权与 gold pair 校准分歧的处理被路由到 review 的 item可按 cookbook/data_labeling/_18_quality_review 的 labeler → reviewer → adjudicator 工作流进行裁决——两个不同 provider 的 labeler 并行独立抽取、reviewer 逐字段 diff、分歧时由 Condition 步触发 adjudicator单一评判模型的打分这些指标所压力测试的 single-judge 打分范式见 cookbook/data_labeling/_17_llm_as_judge。运行方式与前置条件python cookbook/data_labeling/_19_inter_annotator_agreement/basic.py python cookbook/data_labeling/_19_inter_annotator_agreement/jury_votes.py需要环境变量GOOGLE_API_KEY两例均使用agno.models.google.Gemini的gemini-3.5-flashTEST_LOG.md 记录于 2026-07-18 在 agno 2.7.4 下验证。两个脚本的运行顺序一致先执行self_check()打印self_check passed再发起模型调用构建矩阵、打印指标basic.py 用rich.pretty.pprint输出指标字典、路由分歧 item最后给出汇总行。若更换其他 Gemini 模型版本temperature0虽能消除采样噪声但标签仍可能随模型更新或服务端非确定性发生漂移这已在两个文件的模块 docstring 中明确标注。小结何时使用一致性指标只要超过一个标注者——无论来自不同模型、不同指令框架还是不同人类——触及同一批 item就需要用一致性指标回答他们的一致中有多少是真正的信号。本模块给出的最小可靠实践是以 temperature0 消除采样噪声、以多种指令框架制造可追踪的分歧、以纯标准库实现并先自检机会校正指标、在倾斜标签分布下同时报告 raw agreement 与 Krippendorffs alpha、对非一致 item 路由人工复审。这套流程可以直接复用到产品评论情感标注、DPO 偏好数据构建、指南改写审计等任何多标注者场景。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考