What is a Self-Reflection Agent?
A self-reflection agent evaluates its own output, detects errors, and corrects itself before delivering a final response to the user.
// 5 min read · ● updated 2026-06
// before reading
A self-reflection agent is a system that critically evaluates its own output before finalizing it. Instead of generating a response and sending it directly, the agent reviews it, identifies potential errors, inconsistencies, or improvements, and refines it through one or more correction cycles. This turns the LLM from a single-pass generator into a self-verifying system — similar to how a human re-reads an email before hitting send.
Pro Tip: Reflection is the simplest technique to reduce hallucinations without switching models or adding RAG. A single self-critique cycle can catch 20-40% of factual errors.
What is it
The reflection pattern adds a verification loop after the initial generation. The typical flow is:
- Generate: the LLM produces an initial response to the user's prompt.
- Reflect: the same LLM (or a different one) evaluates the response against defined criteria — accuracy, completeness, tone, safety.
- Refine: if the evaluation finds issues, the model generates a corrected version.
- Repeat: steps 2 and 3 repeat until the response passes evaluation or a limit is reached.
There are two common architectures:
- Self-reflection (same model): the same LLM generates and then evaluates itself. Cheaper, but the model may have the same biases in both phases.
- Reflection with a separate evaluator: a smaller, faster model validates the main model, or vice versa (a larger model evaluates a smaller one).
Note: Reflection is not the same as CoT. CoT happens before the response (step-by-step reasoning). Reflection happens after the response (evaluation and correction).
Mental model
Imagine a writer who finishes an article and then puts on an editor's hat. As a writer, they produce text. As an editor, they read it critically, mark problems, and send it back for revision. The self-reflection agent alternates between these two roles: first writes, then critiques itself, then rewrites.
Initial generation → Is it correct? → Yes → Final response
↓ No
Correction → Is it correct? → Yes → Final response
↓ No
Correction (max N iterations)Each cycle consumes tokens. The cost of reflection is the cost of additional iterations.
How it's used
Self-reflection with a single model
The simplest pattern: after generating, ask the model to critique its own response.
def generate_with_reflection(question, max_iterations=3):
messages = [{"role": "user", "content": question}]
for i in range(max_iterations):
# Step 1: generate response
response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
answer = response.choices[0].message.content
messages.append({"role": "assistant", "content": answer})
# Step 2: ask for self-evaluation
critique = client.chat.completions.create(
model="gpt-4o",
messages=messages + [{
"role": "user",
"content": """Critically evaluate your previous response.
Are there factual errors? Does it miss something important?
Is it clear and complete? If correct, just reply 'ACCEPTABLE'.
If it needs changes, explain what to fix."""
}]
)
feedback = critique.choices[0].message.content
if "ACCEPTABLE" in feedback.upper():
return answer
# Step 3: refine with feedback
messages.append({"role": "user", "content": f"""
Your previous answer has these issues:
{feedback}
Please generate a corrected version.
"""})
# Last attempt as fallback
response = client.chat.completions.create(
model="gpt-4o",
messages=messages + [{"role": "user",
"content": "Generate the best final version."}]
)
return response.choices[0].message.contentWarning: Models tend to be lenient with themselves during self-evaluation. For more objective results, use a harsh critique prompt or a separate evaluator model.
Reflection with a separate evaluator
Use a cheaper model (e.g., GPT-4o mini) to evaluate the main model:
def generate_with_evaluator(question):
main_model = "gpt-4o"
evaluator_model = "gpt-4o-mini"
# Generate initial response
response = client.chat.completions.create(
model=main_model,
messages=[{"role": "user", "content": question}]
)
answer = response.choices[0].message.content
# Evaluate with a separate model
eval_response = client.chat.completions.create(
model=evaluator_model,
messages=[{
"role": "system",
"content": "You are a strict evaluator. Review the assistant's response."
}, {
"role": "user",
"content": f"Question: {question}\nAnswer: {answer}\n\nIs the answer factually correct and complete? If not, explain what's missing."
}]
)
feedback = eval_response.choices[0].message.content
if "correct" in feedback.lower() and "complete" in feedback.lower():
return answer
# Refine with feedback
refinement = client.chat.completions.create(
model=main_model,
messages=[{"role": "user", "content": question},
{"role": "assistant", "content": answer},
{"role": "user", "content": f"Fix this: {feedback}"}]
)
return refinement.choices[0].message.contentStructured reflection with explicit criteria
Instead of free-form critique, define specific criteria for the evaluator:
criteria = [
"Does the response directly answer the user's question?",
"Is every factual claim verifiable?",
"Does the response cite sources when applicable?",
"Is the tone appropriate for the context?",
"Is the response self-contained (no additional context needed)?"
]
def evaluate_with_criteria(question, answer):
prompt = f"""Evaluate the following response against these criteria.
Reply with a JSON where each criterion is marked "pass" or "fail".
Question: {question}
Response: {answer}
Criteria:
{chr(10).join(f'- {c}' for c in criteria)}
"""
result = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"}
)
return json.loads(result.choices[0].message.content)When to use it / when not to
| ✅ Use it when | ❌ Don't use it when |
|---|---|
| Accuracy is critical (medicine, finance, legal) | Latency matters more than accuracy |
| The model makes predictable errors on certain topics | Cost per call must be minimal |
| You don't have access to a larger model or RAG | A single generation pass already gives good results |
| The user values polished, reviewed responses | The response is ephemeral (e.g., real-time suggestions) |
| You want to reduce hallucinations without extra infrastructure | You don't have clear criteria for what "correct" means |
Pro Tip: Set a limit of 2-3 iterations maximum. Beyond that, models tend to overcorrect, introducing new errors or unnecessarily lengthening the response. Measure how many iterations actually improve quality before setting the limit.
History and evolution
View history
The self-reflection pattern was formalized in the paper "Reflexion: Language Agents with Verbal Reinforcement Learning" (Shinn et al., 2023), where the authors proposed that an agent maintain "episodic memory" of past mistakes and use textual feedback to self-correct.
Around the same time, works like "Self-Critiquing Models" and "Constitutional AI" (Anthropic, 2023) explored how models can evaluate their own output against defined principles. Constitutional AI trains the model to prefer responses that meet certain rules, baking reflection into the weights.
Today reflection is a standard component in multi-agent systems and generation pipelines where quality is critical, complementing techniques like RAG and guardrails.
// related