LangChain ReAct Agent Loop (Legacy)
LangChain ReAct Agent Loop (Legacy)
Deprecated at
0.1.0, removed at1.0. Defined inlangchain_classic/agents/react/base.py.
Implements the ReAct paper (arXiv 2210.03629): interleave Reasoning (Thought) and Acting (tool calls) in a single text stream.
Prompt template: the control protocol lives in text
The loop is driven by two template variables filled into a PromptTemplate:
| Variable | Role |
|---|---|
{input} |
The question/task — filled once at invocation |
{agent_scratchpad} |
Growing string of Thought:/Action:/Observation: turns |
SUFFIX = """\nQuestion: {input}
{agent_scratchpad}"""
WIKI_PROMPT = PromptTemplate.from_examples(EXAMPLES, SUFFIX, ["input", "agent_scratchpad"])
from_examples() prepends static few-shot demonstrations showing the Thought/Action/Observation/Finish pattern; the LLM learns the protocol from them.
Control signals — all text
| Signal | Form | Who produces it |
|---|---|---|
| Tool call | Action: ToolName[argument] e.g. Search[Colorado orogeny] |
LLM (plain text) |
| Exit | Action: Finish[answer] |
LLM (plain text) |
| Stop generation | stop token "\nObservation:" |
Framework (injected as stop sequence) |
| LLM prefix | "Thought:" |
Framework (llm_prefix property) |
| Result injection | "Observation: <result>" appended to scratchpad |
Framework |
ReActOutputParser reads Action: / Action Input: lines from the LLM's text to determine what to execute. There is no structured object — the entire control protocol is a text convention enforced by the prompt format and the parser together.
Loop mechanics
The loop lives in the parent AgentExecutor class, not in ReActDocstoreAgent itself:
┌──────────────────────────────────────────────────────┐
│ Fill {input} + {agent_scratchpad} into template │
│ LLM call with prefix "Thought:", stop "\nObs:" │
│ ReActOutputParser reads Action: ToolName[arg] │
│ Execute tool → observation string │
│ Append "Observation: <result>" to scratchpad │
│ Repeat until LLM writes "Action: Finish[answer]" │
└──────────────────────────────────────────────────────┘
- LLM prefix:
"Thought:" - Stop sequence:
["\nObservation:"] - Output parser:
ReActOutputParser(parsesAction:/Action Input:/Final Answer:)
Class hierarchy
ReActDocstoreAgent(Agent)
↑ used by
ReActChain(AgentExecutor) ← thin wrapper that wires DocstoreExplorer
Tool constraints
Validated at construction; hard-coded to exactly {"Lookup", "Search"}. The DocstoreExplorer helper bridges these to an abstract Docstore:
| Tool | What it does |
|---|---|
Search |
Retrieves a document; saves it as current document |
Lookup |
Finds next occurrence of a term in the saved document (paginated) |
DocstoreExplorer is stateful: it tracks the current document and lookup cursor across turns.
Comparison
See Source - LangChain Agent Loop for full legacy vs modern comparison table.
Modern replacement: LangChain LangGraph Agent Loop.
Related
- Hermes Agent Loop — another class-based agent loop, multi-provider
- Agent Loop (OpenClaw) — gateway-layer loop above LLM calls