You are viewing the v1 docs for LangChain, which is currently under active development. Learn more.

Overview

Tools are components that Agents call to perform actions. They extend model capabilities by letting them interact with the world through well-defined inputs and outputs.

Creating tools

Basic tool definition

The simplest way to create a tool is by importing the tool function from the langchain package. You can use zod to define the tool’s input schema:
import { z } from "zod"
import { tool } from "langchain"

const searchDatabase = tool(
    ({ query, limit }) => {
        return `Found ${limit} results for '${query}'`
    },
    {
        name: "search_database",
        description: "Search the customer database for records matching the query.",
        schema: z.object({
            query: z.string().describe("Search terms to look for"),
            limit: z.number().describe("Maximum number of results to return")
        })
    }
);
Alternatively, you can define the schema property as a JSON schema object:
const searchDatabase = tool(
    (input) => {
        const { query, limit } = input as { query: string; limit: number }
        return `Found ${limit} results for '${query}'`
    },
    {
        name: "search_database",
        description: "Search the customer database for records matching the query.",
        schema: {
            type: "object",
            properties: {
                query: { type: "string", description: "Search terms to look for" },
                limit: { type: "number", description: "Maximum number of results to return" }
            },
            required: ["query", "limit"]
        }
    }
);

Using tools with agents

Agents go beyond simple tool binding by adding reasoning loops, state management, and multi-step execution.
To see examples of how to use tools with agents, see Agents.

Advanced tool patterns

ToolNode

ToolNode is a prebuilt LangGraph component that handles tool calls within an agent’s workflow. It works seamlessly with createAgent(), offering advanced tool execution control, built in parallelism, and error handling.

Configuration options

ToolNode accepts the following parameters:
import { ToolNode } from "langchain";

const toolNode = new ToolNode([searchDatabase, calculate], {
    name: "tools",
    tags: ["tool-execution"],
    handleToolErrors: true
})
tools
A list of LangChain tool objects.
handleToolErrors
Controls how tool execution failures are handled. Can be:
  • boolean
    • ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined)
See Error handling strategies below for details. Default: true

Error handling strategies

ToolNode provides built-in error handling for tool execution through its handleToolErrors property. To customize the error handling behavior, you can configure handleToolErrors to either be a boolean or a custom error handler function:
  • true: Catch all errors and return a ToolMessage with the default error template containing the exception details. (default)
  • false: Disable error handling entirely, allowing exceptions to propagate.
  • ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined): Catch all errors and return a ToolMessage with the result of calling the function with the exception.
Examples of how to use the different error handling strategies:
const toolNode = new ToolNode([my_tool], {
    handleToolErrors: true
})

const toolNode = new ToolNode([my_tool], {
    handleToolErrors: (error, toolCall) => {
        return new ToolMessage({
            content: "I encountered an issue. Please try rephrasing your request.",
            tool_call_id: toolCall.id
        })
    }
})

Agent creation

Pass a configured ToolNode directly to createAgent():
import { z } from "zod"
import { ChatOpenAI } from "@langchain/openai"
import { ToolNode, createAgent } from "langchain"

const searchDatabase = tool(
    ({ query }) => {
        return `Results for: ${query}`
    },
    {
        name: "search_database",
        description: "Search the database.",
        schema: z.object({
            query: z.string().describe("The query to search the database with")
        })
    }
);

const sendEmail = tool(
    ({ to, subject, body }) => {
        return `Email sent to ${to}`
    },
    {
        name: "send_email",
        description: "Send an email.",
        schema: z.object({
            to: z.string().describe("The email address to send the email to"),
            subject: z.string().describe("The subject of the email"),
            body: z.string().describe("The body of the email")
        })
    }
);

// Configure ToolNode with custom error handling
const toolNode = new ToolNode([searchDatabase, sendEmail], {
    name: "email_tools",
    handleToolErrors: (error, toolCall) => {
        return new ToolMessage({
            content: "I encountered an issue. Please try rephrasing your request.",
            tool_call_id: toolCall.id
        });
    }
});

// Create agent with the configured ToolNode
const agent = createAgent({
    model: new ChatOpenAI({ model: "gpt-5" }),
    tools: toolNode, // Pass ToolNode instead of tools list
    prompt: "You are a helpful email assistant."
});

// The agent will use your custom ToolNode configuration
const result = await agent.invoke({
    messages: [{ role: "user", content: "Search for John and email him" }]
})
When you pass a ToolNode to createAgent(), the agent uses your exact configuration including error handling, custom names, and tags. This is useful when you need fine-grained control over tool execution behavior.

State, context, and memory