0Pricing
Claude Architect · 课时

何时重试有帮助(以及何时无效)

重试非常适合处理格式错误;对于缺失数据则毫无用处。

何时重试有帮助(以及何时无效) 是 CoddyKit 上的免费 Claude Architect 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Claude Architect 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Claude Architect 课程共包含 4 节课。

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

The Retry Reflex

When a model's output fails validation, the tempting move is to just try again. Sometimes that works beautifully. Sometimes it burns tokens and latency for nothing.

As an architect, your job is to know which failure you are looking at before you wire up a retry loop. Retry is a precision tool, not a blanket safety net.

This lesson draws a hard line: retry is excellent for format and structural errors, and useless when the needed information is simply absent from the source.

Two Very Different Failures

Extraction and structured-output pipelines fail in two fundamentally different ways:

  • Format / structural / arithmetic errors — the answer exists in the source, but the model rendered it wrong: invalid JSON, a missing required field it actually had data for, a total that doesn't add up.
  • Absent information — the source document simply does not contain the value. There is nothing to extract.

Retry-with-feedback can fix the first class. It cannot conjure data that was never there. Confusing the two is a classic anti-pattern.

What Retry-With-Feedback Actually Sends

A good retry is not "run the same prompt again and hope." It is a corrective retry. You send the model three things:

  • The original source document
  • The wrong output it produced
  • The exact validation error that was raised

This gives the model the specific signal it needs to self-correct. Vague feedback like "that was wrong, try harder" performs far worse than handing it the precise validator message.

def retry_with_feedback(client, source_doc, bad_output, validation_error):
    return client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=1024,
        messages=[
            {"role": "user", "content": (
                "Extract the invoice fields as JSON.\n\n"
                f"SOURCE DOCUMENT:\n{source_doc}\n\n"
                f"YOUR PREVIOUS OUTPUT (rejected):\n{bad_output}\n\n"
                f"VALIDATION ERROR:\n{validation_error}\n\n"
                "Fix only what the error names. Return corrected JSON."
            )}
        ],
    )

Format Errors: Retry's Sweet Spot

Format and structural problems are exactly where retry shines, because the correct answer is recoverable from the same input:

  • Malformed JSON or a stray trailing comma
  • A field present in the doc but missing from the output
  • Wrong enum casing or an unexpected key
  • Arithmetic that doesn't reconcile

On the second pass, armed with the validator's message, the model almost always lands the corrected structure. Even better: enforce structure up front with tool_use + a JSON Schema so most syntax errors never happen at all.

Catching Arithmetic With Self-Correction

Arithmetic discrepancies are a format-class error retry can fix — but first you have to detect them. The technique: extract both the value the model computes and the value the document states, then compare.

Pull out calculated_total (sum of line items) AND stated_total (the printed total). If they diverge, you have a concrete, retryable validation error to feed back — not a vague hunch.

from pydantic import BaseModel, model_validator

class Invoice(BaseModel):
    line_items: list[float]
    calculated_total: float
    stated_total: float

    @model_validator(mode="after")
    def totals_match(self):
        if round(self.calculated_total, 2) != round(self.stated_total, 2):
            raise ValueError(
                f"calculated_total {self.calculated_total} != "
                f"stated_total {self.stated_total}"
            )
        return self

Where Retry Hits a Wall

Now the hard limit. If a field is not present in the source, retrying does nothing useful. The model has two bad options on each loop:

  • Return the same "missing" result — wasted latency and cost.
  • Fabricate a plausible-looking value to satisfy the validator — far worse, because now you've injected a hallucination into trusted data.

Retry pressure on absent data actively encourages invention. No amount of re-prompting extracts a value that was never written down.

The Schema Trap: Required Fields

This is where a subtle schema design choice bites. Mark a field required ONLY if it is always present. Never require a field that may be absent — the model will fabricate it to satisfy the schema, and your retry loop will keep accepting garbage.

For optional data, make the field optional and let the model report absence honestly. A retry can't rescue a schema that forces invention.

tax_id_tool = {
    "name": "extract_vendor",
    "description": "Extract vendor fields from an invoice.",
    "input_schema": {
        "type": "object",
        "properties": {
            "vendor_name": {"type": "string"},
            # tax_id is OFTEN absent -> optional, never required
            "tax_id": {"type": ["string", "null"]},
        },
        # require ONLY the always-present field
        "required": ["vendor_name"],
    },
}

Make Absence a First-Class Result

The fix for absent data is not retry — it is letting the model say so explicitly. Distinguish a genuine access/format failure (maybe retryable) from a valid empty result (no value exists — stop, don't loop).

Use an enum with an "other"/"not_present" value plus a free-text detail field. That keeps the schema extensible and gives downstream code a clean signal to skip the field instead of triggering a doomed retry.

{
  "properties": {
    "discount_status": {
      "type": "string",
      "enum": ["applied", "none", "not_present", "other"]
    },
    "discount_detail": { "type": "string" }
  },
  "required": ["discount_status"]
}

Route by Error Type, Not by Reflex

Mature pipelines branch on why validation failed. Structured errors enable this; generic ones ("Operation failed") block it.

  • validation / format / arithmetic mismatch → retry-with-feedback.
  • transient (timeout, rate limit) → retry locally, the value still exists.
  • absent data / valid empty result → record "not present" and move on. Do NOT retry.

This mirrors structured MCP errors: an errorCategory and an isRetryable flag let your loop make an intelligent routing decision instead of blindly looping.

def handle(result):
    if result.error_category in ("validation", "arithmetic"):
        return "retry_with_feedback"   # answer is recoverable
    if result.error_category == "transient" and result.is_retryable:
        return "retry_local"           # network/rate-limit blip
    if result.error_category == "absent":
        return "record_not_present"    # NEVER retry absent data
    return "escalate"

Cap the Loop, But Don't Lean on the Cap

Even for genuinely retryable format errors, bound the loop. A retry budget of 2–3 attempts is plenty — if a corrective retry hasn't converged by then, the problem usually isn't format; it's missing data or an over-strict schema.

Treat the cap as a safety net, never the primary stop mechanism. The real terminator is "validation passed." If you find yourself relying on the cap to exit, that's a signal you're retrying something retry can't fix.

def extract(client, doc, validate, max_attempts=3):
    out = first_pass(client, doc)
    for _ in range(max_attempts):
        try:
            return validate(out)          # PRIMARY stop: it's valid
        except ValidationError as e:
            out = retry_with_feedback(client, doc, out, str(e))
    # SAFETY NET only -- not the intended exit path
    raise RuntimeError("unresolved after retries; likely absent data")

When Even a Good Retry Won't Save You

Two more honest limits an architect must respect:

  • A fresh, independent reviewer beats same-session self-review. An author retains its own reasoning and won't challenge itself — so for a true second opinion, validate with a fresh instance, not another turn of the same context.
  • Blocking, time-sensitive checks belong inline. The Batch API is 50% cheaper but has no latency SLA and a window up to 24h — great for overnight audits, wrong for a pre-merge or real-time validation gate.

Retry tuning can't compensate for the wrong validation architecture underneath it.

Quick Check: Retry or Not?

A structured-extraction pipeline pulls fields from supplier invoices. The Pydantic validator rejects an output because the tax_id field is empty. On inspection, this particular invoice has no tax ID printed anywhere on it. What is the correct architecture?

Recap: Retry Is a Scalpel, Not a Hammer

Key takeaways:

  • Retry fixes format, structural, and arithmetic errors — send the original doc + the wrong output + the exact validation error.
  • Retry can't fix absent data. If it's not in the source, looping only wastes cost and invites fabrication.
  • Never require a possibly-absent field — make it optional and let the model report "not present."
  • Route by error type: validation/arithmetic → retry-with-feedback; transient → retry locally; absent → record and stop.
  • Cap attempts (2–3) as a safety net; the primary stop is "validation passed."
  • For true second opinions use a fresh instance; keep blocking checks inline, not on the Batch API.

常见问题解答

「何时重试有帮助(以及何时无效)」课时是免费的吗?

是的 — 「何时重试有帮助(以及何时无效)」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Claude Architect 课程的其余内容,请升级到 CoddyKit PRO。 Claude Architect 课程共包含 4 节课。

「何时重试有帮助(以及何时无效)」这节课中我会学到什么?

重试非常适合处理格式错误;对于缺失数据则毫无用处。 你通过在浏览器中直接运行的动手代码来练习 Claude Architect,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Claude Architect 需要有经验吗?

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

「何时重试有帮助(以及何时无效)」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. 何时重试有帮助(以及何时无效)
  2. 带反馈的重试提示词
  3. 自我纠正
  4. 多轮处理与独立审查
← 返回 Claude Architect