课程大纲 › 领域 5:上下文管理与可靠性

5.5 设计人工审核工作流与置信度校准

タスクステートメント5.5:人間によるレビューのワークフローと確信度のキャリブレーションを設計する

官方大纲原文(日文):知识 4 条 · 技能 4 条

需要掌握的知识

  • 集計された精度指標(例:全体で97%)が、特定の文書の種類やフィールドにおける低いパフォーマンスを覆い隠す可能性があるというリスク
  • 確信度の高い抽出におけるエラー率を測定し、新しいエラーパターンを検出するための層化無作為抽出
  • レビューの注意を振り分けるための、ラベル付き検証セットを用いてキャリブレーションされたフィールドレベルの確信度スコア
  • 確信度の高い抽出を自動化する前に、文書の種類およびフィールドのセグメントごとに精度を検証することの重要性

需要能做到的事

  • 継続的なエラー率の測定と新しいパターンの検出のために、確信度の高い抽出に対する層化無作為抽出を実装する
  • 人間によるレビューを減らす前に、文書の種類およびフィールドごとに精度を分析し、すべてのセグメントで一貫したパフォーマンスが得られていることを確認する
  • モデルにフィールドレベルの確信度スコアを出力させ、その後、ラベル付き検証セットを用いてレビューのしきい値をキャリブレーションする
  • モデルの確信度が低い抽出や、ソース文書が曖昧または矛盾している抽出を人間によるレビューに回し、限られたレビュー担当者のキャパシティに優先順位を付ける

课程讲解 · AI 草稿,未经人工审核 以官方文档为准

这一条考什么

这一条考你在设计抽取系统的人工审核流程时,能不能正确判断哪些结果可以放心自动化、有限的审核人力该花在哪里。你要知道汇总准确率会掩盖局部短板,会用分层随机抽样持续监测高置信度结果,会用带标签的验证集校准字段级置信度,也会把低置信度或来源有歧义、有矛盾的结果优先交给人工。

核心概念

汇总准确率的陷阱

"整体准确率 97%"听起来可以上线了,但这个数字是所有文档类型、所有字段的平均值。拆开看可能是这样:

  • 发票(占 80% 的量):99%
  • 手写收据(占 3%):71%
  • tax_id 字段:在所有类型上都只有 85%

低量的文档类型和关键字段的问题,被大量简单样本平均掉了。如果仅凭 97% 就取消人工审核,手写收据和税号字段的错误就会直接流进下游系统。

按文档类型 × 字段分段验证

在减少人工审核、开启自动化之前,必须按文档类型和字段两个维度分段统计准确率,确认每一段都达标。没达标的段落继续保留人工审核,达标的段落才能自动化。自动化的放行条件是"每个段落都稳定",而不是"平均值好看"。

from collections import defaultdict

def segment_accuracy(records):
    stats = defaultdict(lambda: [0, 0])  # (doc_type, field) -> [correct, total]
    for r in records:
        for field, ok in r["field_correct"].items():
            s = stats[(r["doc_type"], field)]
            s[0] += ok
            s[1] += 1
    return {k: round(c / t, 3) for k, (c, t) in stats.items()}

字段级置信度 + 用带标签的验证集校准

让模型对每个字段输出置信度,比如 {"value": "2026-03-14", "confidence": 0.93},而不是对整份文档只给一个分数。但模型自报的数字本身没有校准,"0.9"不一定代表 90% 的正确率。

校准的方法是:拿一个人工标注好的验证集,按置信度区间统计实际准确率,比如"0.9 以上的区间实际准确率 98%,0.7 到 0.9 之间只有 84%",然后据此为每个字段设定审核阈值。这样置信度才能真正用来分配审核注意力。阈值要按字段分别定,因为不同字段的校准曲线可能差很多。

分层随机抽样:持续监测高置信度结果

就算已经自动放行了高置信度结果,也不能从此不看。原因有两个:

  • 需要持续测量高置信度结果的实际错误率,确认校准没有漂移;
  • 会出现新的错误模式,比如供应商换了发票模板,模型仍然很自信,但开始抽错。

做法是从自动放行的结果里,按层(文档类型、字段、来源格式、供应商等)各抽一定比例交给人工复核。分层能保证低量的类别也有足够的样本;纯随机抽样会让小类别几乎抽不到。

审核分流:把有限人力用在风险最高的地方

审核人员有限,应该优先审核:

  • 模型置信度低的字段或文档;
  • 来源文档本身有歧义或矛盾的(比如 conflict_detected: true,或者同一字段出现多个值,参见 4.4);
  • 再加上上面说的分层抽样样本,用于质量监控。

不该做的:全量审核(人力不够)、只按"格式异常"审核(JSON 结构正确不代表值正确)、对所有财务字段一律审核而不管置信度(浪费人力在本来就准的结果上)。

{"field": "total_amount", "value": 1240.0, "confidence": 0.58,
 "route": "human_review", "reason": "低于该字段校准阈值 0.80;明细合计与票面总额冲突"}

正确做法与反模式

  • 正确:在减少人工审核前,按文档类型和字段逐段分析准确率。反模式:看到整体 97% 就全面自动化。
  • 正确:让模型输出字段级置信度,再用带标签的验证集校准各字段阈值。反模式:直接拍一个"置信度 > 0.9 就放行",或者只用文档级的单一分数。
  • 正确:对高置信度、自动放行的结果做分层随机抽样复核,持续测错误率、发现新模式。反模式:一旦放行就不再检查,或者只做简单随机抽样,小类别抽不到。
  • 正确:优先把低置信度、来源有歧义或矛盾的结果送人工。反模式:全量审核,或者按格式异常、按字段类型一刀切地审核。
  • 正确:阈值根据复核反馈定期重新校准。反模式:阈值一次定好就永远不变。

常见陷阱

  • "97% 已超过 95% 的目标,可以取消人工审核":汇总指标会掩盖分段短板。正确选项会提到按文档类型和字段分段验证。
  • "比较 85%、90%、95% 几个阈值,选自动化率最高的":如果没有先做分段验证、没有用标签数据校准,挑哪个阈值都是在平均值上做优化。
  • "对高置信度文档再抽取一次,两次不一致就送审":自一致性只能发现不稳定的错误,模型稳定地犯同一个错时就发现不了,而且成本翻倍。分层随机抽样才是无偏的监测手段。
  • "随机抽 20% 审核":没有分层,也没有利用置信度来分流,人力利用率低。
  • "直接相信模型自报的置信度":未经校准的置信度不可靠,必须用标签验证集把分数映射到实际准确率。
  • "财务和日期字段一律送审,不管置信度":看起来稳妥,但人力被大量本来正确的结果占用,真正高风险的反而排不上。

实操练习

目标:用一个小的标注验证集校准字段级置信度阈值,并生成审核路由。

  1. 准备 20 份带人工标注答案的小文档(发票、收据混合),保存为 labeled.jsonl,每行包含 text、doc_type、gold(字段→正确值)。
  2. 用 tool use 抽取,要求每个字段返回 value 和 confidence。
  3. 按"文档类型 × 字段 × 置信度区间"统计准确率。
  4. 为每个字段选出能让准确率 ≥ 95% 的最低阈值,然后路由新的结果。
import json
from collections import defaultdict
import anthropic

client = anthropic.Anthropic()
FIELDS = ["vendor", "date", "total"]
field_schema = {"type": "object", "properties": {"value": {"type": ["string", "null"]},
                "confidence": {"type": "number"}}, "required": ["value", "confidence"]}
tool = {"name": "extract", "description": "抽取字段。每个字段给出 value(缺失为 null)和 0-1 的 confidence。",
        "input_schema": {"type": "object", "properties": {f: field_schema for f in FIELDS}, "required": FIELDS}}

def extract(text):
    r = client.messages.create(model="claude-sonnet-4-5", max_tokens=512, tools=[tool],
                               tool_choice={"type": "tool", "name": "extract"},
                               messages=[{"role": "user", "content": text}])
    return next(b.input for b in r.content if b.type == "tool_use")

rows = []
for line in open("labeled.jsonl", encoding="utf-8"):
    d = json.loads(line)
    out = extract(d["text"])
    for f in FIELDS:
        ok = str(out[f]["value"]).strip() == str(d["gold"][f]).strip()
        rows.append((d["doc_type"], f, out[f]["confidence"], ok))

seg = defaultdict(list)
for dt, f, c, ok in rows:
    seg[(dt, f)].append(ok)
print("分段准确率:", {k: round(sum(v) / len(v), 2) for k, v in seg.items()})

thresholds = {}
for f in FIELDS:
    for t in [0.5, 0.6, 0.7, 0.8, 0.9, 0.95]:
        sel = [ok for _, ff, c, ok in rows if ff == f and c >= t]
        if sel and sum(sel) / len(sel) >= 0.95:
            thresholds[f] = t
            break
    else:
        thresholds[f] = None  # 无法达标:该字段全部人工审核
print("校准后的阈值:", thresholds)

要检查的结果:分段准确率里通常会有某个"文档类型 × 字段"明显低于整体平均;不同字段的校准阈值往往不一样,有的字段可能是 None,也就是必须全部人工审核。再用 random.sample 在每个 doc_type 层内各抽 2 条高置信度结果,作为分层抽样的复核队列。

自测清单

  • 为什么整体 97% 的准确率不足以支持取消人工审核?应该怎么验证?
  • 字段级置信度为什么要用带标签的验证集校准?校准的具体做法是什么?
  • 分层随机抽样解决了哪两个问题?为什么要"分层"?
  • 有限的审核人力应该优先分配给哪些结果?
  • 为什么"再抽取一次看是否一致"不能代替分层抽样?

对应题目(4)

题目归类由 AI 判断,仅供参考。

练习这 4 道题