返回 AIPA 笔记
AIPA Day 9

开放编码 open coding

开放编码 open coding

2026-06-23
open-codinggrounded-theoryerror-analysisqualitative

日期: 2026-06-23 阶段: Phase 1 - 产品定义×评测×可观测底座 标签: #open-coding #grounded-theory #error-analysis #qualitative

核心问题

Day 8 把 agent-v2 的真实 traces 导出并分层采样出 100 条进了分析队列。现在面对这 100 条 trace,第一步该做什么?错误的做法是「先列一张 5 类失败清单,逐条打勾」——这会让你只看见你预设的失败。Hamel/Shreya 方法论的第一步是开放编码(open coding):逐条 trace 写自由文本标注,不预设分类,让失败类别从数据里涌现

这套方法不是 LLM 时代发明的,它直接借自社会学的扎根理论(grounded theory)——Glaser & Strauss 1960 年代提出的「理论从数据涌现而非预设」的定性研究范式。今天回答三件事:(1) 扎根理论的开放编码到底是什么、「涌现而非预设」的认识论意义;(2) 在 LLM trace 上做开放编码的操作规范(逐条自由标注 / 常量比较法 / 饱和判据);(3) 三个最常见的踩坑(过早归类 / 标注漂移 / 确认偏误)及缓解。

关键内容

A. 扎根理论的开放编码:「涌现而非预设」

扎根理论由社会学家 Barney Glaser 与 Anselm Strauss 于 1960 年代提出(The Discovery of Grounded Theory, 1967,经典),核心是常量比较法(constant comparative method):理论不是先有假设再去验证,而是从数据中逐步涌现(emergence)。其四阶段(simplypsychology 2025 整理):

开放编码(open coding)
  → 逐行(line-by-line)分析数据,用动名词(gerund,"动作词")给现象贴初始码
  → 纪律:close to the data,不套既有框架
轴向编码(axial coding,Day 10)
  → 拿新数据与已编码材料比较,相似码合并、相异码拆分
范畴化(category creation)
  → 概念相关的码聚成更宽的范畴;涌现出整合全局的"核心范畴"
理论抽样(theoretical sampling)
  → 按比较暴露出的缺口,有目的地补采数据
全程贯穿 memo writing:记录比较与洞察,形成可审计的思维链

两条认识论支柱:

  1. 理论敏感性(theoretical sensitivity)/ emergence not preconception:Glaser 派定义为「对正在发生的事保持开放,对可能涌现的东西不持预设观点」。这与 PM 的本能直接冲突——PM 习惯先立 KPI 再测量;扎根理论要求先悬置对「会出什么错」的判断。
  2. 理论饱和(theoretical saturation):常量比较持续到「数据中不再涌现新信息或洞察」为止——与 Day 8 引的 Hamel「连续 ~20 条无新类即停」是同一判据的工程化版本。

反直觉洞察(先立指标=污染数据):在定性研究里,预设编码表是方法论错误,不是效率优化。一旦你带着「会幻觉、会工具失败」的清单进场,确认偏误(confirmation bias)会让你「看见你预期看见的、确认偏见,而不是发现 LLM 输出的真实问题」(thingsithinkithink LLM Evals Lesson 2,2025-06)。代价不是慢,是系统性盲区:你预设清单之外的失败类别(如 Day 8 提的 context_pollution)永远不会被记录,因为你根本没在找它。所以「先立指标」对错误分析是污染数据源,不是省事。

B. 在 LLM trace 上做开放编码的操作规范

把扎根理论的纪律落到 Day 8 导出的 100 条 RunTrace 上,得到一套可执行流程:

逐条开放编码算法(输入:100 条采样 RunTrace;输出:每条一段自由文本标注):
  for each trace t in sampled_traces:           # Day 8 的分层 100 条
    1. 端到端读 t:用户 query → 各 StepTrace → ToolCallTrace → 最终答案
    2. 写自由文本标注(gerund 风格),描述"哪里不对/意外/有问题"
         例:"漏判了贴线现金存款模式"(动名词,描述动作)
         而非贴一个预设标签 "structuring_miss"(那是 Day 10 才做的事)
    3. 只记 FIRST failure:定位到第一个出错的 span,记一次
         (Day 8 A 节口径:防连锁反应放大频次)
    4. 常量比较:把 t 的标注与已读 trace 的标注两两比对
         相似 → 自然向同一措辞收敛
         相异 → 保留为潜在新类(不强行归类)
    5. 饱和判据:连续 ~20 条不再涌现新措辞/新失败 → 可停(但 ≥100 起步)
  产出:~100 段自由标注 + memo(为何这样标)

四条 LLM 场景特有的硬规则(综合 hamel.dev error-analysis FAQ 2025-09 + thingsithinkithink 2025-06):

规则内容反例
自由文本先于标签先写「漏了贴线模式」,不写 STRUCT_MISS直接贴预设标签 → 跳过涌现
每 trace 只记 first failure根因一次,不数连锁错误一条 trace 记 5 个错 → 频次失真
二元判据先于 Likert先「合格/不合格」二分,别上来打 1–5 分「criteria 未定就上 Likert 分」过早量化
人工开放编码不可外包给 LLMLLM 缺你的领域上下文与「部落知识」LLM 自标 → 丢失 AML 调查员的隐性判断

第四条对本项目尤其关键:AML 调查员对「这笔 $9,500 是售车款还是结构化」的判断依赖领域 tribal knowledge(memo 语义、客户画像、行业惯例),这正是 src/aml/generator.ts 的固定 memo 池表达不出的——所以开放编码必须人工,与 Day 3 D 节「关键评分保留人工抽检」「不允许 LLM 生成+LLM 自标闭环」一脉相承。

C. 三个踩坑及缓解(单人项目语境)

本项目是单人作品集,没有第二个标注者交叉校验,三个偏误风险被放大:

踩坑机制缓解
过早归类(premature categorization)第 10 条就急着定 5 类,后 90 条硬塞进去强制前 100 条只写自由文本,禁止建标签表到 Day 10
标注漂移(annotation drift)第 1 条与第 80 条对「不合格」的隐性标准不一致全程写 memo 记判据;末尾回扫前 20 条用最终判据复标(criteria drift 是特性,要回扫吸收)
确认偏误(confirmation bias)带着「会幻觉」的预期,只看见幻觉悬置预设;标注用中性 gerund 描述现象,不用因果归因

反直觉洞察(标注漂移不是 bug,是要吸收的信号):直觉上「前后标准不一致」是错误,应该一开始就定死判据。但 thingsithinkithink(2025-06)指出:「第一遍就停手会错过 criteria drift 的好处」——你对「什么算不合格」的理解本身在看数据的过程中演化,这是开放编码在生成判据而非套用判据。正确做法不是冻结判据,而是全程 memo 记录判据演化,最后用收敛后的判据回扫早期样本复标。把漂移当 bug 去消灭,反而扼杀了开放编码的产出物(一套数据驱动的判据)。

反直觉洞察(不能外包给 LLM 的自证循环):用 LLM 做开放编码看似省事,但 arXiv 2309.17147(Using LLMs for Qualitative Analysis can Introduce Serious Bias)证明它引入系统性偏差。更深的问题是闭环:若 agent-v2(被评对象)和开放编码者是同一族模型,模型对「什么算错」的盲区会同时出现在产出和评判两端——自己看不见自己的失败模式。这就是 Day 3 D 节「禁止 LLM 生成+LLM 自标」在错误分析阶段的复现。

设计要点/决策表

决策选择理由
编码顺序开放编码(自由文本)先于任何标签表涌现而非预设(A 节)
标注粒度每 trace 一段自由文本 + first-failure span防频次失真(B 节)
量化时机二元判据先,Likert 推迟到判据稳定后避免过早量化(C 节)
标注者人工(作者本人),不外包 LLM领域 tribal knowledge + 防自证循环
漂移处理全程 memo + 末尾回扫复标吸收 criteria drift(C 节)
停止判据连续 ~20 条无新类,≥100 起步理论饱和(A 节)
交接物~100 段自由标注,未聚类Day 10 轴向编码的输入

对本项目的落地

  • 新建 src/agent/eval/openCoding.ts(数据 + 类型):定义 OpenCode { traceId, freeText, firstFailureSpanId?, memo? },承接 Day 8 exportTraces.ts 预留的 annotations: [] 字段。刻意不带 category 字段——分类是 Day 10 轴向编码的产物,此处留空是方法论纪律的代码化(防过早归类)。
  • 标注语料来源:Day 8 sampleTraces.ts 输出的 100 条分层 RunTrace。真实 agent-v2 流量不足时,用 getGoldenDataset() 的 66 案 + 少量真人手动 run 凑数;笔记与代码注释诚实标注「W2 样本以合成+少量真实混合,真实失败类别待真实流量补全」(呼应 Day 8 C 节:合成只能覆盖已知失败)。
  • 开放编码 UI(教学 lab 模式,参考 src/dsdb-lab/:一个 trace 查看器,左侧渲染 RunTrace 的 step/tool 树(复用 useTraceStore 数据模型),右侧自由文本框 + memo 框。故意不提供下拉标签选择器——强制自由文本输入,把「不能过早归类」做成 UI 约束而非自律。
  • 饱和监控:界面显示「最近 20 条新增类别计数」,归零时提示「可停」——把 Hamel 的饱和判据可视化。
  • 与 AML 领域绑定:开放编码标注示例库预置 AML 语境的 gerund 措辞(如「漏判贴线现金模式」「把售车款误读为结构化」「SAR 引用了不存在的交易 ID」),作为标注者的措辞参考但不作为预设分类——示例是降低冷启动门槛,分类仍须涌现。
  • 接 Day 10openCoding.tsOpenCode[] 自由标注集是轴向编码的唯一输入;Day 10 在此之上做聚类→范畴化→频次×严重度矩阵,产出 failureTaxonomy.ts(Day 11 定稿)。

参考资料

  1. Glaser & Strauss — The Discovery of Grounded Theory(常量比较法、理论涌现、理论饱和的奠基)1967,经典;配近期整理 simplypsychology.org Constant Comparative Method (2025) 与 Grounded Theory: A Practical Guide (2025)
  2. Hamel Husain — Why is error analysis so important in LLM evals(开放编码=逐条自由标注、每 trace 记 first failure、≥100 条 + 饱和停、不可外包 LLM)hamel.dev evals-faq (2025-09)
  3. thingsithinkithink — LLM Evals Lesson 2: Error Analysis(确认偏误使你「看见预期」、二元判据先于 Likert、criteria drift 是特性需回扫)(2025-06)
  4. Using Large Language Models for Qualitative Analysis can Introduce Serious Bias — LLM 做定性编码引入系统性偏差,arXiv 2309.17147 (2023,仍是被引基准)
  5. Variance-Aware LLM Annotation for Strategy Research — LLM 标注方差来源与可靠测量协议,arXiv 2601.02370 (2026-01)

SOTA 检查 (2026-06-11)

  • 扎根理论开放编码作为错误分析底层方法论,2026-06 仍是事实标准:Hamel/Shreya 课程持续引用,本日 WebSearch 未发现替代定性方法;扎根理论本身 60 年稳定(定义层无更新)。
  • 「不能外包给 LLM」的判断仍稳健且在加强:arXiv 2601.02370(2026-01)继续量化 LLM 标注的方差与偏差,与 2309.17147(2023)方向一致——说明用 LLM 替代人工开放编码的风险随研究增多而更被确认,不是被推翻。
  • 方法论 vs 实证证据等级提醒:本笔记 A/B 节的开放编码流程是框架性方法论(Hamel/扎根理论),C 节的偏误是有实证支撑的(arXiv 论文)——引用时区分证据等级,与 Day 3 对「叙事 vs 实证」的区分一致。
  • 过时警示:「上来就用 1–5 Likert 给 trace 打分」在 2025 已被指为过早量化;「LLM 自动归类省人力」被证伪——本笔记 B/C 节均已规避。
  • 待跟踪:单人项目缺第二标注者,Day 10 的编码者间信度(Cohen's kappa)如何在单人场景缓解,留作 Day 10 主题;本笔记产出的自由标注语料量在真实流量增长后需复编码。