Advertisement

New In-article Ad

Reflection Agents in LangGraph: Build a Self-Correcting AI Agent

Reflection Agents in LangGraph: Build a Self-Correcting AI Agent

Generate → Critique → Revise → Verify → Repeat

Large Language Models are very good at generating answers, but they are not guaranteed to produce the best answer on the first attempt.

A production AI system often needs more than:

User → LLM → Response

What if the AI could:

  1. Generate an answer
  2. Inspect its own answer
  3. Identify weaknesses
  4. Search for additional information
  5. Revise the answer
  6. Repeat the process until the answer reaches an acceptable quality

That is the basic idea behind a Reflection Agent.


In this tutorial, we will build a practical self-correcting AI agent using LangGraph, LangChain, Pydantic structured output, and an external search tool.

The architecture will look like this:

                    ┌─────────────────┐
                    │   User Query    │
                    └────────┬────────┘
                             │
                             ▼
                    ┌─────────────────┐
                    │    Responder    │
                    │  Generate Draft │
                    └────────┬────────┘
                             │
                             ▼
                    ┌─────────────────┐
                    │    Reflector    │
                    │    Critique     │
                    └────────┬────────┘
                             │
                    Missing information?
                    Need verification?
                             │
                             ▼
                    ┌─────────────────┐
                    │  External Tool  │
                    │  Web / Search   │
                    └────────┬────────┘
                             │
                             ▼
                    ┌─────────────────┐
                    │     Revisor     │
                    │ Improve Answer  │
                    └────────┬────────┘
                             │
                             ▼
                     Quality acceptable?
                        /          \
                      No            Yes
                      │              │
                      └──────┐       ▼
                             │    Final Answer
                             │
                             └──→ Another iteration

The important point is that reflection is not simply asking the same LLM to "try again."

A useful reflection architecture explicitly separates generation, evaluation, evidence gathering, revision, state, and routing.


1. What Is a Reflection Agent?

A Reflection Agent is an AI workflow where one model generates an output and another model—or another reasoning step—evaluates that output and provides feedback.

The basic loop is:

Generation
    ↓
Critique
    ↓
Revision
    ↓
Generation
    ↓
Critique
    ↓
Revision

The course material describes this using two roles:

  • Generator — creates the initial answer
  • Reflector — analyzes and critiques the answer

The same pattern was demonstrated using a LinkedIn-post optimization agent: the generator creates a post, the reflector critiques it, and the feedback is fed back into generation for another iteration.

Simple example

Suppose the user asks:

Write a LinkedIn post about becoming a better software engineer.

The generator might produce:

Be consistent.
Learn new technologies.
Practice coding every day.
Build projects.

The reflector might say:

The response is generic.

Problems:
1. No specific actionable advice.
2. No concrete examples.
3. No strong opening hook.
4. No conclusion or call to action.

The generator receives that feedback and produces:

You don't become a better software engineer by learning
100 frameworks.

You become better by solving harder problems.

Build.
Debug.
Read production code.
Review your decisions.
Repeat.

Every bug is feedback.
Every project is practice.
Every review is an opportunity to improve.

What engineering skill are you working on this month?

The second answer is not necessarily correct because it is "more verbose."

It is better because the system explicitly evaluated the first attempt against quality criteria.


2. Why Do We Need Reflection Agents?

A normal LLM call has this structure:

Prompt
  ↓
LLM
  ↓
Answer

The problem is that an LLM can:

  • miss important requirements
  • provide incomplete answers
  • hallucinate facts
  • use outdated information
  • ignore part of the question
  • produce weak structure
  • repeat irrelevant information
  • fail to provide evidence
  • make an incorrect assumption

Reflection introduces a quality-control loop.

             ┌────────────────────┐
             │      Generate      │
             └─────────┬──────────┘
                       │
                       ▼
             ┌────────────────────┐
             │      Critique      │
             └─────────┬──────────┘
                       │
                       ▼
             ┌────────────────────┐
             │      Revise       │
             └─────────┬──────────┘
                       │
                       └──────────────┐
                                      │
                                      ▼
                                  Better Output

This is particularly useful when the quality of the answer matters more than minimizing the number of model calls.


3. Reflection Agent vs Reflexion Agent

The terminology can be confusing.

Your course distinguishes a basic reflection agent from a Reflexion agent.

A basic reflection system can be:

User
 ↓
Generator
 ↓
Reflector
 ↓
Generator
 ↓
Final answer

A Reflexion-style system extends this idea by incorporating:

  • self-critique
  • external tools
  • current information
  • citations
  • structured outputs
  • iterative revision

The course describes Reflexion as going beyond simply improving an opinion: the system can use external information and produce more verifiable, citation-backed responses.

The external-knowledge version follows this pattern:

User Question
      ↓
Responder
      ↓
Structured Critique
      ↓
Search Queries
      ↓
External Search
      ↓
Search Results
      ↓
Revisor
      ↓
Improved Answer + References
      ↓
Another Iteration?
   ↙          ↘
 Yes           No
  ↓             ↓
Search       Final Answer

The attached reference specifically describes the responder producing fields such as the answer, reflection, missing information, and search queries, followed by a revisor that uses tool output and adds references.


4. Where Does Reflection Fit in AI Agent Architecture?

It helps to understand reflection in the broader progression of AI agents.

A simplified progression is:

Simple Reflex Agent
        ↓
Model-Based Agent
        ↓
Goal-Based Agent
        ↓
Utility-Based Agent
        ↓
Learning Agent
        ↓
LLM-Based Agent
        ↓
Reflection / Reflexion Agent

A simple reflex agent follows predefined condition-action rules.

A model-based agent maintains state.

A goal-based agent chooses actions according to goals.

A utility-based agent evaluates the desirability of outcomes.

A learning agent improves based on feedback.

The attached course material uses these categories to explain why increasingly sophisticated agents need state, goals, evaluation, and learning mechanisms.

Reflection agents bring an important idea into LLM applications:

The output itself becomes an object that can be evaluated and improved.


5. Reflection Is Not the Same as Training the Model

This distinction is extremely important.

Suppose GPT generates:

Draft A

Then reflection generates:

Critique A

And the model creates:

Draft B

The model has not necessarily changed its weights.

Instead, the application is using the previous output and critique as additional context.

Model weights
      │
      │ unchanged
      ▼
┌───────────────────┐
│ Reflection Loop   │
│                   │
│ Draft             │
│ Critique          │
│ Evidence          │
│ Revision          │
└───────────────────┘

This is runtime self-correction, not model fine-tuning.

That makes reflection particularly useful because you can improve the behavior of an application without retraining the underlying model.


6. Real-World Project: AI Customer Support Response Agent

Let's build something closer to an industry application.

Imagine an e-commerce company.

A customer asks:

"My order arrived damaged. I want a replacement. What is the process?"

A simple LLM might answer:

Sorry about that. Please contact customer support
and provide your order number.

That's okay, but a production system may need to:

  • understand the customer's issue
  • check company policy
  • verify replacement rules
  • identify missing information
  • provide accurate instructions
  • cite the relevant policy
  • avoid inventing policies

So we create:

Self-Correcting Customer Support Agent

Architecture:

                    Customer
                       │
                       ▼
                ┌─────────────┐
                │  Responder  │
                └──────┬──────┘
                       │
                       ▼
                ┌─────────────┐
                │  Reflector  │
                └──────┬──────┘
                       │
              Missing policy?
              Missing information?
                       │
                       ▼
                ┌─────────────┐
                │ Knowledge   │
                │ Search      │
                └──────┬──────┘
                       │
                       ▼
                ┌─────────────┐
                │   Revisor   │
                └──────┬──────┘
                       │
                       ▼
                  Quality Check
                    /       \
                  No         Yes
                  │           │
                  └─────┐     ▼
                        │  Final Answer
                        │
                        └── Loop

This is a realistic pattern for:

  • customer support
  • technical support
  • developer documentation
  • research assistants
  • compliance assistants
  • financial research
  • internal knowledge assistants
  • content quality systems

7. Technology Stack

We will use:

Python
│
├── LangChain
│     └── LLM + prompts + structured output
│
├── Pydantic
│     └── Output schemas
│
├── LangGraph
│     └── Workflow + state + routing
│
└── Tavily
      └── External knowledge/search

The current LangChain documentation supports structured output using Pydantic models, dataclasses, TypedDict, and JSON Schema.

Tavily is available as a LangChain integration through the langchain-tavily package and provides search results containing information such as titles, URLs, and content snippets.


8. Project Setup

Install the required packages:

pip install -U \
    langgraph \
    langchain \
    langchain-openai \
    langchain-tavily \
    pydantic \
    python-dotenv

Create a .env file:

OPENAI_API_KEY=your-openai-key
TAVILY_API_KEY=your-tavily-key
OPENAI_MODEL=gpt-4o

Then:

from dotenv import load_dotenv

load_dotenv()

9. Step 1 — Create the Pydantic Schemas

This is one of the most important parts of the architecture.

Instead of asking the LLM to return arbitrary text:

"Please critique this answer and tell me what is missing."

we define an explicit contract.

from pydantic import BaseModel, Field


class Reflection(BaseModel):
    critique: str = Field(
        description="Critical evaluation of the current answer"
    )

    missing: str = Field(
        description="Important information missing from the answer"
    )

    superfluous: str = Field(
        description="Information that is unnecessary or irrelevant"
    )


class DraftResponse(BaseModel):
    answer: str = Field(
        description="The answer to the user's question"
    )

    reflection: Reflection

    search_queries: list[str] = Field(
        default_factory=list,
        description="Search queries needed to verify or improve the answer"
    )


class RevisedResponse(DraftResponse):
    citations: list[str] = Field(
        default_factory=list,
        description="URLs or references supporting the revised answer"
    )

Now the LLM has a predictable output contract.

Conceptually:

DraftResponse
│
├── answer
│
├── reflection
│   ├── critique
│   ├── missing
│   └── superfluous
│
└── search_queries

This follows the course's AnswerQuestion / Reflection design where the response contains the answer, reflection information, missing details, unnecessary information, and search queries.

Modern LangChain also provides with_structured_output() for obtaining model responses that conform to a defined schema.


10. Why Structured Output Matters

Without a schema, you might receive:

The answer is okay but should mention the refund policy.
Maybe search for the current replacement policy.
Also mention the delivery window.

Now your Python code has to parse natural language.

That's fragile.

With a schema:

{
  "answer": "...",
  "reflection": {
    "critique": "...",
    "missing": "...",
    "superfluous": "..."
  },
  "search_queries": [
    "company damaged item replacement policy"
  ]
}

Your application can directly access:

result.reflection.missing

or:

result.search_queries

This is much easier to route through a graph.


11. Step 2 — Initialize the LLM

import os
from langchain_openai import ChatOpenAI


llm = ChatOpenAI(
    model=os.getenv("OPENAI_MODEL", "gpt-4o"),
    temperature=0
)

We use a low temperature because this application is focused on consistency and evaluation rather than creative variation.


12. Step 3 — Create Responder and Revisor Models

We can create two structured LLM pipelines.

responder = llm.with_structured_output(DraftResponse)

revisor = llm.with_structured_output(RevisedResponse)

Now:

Responder
    ↓
DraftResponse

Revisor
    ↓
RevisedResponse

The current LangChain approach can use provider-native structured output when supported, or a tool-calling strategy when native structured output is unavailable.


13. Step 4 — Create the Responder Prompt

RESPONDER_SYSTEM = """
You are an expert customer-support responder.

Your job is to answer the user's question clearly and accurately.

Rules:

1. Answer the user's actual question.
2. Do not invent company policies.
3. Identify important missing information.
4. Identify irrelevant information.
5. Critique your own draft.
6. Generate search queries for claims that need verification.
7. Prefer specific and actionable answers.
8. Keep the response concise but complete.

Return the answer using the required structured schema.
"""

The responder is not only generating an answer.

It is generating:

Answer
+
Self-Critique
+
Missing Information
+
Search Queries

That's what turns a simple LLM call into a reflection-oriented component.


14. Step 5 — Create the Revisor Prompt

The revisor has a different responsibility.

REVISOR_SYSTEM = """
You are a senior customer-support quality reviewer.

Your job is to improve the previous answer using:

- the original user question
- the previous answer
- the critique
- missing information
- external search results

Rules:

1. Fix factual problems.
2. Address missing requirements.
3. Remove irrelevant content.
4. Do not invent facts.
5. Use external evidence when available.
6. Include citations for externally verified claims.
7. Produce a clearer and more useful answer.
8. Generate additional search queries only when more verification is needed.

Return the revised answer using the required schema.
"""

This is similar to the reference architecture where the revisor receives the response history and tool results, then revises the answer and adds references.


15. Step 6 — Add External Knowledge

Now we introduce the most important difference between a basic reflection agent and a Reflexion-style system.

The agent can search for information.

from langchain_tavily import TavilySearch


search_tool = TavilySearch(
    max_results=5,
    topic="general"
)

Tavily's current LangChain integration uses TavilySearch from langchain-tavily, with options such as max_results, search_depth, time_range, and domain filters.

We can call it:

results = search_tool.invoke({
    "query": "damaged product replacement policy"
})

The search result can contain information such as:

title
url
content

The course reference uses the same concept: responder-generated search queries are extracted, passed to the search tool, and the resulting tool messages are added to the response history for the revisor.


16. Step 7 — Define LangGraph State

This is where LangGraph becomes useful.

A reflection agent is not just a chain.

It is a loop.

We need to remember:

Original question
Draft
Critique
Search results
Revision
Iteration count

Current LangGraph applications commonly use StateGraph with an explicit state schema. The graph state persists across node execution, and reducers such as add_messages control how message updates are merged.

Let's define:

from typing import Annotated
from typing_extensions import TypedDict
from langchain_core.messages import AnyMessage
from langgraph.graph.message import add_messages


class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

    draft: DraftResponse | None

    revision: RevisedResponse | None

    search_results: list[str]

    iteration: int

Think of this as the agent's memory for the current workflow.


17. Why State Is Important

Without state:

Responder
   ↓
Revisor

"What was the original question?"

With state:

State
│
├── original question
├── previous draft
├── critique
├── missing information
├── search results
├── revised answer
└── iteration count

Every node can use the relevant information.

This is one of the major reasons to use LangGraph instead of writing a collection of nested Python function calls.

LangGraph is specifically designed for stateful workflows and provides graph nodes, edges, conditional routing, persistence-related infrastructure, and human-in-the-loop capabilities.


18. Step 8 — Create the Responder Node

from langchain_core.messages import HumanMessage


def responder_node(state: AgentState):
    user_message = state["messages"][0].content

    prompt = f"""
{RESPONDER_SYSTEM}

User question:
{user_message}
"""

    result = responder.invoke(prompt)

    return {
        "draft": result,
        "messages": [
            {
                "role": "assistant",
                "content": result.answer
            }
        ],
        "iteration": state.get("iteration", 0) + 1
    }

The responder performs the first generation.

Conceptually:

User Question
      ↓
Responder
      ↓
DraftResponse
      ↓
State

19. Step 9 — Create the Search Node

The responder tells us what needs verification.

For example:

[
    "damaged item replacement policy",
    "replacement eligibility within 30 days"
]

We execute those searches.

def search_node(state: AgentState):
    draft = state["draft"]

    search_results = []

    for query in draft.search_queries:
        result = search_tool.invoke({
            "query": query
        })

        search_results.append(str(result))

    return {
        "search_results": search_results
    }

Now:

Responder
    │
    └── search_queries
             │
             ▼
       Tavily Search
             │
             ▼
       Search Results

20. Step 10 — Create the Revisor Node

Now the revisor receives:

Original Question
+
Draft
+
Critique
+
Missing Information
+
Search Results

Implementation:

def revisor_node(state: AgentState):
    draft = state["draft"]

    evidence = "\n\n".join(
        state.get("search_results", [])
    )

    prompt = f"""
{REVISOR_SYSTEM}

Original question:
{state["messages"][0].content}

Previous answer:
{draft.answer}

Critique:
{draft.reflection.critique}

Missing information:
{draft.reflection.missing}

Superfluous information:
{draft.reflection.superfluous}

External search results:
{evidence}
"""

    result = revisor.invoke(prompt)

    return {
        "revision": result,
        "messages": [
            {
                "role": "assistant",
                "content": result.answer
            }
        ],
        "iteration": state["iteration"] + 1
    }

Now we have:

                    ┌──────────────┐
                    │   Responder  │
                    └──────┬───────┘
                           │
                           ▼
                    ┌──────────────┐
                    │    Search    │
                    └──────┬───────┘
                           │
                           ▼
                    ┌──────────────┐
                    │    Revisor   │
                    └──────────────┘

21. Step 11 — Decide Whether to Continue

An agent should never be allowed to loop forever.

We need a routing function.

from langgraph.graph import END


MAX_ITERATIONS = 3


def should_continue(state: AgentState):
    if state["iteration"] >= MAX_ITERATIONS:
        return END

    return "search"

But in a real production system, iteration count alone is not enough.

A better design is:

                Revisor
                   │
          ┌────────┴────────┐
          │                 │
     Needs more          Good enough
     information              │
          │                   ▼
          ▼                 END
       Search

For example, you could make the revisor return:

class RevisedResponse(BaseModel):
    answer: str
    citations: list[str]
    search_queries: list[str]
    needs_more_research: bool

Then:

def should_continue(state: AgentState):
    revision = state["revision"]

    if state["iteration"] >= MAX_ITERATIONS:
        return END

    if revision.needs_more_research:
        return "search"

    return END

This is much more intelligent than blindly executing exactly four iterations.

LangGraph supports conditional edges specifically for this type of runtime routing.


22. Step 12 — Build the Graph

Now connect the nodes.

from langgraph.graph import StateGraph, START, END


builder = StateGraph(AgentState)

builder.add_node("responder", responder_node)
builder.add_node("search", search_node)
builder.add_node("revisor", revisor_node)

builder.add_edge(START, "responder")

builder.add_edge("responder", "search")

builder.add_edge("search", "revisor")

builder.add_conditional_edges(
    "revisor",
    should_continue,
    {
        "search": "search",
        END: END
    }
)

graph = builder.compile()

The workflow is now:

START
  │
  ▼
Responder
  │
  ▼
Search
  │
  ▼
Revisor
  │
  ├────── Search
  │         │
  │         ▼
  │      Revisor
  │         │
  │         └── ...
  │
  └────── END

LangGraph's current Graph API uses START, END, StateGraph, nodes, normal edges, and conditional edges to represent these workflows.


23. Step 13 — Invoke the Agent

result = graph.invoke({
    "messages": [
        {
            "role": "user",
            "content": """
            My order arrived damaged.
            I want a replacement.
            What should I do?
            """
        }
    ],
    "draft": None,
    "revision": None,
    "search_results": [],
    "iteration": 0
})

Then:

print(result["revision"].answer)

You have now built a self-correcting workflow.


24. What Happens Internally?

Let's simulate the execution.

Iteration 1

User:

My order arrived damaged.
I want a replacement.
What should I do?

Responder:

Sorry about the damaged item.

Please contact support and provide
your order number and photos.

Reflection:

Critique:
The response is useful but generic.

Missing:
Replacement eligibility and current policy.

Search:
"damaged item replacement policy"

External Search

Search tool returns:

Replacement Policy

Damaged products may qualify for replacement
within the applicable return window.

Source:
https://example.com/replacement-policy

Iteration 2

Revisor receives:

Original Question
+
Draft
+
Critique
+
Search Result

It produces:

I'm sorry your order arrived damaged.

To request a replacement:

1. Keep the damaged product and packaging.
2. Take clear photos of the damage.
3. Provide your order number.
4. Submit the replacement request within
   the applicable return window.

The replacement policy should be checked
against the current policy for your order.

Source:
example.com/replacement-policy

The answer is now:

More specific
+
Evidence-backed
+
Actionable

25. The Important Difference: Chain vs Graph

A chain looks like:

A → B → C → D

A graph can look like:

       ┌───────┐
       │       │
       ▼       │
A → B → C → D ─┘
       │
       ▼
      END

That's why reflection is naturally represented as a graph.

You don't know in advance whether the agent should:

stop

or:

search again

or:

ask a human

or:

try another evaluator

LangGraph is designed around exactly this kind of stateful, conditional workflow.


26. Basic Reflection Architecture

For a simple application, you don't even need external search.

        User
         │
         ▼
    ┌──────────┐
    │ Generator│
    └────┬─────┘
         │
         ▼
    ┌──────────┐
    │ Reflector│
    └────┬─────┘
         │
         ▼
   Feedback
         │
         ▼
    Generator
         │
         ▼
       END

This is useful for:

  • writing
  • code generation
  • SQL generation
  • summarization
  • content optimization
  • interview answers
  • documentation generation

The course demonstrates exactly this pattern using a LinkedIn content optimizer, where generation and reflection alternate until a message-count-based stopping condition is reached.


27. Reflexion Architecture with External Knowledge

For more demanding applications:

                     User
                       │
                       ▼
                 ┌───────────┐
                 │ Responder │
                 └─────┬─────┘
                       │
                       ▼
                 ┌───────────┐
                 │ Reflection│
                 └─────┬─────┘
                       │
                Search Queries
                       │
                       ▼
                 ┌───────────┐
                 │   Tools   │
                 └─────┬─────┘
                       │
                 External Data
                       │
                       ▼
                 ┌───────────┐
                 │  Revisor  │
                 └─────┬─────┘
                       │
                       ▼
                 Quality Check
                    /       \
                  No         Yes
                  │           │
                  └──→ Loop   ▼
                           Final

The course's external-knowledge example follows this architecture using a search tool, structured answer/reflection schemas, responder and revisor nodes, and a bounded iteration loop.


28. Why Pydantic Is So Important Here

Reflection systems can become complicated very quickly.

Imagine this output:

Answer:
...

Critique:
...

Missing:
...

Search:
...

Citations:
...

Parsing this manually is fragile.

Instead:

class Reflection(BaseModel):
    critique: str
    missing: str
    superfluous: str

Now your application knows exactly what it expects.

For example:

reflection.critique
reflection.missing
reflection.superfluous

And:

draft.search_queries

This is one of the biggest production benefits of structured LLM output.

LangChain explicitly supports Pydantic-based structured outputs with validation, making them suitable for downstream application logic.


29. Why We Should Not Let the LLM Decide Everything

A common beginner mistake is:

LLM:
"Keep thinking until you are satisfied."

This is dangerous in production.

The model may:

  • loop unnecessarily
  • spend too many tokens
  • make repeated searches
  • oscillate between answers
  • fail to terminate

Instead, enforce deterministic controls.

MAX_ITERATIONS = 3

And:

if state["iteration"] >= MAX_ITERATIONS:
    return END

You can also use LangGraph's recursion controls when appropriate. The current Graph API documents both explicit termination conditions and recursion-limit handling for loops.


30. Quality-Based Stopping

A stronger production design is:

                Revisor
                   │
                   ▼
          Quality Evaluation
                   │
           ┌───────┴───────┐
           │               │
        Score < 0.8     Score >= 0.8
           │               │
           ▼               ▼
         Revise            END

For example:

class Evaluation(BaseModel):
    accuracy: float
    completeness: float
    relevance: float
    groundedness: float
    overall_score: float
    needs_revision: bool

Then:

if evaluation.needs_revision:
    return "revise"

return END

This makes the loop much more controllable.


31. Reflection for Code Generation

This architecture becomes extremely powerful for software engineering agents.

Suppose the user asks:

Write a Python function to find duplicate records.

Normal agent:

Generate code
      ↓
Return code

Reflection agent:

Generate code
      ↓
Review code
      ↓
Identify bugs
      ↓
Run tests
      ↓
Review failures
      ↓
Fix code
      ↓
Run tests again
      ↓
Final code

Architecture:

                 User
                   │
                   ▼
              Code Generator
                   │
                   ▼
              Code Reviewer
                   │
                   ▼
               Test Runner
                   │
              ┌────┴────┐
              │         │
           Failed      Passed
              │         │
              ▼         ▼
         Code Fixer    END
              │
              └──────→ Test Runner

This is much closer to a real coding agent.


32. Reflection for RAG Applications

Suppose you already have a RAG application:

User
 ↓
Retriever
 ↓
Documents
 ↓
LLM
 ↓
Answer

Add reflection:

User
 ↓
Retriever
 ↓
LLM
 ↓
Answer
 ↓
Evaluator
 ↓
Are all claims supported?
 ↓
No
 ↓
Retrieve more documents
 ↓
LLM
 ↓
Revised Answer

This helps address a common RAG problem:

The retrieved documents may contain information, but the generated answer may still fail to use the evidence correctly.

A reflection agent can explicitly check:

Does the answer answer the question?
Are claims supported?
Did the answer miss important information?
Are citations relevant?
Is any statement unsupported?

33. Reflection for SQL Agents

Consider:

Show monthly revenue for 2026.

A SQL agent might generate:

SELECT month, SUM(revenue)
FROM sales
GROUP BY month;

But a reflection agent could detect:

Problem:
The query does not filter for 2026.

Then generate:

SELECT
    DATE_TRUNC('month', order_date) AS month,
    SUM(revenue) AS revenue
FROM sales
WHERE order_date >= '2026-01-01'
  AND order_date < '2027-01-01'
GROUP BY 1
ORDER BY 1;

The workflow becomes:

User
 ↓
SQL Generator
 ↓
SQL Reviewer
 ↓
Database
 ↓
Result Validator
 ↓
Correct?
 ├── No → Fix SQL
 └── Yes → Final Result

This is a highly practical enterprise use case.


34. Reflection for AI Research Agents

A research assistant is an excellent candidate.

Normal:

Question
 ↓
Search
 ↓
Summarize

Reflection:

Question
 ↓
Researcher
 ↓
Draft
 ↓
Critic
 ↓
Missing evidence
 ↓
Search
 ↓
Revisor
 ↓
Citation validation
 ↓
Final report

The course's Reflexion material emphasizes exactly these benefits: external information can be incorporated during the iteration, and the revised response can contain references supporting its claims.


35. Reflection Agent vs ReAct Agent

These concepts are related but different.

ReAct

ReAct focuses on:

Reason
 ↓
Act
 ↓
Observe
 ↓
Reason
 ↓
Act

Example:

Think
 ↓
Search web
 ↓
Observe result
 ↓
Search another source
 ↓
Answer

Reflection

Reflection focuses on:

Generate
 ↓
Critique
 ↓
Revise

Reflexion

Reflexion combines iterative self-evaluation with external information and evidence.

A useful mental model is:

ReAct
= How should I act?

Reflection
= How good was my answer?

Reflexion
= How can I improve my answer using feedback and evidence?

This is why the two patterns can be combined.

For example:

            Research Agent
                 │
        ┌────────┴────────┐
        │                 │
      ReAct            Reflection
        │                 │
   Search/Tools       Critique
        │                 │
        └────────┬────────┘
                 ▼
              Revisor

36. Current LangGraph Note: MessageGraph vs StateGraph

This is important if you are following older tutorials.

Your attached course material uses:

MessageGraph()

and describes it as a graph whose state is an array of messages.

That explanation is useful for understanding the concept.

However, the current LangGraph reference marks MessageGraph as deprecated (since LangGraph v1.0, to be removed in v2.0) and recommends StateGraph with a messages key instead.

So for new projects, prefer:

from langgraph.graph import StateGraph

with:

class State(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

rather than starting a new project with:

MessageGraph()

This is a good example of an important engineering habit:

Learn the architecture from older tutorials, but verify the implementation against the current framework API.


37. Production Architecture

For an industry project, I would not stop at:

Responder → Reflector → Revisor

I would design something closer to:

                         ┌───────────────┐
                         │     User      │
                         └───────┬───────┘
                                 │
                                 ▼
                         ┌───────────────┐
                         │ Intent Router │
                         └───────┬───────┘
                                 │
                                 ▼
                         ┌───────────────┐
                         │   Responder   │
                         └───────┬───────┘
                                 │
                                 ▼
                         ┌───────────────┐
                         │   Critic      │
                         └───────┬───────┘
                                 │
                  ┌──────────────┼──────────────┐
                  │              │              │
                  ▼              ▼              ▼
              Missing       Unsupported     Incorrect
              evidence       claim           logic
                  │              │              │
                  └──────────────┼──────────────┘
                                 ▼
                         ┌───────────────┐
                         │  Tool/Search  │
                         └───────┬───────┘
                                 │
                                 ▼
                         ┌───────────────┐
                         │    Revisor    │
                         └───────┬───────┘
                                 │
                                 ▼
                         ┌───────────────┐
                         │   Evaluator   │
                         └───────┬───────┘
                                 │
                     ┌───────────┴──────────┐
                     │                      │
                 Good enough             Needs work
                     │                      │
                     ▼                      ▼
                   END                   Revisor

This is much closer to what you would expect in an enterprise AI platform.


38. Important Production Improvements

A production reflection agent should have:

1. Maximum iteration limit

MAX_ITERATIONS = 3

2. Token budget

Don't allow unlimited context growth.

3. Tool timeout

External APIs can fail.

4. Retry policy

Transient tool/model errors should be retried safely.

5. Structured outputs

Use Pydantic or another validated schema.

6. Citation validation

Don't blindly trust URLs returned by the model.

7. Observability

Track:

iteration
latency
tokens
tool calls
search queries
critic scores
final quality score

8. Human-in-the-loop

High-risk workflows should allow human approval.

LangGraph specifically provides infrastructure for stateful workflows and human-in-the-loop patterns.


39. Common Mistakes

Mistake 1 — Reflection Without a Goal

Bad:

Critique the answer.

Better:

Evaluate the answer for:

- correctness
- completeness
- relevance
- clarity
- unsupported claims

The reflector needs explicit evaluation criteria.


Mistake 2 — Unlimited Loops

Bad:

while not perfect:
    revise()

Better:

if iteration >= MAX_ITERATIONS:
    return END

Mistake 3 — Asking the Same Model to "Think Harder"

This:

Give me a better answer.

is not a robust reflection architecture.

Instead:

Generator
     ↓
Structured Critique
     ↓
Evidence
     ↓
Revisor

Each stage has a defined responsibility.


Mistake 4 — No State

If previous critiques and search results are lost, the next iteration cannot meaningfully improve the answer.

State is the memory of the workflow.


Mistake 5 — No External Verification

For dynamic information, relying only on the model's training data can produce stale information.

A tool-enabled reflection agent can retrieve current information before revising the answer. The course specifically highlights this as a key benefit of Reflexion.


Mistake 6 — Assuming Reflection Guarantees Correctness

Reflection does not magically make an LLM correct.

It can improve:

completeness
clarity
evidence
consistency

but the critic can also make mistakes.

Therefore:

Reflection ≠ Truth

For high-risk applications, combine reflection with:

  • deterministic validation
  • trusted databases
  • domain-specific rules
  • tests
  • human review

40. How to Evaluate a Reflection Agent

Don't just ask:

"Does the final answer look better?"

Create measurable evaluation criteria.

For example:

Accuracy        0–1
Completeness    0–1
Relevance       0–1
Groundedness    0–1
Citation quality 0–1

Then:

overall_score = (
    accuracy * 0.30 +
    completeness * 0.25 +
    relevance * 0.20 +
    groundedness * 0.20 +
    citation_quality * 0.05
)

Then your routing can be:

if overall_score >= 0.85:
    END
else:
    revise

This turns reflection from a vague concept into an engineering system.


41. Reflection Loop as a State Machine

The entire architecture can be represented mathematically as:

S₀ = User Query

S₁ = Generate(S₀)

S₂ = Critique(S₁)

S₃ = Retrieve(S₂)

S₄ = Revise(S₁, S₂, S₃)

S₅ = Evaluate(S₄)

if Quality(S₅) >= threshold:
    return S₅

else:
    repeat

In other words:

State(t+1) = f(State(t), feedback, evidence)

This is why LangGraph is such a natural fit.


42. The Most Important Mental Model

If you remember only one architecture from this tutorial, remember this:

                    ┌───────────────┐
                    │    GENERATE   │
                    └───────┬───────┘
                            │
                            ▼
                    ┌───────────────┐
                    │    CRITIQUE   │
                    └───────┬───────┘
                            │
                            ▼
                    ┌───────────────┐
                    │   RESEARCH    │
                    └───────┬───────┘
                            │
                            ▼
                    ┌───────────────┐
                    │     REVISE    │
                    └───────┬───────┘
                            │
                            ▼
                    ┌───────────────┐
                    │    EVALUATE   │
                    └───────┬───────┘
                            │
                       Good enough?
                        /       \
                      Yes        No
                       │          │
                       ▼          │
                      END ────────┘

That is the foundation.


43. Complete Conceptual Architecture

For an industry-level AI application, think in terms of six components:

1. GENERATOR
   ↓
   Creates the first answer.

2. CRITIC
   ↓
   Finds weaknesses.

3. TOOL
   ↓
   Retrieves evidence or performs actions.

4. REVISOR
   ↓
   Creates a better answer.

5. EVALUATOR
   ↓
   Measures quality.

6. ROUTER
   ↓
   Decides whether to stop or continue.

LangGraph becomes the orchestration layer:

             ┌──────────────────────────┐
             │        LangGraph         │
             │                          │
             │  State + Nodes + Edges   │
             │  Routing + Iterations    │
             └──────────────────────────┘

44. Reflection Agent vs Traditional LLM Application

Traditional LLM Reflection Agent
One generation Multiple iterations
One prompt Multiple specialized prompts
No explicit critique Critic/reflection stage
Static knowledge Can use external tools
Free-form output Structured output
Linear flow Graph-based workflow
No quality gate Evaluation + routing
More likely to miss requirements Can explicitly check requirements
Simple architecture More complex architecture
Lower latency Higher latency
Lower cost Higher cost

The key trade-off is:

Better quality
      ↑
      │
      │
      │
      └──────────────→ More model calls
                      More latency
                      More cost

Reflection should therefore be used where the quality improvement justifies the additional cost.


45. When Should You Use Reflection Agents?

Use reflection when:

Quality is important
AND
Errors are expensive
AND
The task can be evaluated

Excellent use cases:

  • coding agents
  • SQL generation
  • research agents
  • document generation
  • customer support
  • compliance workflows
  • RAG answer verification
  • technical documentation
  • content optimization
  • data analysis
  • report generation

Don't necessarily use it for:

"What is 2 + 2?"

A reflection loop would add unnecessary latency and cost.


46. A Practical Rule for AI Engineers

When designing an agent, ask:

Question 1

Can I evaluate the output?

If no, reflection may be difficult.

Question 2

Can I identify specific failure modes?

For example:

Missing facts
Incorrect facts
Unsupported claims
Bad formatting
Incomplete requirements

If yes, reflection becomes useful.

Question 3

Can I obtain additional evidence?

If yes, add tools.

Question 4

Can I define a stopping condition?

If yes, the workflow can be safely bounded.


47. Final Architecture for Your Own Projects

If you are building an industry-level GenAI project, I recommend starting with:

                   USER
                    │
                    ▼
             ┌─────────────┐
             │   ROUTER    │
             └──────┬──────┘
                    │
                    ▼
             ┌─────────────┐
             │  GENERATOR  │
             └──────┬──────┘
                    │
                    ▼
             ┌─────────────┐
             │   CRITIC    │
             └──────┬──────┘
                    │
            ┌───────┴────────┐
            │                │
         Evidence         No evidence
            │                │
            ▼                │
        TOOL CALL            │
            │                │
            └───────┬────────┘
                    ▼
             ┌─────────────┐
             │   REVISOR   │
             └──────┬──────┘
                    │
                    ▼
             ┌─────────────┐
             │  EVALUATOR  │
             └──────┬──────┘
                    │
              ┌─────┴─────┐
              │           │
          Continue       Finish
              │           │
              ▼           ▼
           Revisor       END

This architecture gives you a very strong foundation for building more sophisticated agentic systems later.


48. Key Takeaways

A Reflection Agent does not simply generate an answer.

It creates a feedback loop:

Generate
   ↓
Critique
   ↓
Revise

A Reflexion-style agent extends this pattern with:

Self-Critique
+
External Knowledge
+
Structured Output
+
Citations
+
Iterative Revision

LangChain provides the LLM and structured-output layer.

Pydantic provides the schema contract.

External tools such as Tavily provide current information.

LangGraph provides:

State
+
Nodes
+
Edges
+
Conditional Routing
+
Iteration Control

The attached course material describes the same overall architecture: responder → tool/search → revisor, with structured schemas and a bounded iteration loop.

For new LangGraph projects, use the current StateGraph approach rather than starting with the older MessageGraph abstraction, because the latter is now deprecated.

The most important idea is this:

A good AI agent should not only know how to generate an answer; it should know how to inspect that answer, identify what is missing, gather evidence, improve the answer, and know when to stop.

That is where a simple LLM call starts becoming an AI engineering system rather than just a chatbot.


References

Post a Comment

0 Comments

Multiplex ad