Reflection Pattern
The reflection pattern is not "ask the model to check its work." It is a critique-and-revise loop: the agent produces a draft, a second prompt critiques that draft against explicit criteria, and a third prompt revises it using the critique.
That distinction matters. A vague review prompt usually produces a vague reassurance. A critique with a rubric, a policy, or a test result can catch a real defect.
A Concrete Failure
A support agent drafts this reply:
"We'll refund you in full."
The policy says refunds over $50 need a manager's approval. The draft promises a refund the agent cannot authorize.
Ask the model, "Is this good?" and it will often answer: "Yes, the tone is clear and helpful." The policy violation is invisible because the review prompt never asked about policy.
Ask three specific questions instead:
- What is missing? — The manager approval for a refund over $50.
- What is unclear? — The timeline and the amount are not stated.
- What is factually wrong or unsupported? — "In full" is not authorized.
Now the revision has something to fix. It can say: "I can process up to $50 today. For the full amount, I need a manager to approve it first."
That is the pattern: the critique must have access to information the draft did not use — a policy, a test, a rubric, a retrieved document, or a tool result. If the critique has no new evidence, it is just a second guess.
The Loop
CRITIQUE_PROMPT = """You are reviewing a draft for a customer-support agent.
Task: {task}
Draft: {draft}
Policy: {policy}
Answer these three questions:
1. What is missing?
2. What is unclear?
3. What is factually wrong or unsupported?
Return a numbered list. Do not rewrite the draft yet.
"""
REVISE_PROMPT = """Rewrite the draft using the critique.
Task: {task}
Draft: {draft}
Critique: {critique}
Policy: {policy}
Return only the revised response.
"""
def reflect_and_improve(task, draft, policy, max_cycles=2):
for _ in range(max_cycles):
critique = llm.generate(
CRITIQUE_PROMPT.format(task=task, draft=draft, policy=policy)
)
# Stop when the critique has nothing actionable left.
if "no issues" in critique.lower():
break
draft = llm.generate(
REVISE_PROMPT.format(
task=task, draft=draft, critique=critique, policy=policy
)
)
return draft
llm.generate is a stand-in for your provider wrapper. The important part is that the critique and the revision are separate calls with different instructions.
Why It Works — and When It Doesn't
Reflection helps when the critique introduces new information: a policy, a failing test, a retrieved source, or a checklist. Research on verbal reinforcement (Reflexion) and iterative self-feedback (Self-Refine) shows gains on tasks where the model can act, observe the result, and try again.
It does not reliably fix reasoning. A model that is confidently wrong can produce a confident critique of the same wrong answer. The ICLR 2024 study “LLMs Cannot Self-Correct Reasoning Yet” found that intrinsic self-correction often makes reasoning worse unless an external signal is added. Treat reflection as revision against evidence, not as a magic quality switch.
| Use reflection when | Skip it when |
|---|---|
| A wrong answer is expensive (money, safety, customer-facing) | The answer is low-stakes chat |
| You have a policy, rubric, test, or retrieved source | The critique has no new evidence |
| You can afford 2–3 model calls and the extra latency | You are in a real-time or voice loop with a tight budget |
| You can measure whether the revision is better | You have no way to evaluate the revision |
Cost and Stopping
Every cycle is another call. If a draft is 500 tokens and a critique-plus-revision is 1,500 tokens, three cycles is roughly 4,500 tokens — about nine times the input of a single answer. That is often worth it for a refund reply and rarely worth it for a chat message.
Set a hard cap of 2–3 cycles, then compare the drafts. If the third draft is not measurably better than the second, stop. "More reflective" is not a quality setting.
A Checklist You Can Reuse
Before you add reflection to an agent, answer these:
- What new information does the critique get? (policy, test, retrieval, tool result)
- What are the three questions it must answer?
- How many cycles are allowed, and what is the cost ceiling?
- How will you measure whether the revision is better?
- What happens when the critique and the draft disagree?
If you cannot answer the first and fourth questions, reflection will add latency without adding quality.
Key Takeaways
- Reflection is critique + revision, not "review your answer."
- The critique needs a rubric, policy, test, or source; otherwise it is a second guess.
- Cap the loop at 2–3 cycles and compare the outputs.
- Reflection is for expensive mistakes, not every response.
References
- Shinn et al., Reflexion: Language Agents with Verbal Reinforcement Learning (NeurIPS 2023).
- Madaan et al., Self-Refine: Iterative Refinement with Self-Feedback (NeurIPS 2023).
- Huang et al., Large Language Models Cannot Self-Correct Reasoning Yet (ICLR 2024).
Next, we'll explore how agents extend their capabilities through tool use — and why a confident wrong answer becomes more expensive once the agent can act.