Tools are components that Agents call to perform actions. They extend a model’s capabilities beyond text by letting it interact with the world through well-defined inputs and outputs.
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:
Copy
Ask AI
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:
Copy
Ask AI
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"] } });
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.
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:
Copy
Ask AI
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 }) }})
Pass a configured ToolNode directly to createAgent():
Copy
Ask AI
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 handlingconst 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 ToolNodeconst 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 configurationconst 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.
runtime: The execution environment of your agent, containing immutable configuration and contextual data that persists throughout the agent’s execution (e.g., user IDs, session details, or application-specific configuration).
Tools can access an agent’s runtime context through the config parameter:
Copy
Ask AI
import { z } from "zod"import { ChatOpenAI } from "@langchain/openai"import { ToolNode, createAgent } from "langchain"const getUserName = tool( (_, config) => { return config.context.user_name }, { name: "get_user_name", description: "Get the user's name.", schema: z.object({}) });const contextSchema = z.object({ user_name: z.string()});const agent = createAgent({ model: new ChatOpenAI({ model: "gpt-4o" }), tools: [getUserName], contextSchema,})const result = await agent.invoke( { messages: [{ role: "user", content: "What is my name?" }] }, { context: { user_name: "John Smith" } });