Reflexion: Adding Self-Correction to the Loop
An agent failed the same task four times, the same way, without noticing. A reflexion agent loop breaks that cycle by making failure a lesson. Here's how to add self-correction step by step.
def reflexion_loop(task, model, max_attempts=4):
reflections = []
for attempt in range(max_attempts):
result = try_task(task, model, memory=reflections)
if result.passed:
return result
lesson = model.reflect(task, result.attempt, result.error)
reflections.append(lesson) # carried into the next attempt
return result # best effort after N triesWatch an agent fail a coding task four times in a row, the same way each time — same wrong import, same test failure, same confident retry — and you understand the core weakness of a plain loop: it has no memory of its own mistakes. Each attempt starts fresh, so it walks into the same wall over and over, never learning that the wall is there. A reflexion agent loop fixes exactly this. It inserts a step where the agent writes down why it failed, then carries that lesson into the next attempt. Suddenly the agent stops repeating itself.
Reflexion is self-correction turned into a loop mechanic. After an attempt fails, the agent reflects — in words — on what went wrong and what to try differently. That reflection is stored and fed back in on the next attempt, so failure becomes information instead of a dead end. This guide builds one from scratch.
Quick-Start (Copy This Right Now)
[object Object], ,[object Object],(,[object Object],):
reflections = []
,[object Object], attempt ,[object Object], ,[object Object],(max_attempts):
result = try_task(task, model, memory=reflections)
,[object Object], result.passed:
,[object Object], result
lesson = model.reflect(task, result.attempt, result.error)
reflections.append(lesson) ,[object Object],
,[object Object], result ,[object Object],What this does: runs the task, and on failure asks the model to write a short lesson about why it failed, then feeds every accumulated lesson into the next attempt — so each try is informed by all the ones before it.
That single
reflectionsUnderstanding the Variables
Three things make a reflexion agent loop work, and each has a failure mode if you get it wrong.
The attempt is a normal agent run — a plan, actions, a result. The evaluation decides pass or fail; it must be concrete (a test suite, a checker, a rubric), because a vague "did it work?" produces vague reflections. And the reflection is a short natural-language lesson: what went wrong and what to change, not a restatement of the error. The quality of your reflections is the quality of your loop.
The subtle part is that reflections accumulate. Attempt three sees the lessons from attempts one and two. That growing memory is what lets the agent triangulate — "I tried X, it broke; I tried Y, it broke differently; so the issue is probably Z."
There's a counterintuitive risk here: a reflexion loop can talk itself into a worse answer. If the evaluation is noisy — a flaky test, a subjective rubric — the agent may reflect on a failure that wasn't real and correct away from a good solution. Reflexion amplifies whatever signal your evaluator provides, good or bad. A sharp evaluator makes reflection a superpower; a noisy one makes it an elaborate way to overthink. Fix the evaluator before you tune the reflection.
⚡ Pro tip: Gate reflection on confident failures only. If your evaluator returns a score or margin, skip reflection on borderline calls — reflecting on a near-pass often nudges the agent to "fix" something that was basically right. Reflect on clear failures; leave close calls alone.
⚡ Pro tip: Force reflections to be actionable. A reflection that says "the test failed" is useless; one that says "I assumed the API returns a list but it returns a paginated object — next time, check the response shape first" changes the next attempt. Prompt for the change, not the postmortem.
Step-by-Step: Building a Reflexion Agent Loop
Add self-correction in three layers.
First, make failure legible — your evaluation must return not just pass/fail but the specific error, so the reflection has raw material. Second, prompt the reflection deliberately, asking for a diagnosis and a concrete change. Third, inject the accumulated reflections into the next attempt's context, clearly labeled as lessons from prior tries.
REFLECT_PROMPT = (
,[object Object],
,[object Object],
,[object Object],
,[object Object],
)What this does: steers the model toward a diagnosis-plus-fix reflection rather than a restatement of the error, so the lesson it stores actually redirects the next attempt.
[object Object], ,[object Object],(,[object Object],):
ctx = [task]
,[object Object], reflections:
ctx.append(,[object Object],)
ctx.extend(,[object Object], ,[object Object], r ,[object Object], reflections)
ctx.append(,[object Object],)
,[object Object], ,[object Object],.join(ctx)What this does: assembles the next attempt's context with the accumulated lessons clearly separated and framed as guidance, so the model treats them as constraints to honor rather than background text to skim.
A design decision worth making consciously: whole-attempt reflection versus step-level reflection. The quick-start reflects once per failed attempt, which is simple and usually enough. But for long attempts, you can reflect after individual failing steps too, catching a wrong turn mid-run instead of only at the end. Step-level reflection is more powerful and more expensive; start with attempt-level and add granularity only where whole-attempt reflection proves too coarse to locate the mistake.
⚠️ Common mistake: Letting reflections pile up unbounded. By attempt eight, a reflection memory of seven verbose lessons crowds the context and starts to contradict itself. Cap the memory — keep the most recent few, or have the model periodically consolidate them into one sharpened lesson. Reflexion improves an agent only while the reflections stay focused; past a point, they become the noise they were meant to remove.
Pro-Level Variations
Self-correction adapts across domains.
A software engineer's test-fixing agent reflects on each failed test run and typically converges in two or three attempts where a plain loop would spin indefinitely. A quant researcher's strategy agent reflects on why a backtest underperformed, accumulating lessons about which assumptions kept breaking. A technical writer's doc agent reflects against a style checker, learning across attempts which rules it keeps violating and self-correcting toward the house style.
A support engineer's troubleshooting agent reflects after each failed remediation, so it stops re-suggesting the reboot that already failed twice. Same loop, four evaluators — tests, backtests, style rules, remediation outcomes — each turning a specific kind of failure into a specific kind of lesson.
⚡ Pro tip: Persist reflections across sessions for recurring tasks. An agent that fixes the same class of bug weekly can keep a durable lesson file, so it starts each new run already knowing the traps it learned last time. Reflexion within a run is powerful; reflexion across runs compounds.
Troubleshooting Common Issues
If your agent reflects but doesn't improve, your reflections are too vague — they describe the failure instead of prescribing a change. Tighten the reflect prompt to demand a concrete next action.
If your agent gets worse over attempts, reflections are probably contradicting each other or overwhelming the context. Cap the memory and consider consolidation.
If your agent passes evaluation but the output is still bad, your evaluator is too weak — the reflexion agent loop is only as good as the signal that tells it pass or fail. A loose checker teaches loose lessons. Strengthen the evaluation before you touch the reflection logic — a reflexion loop built on a weak evaluator will confidently learn the wrong things and get worse with every attempt.
⚡ Pro tip: Log every reflection alongside whether the next attempt improved. Over time you'll see which kinds of reflection actually help — and you can prompt for more of those. The reflection step is itself tunable, and most people never look at whether their reflections are any good.
Your Turn
Take an agent that currently fails silently and add the three layers: a concrete evaluator, an actionable reflect prompt, and an accumulated-lessons context. Give it a task it usually flubs and watch it work the problem across attempts instead of re-hitting the same wall. The first time you see it say "last attempt I assumed X — this time I'll check first," the value is obvious.
One honest caveat before you add reflexion everywhere: it costs extra model calls — one reflection per failure, plus a longer context on each retry. On tasks your agent already passes first try, that's pure overhead. Reflexion earns its cost on tasks with a real failure-and-retry loop and a solid evaluator to guide it. Add it where agents actually struggle, not as a default garnish on every loop.
Once your reflection prompt and memory logic are tuned, they're reusable across every self-correcting agent you build. I keep the reflect prompt, the memory-consolidation step, and the context builder saved in PromptABCD, so a new reflexion agent loop starts from language that already produced good lessons — instead of a first-draft reflect prompt that yields postmortems the agent can't act on. The reflect prompt is the part that takes iterations to get right; saving the good version is what turns a clever demo into a dependable pattern.
Continue Reading
Save the prompts from this post
PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.
