Separate judge (default)

Evaluator-Optimizer diagramTask, Generator, Evaluator, Output. Step captions follow the diagram.TaskGeneratorEvaluatorOutputEvaluator-Optimizer diagramTask, Generator, Evaluator, Output. Step captions follow the diagram.TaskGeneratorEvaluatorOutput

All steps

Fails twice, then passes

Passes first time

Parts of this pattern
Task Input / output
The request that starts the loop, such as 'Write a board memo on the Q3 churn spike'.
Generator LLM call
Writes the first draft from the task, then rewrites it using the evaluator's critique each round.
Evaluator Evaluator
Judges each draft against the criteria and returns JSON: passed, plus a critique when it fails.
Output Input / output
The accepted draft, returned only once the evaluator says it meets every criterion.
Task → Generator
The task goes to the generator; the criteria are kept for the evaluator.Task: Write a one-page board memo on Q3 churn. Criteria: cite a source for every number; formal tone.
Generator → Evaluator
Each draft is sent to the evaluator, which judges it against the criteria.1. Churn hit 4.1% in Q3 (Finance dashboard). 2. Folks mostly bailed over the new pricing. 3. We expect recovery by Q1 (CS forecast).
Evaluator → Generatorrevise
The evaluator's critique goes back so the generator can fix exactly what failed.{"passed": false, "critique": "Claim 2 has no citation; tone too casual for a board memo."}
Evaluator → Outputpass
When passed is true, the draft leaves the loop unchanged.{"passed": true, "critique": ""}

Same model

One model drafts, critiques its own draft under a second prompt, and rewrites from its notes until its own critique says stop.

Evaluator-Optimizer: Same model diagramTask, Model, Draft history, Output. Step captions follow the diagram.TaskModeldraft, critique, refineDraft historyOutputEvaluator-Optimizer: Same model diagramTask, Model, Draft history, Output. Step captions follow the diagram.TaskModeldraft, critique,refineDrafthistoryOutput

All steps
Parts of this pattern
Task Input / output
The request that starts the loop, such as 'Write a board memo on the Q3 churn spike'.
Model LLM call
One model in three roles: it writes the draft, critiques it under a second prompt, and rewrites it under a third.
Draft history Memory
Every draft so far, each with the model's own critique of it, passed back in full to the refine prompt.
Output Input / output
The draft in which the model's own critique found nothing left to fix.
Task → Model
The task and the criteria go to the model, which writes its first draft.Task: Write a one-page board memo on Q3 churn. Criteria: cite a source for every number; formal tone.
Model → Draft historydraft + notes
The draft and the model's critique of it are saved together, so the next rewrite sees both.Draft 1: '2. Folks mostly bailed over the new pricing.' Feedback: claim 2 has no source; the tone is too casual for a board.
Draft history → Modelrefine
The whole history goes into the refine prompt, so the rewrite fixes every listed problem without undoing earlier fixes.<history>Draft 1 ... Feedback: claim 2 uncited; casual tone.</history> Fix every listed problem.
Model → OutputSTOP
When the model's self-critique replies STOP, the current draft leaves the loop unchanged.Feedback: STOP. Returning draft 2: '2. Most churned accounts cited the new pricing (exit survey, n=212).'

Tool-checked

The evaluator checks the draft's claims with a tool, such as a query, a test run or a search, so its critique rests on evidence rather than opinion.

Evaluator-Optimizer: Tool-checked diagramTask, Generator, Evaluator, Metrics DB, Output. Step captions follow the diagram.TaskGeneratorEvaluatorMetrics DBread-only SQLOutputEvaluator-Optimizer: Tool-checked diagramTask, Generator, Evaluator, Metrics DB, Output. Step captions follow the diagram.TaskGeneratorEvaluatorMetrics DBread-onlySQLOutput

All steps

A figure is wrong, then fixed

Every figure checks out

Parts of this pattern
Task Input / output
The request that starts the loop, such as 'Write a board memo on the Q3 churn spike'.
Generator LLM call
Writes the draft from the task, then rewrites it to match the evidence the evaluator quotes back.
Evaluator Evaluator
An LLM reviewer with tools: it picks out the draft's checkable claims, verifies them, then returns JSON with passed and a critique.
Metrics DB Tool
A read-only query tool over the company's metrics, which the evaluator uses to check every figure in the draft.
Output Input / output
The accepted draft, returned only once every figure it states matches the tool's evidence.
Task → Generator
The task goes to the generator; the criteria are kept for the evaluator.Task: Write a one-page board memo on Q3 churn. Criteria: every number matches the metrics DB; formal tone.
Generator → Evaluator
Each draft is sent to the evaluator, which decides which of its claims a tool can check.1. Churn hit 4.1% in Q3 (Finance dashboard). 2. Most churned accounts cited the new pricing. 3. We expect recovery by Q1.
Evaluator → Metrics DBcheck
The evaluator asks the tool to confirm a claim from the draft, one query per checkable figure.SELECT churn_rate FROM quarterly_metrics WHERE quarter = '2026-Q3'
Metrics DB → Evaluatorevidence
The tool's answer comes back as evidence, which the critique must quote when a claim fails.churn_rate = 3.6% (quarterly_metrics, refreshed 2026-10-01)
Evaluator → Generatorrevise
The critique goes back with the evidence attached, so the generator corrects the claim instead of guessing.{"passed": false, "critique": "Claim 1: Q3 churn was 3.6%, not 4.1% (quarterly_metrics). Use 3.6% and cite the metrics DB."}
Evaluator → Outputpass
When every checked claim matches the evidence and the criteria are met, the draft leaves the loop.{"passed": true, "critique": ""}

← → neighboursesc atlas

Workflows

Evaluator-Optimizer

Also known as Reflection · Self-Refine · Generator-Critic · Self-correction

One model drafts, another judges; the loop runs until the work clears the bar.

Separate judge: Popularized by Schluntz & Zhang (2024) · Anthropic

Anthropic named the pattern in 2024. The draft, critique and revise loop itself was introduced as Self-Refine by Madaan et al. (CMU, AI2, UW, NVIDIA, UC San Diego, Google Research) in 2023: see the Same model tab.

Same model: Introduced by Madaan et al. (2023) · CMU, AI2 and others

Self-Refine: the same model gives the feedback and does the refining, with no extra training and no second model.

Tool-checked: Introduced by Gou et al. (2023) · Tsinghua University, Microsoft Research Asia and others

This variant applies the CRITIC pattern (Gou et al. 2023, ICLR 2024) inside an evaluator-optimizer workflow. In CRITIC the model checks its own claims with tools such as search or a code interpreter and revises from what they return; here a separate evaluator does the checking, against criteria you wrote.

Measured over one run

Separate judge

Nodes
4. Boxes in the diagram: models, tools, stores, people and plain code.
LLM calls
6. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
Tool calls
0. Messages sent to a tool node in the first scenario.
Steps
4. Steps in the first scenario, with repeated steps counted every time they run.
Scenarios
2. Distinct example runs you can switch between on the diagram.
Loop
yes. Whether the flow cycles back on itself until a condition is met.
Parallel
no. Whether two or more messages are in flight at the same time.
Branch
yes. Whether the flow takes one path out of several, chosen at run time.
Human in the loop
no. Whether a person appears as a node, to approve, correct or answer.
Autonomy
low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
Cost
medium. Relative token spend per request.
Latency
high. Relative wall-clock time per request.

Same model

Nodes
4. Boxes in the diagram: models, tools, stores, people and plain code.
LLM calls
4. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
Tool calls
0. Messages sent to a tool node in the first scenario.
Steps
3. Steps in the first scenario, with repeated steps counted every time they run.
Scenarios
1. Distinct example runs you can switch between on the diagram.
Loop
yes. Whether the flow cycles back on itself until a condition is met.
Parallel
no. Whether two or more messages are in flight at the same time.
Branch
yes. Whether the flow takes one path out of several, chosen at run time.
Human in the loop
no. Whether a person appears as a node, to approve, correct or answer.
Autonomy
low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
Cost
medium. Relative token spend per request.
Latency
high. Relative wall-clock time per request.

Tool-checked

Nodes
5. Boxes in the diagram: models, tools, stores, people and plain code.
LLM calls
4. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
Tool calls
2. Messages sent to a tool node in the first scenario.
Steps
3. Steps in the first scenario, with repeated steps counted every time they run.
Scenarios
2. Distinct example runs you can switch between on the diagram.
Loop
yes. Whether the flow cycles back on itself until a condition is met.
Parallel
no. Whether two or more messages are in flight at the same time.
Branch
yes. Whether the flow takes one path out of several, chosen at run time.
Human in the loop
no. Whether a person appears as a node, to approve, correct or answer.
Autonomy
low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
Cost
medium. Relative token spend per request.
Latency
high. Relative wall-clock time per request.

Counted from the first scenario's timeline when the site is built.

Problem

First drafts are rarely the best an LLM can do. A model asked to write, translate or code in one shot will miss requirements it would have caught had it reread its own work, but a single prompt gives it no chance to reread.

How it works

A generator produces a draft. An evaluator (a second model, or the same model under a reviewer prompt) checks it against explicit criteria and either passes it or returns a concrete critique. The critique goes back to the generator as context for the next draft. The loop ends when the evaluator passes the draft or a round budget runs out, and the result goes to the output.

The criteria are what make this work: the evaluator needs a bar it can actually check, such as “every claim is cited”, “the code passes these tests” or “the tone matches this example”.

When to use

  • You can state clear evaluation criteria, ideally checkable ones.
  • Revising measurably improves the result: literary translation, complex search, code that must pass tests.
  • A human could give useful feedback on the draft, so a model probably can too.

When to avoid

  • There are no criteria to judge against: the loop just churns.
  • The first draft is usually good enough: you pay two or three times the latency for nothing.
  • The evaluator and generator share a blind spot. Prefer tool-grounded checks (tests, validators) over pure opinion.

Trade-offs

Each round costs at least two model calls, so latency and cost grow with the number of rounds. Always cap the rounds. Quality gains usually flatten after two or three rounds.

Failure modes

  • Endless loop: the evaluator never passes the draft. Mitigate with a round budget and a “best so far” fallback.
  • Rubber-stamping: an evaluator that’s too lenient passes everything. Make the prompt strict and the criteria explicit.
  • Oscillation: fixes for one critique break an earlier one. Pass the full critique history, not just the last one.

Build it with your AI

Separate judge

Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.

Implement the Evaluator-Optimizer pattern in this codebase, using the LLM client and language we already use.

## Goal

Turn a task plus a list of pass criteria into an output that a separate evaluator model has checked against every criterion, revising until it passes or a round budget runs out.

## How it works

1. Take the task and its acceptance criteria as inputs. The generator sees only the task; the criteria go to the evaluator.
2. Call the generator model with the Generator prompt, filling in the task and, after the first round, the latest critique.
3. Send the draft and the criteria to the evaluator model with the Evaluator prompt, and parse its JSON reply into passed and critique.
4. If passed is true, return the draft.
5. Otherwise append the critique to a running list and call the generator again with every critique so far, so a later fix does not undo an earlier one.

## Prompts

### Generator prompt

```markdown
You are writing {{artifact}} for the task below.

<task>{{task}}</task>

{{#if feedback}}
A reviewer rejected your previous draft. Address every point:
<feedback>{{feedback}}</feedback>
{{/if}}

Return only the {{artifact}}, with no commentary.
```

### Evaluator prompt

```markdown
You are a strict reviewer. Judge the draft against each criterion.

<criteria>{{criteria}}</criteria>
<draft>{{draft}}</draft>

Respond in JSON:
{"passed": true|false, "critique": "specific, actionable fixes; empty if passed"}
Only pass the draft if every criterion is fully met.
```

## Stop rule

Stop as soon as the evaluator passes a draft, or after 3 rounds. If the budget runs out, return the last draft together with its unresolved critique and a status saying it did not pass.

## Requirements

- Make the round cap a parameter (default 3); the loop must never run without one.
- If the evaluator's reply is not valid JSON, retry that call once, then count the round as failed with the raw reply as the critique.
- Let the generator and the evaluator use different models and temperatures, configured separately (a strict, low-temperature evaluator works best).
- Log each round: the draft, the verdict, the critique and the token counts.
- Add a test with a stub LLM whose evaluator rejects the first two drafts and passes the third; assert three generator calls and that the third draft is returned.

Same model

Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.

Implement the Evaluator-Optimizer pattern (Same model variant) in this codebase, using the LLM client and language we already use.

## Goal

Have one model improve its own output: draft, critique the draft against the criteria, and rewrite from the critique, until its own critique finds nothing left to fix.

## How it works

1. Call the model with the Draft prompt to write the first draft from the task.
2. Call the same model with the Self-critique prompt, passing the draft and the criteria. It lists concrete problems, or replies with the single word STOP when there are none.
3. If the feedback is STOP, return the current draft.
4. Otherwise append the draft and its feedback to a history list.
5. Call the model with the Refine prompt, passing the task and the whole history, to write the next draft; then go back to the feedback step.

## Prompts

### Draft prompt

```markdown
You are writing {{artifact}} for the task below.

<task>{{task}}</task>

Return only the {{artifact}}, with no commentary.
```

### Self-critique prompt

```markdown
You wrote the draft below. Review it as a strict editor, against each criterion.

<criteria>{{criteria}}</criteria>
<draft>{{draft}}</draft>

List every concrete problem, one per line, each with the fix it needs.
If every criterion is fully met, reply with exactly: STOP
```

### Refine prompt

```markdown
Improve your {{artifact}} using the feedback on each earlier version.

<task>{{task}}</task>
<history>{{drafts_and_feedback}}</history>

Fix every listed problem without bringing back an earlier one.
Return only the revised {{artifact}}, with no commentary.
```

## Stop rule

Stop when the feedback is STOP, or after 3 refinements. If the cap is hit, return the latest draft with its last feedback and a status saying the model was still finding problems.

## Requirements

- Use one model client for all three prompts; only the prompt changes between the roles.
- Cap refinements with a configurable limit (default 3).
- Pass every earlier draft and its feedback to the refine prompt, oldest first, so a fix does not undo an earlier one.
- Treat the feedback as STOP only on an exact match after trimming whitespace, so a critique that merely mentions the word does not end the loop.
- Add a test with a stub LLM whose first feedback lists one problem and whose second is STOP; assert two drafts were written and the second is returned.

Tool-checked

Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.

Implement the Evaluator-Optimizer pattern (Tool-checked variant) in this codebase, using the LLM client and language we already use.

## Goal

Revise an output until an evaluator that verifies its checkable claims with tools passes it, so that every critique quotes evidence from a tool result.

## How it works

1. Call the generator model with the Generator prompt, filling in the task and, after the first round, the latest critique.
2. Send the draft and the criteria to the evaluator model with the Tool-checking evaluator prompt and the tool definitions; it picks the claims a tool can check and requests tool calls.
3. Run each requested tool call (a database query, a test run, a search) and return every result, or its error, to the evaluator.
4. Parse the evaluator's final JSON reply: passed, plus a critique that quotes the evidence for every failed claim.
5. If passed is true, return the draft; otherwise send the critique to the generator and run another round.

## Prompts

### Generator prompt

```markdown
You are writing {{artifact}} for the task below.

<task>{{task}}</task>

{{#if feedback}}
A reviewer checked your previous draft against the data and rejected it.
Fix every point, using the evidence they quote:
<feedback>{{feedback}}</feedback>
{{/if}}

Return only the {{artifact}}, with no commentary.
```

### Tool-checking evaluator prompt

```markdown
You are a strict reviewer with tools. Before judging, use the tools to check
every number, name and date in the draft that they can confirm.

<criteria>{{criteria}}</criteria>
<draft>{{draft}}</draft>

When you have checked the claims, respond in JSON:
{"passed": true|false, "critique": "each failed claim, the tool evidence, and the fix; empty if passed"}
Fail the draft if any checked claim disagrees with the evidence.
```

## Stop rule

Stop when the evaluator passes a draft, or after 3 rounds. On the cap, return the last draft with its critique and the tool evidence, and a status saying it did not pass.

## Requirements

- Give the evaluator read-only tools only, each with a timeout; report a failed or timed-out call to the evaluator as an error instead of retrying it silently.
- Cap tool calls per round (default 5) as well as rounds (default 3).
- Reject a failing verdict whose critique quotes no tool result, and retry the evaluator once.
- Log every tool call with its arguments and result, next to the verdict it supported.
- Add a test with a stub LLM and a fake tool that returns a different figure from the first draft's; assert the critique quotes the tool's figure and the second draft passes.

Prompt templates

Separate judge

Generator prompt
You are writing {{artifact}} for the task below.
<task>{{task}}</task>
{{#if feedback}}
A reviewer rejected your previous draft. Address every point:
<feedback>{{feedback}}</feedback>
{{/if}}
Return only the {{artifact}}, with no commentary.
Evaluator prompt
You are a strict reviewer. Judge the draft against each criterion.
<criteria>{{criteria}}</criteria>
<draft>{{draft}}</draft>
Respond in JSON:
{"passed": true|false, "critique": "specific, actionable fixes; empty if passed"}
Only pass the draft if every criterion is fully met.

Same model

Draft prompt
You are writing {{artifact}} for the task below.
<task>{{task}}</task>
Return only the {{artifact}}, with no commentary.
Self-critique prompt
You wrote the draft below. Review it as a strict editor, against each criterion.
<criteria>{{criteria}}</criteria>
<draft>{{draft}}</draft>
List every concrete problem, one per line, each with the fix it needs.
If every criterion is fully met, reply with exactly: STOP
Refine prompt
Improve your {{artifact}} using the feedback on each earlier version.
<task>{{task}}</task>
<history>{{drafts_and_feedback}}</history>
Fix every listed problem without bringing back an earlier one.
Return only the revised {{artifact}}, with no commentary.

Tool-checked

Generator prompt
You are writing {{artifact}} for the task below.
<task>{{task}}</task>
{{#if feedback}}
A reviewer checked your previous draft against the data and rejected it.
Fix every point, using the evidence they quote:
<feedback>{{feedback}}</feedback>
{{/if}}
Return only the {{artifact}}, with no commentary.
Tool-checking evaluator prompt
You are a strict reviewer with tools. Before judging, use the tools to check
every number, name and date in the draft that they can confirm.
<criteria>{{criteria}}</criteria>
<draft>{{draft}}</draft>
When you have checked the claims, respond in JSON:
{"passed": true|false, "critique": "each failed claim, the tool evidence, and the fix; empty if passed"}
Fail the draft if any checked claim disagrees with the evidence.

Related patterns

Composes well with:

Sources

  1. Building effective agents (Anthropic, 2024)
  2. Self-Refine: Iterative Refinement with Self-Feedback (Madaan et al., 2023)
  3. CRITIC: Large Language Models Can Self-Correct with Tool-Interactive Critiquing (Gou et al., 2023)

From the Agentic Atlas by Joran Kikke · Edit on GitHub · Suggest a correction