返回 AIPA 笔记
AIPA Day 8

agent-v2 真实 traces 导出与采样

agent-v2 真实 traces 导出与采样

2026-06-22
tracessamplingerror-analysisobservability

日期: 2026-06-22 阶段: Phase 1 - 产品定义×评测×可观测底座 标签: #traces #sampling #error-analysis #observability

核心问题

Day 3 立下规矩:evals 不是先拍指标再测量,而是从真实失败归纳指标。但「真实失败」存在哪里、怎么取出来看,才是错误分析能不能落地的前提。本仓库已有 src/agent/trace/useTraceStore.ts——它在浏览器内记录了 orchestrator→sub-agent 的多步 run,但这些 trace 是易失的 zustand 内存态,刷新即丢,更没有导出与采样层。

今天回答三件事:(1) 把 trace 当作分析的最小单元时,粒度该取在 span 树还是整任务级;(2) 该看多少条、怎么抽——为什么「随机抽 100 条」在长尾失败上是个统计学陷阱,分层/重要性采样如何纠偏,并给出采样量与置信区间的量化关系;(3) 为什么错误分析必须从真实 traces 起步,而不是凭空想象指标(Hamel/Shreya「看 100 条真实数据」原则,2025-09)。

关键内容

A. trace 作为分析单元:span 树 vs 任务级,粒度怎么选

一条生产 LLM trace 不是 3 个 span,而是以用户请求为根的 30–300 个 span 的树(futureagi 2026 观测指南口径):根 span 是用户可见操作,每个 LLM 调用 / 检索步 / 工具调用是其子 span。本仓库 useTraceStore 的数据模型恰好已经是这棵树:

RunTrace (root, = 一次用户提问 / 一个任务)
 ├─ StepTrace (agent: orchestrator | research | knowledge | portfolio)
 │   ├─ ToolCallTrace (name, args, result?, error?)   ← 叶子
 │   └─ ToolCallTrace ...
 └─ StepTrace ...
   (字段: inputTokens/outputTokens/startedAt/endedAt/totalCost/aborted/abortReason)

粒度选择是一个分析目标的函数,不是越细越好

分析目标取哪一级单元理由
错误分析 / 开放编码(Day 9)任务级 RunTrace(带下钻)人脑一次只能对「这次提问对不对」下判断;先看根,需要时再下钻到 span 定位根因
工具可靠性回归ToolCallTrace(span 叶子)error 字段直接是 tool_failure 信号,按 name 聚合算失败率
成本/延迟归因StepTrace(span 中间层)inputTokens/outputTokens/duration 在 step 级才有意义
LLM-as-judge 打分RunTrace(整任务输出)judge 评的是「最终答案好不好」,不是单 span

反直觉洞察(粒度陷阱):错误分析的单元必须是任务级,但失败的归因往往在 span 级。Hamel/Shreya 的硬规则是「每条 trace 只记第一个失败」——因为一旦根 span 失败,下游 span 的错误大多是连锁反应而非独立缺陷,若按 span 计数会把一个根因放大成五个「失败」,污染频次统计。所以正确做法是:以 RunTrace 为计数单位,下钻到 span 找根因,但只给那条 trace 记一个 first-failure 标签。

B. 分层/重要性采样的统计学:为什么随机采样漏长尾

错误分析要「看 100 条」,但100 条怎么抽决定了你能不能看见长尾失败。设某失败模式(如 typology_misjudge)在真实分布中占比 p=2%。随机抽 n 条,至少抽到 1 条该失败的概率是:

P(命中≥1) = 1 - (1 - p)^n
p=0.02, n=100 → 1 - 0.98^100 ≈ 0.867    # 还有 13.3% 概率一条都没抽到
p=0.005,n=100 → 1 - 0.995^100 ≈ 0.394   # 6 成概率完全漏掉

反过来用**「三的法则」(rule of three)** 看采样的「看不见≠不存在」:若在 n 条随机样本里零次观察到某失败,对其真实发生率 p 只能给出 95% 置信上界 p ≤ 3/n(来自 p≈−ln(0.05)/n≈2.996/n,Wikipedia Rule of three / Cochrane Handbook 16.9.4):

随机样本量 n零观测时 95% 置信上界 p ≤ 3/n含义
3010%抽 30 条没看到,发生率仍可能高达 1/10
1003%Hamel 的「看 100 条」起步——只能排除 >3% 的高频失败
3001%才敢说「未见的失败 <1%」
10000.3%监管级长尾(如漏报 SAR)才需要

随机采样在罕见缺陷上方差极高、预算效率极低(arXiv Stratified Importance Sampling 2601.22326 / 2026-01 的判断)。分层采样把样本空间切成不相交的层,按层抽样以压低层内方差——对 AML 这种「类别天然不均衡」的场景尤其关键:

分层采样(按任务结果 × 类型学分层)算法:
  1. 用廉价信号给每条 RunTrace 打"层标签":
       L1 = aborted/有 tool error 的 run        (高失败率层, 重点采)
       L2 = 用户给了负反馈的 run                  (高信号层)
       L3 = topTypology 命中但低分(贴阈值)的 run  (边界层, FP/FN 高发)
       L4 = 普通成功 run                          (背景层, 少采)
  2. 按层分配预算(Neyman 配额近似):
       n_h ∝ N_h · σ_h    # 层越大、层内失败率越分散,分得越多
       实操简化:L1/L2/L3 各采尽量多,L4 随机补足到 100
  3. 估计总体失败率时按层权重 N_h/N 加权回插,纠正过采样偏差

反直觉洞察(重要性采样的偏差纠正):分层/重要性采样故意过采样高失败层(L1–L3),这会让你「看见」的失败率高于真实失败率——这是特性不是 bug。但若不做按层权重回插就直接报「失败率 30%」,就把过采样的偏差当成了真实指标。正确口径:用过采样发现并归类失败模式(定性,Day 9–10 用),用加权回插或独立随机样本真实发生率(定量,进 PRD 指标用)。两者混用是 eval 里最隐蔽的口径错误。

Hamel/Shreya 原文给的工程化抽法正是分层的近似:clustering(聚类去重,避免 100 条里 80 条是同一种平凡成功)、sort by user feedback(按负反馈排序)、sort by high-probability failure patterns(按失败概率排序)(hamel.dev error-analysis FAQ,2025-09 抓取)。在观测管线上对应 tail-based sampling:trace 跑完后再决定是否全量留存——比 head-based(请求开始即决定)更能抓住错误案例(futureagi 2026)。

C. 错误分析为何必须从真实 traces 起步

Hamel/Shreya 的核心主张:错误分析是「evals 里最重要的活动」,目的是让你的评测指标由真实应用行为支撑,而不是反生产力的通用指标(why-is-error-analysis FAQ,2025-09 抓取)。两条操作纪律:

  1. 看至少 100 条真实 trace,逐条开放编码,直到理论饱和(theoretical saturation)——「连续 ~20 条不再涌现新失败类别即可停」。
  2. 用的是representative traces of user interactions(真实用户交互的代表性 trace),不是工程师拍脑袋的测试用例。

为什么合成数据不够?合成数据只覆盖你已经想到的失败。本仓库 src/aml/generator.ts 是个绝佳反例与正例并存的样本:它的 genNormalCaseindex===0 的「现金密集型商户」3 笔贴线现金存款,是刻意埋的真实感 FP——这说明合成器能制造你已知的边界。但真实调查员可能因为「memo 字段写了售车款但金额整千」这类生成器没编码的特征组合而误判,这种失败只存在于真实分布里。

真实 traces 起步 vs 凭空设指标,对比:
  凭空设指标:  PM 想象"会幻觉" → 写 hallucination eval → 只测到想象中的失败
              (盲区: 没想到的 context_pollution 永远测不到)
  真实起步:    导出 agent-v2 真实 run → 开放编码 → 涌现出未预期的失败类别
              → 这些类别才进 failure taxonomy (Day 11)

反直觉洞察(合成数据的视野上界):合成数据集的失败覆盖率严格不超过其生成规则的表达力generator.ts 永远生成不出「memo 与金额语义矛盾」类失败,因为它的 memo 是从固定池 r.pick(...) 选的、与金额独立。所以合成金标可以校准已知类型学的 recall/precision(Day 11 用),但 failure taxonomy 的新类别必须从真实 traces 涌现——这就是为什么 Day 8 的导出层必须接 agent-v2 的真实 run,而不能只跑 getGoldenDataset()

设计要点/决策表

决策选择理由
分析单元RunTrace(任务级)为主,span 下钻人工判断在任务级,根因在 span 级
失败计数口径每 trace 只记 first failure防连锁反应放大频次(A 节陷阱)
采样策略分层(L1 失败/L2 负反馈/L3 边界/L4 背景)随机采样漏长尾(B 节 rule of three)
真实率估计按层权重回插 或 独立随机样本过采样不能直接当真实率(B 节偏差)
数据来源agent-v2 真实 run 优先,合成仅校准已知新失败类别只在真实分布出现(C 节)
留存机制tail-based 全量留错误 trace,背景层抽样错误案例信息密度最高
隐私导出默认不含 prompt/completion 文本,opt-in对齐 OTel GenAI semconv(2026-03 仍 experimental)

对本项目的落地

  • 新建 src/agent/trace/exportTraces.ts:从 useTraceStoreruns 序列化为 JSONL(一行一 RunTrace),落 localStorage + 「下载 .jsonl」按钮,把易失内存态变成可离线分析的语料。字段直接复用 RunTrace,新增计算字段 firstFailureSpanId(A 节口径)。
  • 新建 src/agent/trace/sampleTraces.ts:实现 B 节分层采样。层标签函数从现有字段廉价推断——L1 用 run.aborted || step.toolCalls.some(t => t.error),L3「边界层」复用 src/aml/typology.tsassessCase 输出 scores 贴近 ASSESS_THRESHOLD=0.5 的 run。提供 estimateTrueRate(samples, stratumWeights) 做加权回插,并暴露 ruleOfThreeUpperBound(n)=3/n 供「零观测」时报置信上界。
  • 采样配额默认值:目标 100 条进开放编码(Day 9),L1+L2+L3 尽采、L4 随机补足——与 Hamel「看 100 条 + 饱和即停」对齐;导出工具同时打印各层 N_h 与回插后的真实失败率估计。
  • 诚实标注:当前 agent-v2 真实流量样本量小,W2 先用 generator.ts 的 66 案金标 + 少量真人手动 run 凑样本;笔记与代码注释明确「真实率估计在样本量 <300 时只给 rule-of-three 上界,不报点估计」——避免把小样本当成生产指标(B 节偏差陷阱的工程化护栏)。
  • 接 Day 9sampleTraces.ts 的输出(100 条 RunTrace + 层标签)正是开放编码的输入;exportTraces.ts 的 JSONL 格式预留 annotations: [] 字段,供 Day 9 逐条自由标注写回。

参考资料

  1. Hamel Husain — Why is "error analysis" so important in LLM evals, and how is it performed?(看 ≥100 条真实 trace、理论饱和「20 条无新类即停」、clustering/sort-by-feedback/sort-by-failure-prob 采样、每 trace 只记 first failure)hamel.dev evals-faq (2025-09)
  2. Hamel Husain & Shreya Shankar — LLM Evals: Everything You Need to Know / AI Evals 课程(错误分析方法论,已训练 Anthropic/OpenAI/Google/Meta 团队)hamel.dev / Maven (2025-09,FAQ 版 2026-01)
  3. Rule of three (statistics) — 零观测时 95% 置信上界 p≤3/n(Wikipedia;Cochrane Handbook 16.9.4 Confidence intervals when no events are observed)经典统计结论,配近期实践 statology.org 指南 (2025)
  4. Label-Efficient Monitoring via Stratified Importance Sampling — 随机采样在罕见缺陷上方差高、预算效率低;分层切层压低层内方差,arXiv 2601.22326 (2026-01)
  5. FutureAGI — What Is LLM Observability? 2026 Guide(trace = 30–300 span 树为单元;head-based vs tail-based 采样;evaluator 分数挂回同一 span_id)(2026)
  6. OpenTelemetry GenAI semantic conventions — gen_ai.usage.input_tokens 等属性、默认不采集 prompt/completion 内容(opt-in),spec 口径 experimental (2026-03)

SOTA 检查 (2026-06-11)

  • 错误分析「看真实 traces」方法论仍是 2026-06 事实标准:Hamel/Shreya 的 FAQ 版本 2026-01 仍在更新,采样建议(clustering / sort-by-feedback / sort-by-failure-prob)未被取代;本日 WebSearch 未发现替代框架。
  • 分层/重要性采样是活跃前沿:arXiv 2601.22326(2026-01)把「标注预算下的罕见类监控」形式化为分层重要性采样,方向与本笔记 B 节一致;说明「随机抽 100 条」在工业界正被「按层/按失败概率抽」替代。
  • 观测管线 trace-as-tree + tail-based 采样已成共识:FutureAGI/MLflow 2026 指南口径一致;但 OTel GenAI semconv 仍 experimental(2026-03)——导出层属性映射必须留独立适配层(与 Day 3 W4 决策一致),W4 开工前复查是否转 stable。
  • 过时警示:把「跑一次合成金标 recall」当成产品质量门,是 2024 式做法——本笔记 C 节明确合成只能校准已知失败,新类别必须从真实分布涌现。
  • 待跟踪:agent-v2 真实流量样本量增长后,把 rule-of-three 上界升级为带置信区间的点估计的样本量门槛(B 节 n≥300);OTel GenAI semconv 是否在 2026 下半年转 stable。