LangChain v1.0Welcome to the new LangChain documentation! If you encounter any issues or have feedback, please open an issue so we can improve. Archived v0 documentation can be found here.See the release notes and migration guide for a complete list of changes and instructions on how to upgrade your code.
Many AI applications interact with users via natural language. However, some use cases require models to interface directly with external systems—such as APIs, databases, or file systems—using structured input.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. Tools encapsulate a callable function and its input schema. These can be passed to compatible chat models, allowing the model to decide whether to invoke a tool and with what arguments. In these scenarios, tool calling enables models to generate requests that conform to a specified input schema.
Server-side tool useSome chat models (e.g., OpenAI, Anthropic, and Gemini) feature built-in tools that are executed server-side, such as web search and code interpreters. Refer to the provider overview to learn how to access these tools with your specific chat model.
The simplest way to create a tool is with the @tool decorator. By default, the function’s docstring becomes the tool’s description that helps the model understand when to use it:
Copy
from langchain.tools import tool@tooldef 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 as they define the tool’s input schema. The docstring should be informative and concise to help the model understand the tool’s purpose.
Override the auto-generated tool description for clearer model guidance:
Copy
@tool("calculator", description="Performs arithmetic calculations. Use this for any math problems.")def calc(expression: str) -> str: """Evaluate mathematical expressions.""" return str(eval(expression))
Why this matters: Tools are most powerful when they can access agent state, runtime context, and long-term memory. This enables tools to make context-aware decisions, personalize responses, and maintain information across conversations.
Tools can access runtime information through the ToolRuntime parameter, which provides:
State - Mutable data that flows through execution (messages, counters, custom fields)
Context - Immutable configuration like user IDs, session details, or application-specific configuration
Store - Persistent long-term memory across conversations
Stream Writer - Stream custom updates as tools execute
Use ToolRuntime to access all runtime information in a single parameter. Simply add runtime: ToolRuntime to your tool signature, and it will be automatically injected without being exposed to the LLM.
ToolRuntime: A unified parameter that provides tools access to state, context, store, streaming, config, and tool call ID. This replaces the older pattern of using separate InjectedState, InjectedStore, get_runtime(), and InjectedToolCallId annotations.
Accessing state:Tools can access the current graph state using ToolRuntime:
Copy
from langchain.tools import tool, ToolRuntime# Access the current conversation state@tooldef summarize_conversation( runtime: ToolRuntime) -> str: """Summarize the conversation so far.""" messages = runtime.state["messages"] human_msgs = sum(1 for m in messages if m.__class__.__name__ == "HumanMessage") ai_msgs = sum(1 for m in messages if m.__class__.__name__ == "AIMessage") tool_msgs = sum(1 for m in messages if m.__class__.__name__ == "ToolMessage") return f"Conversation has {human_msgs} user messages, {ai_msgs} AI responses, and {tool_msgs} tool results"# Access custom state fields@tooldef get_user_preference( pref_name: str, runtime: ToolRuntime # ToolRuntime parameter is not visible to the model) -> str: """Get a user preference value.""" preferences = runtime.state.get("user_preferences", {}) return preferences.get(pref_name, "Not set")
The tool_runtime parameter is hidden from the model. For the example above, the model only sees pref_name in the tool schema - tool_runtime is not included in the request.
Updating state:Use Command to update the agent’s state or control the graph’s execution flow:
Copy
from langgraph.types import Commandfrom langchain.messages import RemoveMessagefrom langgraph.graph.message import REMOVE_ALL_MESSAGESfrom langchain.tools import tool, ToolRuntime# Update the conversation history by removing all messages@tooldef clear_conversation() -> Command: """Clear the conversation history.""" return Command( update={ "messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)], } )# Update the user_name in the agent state@tooldef update_user_name( new_name: str, runtime: ToolRuntime) -> Command: """Update the user's name.""" return Command(update={"user_name": new_name})
Access immutable configuration and contextual data like user IDs, session details, or application-specific configuration through runtime.context.Tools can access runtime context through ToolRuntime:
Copy
from dataclasses import dataclassfrom langchain_openai import ChatOpenAIfrom langchain.agents import create_agentfrom langchain.tools import tool, ToolRuntimeUSER_DATABASE = { "user123": { "name": "Alice Johnson", "account_type": "Premium", "balance": 5000, "email": "[email protected]" }, "user456": { "name": "Bob Smith", "account_type": "Standard", "balance": 1200, "email": "[email protected]" }}@dataclassclass UserContext: user_id: str@tooldef get_account_info(runtime: ToolRuntime[UserContext]) -> str: """Get the current user's account information.""" user_id = runtime.context.user_id if user_id in USER_DATABASE: user = USER_DATABASE[user_id] return f"Account holder: {user['name']}\nType: {user['account_type']}\nBalance: ${user['balance']}" return "User not found"model = ChatOpenAI(model="gpt-4o")agent = create_agent( model, tools=[get_account_info], context_schema=UserContext, system_prompt="You are a financial assistant.")result = agent.invoke( {"messages": [{"role": "user", "content": "What's my current balance?"}]}, context=UserContext(user_id="user123"))
Access persistent data across conversations using the store. The store is accessed via runtime.store and allows you to save and retrieve user-specific or application-specific data.Tools can access and update the store through ToolRuntime:
Copy
from typing import Anyfrom langgraph.store.memory import InMemoryStorefrom langchain.agents import create_agentfrom langchain.tools import tool, ToolRuntime# Access memory@tooldef get_user_info(user_id: str, runtime: ToolRuntime) -> str: """Look up user info.""" store = runtime.store user_info = store.get(("users",), user_id) return str(user_info.value) if user_info else "Unknown user"# Update memory@tooldef save_user_info(user_id: str, user_info: dict[str, Any], runtime: ToolRuntime) -> str: """Save user info.""" store = runtime.store store.put(("users",), user_id, user_info) return "Successfully saved user info."store = InMemoryStore()agent = create_agent( model, tools=[get_user_info, save_user_info], store=store)# First session: save user infoagent.invoke({ "messages": [{"role": "user", "content": "Save the following user: userid: abc123, name: Foo, age: 25, email: [email protected]"}]})# Second session: get user infoagent.invoke({ "messages": [{"role": "user", "content": "Get user info for user with id 'abc123'"}]})# Here is the user info for user with ID "abc123":# - Name: Foo# - Age: 25# - Email: [email protected]
Stream custom updates from tools as they execute using runtime.stream_writer. This is useful for providing real-time feedback to users about what a tool is doing.
Copy
from langchain.tools import tool, ToolRuntime@tooldef get_weather(city: str, runtime: ToolRuntime) -> str: """Get weather for a given city.""" writer = runtime.stream_writer # Stream custom updates as the tool executes writer(f"Looking up data for city: {city}") writer(f"Acquired data for city: {city}") return f"It's always sunny in {city}!"
If you use runtime.stream_writer inside your tool, the tool must be invoked within a LangGraph execution context. See Streaming for more details.