Claude Architect · 课时

分层抽样与校准

按细分群体抽样;使用带标签的验证集进行校准。

第 4 / 4 课13 个步骤

分层抽样与校准 是 CoddyKit 上的免费 Claude Architect 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Claude Architect 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Claude Architect 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Why Aggregate Accuracy Lies

You ship a Claude extraction pipeline and report 97% accuracy. Leadership approves full automation. Three weeks later, every refund invoice with a foreign-currency line is wrong.

The headline number was real — but it was an average. Aggregate accuracy can hide catastrophic failure on a specific document type or a specific field, because the common cases drown out the rare ones.

This lesson is about the discipline that keeps you honest before you automate: stratified sampling to measure where you actually fail, and calibration on labeled validation sets so your confidence scores mean something.

The Core Rule

Memorize the exam-level principle from the oversight domain:

Aggregate accuracy can hide poor performance on a specific document type or field. Use stratified random sampling plus field-level confidence calibrated on labeled validation sets before automating.

Two moves, in order:

  • Stratify, then sample — partition the population into segments, sample within each, so rare-but-critical slices are actually measured.
  • Calibrate confidence — make the model's per-field confidence correspond to real-world correctness, proven against ground-truth labels.

Skip either step and you are guessing, not governing.

Why Random Sampling Isn't Enough

Plain random sampling oversamples whatever is common. If 95% of your invoices are simple single-currency receipts, a random sample of 200 will be ~190 easy cases and maybe a handful of the hard foreign-currency ones — too few to detect a 40% error rate on that slice.

Stratified sampling fixes this: define segments that matter (document type, language, vendor, field presence), then draw a sample from each segment. Now the rare slice is measured with enough statistical power to fail loudly if it's broken.

You measure the population you're worried about, not the population that happens to be biggest.

Choosing Your Strata

Good strata isolate the dimensions where behavior plausibly diverges. For a structured-extraction pipeline (Scenario 6), useful segments include:

  • Document type — invoice vs. receipt vs. statement.
  • Field — totals, dates, currency, line items. Field-level matters because 97% overall can mask 60% on the currency field.
  • Edge conditions — multi-page docs, scanned/low-quality, multilingual, or records where an optional field is absent.

That last one ties to a schema rule: never mark a possibly-absent field as required, or the model fabricates it. Stratify by presence/absence so you catch fabrication.

Drawing a Stratified Sample

Concretely, group your validation pool by segment and pull a fixed quota from each — enough per stratum to trust the per-stratum metric, not proportional to the population.

import random
from collections import defaultdict

# Each record carries the dimensions we stratify on.
def segment_key(rec):
    return (rec["doc_type"], rec["has_currency_line"], rec["is_multilingual"])

buckets = defaultdict(list)
for rec in validation_pool:
    buckets[segment_key(rec)].append(rec)

# Fixed quota per stratum -> rare slices get real coverage,
# not just a couple of incidental samples.
PER_STRATUM = 40
sample = []
for key, recs in buckets.items():
    random.shuffle(recs)
    sample.extend(recs[:PER_STRATUM])

print({k: min(len(v), PER_STRATUM) for k, v in buckets.items()})

Field-Level Confidence, Not Just a Verdict

To calibrate, the model has to emit a confidence per field, not one blanket score. Force structured output so confidence is a typed field you can audit — not prose you parse.

Use tool_choice to guarantee the model returns the schema. "any" forces it to call some tool; {"type":"tool","name":"X"} forces a specific one. A JSON Schema eliminates syntax errors and enforces required fields.

extract_tool = {
    "name": "emit_extraction",
    "description": "Return extracted fields, each with a per-field confidence in [0,1].",
    "input_schema": {
        "type": "object",
        "properties": {
            "fields": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "name": {"type": "string"},
                        "value": {"type": "string"},
                        "confidence": {"type": "number"}
                    },
                    "required": ["name", "value", "confidence"]
                }
            }
        },
        "required": ["fields"]
    }
}

resp = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    tools=[extract_tool],
    tool_choice={"type": "tool", "name": "emit_extraction"},
    messages=[{"role": "user", "content": invoice_text}],
)

What Calibration Actually Means

A model is calibrated when its stated confidence matches observed accuracy: of all fields it labels 0.90 confident, about 90% should be correct against ground truth.

Raw model confidence is usually over-confident — it says 0.95 but is right 70% of the time. You can't trust an auto-accept threshold built on uncalibrated scores; you'd auto-approve wrong data.

Calibration requires labeled validation sets: human-verified ground truth for your stratified sample. There is no shortcut — the model's self-rated confidence alone is exactly the kind of signal the exam tells you NOT to trust for automated decisions.

Measuring Calibration with Labels

Bucket predictions by stated confidence, then compare each bucket's stated confidence to its actual accuracy on the labeled set. The gap is your calibration error — and you compute it per stratum so a well-calibrated 'easy' slice can't mask a broken 'hard' one.

from collections import defaultdict

# preds: list of {stratum, confidence, predicted, ground_truth}
bins = defaultdict(lambda: {"n": 0, "correct": 0, "conf_sum": 0.0})

for p in preds:
    b = round(p["confidence"], 1)              # 0.0..1.0 buckets
    key = (p["stratum"], b)
    bins[key]["n"] += 1
    bins[key]["conf_sum"] += p["confidence"]
    bins[key]["correct"] += int(p["predicted"] == p["ground_truth"])

for (stratum, b), s in sorted(bins.items()):
    stated = s["conf_sum"] / s["n"]
    actual = s["correct"] / s["n"]
    print(stratum, b, f"stated={stated:.2f} actual={actual:.2f} gap={stated-actual:+.2f}")

Setting Auto-Accept Thresholds Per Segment

Once calibrated, derive a confidence threshold for each stratum that meets your accuracy bar — say, auto-accept only where calibrated accuracy ≥ 99%. The threshold will differ by segment: easy single-currency invoices might auto-accept at 0.85, while foreign-currency lines need 0.98 — or stay human-reviewed entirely.

This is the bridge from measurement to oversight: low-confidence or low-accuracy strata route to a human; high-confidence calibrated strata automate. A single global threshold would either over-trust the hard slice or needlessly gate the easy one.

Self-Correction Strengthens the Signal

Confidence improves when the model can cross-check itself. For numeric extraction, have it emit both a calculated_total (sum of line items) and the stated_total printed on the document, then flag any discrepancy. A mismatch is a hard, deterministic signal — far more reliable than a self-rated confidence number.

Pair this with provenance: keep each claim's source (doc name, quote, page) so a flagged field can be traced and verified, not just re-guessed.

verify_schema = {
    "name": "emit_totals",
    "description": "Extract both the computed and printed total so discrepancies are detectable.",
    "input_schema": {
        "type": "object",
        "properties": {
            "line_items": {"type": "array", "items": {"type": "number"}},
            "calculated_total": {"type": "number"},
            "stated_total": {"type": "number"},
            "source_quote": {"type": "string"}
        },
        "required": ["calculated_total", "stated_total", "source_quote"]
    }
}

# Deterministic check beats trusting a self-rated score:
# discrepancy = abs(out['calculated_total'] - out['stated_total']) > 0.01

Run the Audit Off the Critical Path

Stratified calibration audits are large, non-blocking jobs — exactly what the Message Batches API is for: 50% cheaper, up to a 24-hour window, no latency SLA. Run your overnight calibration sweep as a batch; correlate results with custom_id and re-submit only the failures.

The boundary matters for the exam: never use the Batch API for blocking or time-sensitive checks (it has no latency SLA and does not support multi-turn tool calling). A pre-merge gate or a live extraction stays on the synchronous API; the periodic audit goes to batch.

requests = [
    {
        "custom_id": f"val-{rec['id']}",
        "params": {
            "model": "claude-sonnet-4-5",
            "max_tokens": 1024,
            "tools": [extract_tool],
            "tool_choice": {"type": "tool", "name": "emit_extraction"},
            "messages": [{"role": "user", "content": rec["text"]}],
        },
    }
    for rec in stratified_sample
]

batch = client.messages.batches.create(requests=requests)
# Overnight audit: no latency SLA, 50% cheaper. NOT for pre-merge gates.

Quick Check: Approving Automation

Apply the rule to a real go/no-go decision.

Recap: Measure Before You Trust

Key takeaways for the exam and for production:

  • Aggregate accuracy hides per-type and per-field failure — never automate on a headline average alone.
  • Stratified random sampling partitions by the dimensions that matter (doc type, field, edge conditions) and samples each, giving rare slices real statistical power.
  • Calibration aligns stated confidence with observed accuracy, proven on a labeled validation set; raw model confidence is over-confident and self-rated scores are not a trustworthy automation signal.
  • Set auto-accept thresholds per segment; automate calibrated high-accuracy strata, route the rest to humans.
  • Strengthen the signal with self-correction (calculated vs. stated total) and provenance; run the heavy calibration audit on the Batch API — never on a blocking, time-sensitive path.
免费开始

用 AI 导师学习 Python — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
26
课程
104

常见问题解答

「分层抽样与校准」课时是免费的吗?

是的 — 「分层抽样与校准」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Claude Architect 课程的其余内容,请升级到 CoddyKit PRO。 Claude Architect 课程共包含 4 节课。

「分层抽样与校准」这节课中我会学到什么?

按细分群体抽样;使用带标签的验证集进行校准。 你通过在浏览器中直接运行的动手代码来练习 Claude Architect,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Claude Architect 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Claude Architect 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「分层抽样与校准」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Claude Architect 课中编写并运行代码吗?

能。每节 Claude Architect 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 声明与来源的对应关系
  2. 冲突的数据与日期
  3. 汇总指标会掩盖失败
  4. 分层抽样与校准
← 返回 Claude Architect