Unit tests (default)
All steps
Parts of this pattern
- Task Input / output
- The coding task to solve, such as 'Write merge_intervals(); it must pass these unit tests'.
- Actor LLM call
- Writes code for the task each trial, with the saved lessons from earlier failed trials in its prompt.
- Unit tests Evaluator
- Plain code, no model: runs the attempt against the unit tests and returns pass or a failure trace.
- Reflector LLM call
- Reads the task, failed attempt and test trace, then writes a short first-person lesson, with no code.
- Lessons Memory
- Episodic memory: the list of lessons that persists across trials and is recalled into the actor's prompt.
- Solution Input / output
- The attempt that passed every test, returned as the final code.
- Task → Actor
- The task enters the actor prompt; on trial 1 the lessons list is still empty.
Solve the task below. Your code will be checked by unit tests. <task>Write merge_intervals(intervals)</task>
- Actor → Unit testsattempt
- The actor's code for this trial is sent to be run against the unit tests.
def merge_intervals(iv): iv.sort() ... # code v1
- Unit tests → Reflectorfail
- When a test fails, the failing trace goes to the reflector along with the attempt.
FAILED test_touching: expected [[1, 5]], got [[1, 3], [3, 5]]
- Reflector → Lessonslesson
- The reflector's lesson is appended to the lessons list so it outlives this trial.
I treated touching intervals as separate because I used < instead of <=. Next time, merge when start <= previous end.
- Lessons → Actorrecall
- Saved lessons are put into the next trial's actor prompt so it avoids repeating the mistake.
You have attempted this before. Lessons: I used < instead of <=; merge when start <= previous end.
- Unit tests → Solutionpass
- When every test passes, the attempt leaves the loop as the solution.
All 6 tests passed: returning code v2.
LLM judge
With no unit tests to run, an LLM judge checks each trial against a rubric, and its verdict and reason feed the reflector.
All steps
Parts of this pattern
- Task Input / output
- A task with no unit tests, such as 'Write a product blurb under 50 words that mentions the 2-year warranty'.
- Actor LLM call
- Writes an attempt each trial, with the saved lessons from earlier failed trials in its prompt.
- LLM judge Evaluator
- A separate model call that checks the attempt against the rubric and returns JSON with passed and a reason.
- Reflector LLM call
- Reads the task, the failed attempt and the judge's reason, then writes a short first-person lesson.
- Lessons Memory
- Episodic memory: the list of lessons that persists across trials and is recalled into the actor's prompt.
- Result Input / output
- The attempt the judge passed, returned as the final result.
- Task → Actor
- The task enters the actor prompt; on trial 1 the lessons list is still empty. The rubric is kept for the judge.
Task: Write a product blurb for the Aero kettle. Rubric: under 50 words; mentions the 2-year warranty.
- Actor → LLM judgeattempt
- The actor's attempt for this trial goes to the judge with the rubric.
The Aero kettle boils a litre in three minutes, with a brushed-steel body and a soft-close lid... (72 words)
- LLM judge → Reflectorfail
- When the judge fails the attempt, its reason goes to the reflector along with the attempt.
{"passed": false, "reason": "72 words, over the 50 limit; no mention of the 2-year warranty."}
- Reflector → Lessonslesson
- The reflector's lesson is appended to the lessons list so it outlives this trial.
I wrote too much and left out the warranty. Next time I will write the warranty sentence first and keep to three short sentences.
- Lessons → Actorrecall
- Saved lessons go into the next trial's actor prompt so it avoids repeating the mistake.
Lessons: write the warranty sentence first; keep to three short sentences.
- LLM judge → Resultpass
- When the judge passes the attempt, it leaves the loop as the result.
{"passed": true, "reason": ""} -> 41-word blurb returned.
Insight bank (ExpeL)
Lessons are distilled across many tasks into a shared insight bank, which every new task recalls from its first trial.
All steps
Parts of this pattern
- New task Input / output
- A task never attempted before, such as 'Write days_between(a, b) for dates in two formats'.
- Actor LLM call
- Attempts the new task with the bank's best insights in its first prompt, retrying as in Reflexion if it fails.
- Past trials Memory
- Every finished trial from every earlier task, failures and successes alike, with its steps and outcome.
- Extractor LLM call
- Compares failed and successful trials and edits the insight list: adding, rewording, upvoting or downvoting insights.
- Insight bank Memory
- General rules learned across many tasks, each with a score; the top ones go into every new task's prompt.
- Result Input / output
- The new task's passing attempt.
- New task → Actor
- A new task arrives. It has never been tried, but the bank already holds lessons from similar ones.
Task: Write days_between(a, b) for dates given as 'YYYY-MM-DD' or 'MM/DD/YYYY'.
- Actor → Past trialstrajectory
- Every finished trial, pass or fail, is saved with its task, steps and outcome.
Task 52 days_between: trial 1 passed (8 of 8 tests).
- Past trials → Extractorcompare
- Batches of past trials, especially a failure next to a success on the same task, go to the extractor.
Compare: task 31 parse_date trial 1 (fail: read 02/03 as 2 March) with trial 2 (pass: month first).
- Extractor → Insight bankedit
- The extractor's operations add, reword, upvote or downvote insights that hold across tasks.
ADD: 'For any date input, test month/day order and 29 February before returning.' UPVOTE insight 4.
- Insight bank → Actorinsights
- At the start of a new task, the top-scored insights go into the actor's first prompt.
Insights: 1. For any date input, test month/day order and 29 February. 2. Return early on empty input.
- Actor → Resultpass
- With the insights in view, the new task often passes on its first trial.
days_between passes all 8 tests on trial 1.
← → neighboursesc atlas
Reflexion
Also known as Verbal reinforcement learning · Episodic self-reflection
After a failed attempt, the agent writes a lesson in plain language to memory and tries again with that lesson in context.
Unit tests, LLM judge: Introduced by Shinn et al. (2023) · Northeastern University & MIT and Princeton University
Insight bank (ExpeL): Introduced by Zhao et al. (2023) · Tsinghua University
ExpeL: LLM Agents Are Experiential Learners (AAAI 2024). It extracts insights by comparing failed and successful trials across tasks.
Measured over one run
Unit tests
- Nodes
- 6. Boxes in the diagram: models, tools, stores, people and plain code.
- LLM calls
- 3. 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
- 6. 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
- medium. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
- Cost
- high. Relative token spend per request.
- Latency
- high. Relative wall-clock time per request.
LLM judge
- Nodes
- 6. 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
- 5. 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
- medium. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
- Cost
- high. Relative token spend per request.
- Latency
- high. Relative wall-clock time per request.
Insight bank (ExpeL)
- Nodes
- 6. Boxes in the diagram: models, tools, stores, people and plain code.
- LLM calls
- 2. 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
- 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
- no. 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
- medium. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
- Cost
- high. 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
An agent that fails a task and simply tries again usually repeats the same mistake. Retraining the model after each failure is slow and expensive, and often impossible because the weights are not yours. Yet a person who fails a coding exercise does something cheap and effective: they work out why it failed and carry that lesson into the next attempt.
How it works
Reflexion, from Shinn et al., calls this verbal reinforcement learning. Instead of updating weights, the agent updates text.
The actor attempts the task, for example writing a function. The attempt runs against unit tests, which give an objective signal. If they pass, the solution is returned. If they fail, the failing output goes to the reflector, a model call whose only job is diagnosis. It writes a short, specific lesson such as “I treated the range as inclusive; the tests expect exclusive upper bounds”. That lesson is saved to memory.
On the next trial, the stored lessons are placed in the actor’s prompt, so the new attempt starts from what the last one learned. The loop repeats until the tests pass or a trial budget runs out, and the passing code goes to the solution.
The difference from a plain retry is the memory: lessons persist from one trial to the next within the task. The LLM judge tab swaps the tests for a model that checks a rubric, as the paper suggests for tasks without tests, and the Insight bank tab (ExpeL) carries lessons across tasks rather than only across retries.
When to use
- You have a trustworthy signal for success or failure: tests, a validator, a game score.
- Failures are informative, and a human could say “next time, do X instead”.
- The task can be attempted repeatedly, as in coding, puzzle solving or multi-step web tasks.
When to avoid
- There is no reliable evaluator. The reflector will invent a plausible but wrong diagnosis, and the lesson will mislead later attempts.
- Attempts are expensive or have side effects that cannot be undone.
- One more careful pass over the same draft would do. Evaluator-Optimizer is simpler.
Trade-offs
Each failed trial costs an actor call, a test run and a reflection call, and the lessons add prompt tokens to every later attempt. In return, the improvement carries forward without any training. Most of the gain tends to arrive in the first few trials, so keep the budget small.
Failure modes
- Wrong lessons: a mistaken diagnosis is written into memory and poisons later trials. Ground reflection in the actual test output, not in vibes.
- Vague lessons: “be more careful” teaches nothing. Require the specific mistake and the specific change.
- Memory bloat: lessons pile up and crowd the prompt. Keep only the most recent or most relevant few.
- Overfitting to the tests: the actor special-cases the visible tests. Hold some tests back.
Build it with your AI
Unit tests
Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.
Implement the Reflexion pattern in this codebase, using the LLM client and language we already use.
## Goal
Solve a task that has an automatic pass or fail check by retrying it in fresh trials, each carrying the plain-language lessons the model wrote after earlier failures.
## How it works
1. Run trial 1: call the actor model with the Actor prompt, filling in the task and an empty lessons list.
2. Run the attempt against the unit tests in a sandbox and capture pass or fail, plus the failing test output.
3. If every test passes, return the attempt.
4. Otherwise call the reflector with the Reflection prompt, passing the task, the attempt and the test output, and append its lesson to the lessons list.
5. Start the next trial with a fresh actor call that includes the lessons list, but not the earlier attempts or their transcripts.
## Prompts
### Actor prompt
```markdown
Solve the task below. Your code will be checked by unit tests.
<task>{{task}}</task>
{{#if lessons}}
You have attempted this before. Lessons you wrote for yourself:
<lessons>{{lessons}}</lessons>
Do not repeat a mistake listed here.
{{/if}}
Return only the code.
```
### Reflection prompt
```markdown
Your attempt failed. Work out why, and write a lesson for your next try.
<task>{{task}}</task>
<attempt>{{attempt}}</attempt>
<test_output>{{trace}}</test_output>
In two or three sentences, state:
1. the specific mistake (not "the code was wrong")
2. what to do differently next time
Write in the first person. Do not write code.
```
## Stop rule
Stop when an attempt passes every test, or after 4 trials. At the cap, return the attempt that passed the most tests, with every lesson and a status saying it did not pass.
## Requirements
- Make the trial cap (default 4) and the number of lessons kept in the prompt (default the 3 most recent) parameters.
- Run the tests with a timeout (default 30 seconds), and pass a timeout or crash to the reflector as the failure trace.
- If the reflector's reply is empty or contains code, retry it once; if it fails again, use the first 500 characters of the test output as the lesson.
- Store the lessons with the task id, so a rerun of the same task can start from them.
- Add a test with a stub LLM whose first attempt fails a fake test and whose second passes; assert the reflector ran once and the second actor prompt contains its lesson verbatim.
LLM judge
Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.
Implement the Reflexion pattern (LLM judge variant) in this codebase, using the LLM client and language we already use.
## Goal
Retry a task that has no automatic tests in fresh trials, using an LLM judge with a rubric to decide success and carrying forward the lessons the model writes after each failed trial.
## How it works
1. Call the actor with the Actor prompt, filling in the task and the lessons list (empty on trial 1).
2. Send the task, its rubric and the attempt to a separate judge call with the Judge prompt; parse its JSON reply into passed and reason.
3. If passed is true, return the attempt.
4. Otherwise call the reflector with the Reflection prompt, passing the task, the attempt and the judge's reason, and append its lesson to the lessons list.
5. Start the next trial with a fresh actor call that includes the updated lessons list.
## Prompts
### Actor prompt
```markdown
Complete the task below. A reviewer will check your work against a rubric.
<task>{{task}}</task>
{{#if lessons}}
You have attempted this before. Lessons you wrote for yourself:
<lessons>{{lessons}}</lessons>
Do not repeat a mistake listed here.
{{/if}}
Return only the result.
```
### Judge prompt
```markdown
You check one attempt against a rubric. Be strict and literal.
<task>{{task}}</task>
<rubric>{{rubric}}</rubric>
<attempt>{{attempt}}</attempt>
Check every rubric item. Respond in JSON:
{"passed": true|false, "reason": "each failed item and why; empty if passed"}
```
### Reflection prompt
```markdown
Your attempt failed review. Work out why, and write a lesson for your next try.
<task>{{task}}</task>
<attempt>{{attempt}}</attempt>
<review>{{reason}}</review>
In two or three sentences, state:
1. the specific mistake
2. what to do differently next time
Write in the first person. Do not rewrite the attempt.
```
## Stop rule
Stop when the judge passes an attempt, or after 4 trials. At the cap, return the last attempt with the judge's last reason and every lesson, flagged as not passed.
## Requirements
- Make the trial cap a parameter (default 4), and run the judge at temperature 0.
- If the judge's reply is not valid JSON, retry it once; if it fails again, count the trial as failed with the raw reply as the reason.
- Write the rubric as checkable items, such as a word limit or a required fact; a vague rubric lets weak attempts pass.
- Log each trial's attempt, verdict, reason and lesson together.
- Add a test with a stub LLM whose judge fails trial 1 with the reason 'no warranty' and passes trial 2; assert two actor calls, one reflector call, and that the second actor prompt contains the lesson.
Insight bank (ExpeL)
Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.
Implement the Reflexion pattern (Insight bank (ExpeL) variant) in this codebase, using the LLM client and language we already use.
## Goal
Make an agent improve across tasks by distilling insights from its past successes and failures into a shared bank that is recalled at the start of every new task.
## How it works
1. Run each task with the actor as in plain Reflexion, and save every finished trial (task id, steps, outcome) to a trajectory store, failures and successes alike.
2. After every 20 new trajectories, send the extractor pairs of a failed and a successful trial on the same task, together with the current insight list.
3. Parse the extractor's reply as a list of operations (ADD, EDIT, UPVOTE, DOWNVOTE) and apply them to the insight bank; remove any insight whose score falls to zero.
4. When a new task starts, put the 5 highest-scored insights and the 2 most similar successful trajectories into the actor's first prompt (ExpeL itself includes the whole insight list; the cap keeps prompts short).
5. Run the task and save its trajectories for the next round of extraction.
## Prompts
### Actor prompt
```markdown
Solve the task below. Your code will be checked by unit tests.
<task>{{task}}</task>
{{#if lessons}}
You have attempted this before. Lessons you wrote for yourself:
<lessons>{{lessons}}</lessons>
Do not repeat a mistake listed here.
{{/if}}
Return only the code.
```
### Reflection prompt
```markdown
Your attempt failed. Work out why, and write a lesson for your next try.
<task>{{task}}</task>
<attempt>{{attempt}}</attempt>
<test_output>{{trace}}</test_output>
In two or three sentences, state:
1. the specific mistake (not "the code was wrong")
2. what to do differently next time
Write in the first person. Do not write code.
```
## Stop rule
Each task stops as in Reflexion: on a pass or after 4 trials. Extraction runs in the background and never blocks a task.
## Requirements
- Make the extraction batch (default 20), the insights recalled (default 5) and the examples recalled (default 2) parameters.
- If a line of the extractor's reply does not parse as an operation, skip it and log it; apply the rest.
- Store each insight with its score, creation date and the trajectory ids it came from, so a bad insight can be traced and removed.
- Cap the bank (default 30 insights), dropping the lowest-scored one when it is full.
- Add a test with the extraction batch set to 1 and a stub extractor that returns 'ADD: check 29 February'; after one saved trajectory, assert the next new task's first actor prompt contains 'check 29 February'.
Prompt templates
Unit tests · Insight bank (ExpeL)
Solve the task below. Your code will be checked by unit tests.
<task>{{task}}</task>
{{#if lessons}}You have attempted this before. Lessons you wrote for yourself:<lessons>{{lessons}}</lessons>Do not repeat a mistake listed here.{{/if}}
Return only the code.Your attempt failed. Work out why, and write a lesson for your next try.
<task>{{task}}</task><attempt>{{attempt}}</attempt><test_output>{{trace}}</test_output>
In two or three sentences, state:1. the specific mistake (not "the code was wrong")2. what to do differently next time
Write in the first person. Do not write code.LLM judge
Complete the task below. A reviewer will check your work against a rubric.
<task>{{task}}</task>
{{#if lessons}}You have attempted this before. Lessons you wrote for yourself:<lessons>{{lessons}}</lessons>Do not repeat a mistake listed here.{{/if}}
Return only the result.You check one attempt against a rubric. Be strict and literal.
<task>{{task}}</task><rubric>{{rubric}}</rubric><attempt>{{attempt}}</attempt>
Check every rubric item. Respond in JSON:{"passed": true|false, "reason": "each failed item and why; empty if passed"}Your attempt failed review. Work out why, and write a lesson for your next try.
<task>{{task}}</task><attempt>{{attempt}}</attempt><review>{{reason}}</review>
In two or three sentences, state:1. the specific mistake2. what to do differently next time
Write in the first person. Do not rewrite the attempt.Related patterns
Composes well with:
Sources
From the Agentic Atlas by Joran Kikke · Edit on GitHub · Suggest a correction