# How to Build Tool-Using Agents with LangChain

> Learn to build tool-using agents with LangChain. Implement a ReAct loop using custom prompts, structured output, and AgentExecutor to let LLMs use external tools dynamically.

- Repository: [OpenAI/openai-cookbook](https://github.com/openai/openai-cookbook)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Build tool-using agents with LangChain by implementing a ReAct (Reasoning and Acting) loop that combines a custom prompt template, structured output parser, and AgentExecutor to enable LLMs to dynamically invoke external tools like web search APIs.**

The [openai/openai-cookbook](https://github.com/openai/openai-cookbook) repository provides a complete reference implementation in `examples/How_to_build_a_tool-using_agent_with_Langchain.ipynb` that demonstrates how to build tool-using agents with LangChain from scratch. This guide breaks down the modular architecture—covering tool definition, prompt engineering, and agent execution—that transforms a standard LLM into a reasoning system capable of calling external APIs to answer real-time queries.

## Installing Dependencies and Imports

Start by installing the required packages and importing the necessary LangChain classes. According to the source code in `examples/How_to_build_a_tool-using_agent_with_Langchain.ipynb` (lines 69-76 and 85-104), you need `langchain`, `openai`, and supporting libraries for external integrations.

```python
!pip install openai pinecone-client pandas langchain wget tqdm

import os, re
from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser
from langchain.prompts import BaseChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain, SerpAPIWrapper
from langchain.schema import HumanMessage, AgentAction, AgentFinish

```

## Configuring External Tools

Tool-using agents require callable functions that the LLM can invoke. The notebook demonstrates this using `SerpAPIWrapper` to create a web search tool (lines 200-218). Wrap the search functionality in a `Tool` object with a descriptive name and purpose so the LLM understands when to use it.

```python
search = SerpAPIWrapper()

tools = [
    Tool(
        name="Search",
        func=search.run,
        description="useful for when you need to answer questions about current events",
    )
]

```

## Designing the ReAct Prompt Template

The **ReAct** (Reasoning and Acting) pattern requires a specific prompt structure that guides the LLM through a loop of Thought → Action → Observation. As implemented in `examples/How_to_build_a_tool-using_agent_with_Langchain.ipynb` (lines 228-247), the template must include placeholders for `{tools}`, `{tool_names}`, user `{input}`, and `{agent_scratchpad}` for intermediate reasoning.

```python
template = """
Answer the following questions as best you can, but speaking as a pirate might speak.
You have access to the following tools:

{tools}

Use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

Begin!

Question: {input}
{agent_scratchpad}
"""

```

## Implementing Custom Agent Components

Tool-using agents with LangChain require two critical custom classes: a prompt template handler and an output parser. These components translate between the LLM's text output and executable program logic.

### The Custom Prompt Template Class

The `CustomPromptTemplate` class (lines 255-283) inherits from `BaseChatPromptTemplate` and injects dynamic content into the prompt. The `format_messages` method processes `intermediate_steps` to build the reasoning scratchpad and returns a `HumanMessage` for the LLM.

```python
class CustomPromptTemplate(BaseChatPromptTemplate):
    template: str
    tools: list[Tool]

    def format_messages(self, **kwargs):
        intermediate_steps = kwargs.pop("intermediate_steps")
        thoughts = ""
        for action, observation in intermediate_steps:
            thoughts += action.log
            thoughts += f"\nObservation: {observation}\nThought: "
        
        kwargs["agent_scratchpad"] = thoughts
        kwargs["tools"] = "\n".join([f"{t.name}: {t.description}" for t in self.tools])
        kwargs["tool_names"] = ", ".join([t.name for t in self.tools])
        
        formatted = self.template.format(**kwargs)
        return [HumanMessage(content=formatted)]

prompt = CustomPromptTemplate(
    template=template,
    tools=tools,
    input_variables=["input", "intermediate_steps"]
)

```

### The Output Parser Class

The `CustomOutputParser` class (lines 298-327) inherits from `AgentOutputParser` and converts raw LLM text into structured actions. It detects `Final Answer:` to terminate the loop or extracts `Action:` and `Action Input:` using regex to create `AgentAction` objects.

```python
class CustomOutputParser(AgentOutputParser):
    def parse(self, llm_output: str):
        if "Final Answer:" in llm_output:
            return AgentFinish(
                return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
                log=llm_output,
            )
        
        regex = r"Action: (.*?)[\n]*Action Input:[\s]*(.*)"
        match = re.search(regex, llm_output, re.DOTALL)
        
        if not match:
            raise ValueError(f"Could not parse LLM output: `{llm_output}`")
        
        action = match.group(1).strip()
        action_input = match.group(2).strip(' "')
        
        return AgentAction(tool=action, tool_input=action_input, log=llm_output)

output_parser = CustomOutputParser()

```

## Assembling the Agent and Executor

Combine the components into a functional agent using `LLMSingleActionAgent` and `AgentExecutor` (lines 336-366). The `stop` parameter tells the LLM when to pause for tool execution, while `verbose=True` enables debugging output that shows the thought process.

```python
llm = ChatOpenAI(temperature=0)
llm_chain = LLMChain(llm=llm, prompt=prompt)

agent = LLMSingleActionAgent(
    llm_chain=llm_chain,
    output_parser=output_parser,
    stop=["\nObservation:"],
    allowed_tools=[t.name for t in tools],
)

agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent, 
    tools=tools, 
    verbose=True
)

```

## Executing Agent Queries

With the executor initialized, you can run queries that require tool usage. The example in lines 380-394 demonstrates the agent processing a question about current events, invoking the search tool twice, and synthesizing a pirate-styled final answer.

```python
answer = agent_executor.run("Canada population 2023")
print(answer)

# Output: "The population of Canada as of 2023 is 38,664,637. Arg!"

```

The console output reveals the full ReAct trace: the agent generates a Thought, selects the Search tool with an Action Input, receives an Observation, and repeats until reaching a Final Answer.

## Summary

- **Tool Definition**: Wrap external APIs like `SerpAPIWrapper` in LangChain `Tool` objects to give the agent callable functions.
- **ReAct Prompting**: Structure prompts with `{tools}`, `{tool_names}`, and `{agent_scratchpad}` placeholders to enforce the thought-action-observation loop.
- **Custom Classes**: Implement `CustomPromptTemplate` to format intermediate reasoning steps and `CustomOutputParser` to translate LLM text into `AgentAction` or `AgentFinish` objects.
- **Agent Assembly**: Use `LLMSingleActionAgent` to bind the LLM, prompt, and parser, then wrap with `AgentExecutor` to manage the execution loop.
- **Source Reference**: The complete implementation resides in `examples/How_to_build_a_tool-using_agent_with_Langchain.ipynb` within the openai/openai-cookbook repository.

## Frequently Asked Questions

### What is the ReAct pattern in LangChain agents?

The ReAct (Reasoning and Acting) pattern is a framework that interleaves reasoning traces (Thoughts) with task-specific actions. In the openai/openai-cookbook implementation, the LLM generates a Thought about what to do next, selects an Action (tool name) and Action Input, observes the result, and repeats until determining a Final Answer. This pattern enables the agent to solve multi-step problems by combining internal reasoning with external tool usage.

### How do I add custom tools to a LangChain agent?

Define a Python function that performs the desired operation, then wrap it in a LangChain `Tool` object with a name and description. As shown in the source code, you pass a list of these Tool objects to both the `CustomPromptTemplate` (for prompt rendering) and the `AgentExecutor` (for execution). The agent selects tools based on their descriptions in the prompt.

### Why is a custom output parser necessary for tool-using agents?

Standard LLM outputs free-form text, but agents require structured decisions. The `CustomOutputParser` demonstrated in the cookbook intercepts the raw LLM output to detect termination (via "Final Answer:") or extract tool calls (via regex matching "Action:" and "Action Input:"). Without this parser, the system cannot convert text into executable `AgentAction` objects.

### Can I use different LLMs or vector stores with this agent architecture?

Yes. The modular design allows you to swap components without rewriting the core logic. Replace `ChatOpenAI` with `AzureChatOpenAI` or another LangChain LLM class in the `llm_chain` initialization. Similarly, replace `SerpAPIWrapper` with other tools like vector stores (Pinecone, FAISS) or calculators by updating the `tools` list and corresponding descriptions.