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