ReAct Pattern: Interleaving Reasoning and Action for LLM Agents › Integration with Real LLMs

Michael BrenndoerferFebruary 3, 20263 min read
Language AI HandbookAll chapters
Part 48 of 67Tool Use and Agents
Chapter 365ReAct Pattern: Interleaving Reasoning and Action for LLM Agents › Integration with Real LLMs
Reading section 9 of 14 · Integration with Real LLMs · 3 minSection 9 of 14 · 3 min

Book contents

Section 9 of 14 · 3 min read

ReAct Pattern: Interleaving Reasoning and Action for LLM Agents › Integration with Real LLMsOne section · Sections in this chapter9 / 14 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

In production systems, the llm_simulator function would be replaced with actual API calls to models like GPT-4, Claude, or open-source alternatives such as Llama or Mistral. Modern models trained with instruction tuning (covered in Part XXXVI) and RLHF (covered in Part XXXVII) typically require minimal few-shot examples to adopt the ReAct pattern effectively, though the specific formatting may need adjustment based on the model's training.

The following example integrates the pattern with the OpenAI API:

In[2]:
Code
import openai


def llm_call(prompt: str, model: str = "gpt-4") -> str:
    """Call OpenAI API with ReAct-formatted prompt."""
    client = openai.OpenAI()
    response = client.chat.completions.create(
        model=model,
        messages=[
            {
                "role": "system",
                "content": "You are a helpful assistant that uses tools by thinking step-by-step.",
            },
            {"role": "user", "content": prompt},
        ],
        temperature=0,  # Low temperature for deterministic reasoning
        stop=["\nObservation:"],  # Stop before generating observation
    )
    return response.choices[0].message.content

The stop parameter is important: it prevents the model from hallucinating observations. By specifying that generation should halt before creating an observation line, we ensure that observations come exclusively from actual tool execution rather than the model's imagination. This maintains the integrity of the grounding mechanism that makes ReAct reliable. Without this stop sequence, a sufficiently confident model might generate both the action and its supposed result in a single pass, completely bypassing the external tool call.

The temperature setting also matters. Low temperatures (0.0-0.2) produce more deterministic reasoning that follows the expected format reliably. Higher temperatures can cause format drift, where the model starts omitting the "Thought:" prefix or using slightly different action syntax. For most ReAct applications, temperature 0 is the right choice.

Structured Output Approach

An alternative to parsing free-form text is to use structured outputs or function calling to extract actions. Instead of asking the model to generate Action: search[query] in text and parsing it with regex, you ask the model to generate a JSON object with a defined schema:

In[4]:
Code
import openai

tools_spec = [
    {
        "type": "function",
        "function": {
            "name": "search",
            "description": "Search for information on a topic",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "The search query",
                    }
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Evaluate a mathematical expression",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "Mathematical expression to evaluate",
                    }
                },
                "required": ["expression"],
            },
        },
    },
]


def llm_call_structured(messages: list, tools: list) -> dict:
    """Call OpenAI API with structured tool definitions."""
    client = openai.OpenAI()
    response = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )
    return response.choices[0].message

The structured approach eliminates the need for regex parsing and reduces format errors significantly. The tradeoff is that the model no longer generates explicit thought text before each action, which reduces the interpretability of its reasoning. Some implementations address this by asking the model to include its reasoning in the tool call arguments or in a separate "thinking" step before calling tools.