Reflexion
A self-improvement technique that analyzes failures in language, stores them in memory, and avoids repeating the same mistake
Contents
Analyze a failure in language, keep it in memory, and consult that lesson on the next attempt to avoid the same mistake.
The Idea
Reflexion analyzes a failed attempt in language and stores it in memory so that the same mistake is not repeated on the next attempt.
How It Works
- First attempt fails
- Reflection -- analyze "why did it fail?" in language
- Store the lesson in memory -- record the reflection as text
- Second attempt -- consult memory, avoid the same mistake, and succeed
Example
# [First attempt]
def book_hotel(name, dates, room_type):
reservation = {
"name": name,
"dates": dates,
"room": room_type
}
return confirm_booking(reservation)
# Result: RuntimeError - 'dates' must be a listReflection: "The dates variable needs type validation. The user may pass a string or another type."
Stored in memory
# [Second attempt] - with memory
def book_hotel(name, dates, room_type):
# learned from memory: type validation needed
if not isinstance(dates, list):
raise ValueError("dates must be a list")
reservation = {
"name": name,
"dates": dates,
"room": room_type
}
return confirm_booking(reservation)
# Result: successKey Properties
| Property | Description |
|---|---|
| No weight changes | No model retraining required |
| Text-based memory | Efficient and interpretable |
| Cumulative learning | Improves as experience accumulates |
Performance
| Benchmark | Previous state-of-the-art (SOTA) GPT-4 | Reflexion |
|---|---|---|
| HumanEval (coding, pass@1) | 80% | 91% |
As reported in the Reflexion paper (arXiv:2303.11366), HumanEval pass@1 rose from 80% to 91%, 11 percentage points ahead of GPT-4 at 80%, which was the SOTA at the time.
How It Differs From Plain Retrying
- Plain retrying: first failure -- second failure (same mistake) -- third failure (same mistake again). Without feedback, repetition brings no improvement.
- Reflexion: after the first failure it reflects that "there was no type validation", then adds type validation on the second attempt and succeeds. Because it analyzes the cause of the failure, it improves quickly.
Memory Structure
# Reflexion memory example
memory = [
{
"task": "implement the book_hotel function",
"failure": "TypeError: dates must be a list",
"reflection": "input type validation is needed",
"solution": "add an isinstance() check"
},
{
"task": "API call function",
"failure": "ConnectionError",
"reflection": "network error handling is needed",
"solution": "add try-except and retry logic"
}
]Using the Memory
New task: "implement a payment API function"
Memory lookup -- related experience: "API call function" - needs network error handling
Application -- include try-except and retry logic from the start and succeed on the first attempt.
How It Differs From Self-Refine
| Reflexion | Self-Refine | |
|---|---|---|
| Trigger | Reflection after a failure | Continuous improvement |
| Failure signal | Requires a clear failure | Improves without failure |
| Memory | Stored in long-term memory | Applied immediately |
| Fits | Coding, QA | Writing, summarization |
The Loop
def reflexion_loop(task, max_attempts=3):
memory = load_memory()
for attempt in range(max_attempts):
# attempt with memory as context
result = execute_with_memory(task, memory)
if result.success:
return result
# reflect on failure
reflection = reflect_on_failure(
task=task,
error=result.error,
code=result.code
)
# store in memory
memory.append({
"task": task,
"failure": result.error,
"reflection": reflection
})
return resultload_memory loads the lessons accumulated from earlier attempts, and execute_with_memory runs the task with that memory as context. On failure, reflect_on_failure takes the error and the code and states the cause in language, and memory.append accumulates that reflection for use in the next attempt.
Where It Applies
| Scenario | Fit |
|---|---|
| Coding problems (with tests) | Very good |
| Clear success/failure criteria | Good |
| Fact-based QA | Good (combined with CRITIC) |
| Creative writing | Poor (Self-Refine is preferable) |
Limits
- Needs a clear failure signal: unsuitable for tasks where success and failure are ambiguous
- Memory retrieval quality: the relevant experience may not be found
- Generalization: similar situations may not be recognized as similar
Summary
Reflexion analyzes a failed attempt in language and keeps it in text memory so that the next attempt avoids the same mistake. Because it updates only the memory and never the model weights, cumulative learning happens without retraining. The effect is only clear on tasks where success and failure are cleanly separated, and no improvement occurs when the relevant experience cannot be retrieved from memory. It fits areas with a sharp failure signal, such as coding problems with tests, while Self-Refine is a better fit for open-ended work such as creative writing.
Related Concepts
- Self-Refine: continuous improvement (no failure required)
- CRITIC: verification with external tools
- ReAct: the underlying framework
- Self-Debug (arXiv 2304.05128): self-correction that reads code execution traces and debugs itself