Back to roadmaps langgraph Course

Implementing the ReAct Agent Pattern with Loops

The ReAct (Reason-Act) pattern is the foundation of autonomous agents. The LLM reviews a prompt, decides to run a tool, executes it, observes the result, and loops back to decide if another tool is needed. Let us implement a ReAct agent using LangGraph.


1. ReAct Loop Workflow

The flow requires a conditional edge that inspects the LLM's response. If the LLM requests a tool call, we route to the tool node. If the LLM outputs a final text answer, we route to end.

graph TD
    A[Start: User prompt] --> B[Node: CallLLM]
    B -->|Conditional Edge| C{Should call tool?}
    C -->|Yes| D[Node: CallTool]
    D --> B
    C -->|No| E[__end__]

2. Coding the ReAct Agent

Create a TypeScript ReAct agent using @langchain/langgraph/prebuilt:

// src/services/reactAgent.ts
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { createReactAgent } from "@langchain/langgraph/prebuilt";

// 1. Declare tool
const calculateShippingTax = tool(
  async ({ country }) => {
    if (country.toLowerCase() === "canada") return "Shipping tax is $15";
    return "Shipping tax is $5";
  },
  {
    name: "calculateShippingTax",
    description: "Get shipping tax costs for a target country.",
    schema: z.object({ country: z.string() }),
  }
);

const toolsList = [calculateShippingTax];
const model = new ChatOpenAI({ modelName: "gpt-4o-mini", temperature: 0 });

// 2. Prebuilt createReactAgent handles State definition and Tool nodes composition
export const agent = createReactAgent({
  llm: model,
  tools: toolsList,
});

export async function runReactAgent(userPrompt: string) {
  const result = await agent.invoke({
    messages: [["user", userPrompt]],
  });

  // The final message in the returned state array holds the model's ultimate answer
  const finalMessage = result.messages[result.messages.length - 1];
  console.log("Final answer content:", finalMessage.content);
  return finalMessage.content;
}

3. Invocation Trace Analysis

If you trigger runReactAgent("What is the shipping tax for Canada?"), the loop executes as follows:

  1. Model Node: Generates a tool call requesting calculateShippingTax with parameter { country: "Canada" }.
  2. Conditional Edge: Detects the tool call request and routes execution to the prebuilt tools node.
  3. Tools Node: Executes calculateShippingTax, returns the result string, and appends it to the messages state.
  4. Model Node (Loop back): Reads the tool output and generates the final response: "The shipping tax for Canada is $15."
Published on Last updated: