📚 首页 / 12-evaluation-observability/labs / lab.md

Lab 12 — 评估与可观测性

预计 75–100 分钟。标注 ✅ 的步骤无需 API key;🔑 需要 ANTHROPIC_API_KEY(先在环境中设置该变量再运行,代码不硬编码密钥)。 所有 ✅ 实验已由构建者实跑验证(见各步骤「预期输出」)。

Lab A:金标集评分器与 CI 回归门禁 ✅

🎯 学习重点:观察关键 grader 一票否决如何把业务规则变成可执行发布门禁。
  1. 运行 python3 examples/01_golden_dataset_scorer.py,先看逐 task 逐 trial 明细:
  1. 看汇总段:同一份结果里同时给出 pass@3=PASS 与 pass^3=FAIL(T01:1/3)。用 T01 解释为什么面向用户的系统必须看 pass^k。
  2. 观察 exit code:脚本以 CI 回归门禁: FAIL 退出(echo $? 应为 1)——regression 套件 pass^k 未达 100% 即阻断发布。把 TRIALS 里 T01 trial 2/3(补齐调用与终态、鉴权先行)与 T02 trial 3(改为合规升级)修成全绿,重跑观察门禁转 PASS、exit 0(构建者已实测:修绿后 CI 回归门禁: PASS,exit 0)。
  3. 思考(对照 README §6.2):

Lab B:检索指标与「指标作弊」✅

🎯 学习重点:同时观察 recall 与 precision,识别靠增大 k 制造的虚假改进。
  1. 运行 python3 examples/02_retrieval_metrics.py,对照 lexical k=3 vs baseline k=3 两张表:无信号基线 recall 宏平均 0.20 vs lexical 0.93——先有金标才能量化「检索有没有信号」。
  2. 重点看 k=3 → k=8 对比:recall 0.93→1.00(单调不降),precision 0.53→0.23(被无关块稀释)。解释为什么「全库塞入」式方案能让 recall 100% 却不可用。
  3. 找出 nDCG 的位置折损现场:k=3 表中「退款要多久到账?」一行 nDCG=0.817 < 1.0——因为完美答案块 c04(rel=3) 排在第 2、相关块 c01(rel=2) 排在第 1。手算验证:DCG = 2/log2(2) + 3/log2(3),理想排序为 [3,2,1],IDCG = 3/log2(2) + 2/log2(3) + 1/log2(4),比值 ≈ 0.817。
  4. 动手改 GOLDEN:新增一条查询(自选 1–2 个金标块与分级相关度),重跑并预测 lexical 能否把它排进 Top-3;再用「怎么开发票?」的案例解释玩具分词的局限(奇偶偏移 bigram 已修复,但仍是字符级近似,真实系统用嵌入/BM25)。
  5. 思考:为什么这套指标必须在金标集上算,而不能拿生产点击日志直接算?(答:无金标时 precision/recall 无从定义;点击日志可做在线信号但稀疏有偏——两层并用。)

Lab C:接地性检查与幻觉率 ✅

🎯 学习重点:groundedness 必须与弃答率同报,防止系统用拒答刷高分。
  1. 运行 python3 examples/03_groundedness_simulator.py,对照三个回答:
  1. 解释汇总表为什么 C 的 groundedness 是 100% 却不能当「优等生」汇报。(答:分母只剩 1 条非弃答主张;弃答率 50% 意味着一半问题没被服务——两个指标必须同看,防「用拒答刷分」。)
  2. 动手改 EVIDENCE/ANSWERS:构造一个「有据但错误」的案例(例如证据里写一个过时价格,回答如实引用)——验证脚本判 supported,从而体感理解 groundedness ≠ answer correctness。
  3. 思考:本脚本的支撑判定是「内容词覆盖 ≥ 60%」,它会在哪些情况下误判?(提示:否定翻转——「不提供 7×24 支持」会与「提供 7×24 支持」词面几乎重合。)真实系统为什么必须换校准过的 LLM-as-judge 或平台 Citations?(对照 README §6.4 的三层工程化路径。)

Lab D:真实 LLM-as-Judge 🔑(可选进阶)

🎯 学习重点:rubric 要可执行、输出要结构化,并保留 Unknown 出口与人工校准。
密钥通过环境变量提供(先设置环境变量 ANTHROPIC_API_KEY 再运行),代码中不硬编码。官方 Python SDK 会自动读取该环境变量。
  1. 用官方 develop-tests 的 grader 模式写一个小评分脚本:build_grader_prompt(answer, rubric) —— 让 judge 先在 <thinking> 标签推理、再在 <result> 标签输出 correct/incorrect,解析时只取 <result>(推理丢弃)。
  1. 把 Lab C 的三个回答喂给你的 judge,与 Lab C 的词覆盖判定对比:分歧点在哪里?(预期:judge 能抓住否定翻转与「部分对部分编」的细微情况,词覆盖会漏。)
  2. 加 Unknown 出口:在 rubric 中写明「若信息不足以判断,输出 unknown」。构造一条信息不足的样本验证它不会硬猜。
  3. 校准动作:自己人工判 10 条主张,与 judge 对比,记录一致率;任何 rubric 修改后重跑这 10 条——这就是「judge 校准」的最小可行版。

Lab E:Citations 与主张级溯源 🔑(可选进阶)

🎯 学习重点:逐主张验证引用是否真正蕴含结论,而非只检查“有链接”。
  1. 用 Messages API 的 document content block,citations: {"enabled": true} 开启引用,对 Lab C 的证据库 e1–e3 提问「基础版多少钱?企业版有什么能力?」。
  2. 检查响应中的 cited_text:每条主张对应的确切原文段落——把它与 Lab C 脚本的「supported ← e1」输出对照:平台替你做了支撑关系的对齐。
  3. 验证计费行为:对比开/关 citations 的 usage.output_tokens(引用文本不计入输出 token——模块 07 已核验的官方行为)。
  4. 思考:有了 Citations 之后,groundedness 抽检管道还需要 LLM judge 吗?(答:还需要——Citations 证明「引用存在且指向所给文档」,但「引用是否真的支撑该主张」以及未引用部分的主张仍需判定;两者互补。)

完成检查表

🎯 学习重点:完成标准是能解释指标含义与失效方式,而不只是跑出脚本结果。

记录模板

🎯 学习重点:记录版本、任务、trial、grader 与成本,保证结果可复现和可审计。
日期实验关键观察待深挖
Lab A:门禁 FAIL→修复→PASS
Lab B:k 作弊演示数字
Lab C:弃答 vs 幻觉边界
Lab D/E(如做):judge 分歧点
📚 目录