Self-Refine and CRITIC: Iterative Output Improvement
Self-Refine (Madaan et al., 2023) runs one LLM in three roles, generate, feedback, refine, and loops until the output is good. It averages +20 absolute across 7 tasks. CRITIC (Gou et al., 2023) hardens the feedback step by routing verification through external tools. In 2026 the pattern ships in every framework as "evaluator-optimizer" (Anthropic) or a guardrail loop (OpenAI Agents SDK).
Learning Objectives
- State Self-Refine's three prompts (generate, feedback, refine) and explain why history matters for the refine prompt.
- Explain CRITIC's critical insight: LLMs are unreliable at self-verification without external grounding.
- Implement a stdlib Self-Refine loop with history and an optional external verifier.
- Map this pattern to Anthropic's "evaluator-optimizer" workflow and OpenAI Agents SDK's output guardrails.
The Problem
An agent produces an answer that is almost right. A line of code has a syntax error, a summary runs too long, a plan misses an edge case. The obvious move is to have the agent critique its own output and fix it.
Self-Refine shows this works with a single model and no training data or RL. The catch is that LLMs are bad at self-verification on hard facts. CRITIC fixes that by routing the verify step through external tools: search, a code interpreter, a calculator, a test runner.
Together the two papers set the 2026 default for iterative improvement. Generate, verify (externally when you can), refine, and stop when the verifier passes.
The Concept
Self-Refine (Madaan et al., NeurIPS 2023)
Self-Refine is a loop where one LLM generates an output, critiques it, and rewrites it using that critique, repeating until the critique finds nothing left to fix. Three roles, one model:
generate(task) -> output_0
feedback(task, output_0) -> critique_0
refine(task, output_0, critique_0, history) -> output_1
feedback(task, output_1) -> critique_1
refine(task, output_1, critique_1, history) -> output_2
...
stop when feedback says "no issues" or budget exhausted.
The detail that matters is history. The refine step sees every prior output and critique, so it doesn't repeat mistakes it already made. The paper ablates this, and quality drops sharply without it.
The headline result is +20 absolute improvement averaged across 7 tasks (math, code, acronym, dialog), GPT-4 included. No training, no external tools, one model.
CRITIC (Gou et al., arXiv:2305.11738, v4 Feb 2024)
CRITIC is Self-Refine with the feedback step replaced by verify(task, output, tools), a critique grounded in what external tools report instead of what the model believes. The reason is that self-scoring is the weak link. For factual claims it's unreliable, because a hallucination often looks convincing to the model that produced it. The tools can be:
- A search engine for factual claims.
- A code interpreter for code correctness.
- A calculator for arithmetic.
- Domain-specific verifiers: unit tests, type checkers, linters.
The verifier emits a structured critique built from tool results, and the refiner conditions on that.
CRITIC beats Self-Refine on factual tasks because the critique has something real behind it. On tasks with no external verifier (creative writing, formatting), it reduces to Self-Refine.
The stop condition
Two common shapes:
- Verifier passes. An external test returns success. Use this whenever you can get it: unit tests, a type checker, a guardrail assertion.
- No feedback issued. The model says the output is fine. Cheaper, but unreliable, so pair it with a max-iteration cap.
The 2026 default combines them: stop if the verifier passes, OR the model says fine AND iterations >= 2, OR iterations >= max_iterations.
Evaluator-Optimizer (Anthropic, 2024)
Anthropic's Dec 2024 post names this as one of five workflow patterns. It's Self-Refine/CRITIC in Anthropic's framing, with two roles:
- Evaluator: scores the output and produces a critique.
- Optimizer: revises the output given the critique.
The loop runs until the evaluator passes. The engineering detail Anthropic adds is that the evaluator and optimizer prompts should be substantially different, otherwise the model just rubber-stamps its own work.
OpenAI Agents SDK output guardrails
The OpenAI Agents SDK ships the same idea as "output guardrails." A guardrail is a validator that runs on an agent's final output. If it trips (raises OutputGuardrailTripwireTriggered), the output is rejected and the agent can retry. A guardrail can call tools (CRITIC-style) or be a pure function (Self-Refine-style).
2026 pitfalls
- Rubber-stamp loops. The same model generating and critiquing in the same prompt style converges on "looks good to me." Use structurally different prompts, or a smaller, cheaper model for the critique.
- Over-refinement. Every refine pass costs latency and tokens. Budget 1-3 passes, then escalate to human review.
- CRITIC on trivial tasks. With no external verifier, CRITIC degenerates to Self-Refine. Don't pay latency for a stub verifier.
Build It
code/main.py implements Self-Refine and CRITIC on a toy task: produce a short bullet list for a topic. The verifier checks format (3 bullets, each under 60 chars). CRITIC adds an external "fact verifier" that penalizes known hallucinations.
Components:
generate: scripted producer.feedback: LLM-style self-critique.verify_external: CRITIC-style grounded verifier.refine: rewrites output given history.- Stop condition: verifier passes or max 4 iterations.
Run it:
python3 code/main.py
Compare the two runs. CRITIC catches a factual error that Self-Refine misses, because the external verifier has grounding the self-critic lacks.
Use It
Anthropic's evaluator-optimizer is this pattern in Claude-friendly language. OpenAI Agents SDK output guardrails are CRITIC-shaped, since guardrails can call tools. LangGraph ships a reflection node that reads like Self-Refine. Google's Gemini 2.5 Computer Use adds a per-step safety evaluator, a CRITIC variant that verifies every action before it commits.
Ship It
outputs/skill-refine-loop.md configures an evaluator-optimizer loop from task shape, verifier availability, and iteration budget. It emits prompts for the generator, evaluator/verifier, and optimizer, plus a stop policy.
The first thing to check in any refine loop is whether the critic can actually be wrong in a way the generator can't. If both are the same model reading the same context, "no issues found" tells you almost nothing. A loop can burn three passes polishing prose around a fact that was invented in pass zero. Put a real check in the loop (a test, a lookup, a schema validator) even if it's crude, and the loop starts earning its latency. Without one, cap it at one pass and move on.
Exercises
- Run the toy with max_iterations=1. Does CRITIC still help?
- Replace the external verifier with a noisy one (random 30% false positives). What does the loop do? This is the 2026 reality of most guardrail stacks.
- Implement a generator-critic split across models: big model generates, small model critiques. Does it beat same-model?
- Read CRITIC Section 3 (arXiv:2305.11738 v4). Name the three verification-tool categories and give an example for each.
- Map OpenAI Agents SDK's
output_guardrailsto CRITIC's verifier role. What does the SDK get wrong, and what does it get right?
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| Self-Refine | "LLM that fixes itself" | Generate -> feedback -> refine loop in one model, with history |
| CRITIC | "Tool-grounded verification" | Replace feedback with an external verifier (search, code, calc, tests) |
| Evaluator-Optimizer | "Anthropic workflow pattern" | Two roles, evaluator scores and optimizer revises, looped to convergence |
| Output guardrail | "Post-hoc check" | OpenAI Agents SDK validator that runs after an agent produces output |
| Verify step | "Critique phase" | The load-bearing decision: grounded or self-rated |
| Refine history | "What the model already tried" | Prior outputs + critiques prepended to the refine prompt; drop it and quality collapses |
| Rubber-stamp loop | "Self-agreement failure" | Same-prompt critique returns "looks good"; fix with structurally different prompts |
| Stop condition | "Convergence test" | Verifier passes OR no feedback AND iteration cap; never a single condition |
Further Reading
- Madaan et al., Self-Refine (arXiv:2303.17651): the canonical paper
- Gou et al., CRITIC (arXiv:2305.11738): tool-grounded verification
- Anthropic, Building Effective Agents: evaluator-optimizer workflow pattern
- OpenAI Agents SDK docs: output guardrails as CRITIC-shaped verifiers
Code
- main.py (python, 125 lines)