Who this is for and what you will build
This article is for readers who already run a first LangChain agent and want it to call functions they wrote. By the end you will know how to define a tool with @tool, name it and describe it, declare its inputs, control what it returns, and handle its errors.
What a tool is
A tool is a callable function with well-defined inputs and outputs, passed to a chat model. The model decides when to call a tool and which arguments to pass[1]. Tool calls can be traced and debugged with LangSmith[1].
Writing a tool in Python
The simplest way is the @tool decorator from langchain.tools. By default, the function's docstring becomes the tool description, and the model uses it to decide when the tool is relevant[1]:
from langchain.tools import tool
@tool
def search_database(query: str, limit: int = 10) -> str:
"""Search the customer database for records matching the query.
Args:
query: Search terms to look for
limit: Maximum number of results to return
"""
return f"Found {limit} results for '{query}'"Type hints are required, because they define the input schema the model sees. Keep the docstring short and say what the tool is for and what its arguments mean[1].
Writing a tool in JavaScript
The JavaScript version imports tool from langchain and uses zod to describe the input. The name, description and schema are passed in the second argument[1]:
import * as z from "zod"
import { tool } from "langchain"
const searchDatabase = tool(
({ query, limit }) => `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"),
}),
}
);Naming tools and writing descriptions
In Python, the tool name defaults to the function name. To choose a more descriptive name, write @tool("web_search")[1]:
@tool("web_search") # Custom name
def search(query: str) -> str:
"""Search the web for information."""
return f"Results for: {query}"
print(search.name) # web_searchThe @tool decorator also accepts a description argument that replaces the generated description[1]. Use snake_case names such as web_search rather than Web Search. Some model providers reject names with spaces or special characters, so letters, digits, underscores and hyphens give the widest compatibility[1].
Declaring complex inputs
When a tool takes several parameters, define them in a Pydantic model, pass the model through the args_schema argument, and describe each field with Field(description=...). A JSON Schema can be passed the same way[1].
Two reserved argument names
config and runtime are reserved, and using either as a tool argument causes a runtime error[1]. To read conversation state, context or long-term storage, add a runtime: ToolRuntime parameter. ToolNode injects it at call time and it is not included in the schema the model sees. Read conversation state through runtime.state[1].
Return values
A tool can return a string, an object, multimodal content, or a Command. A plain return value is wrapped in a ToolMessage and sent back to the model[1].
Returning directly and skipping the model
Setting return_direct to True makes the agent return the tool's output immediately, without another pass through the model[1]. The rule for parallel calls matters. If the model calls an ordinary tool in the same step, the agent does not exit; it sends every result back to the model. The loop ends only when every tool in that step has return_direct=True[1]. Results that still need reasoning, summarization or chaining with other tools are not a good fit for this setting[1].
A tool that returns a Command targeting the current graph must also include a ToolMessage with the matching tool_call_id in Command.update. Otherwise ToolNode raises a ValueError[1].
Handling errors
When a tool fails, agent middleware can retry the failed call or return a custom error message[1].
Common problems
- A name rejected by the provider: usually the name contains a space or a special character. Switch to snake_case, as described above[1].
- Built-in server-side tools: some models ship with web search or code interpreter tools that run on the provider's side. They are different from the tools you write yourself[1].
- Reserved names:
configandruntimecannot be used as argument names, as covered above[1].
Next steps
LangChain offers a large set of prebuilt tools and toolkits for web search, code interpretation and database access, and the integrations page lists them[1]. LangChain also supports tools that come from MCP servers[1].
Adapted from the Tools page of LangChain's open-source documentation[1], released under the MIT License.
Sources
- 1ToolsLangChain docs (MIT)
Cite this page: Tools in LangChain. TellWorld, https://www.tellworld.net/practice/practice-langchain-tools. Updated 2026-11-14