给 AI 标注员的码本:把编码方案变成可靠的 LLM 标注器
如何编写一份 LLM 真正能执行的标注码本,用人工编码来验证它的标签,并让人始终参与其中,附一份可运行的 Potato 配置。
几十年来,码本一直是你交给人看的文档。它告诉一组编码员每个标签的含义、哪些情况算数、边界上的棘手之处在哪里。如今读这份码本的编码员,往往是一个语言模型;而一份为第三次培训的研究生写的码本,并不能干净利落地迁移到一个只会把它通读一遍、再也不会提出澄清问题的模型上。
码本是你的标签与世界之间的契约:对每个码,它规定什么含义、什么算、什么不算,再加一两个示例。要用 LLM 做标注员,你要重写这份契约,让模型无需来回沟通就能执行;然后在信任它之前,用人工编码员来核对它的输出。 这篇文章讲的就是这次重写和这次核对。文末的 Potato 配置展示了运行整个流程的一种方式。
码本究竟是什么
在内容分析和质性研究中,码本是一项研究里每个码的共享定义。经典参考是 MacQueen 等人 1998 年的模板:它给每个码一个名称、一句简短定义、一段说明何时适用何时不适用的更完整描述,以及示例文段。把这些都写下来是为了可靠性——两名读同一份码本的编码员,面对同一段文本应当得出同样的标签,而你可以测量他们是否如此。
码本有两种脾性。固定码本在编码开始前就已定型,大多数机器学习标签集和众包任务都是这样。活的码本则在阅读中生长,属于扎根理论传统:你注意到一个反复出现的想法,给它命名,之后发现两个码其实是同一回事便把它们合并。两者都能驱动 LLM 标注员,但它们失败的方式不同,这值得记在心里。
为什么为人写的码本会让 LLM 出错
人工编码员会用判断力、以及那场一起讨论疑难案例的培训来填补码本的空白。模型两者都没有。它只读页面上的字,而你留白的地方,正是它出错的地方。
- 未定义的边界。 「当参与者提到钱时编码为费用顾虑」并没有说清楚随口一句「也不便宜」算不算。人会追问;模型只能猜,而且在整个语料里猜得前后不一。
- 缺失反例。 人工编码员从「看着像 X 其实不是」中学到的,和从正例中学到的一样多。码本很少把这些写下来,因为培训者是当场口头补上的。
- 照字面执行指令。 告诉模型「最多应用三个码」,它往往不管文本是否需要都凑满三个。人把这读成上限;模型把它读成目标。
- 没有切分步骤。 人会自然地把访谈切成可编码的单元。模型需要被明确告知先切分、再对每个单元编码,否则它会把整段当作一整块来编码,丢掉你想要的粒度。
这些都不是回避 LLM 标注员的理由。它们只是把一份人用的码本改造成模型能运行的码本所需的编辑。
编写一份 LLM 能执行的码本
一旦知道要补什么,这次重写就很机械。对每个码,把人本会自行推断的四样东西写明白:
- 一句话定义,用平实语言,而不是码名的同义词。
- 纳入规则:意味着该码适用的信号。
- 排除规则:那些擦边但不算数的情况,每种配一个简短示例。
- 两三个真实示例,最好包含一个新手会编码错的。
然后把结构和标签分开处理。让模型先把文本切成单元,逐个单元对照码本编码,当没有合适的码时选择弃权,而不是硬找一个最接近的。一个明确的「以上皆非」选项,对数据质量的帮助胜过再写一段指令,因为它给了模型一个安放码本未覆盖情况的去处,而不是把它们硬塞进一个不该属于的码里。
可靠性问题
你核对 LLM 标注员,不是因为它差,而是因为你事先无从判断。在若干成熟任务上它确实不错:Gilardi、Alizadeh 和 Kubli(2023)发现 ChatGPT 在相关性、立场和框架检测上追平甚至超过众包工人,编码员间一致性更高,每条标签成本不到一美分。但「在那些任务上不错」并不能说明你的任务,而唯一的办法就是测量。
这次测量和你对两名人工编码员做的完全一样。让人标一份样本,让模型标同一份样本,再算一个像 Cohen 或 Krippendorff 那样对偶然一致做了校正的一致性统计量。一致性高的地方,模型可以承担语料的大头;一致性低的地方,你就找到了一个定义没你以为那么管用的码,而修正通常在码本里,而不是在模型上。
从人工码本到 LLM 标注员,含打磨回路
有两种失败模式值得专门盯着。当你给模型一个上限却没给它保持在上限以下的理由时,它会过度施码,于是一致性在「是否出现」上看着还行,在「数量」上却崩掉。而当人去核对模型、而不是重新标注时,自动化偏见便悄然而至:接受一个看似合理的码比质疑它更快,于是核对者不声不响地追认了模型的错误。这两点都是要留一份真正盲测、纯人工标签作为标尺的理由。
让人始终在环内
可行的安排既不是「模型标注一切」,也不是「人标注一切」,而是一个由一致性数字决定的分工。
按一致性分流:让有把握的编码通过,把其余送回
在一份带标签的黄金样本上跑模型,看它在哪里与人一致,据此分流。模型可靠标对的码,配一次轻量抽查后放行;它标错的码,以及它弃权或看起来没把握的单元,交给人工编码员。人解决这些时,分歧会回流到码本里,下一轮也因此更好。这就是预标注背后的人在环内思路,只是从单个标签放大到了整套编码方案。
在 Potato 里怎么做
Potato 在一个工具里跑通这个回路:一套以码本为依托的编码方案、一个做预标注的 LLM、做核对的人工编码员,以及对结果的可靠性指标。码本存放在一个标记为码本依托的 span 方案里,正是它把一个普通标签集变成可编辑、有层级的编码方案。
annotation_schemes:
- annotation_type: span
name: codes
description: Highlight a passage and apply a code from the codebook
codebook: true
labels: [access barriers, cost concerns, provider trust]在 QDA 模式下码本默认为 open,编码员可以在方案定型的过程中添加、重命名或合并码。一旦有了稳定的码本,在扩大规模前把它切到 fixed,共享方案就不会在模型和编码员脚下继续移动。
要让模型预先施码,打开 AI 支持并指向你使用的端点:
ai_support:
enabled: true
endpoint_type: anthropic # or openai, gemini, ollama, ...
ai_config:
model: claude-opus-4-8
api_key: ${ANTHROPIC_API_KEY}
temperature: 0.2模型提出码;标注员确认或纠正。为了让自动化偏见可测量,不要给你留作测一致性的条目做预填。留一份纯人工的盲测切片并以它作对照,正如预标注指南所述。
一轮跑完后,两个导出器给你交付物和审计轨迹:
python -m potato.export config.yaml --format codebook -o codebook.csv
python -m potato.export config.yaml --format quotation_report \
--option include_memos=true -o quotations.csvcodebook 导出每个码一行,带其描述和使用次数,于是你能看到模型倚重了哪些码、哪些从未触发。quotation_report 每个已编码文段一行,正是你实际用来核对模型的那份文件。Potato 会对这些码报告 Cohen 和 Fleiss 的 kappa,因此模型对人工的比较是一个数字,而不是一种感觉。
继续阅读
- 编写有效的标注指南,同一门手艺里属于人的那一面。
- LLM 与视觉预标注,讲模型建议的机制和防自动化偏见的护栏。
- 标注者间一致性详解,讲决定分工的可靠性统计量。
- 把质性编码带入 Potato,讲这套流程所依托的码本、备忘录和个案。
以码本为重的数据集展示了一套规格清晰的方案在实践中的样子:GoEmotions 里细粒度的情绪码、Social Chemistry 里的社会规则判断,以及 Media Frames 里的框架标签。