diff --git a/docs/docs/concepts/multi_agent.md b/docs/docs/concepts/multi_agent.md index 3abfc4fbc..0cd4e7f61 100644 --- a/docs/docs/concepts/multi_agent.md +++ b/docs/docs/concepts/multi_agent.md @@ -382,7 +382,7 @@ Agents can **share the full history** of their thought process (i.e., "scratchpa Agents can have their own private "scratchpad" and only **share the final result** with the rest of the agents. This approach might work better for systems with many agents or agents that are more complex. In this case, you would need to define agents with [different state schemas](#using-different-state-schemas). -For agents called as tools, the supervisor determines the inputs based on the tool schema. Additionally, LangGraph allows [passing state](../how-tos/tool-calling.ipynb#read-state) to individual tools at runtime, so subordinate agents can access parent state, if needed. +For agents called as tools, the supervisor determines the inputs based on the tool schema. Additionally, LangGraph allows [passing state](../how-tos/tool-calling.md#short-term-memory) to individual tools at runtime, so subordinate agents can access parent state, if needed. #### Indicating agent name in messages diff --git a/docs/docs/concepts/tools.md b/docs/docs/concepts/tools.md index 311c505ba..8a2e693af 100644 --- a/docs/docs/concepts/tools.md +++ b/docs/docs/concepts/tools.md @@ -1,62 +1,64 @@ # Tools -Many AI applications interact directly with humans. In these cases, it is appropriate for models to respond in natural language. -But what about cases where we want a model to also interact *directly* with systems, such as databases or an API? -These systems often have a particular input schema; for example, APIs frequently have a required payload structure. You can use [tool calling](https://platform.openai.com/docs/guides/function-calling/example-use-cases) to request model responses that match a particular schema. +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. In these scenarios, [tool calling](../how-tos/tool-calling.md) enables models to generate requests that conform to a specified input schema. -[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs. - -**Tools** can be passed to [chat models](https://python.langchain.com/docs/concepts/chat_models) that support [tool calling](https://python.langchain.com/docs/concepts/tool_calling) allowing the model to request the execution of a specific function with specific inputs. - -You can [create custom tools](https://python.langchain.com/docs/how_to/custom_tools/) or use [prebuilt](#prebuilt-tools) tools. +**Tools** encapsulate a callable function and its input schema. These can be passed to compatible [chat models](https://python.langchain.com/docs/concepts/chat_models), allowing the model to decide whether to invoke a tool and with what arguments. ## Tool calling ![Diagram of a tool call by a model](./img/tool_call.png) -A key principle of tool calling is that the model decides when to use a tool based on the input's relevance. The model doesn't always need to call a tool. -For example, given an input that is *irrelevant to the tool*, the model would not call the tool: +Tool calling is typically **conditional**. Based on the user input and available tools, the model may choose to issue a tool call request. This request is returned in an `AIMessage` object, which includes a `tool_calls` field that specifies the tool name and input arguments: ```python -result = llm_with_tools.invoke("Hello world!") +llm_with_tools.invoke("What is 2 multiplied by 3?") +# -> AIMessage(tool_calls=[{'name': 'multiply', 'args': {'a': 2, 'b': 3}, ...}]) ``` -The result would be an `AIMessage` containing the model's response in natural language (e.g., "Hello!"). -However, if we pass an input *relevant to the tool*, the model should choose to call it: +If the input is unrelated to any tool, the model returns only a natural language message: ```python -result = llm_with_tools.invoke("What is 2 multiplied by 3?") +llm_with_tools.invoke("Hello world!") # -> AIMessage(content="Hello!") ``` -As before, the output `result` will be an `AIMessage`. -But, if the tool was called, `result` will have a `tool_calls` attribute. -This attribute includes everything needed to execute the tool, including the tool name and input arguments: +Importantly, the model does not execute the tool—it only generates a request. A separate executor (such as a runtime or agent) is responsible for handling the tool call and returning the result. -``` -result.tool_calls -{'name': 'multiply', 'args': {'a': 2, 'b': 3}, 'id': 'xxx', 'type': 'tool_call'} -``` - -For more details on usage, see the [how-to guide](../how-tos/tool-calling.ipynb). - -## Execute tools - -LangGraph offers pre-built components — [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] and [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] — that invoke the tools on behalf of the user. - -See this [how-to guide](../how-tos/tool-calling.ipynb#use-prebuilt-toolnode) on tool calling. +See the [tool calling guide](../how-tos/tool-calling.md) for more details. ## Prebuilt tools -LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development. +LangChain provides prebuilt tool integrations for common external systems including APIs, databases, file systems, and web data. -You can browse the full list of available integrations in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/tools/). +Browse the [integrations directory](https://python.langchain.com/docs/integrations/tools/) for available tools. -Some commonly used tool categories include: +Common categories: -- **Search**: Bing, SerpAPI, Tavily -- **Code interpreters**: Python REPL, Node.js REPL -- **Databases**: SQL, MongoDB, Redis -- **Web data**: Web scraping and browsing -- **APIs**: OpenWeatherMap, NewsAPI, and others +* **Search**: Bing, SerpAPI, Tavily +* **Code execution**: Python REPL, Node.js REPL +* **Databases**: SQL, MongoDB, Redis +* **Web data**: Scraping and browsing +* **APIs**: OpenWeatherMap, NewsAPI, etc. -These integrations can be configured and added to your agents using the same `tools` parameter shown in the examples above. \ No newline at end of file +## Custom tools + +You can define custom tools using the `@tool` decorator or plain Python functions. For example: + +```python +from langchain_core.tools import tool + +@tool +def multiply(a: int, b: int) -> int: + """Multiply two numbers.""" + return a * b +``` + +See the [tool calling guide](../how-tos/tool-calling.md) for more details. + +## Tool execution + +While the model determines when to call a tool, execution of the tool call must be handled by a runtime component. + +LangGraph provides prebuilt components for this: + +* [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode]: A prebuilt node that executes tools. +* [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]: Constructs a full agent that manages tool calling automatically. diff --git a/docs/docs/how-tos/tool-calling.ipynb b/docs/docs/how-tos/tool-calling.ipynb deleted file mode 100644 index c35117560..000000000 --- a/docs/docs/how-tos/tool-calling.ipynb +++ /dev/null @@ -1,1044 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Use tools\n", - "\n", - "[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs. This guide shows how you can create tools and use them in your graphs.\n", - "\n", - "## Create tools\n", - "\n", - "### Define simple tools\n", - "\n", - "To create tools, you can use [@tool](https://python.langchain.com/api_reference/core/tools/langchain_core.tools.convert.tool.html) decorator or vanilla Python functions.\n", - "\n", - "=== \"`@tool` decorator\"\n", - " ```python\n", - " from langchain_core.tools import tool\n", - "\n", - " # highlight-next-line\n", - " @tool\n", - " def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " return a * b\n", - " ```\n", - "\n", - "=== \"Python functions\"\n", - "\n", - " This requires using LangGraph's prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] or [agent](../../agents/agents), which automatically convert the functions to [LangChain tools](https://python.langchain.com/docs/concepts/tools/#tool-interface).\n", - " \n", - " ```python\n", - " def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " return a * b\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Customize tools\n", - "\n", - "For more control over tool behavior, use the `@tool` decorator:\n", - "\n", - "```python\n", - "# highlight-next-line\n", - "from langchain_core.tools import tool\n", - "\n", - "# highlight-next-line\n", - "@tool(\"multiply_tool\", parse_docstring=True)\n", - "def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\n", - "\n", - " Args:\n", - " a: First operand\n", - " b: Second operand\n", - " \"\"\"\n", - " return a * b\n", - "```\n", - "\n", - "You can also define a custom input schema using Pydantic:\n", - "\n", - "```python\n", - "from pydantic import BaseModel, Field\n", - "\n", - "class MultiplyInputSchema(BaseModel):\n", - " \"\"\"Multiply two numbers\"\"\"\n", - " a: int = Field(description=\"First operand\")\n", - " b: int = Field(description=\"Second operand\")\n", - "\n", - "# highlight-next-line\n", - "@tool(\"multiply_tool\", args_schema=MultiplyInputSchema)\n", - "def multiply(a: int, b: int) -> int:\n", - " return a * b\n", - "```\n", - "\n", - "For additional customization, refer to the [custom tools guide](https://python.langchain.com/docs/how_to/custom_tools/)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Hide arguments from the model\n", - "\n", - "Some tools require runtime-only arguments (e.g., user ID or session context) that should not be controllable by the model.\n", - "\n", - "You can put these arguments in the [`state`](#read-state) or [`config`](#access-config) of the agent, and access\n", - "this information inside the tool:\n", - "\n", - "```python\n", - "from langchain_core.tools import tool\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langgraph.prebuilt import InjectedState\n", - "from langgraph.graph import MessagesState\n", - "\n", - "@tool\n", - "def my_tool(\n", - " # This will be populated by an LLM\n", - " tool_arg: str,\n", - " # access information that's dynamically updated inside the agent\n", - " # highlight-next-line\n", - " state: Annotated[MessagesState, InjectedState],\n", - " # access static data that is passed at agent invocation\n", - " # highlight-next-line\n", - " config: RunnableConfig,\n", - ") -> str:\n", - " \"\"\"My tool.\"\"\"\n", - " do_something_with_state(state[\"messages\"])\n", - " do_something_with_config(config)\n", - " ...\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Access config\n", - "\n", - "You can provide static information to the graph at runtime, like a `user_id` or API credentials. This information can be accessed inside the tools through a special parameter **annotation** — `RunnableConfig`:\n", - "\n", - "```python\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langchain_core.tools import tool\n", - "\n", - "@tool\n", - "def get_user_info(\n", - " # highlight-next-line\n", - " config: RunnableConfig,\n", - ") -> str:\n", - " \"\"\"Look up user info.\"\"\"\n", - " # highlight-next-line\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", - "```\n", - "\n", - "??? example \"Access config in tools\"\n", - "\n", - " ```python\n", - " from langchain_core.runnables import RunnableConfig\n", - " from langchain_core.tools import tool\n", - " from langgraph.prebuilt import create_react_agent\n", - " \n", - " def get_user_info(\n", - " # highlight-next-line\n", - " config: RunnableConfig,\n", - " ) -> str:\n", - " \"\"\"Look up user info.\"\"\"\n", - " # highlight-next-line\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", - " \n", - " agent = create_react_agent(\n", - " model=\"anthropic:claude-3-7-sonnet-latest\",\n", - " tools=[get_user_info],\n", - " )\n", - " \n", - " agent.invoke(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": \"look up user information\"}]},\n", - " # highlight-next-line\n", - " config={\"configurable\": {\"user_id\": \"user_123\"}}\n", - " )\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Short-term memory\n", - "\n", - "LangGraph allows agents to access and update their [short-term memory](../../concepts/memory#short-term-memory) (state) inside the tools." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Read state\n", - "\n", - "To access the graph state inside the tools, you can use a special parameter **annotation** — [`InjectedState`][langgraph.prebuilt.InjectedState]: \n", - "\n", - "```python\n", - "from typing import Annotated\n", - "from langchain_core.tools import tool\n", - "# highlight-next-line\n", - "from langgraph.prebuilt import InjectedState\n", - "\n", - "class CustomState(AgentState):\n", - " # highlight-next-line\n", - " user_id: str\n", - "\n", - "@tool\n", - "def get_user_info(\n", - " # highlight-next-line\n", - " state: Annotated[CustomState, InjectedState]\n", - ") -> str:\n", - " \"\"\"Look up user info.\"\"\"\n", - " # highlight-next-line\n", - " user_id = state[\"user_id\"]\n", - " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", - "```\n", - "\n", - "??? example \"Access state in tools\"\n", - "\n", - " ```python\n", - " from typing import Annotated\n", - " from langchain_core.tools import tool\n", - " from langgraph.prebuilt import InjectedState, create_react_agent\n", - " \n", - " class CustomState(AgentState):\n", - " # highlight-next-line\n", - " user_id: str\n", - "\n", - " @tool\n", - " def get_user_info(\n", - " # highlight-next-line\n", - " state: Annotated[CustomState, InjectedState]\n", - " ) -> str:\n", - " \"\"\"Look up user info.\"\"\"\n", - " # highlight-next-line\n", - " user_id = state[\"user_id\"]\n", - " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", - " \n", - " agent = create_react_agent(\n", - " model=\"anthropic:claude-3-7-sonnet-latest\",\n", - " tools=[get_user_info],\n", - " # highlight-next-line\n", - " state_schema=CustomState,\n", - " )\n", - " \n", - " agent.invoke({\n", - " \"messages\": \"look up user information\",\n", - " # highlight-next-line\n", - " \"user_id\": \"user_123\"\n", - " })\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Update state\n", - "\n", - "You can return state updates directly from the tools. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts.\n", - "\n", - "```python\n", - "from langgraph.graph import MessagesState\n", - "from langgraph.types import Command\n", - "from langchain_core.tools import tool, InjectedToolCallId\n", - "\n", - "class CustomState(MessagesState):\n", - " # highlight-next-line\n", - " user_name: str\n", - "\n", - "@tool\n", - "def update_user_info(\n", - " tool_call_id: Annotated[str, InjectedToolCallId],\n", - " config: RunnableConfig\n", - ") -> Command:\n", - " \"\"\"Look up and update user info.\"\"\"\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " name = \"John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", - " # highlight-next-line\n", - " return Command(update={\n", - " # highlight-next-line\n", - " \"user_name\": name,\n", - " # update the message history\n", - " \"messages\": [\n", - " ToolMessage(\n", - " \"Successfully looked up user information\",\n", - " tool_call_id=tool_call_id\n", - " )\n", - " ]\n", - " })\n", - "```\n", - "\n", - "??? example \"Update state from tools\"\n", - "\n", - " This is an example of using the prebuilt agent with a tool that can update graph state.\n", - "\n", - " ```python\n", - " from typing import Annotated\n", - " from langchain_core.tools import tool, InjectedToolCallId\n", - " from langchain_core.runnables import RunnableConfig\n", - " from langchain_core.messages import ToolMessage\n", - " from langgraph.prebuilt import InjectedState, create_react_agent\n", - " from langgraph.prebuilt.chat_agent_executor import AgentState\n", - " from langgraph.types import Command\n", - " \n", - " class CustomState(AgentState):\n", - " # highlight-next-line\n", - " user_name: str\n", - "\n", - " @tool\n", - " def update_user_info(\n", - " tool_call_id: Annotated[str, InjectedToolCallId],\n", - " config: RunnableConfig\n", - " ) -> Command:\n", - " \"\"\"Look up and update user info.\"\"\"\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " name = \"John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", - " # highlight-next-line\n", - " return Command(update={\n", - " # highlight-next-line\n", - " \"user_name\": name,\n", - " # update the message history\n", - " \"messages\": [\n", - " ToolMessage(\n", - " \"Successfully looked up user information\",\n", - " tool_call_id=tool_call_id\n", - " )\n", - " ]\n", - " })\n", - " \n", - " def greet(\n", - " # highlight-next-line\n", - " state: Annotated[CustomState, InjectedState]\n", - " ) -> str:\n", - " \"\"\"Use this to greet the user once you found their info.\"\"\"\n", - " user_name = state[\"user_name\"]\n", - " return f\"Hello {user_name}!\"\n", - " \n", - " agent = create_react_agent(\n", - " model=\"anthropic:claude-3-7-sonnet-latest\",\n", - " tools=[get_user_info, greet],\n", - " # highlight-next-line\n", - " state_schema=CustomState\n", - " )\n", - " \n", - " agent.invoke(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": \"greet the user\"}]},\n", - " # highlight-next-line\n", - " config={\"configurable\": {\"user_id\": \"user_123\"}}\n", - " )\n", - " ```\n", - "\n", - "!!! important\n", - "\n", - " If you want to use tools that return `Command` and update graph state, you can either use prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] / [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] components, or implement your own tool-executing node that collects `Command` objects returned by the tools and returns a list of them, e.g.:\n", - " \n", - " ```python\n", - " def call_tools(state):\n", - " ...\n", - " commands = [tools_by_name[tool_call[\"name\"]].invoke(tool_call) for tool_call in tool_calls]\n", - " return commands\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Long-term memory\n", - "\n", - "Use [long-term memory](../../concepts/memory#long-term-memory) to store user-specific or application-specific data across conversations. This is useful for applications like chatbots, where you want to remember user preferences or other information.\n", - "\n", - "To use long-term memory, you need to:\n", - "\n", - "1. [Configure a store](../persistence#add-long-term-memory) to persist data across invocations.\n", - "2. Use the [`get_store`][langgraph.config.get_store] function to access the store from within tools or prompts.\n", - "\n", - "### Read\n", - "\n", - "```python\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langchain_core.tools import tool\n", - "from langgraph.graph import StateGraph\n", - "# highlight-next-line\n", - "from langgraph.config import get_store\n", - "\n", - "@tool\n", - "def get_user_info(config: RunnableConfig) -> str:\n", - " \"\"\"Look up user info.\"\"\"\n", - " # Same as that provided to `builder.compile(store=store)` \n", - " # or `create_react_agent`\n", - " # highlight-next-line\n", - " store = get_store()\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " # highlight-next-line\n", - " user_info = store.get((\"users\",), user_id)\n", - " return str(user_info.value) if user_info else \"Unknown user\"\n", - "\n", - "builder = StateGraph(...)\n", - "...\n", - "graph = builder.compile(store=store)\n", - "```\n", - "\n", - "??? example \"Access long-term memory\"\n", - "\n", - " ```python\n", - " from langchain_core.runnables import RunnableConfig\n", - " from langchain_core.tools import tool\n", - " from langgraph.config import get_store\n", - " from langgraph.prebuilt import create_react_agent\n", - " from langgraph.store.memory import InMemoryStore\n", - " \n", - " # highlight-next-line\n", - " store = InMemoryStore() # (1)!\n", - " \n", - " # highlight-next-line\n", - " store.put( # (2)!\n", - " (\"users\",), # (3)!\n", - " \"user_123\", # (4)!\n", - " {\n", - " \"name\": \"John Smith\",\n", - " \"language\": \"English\",\n", - " } # (5)!\n", - " )\n", - "\n", - " @tool\n", - " def get_user_info(config: RunnableConfig) -> str:\n", - " \"\"\"Look up user info.\"\"\"\n", - " # Same as that provided to `create_react_agent`\n", - " # highlight-next-line\n", - " store = get_store() # (6)!\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " # highlight-next-line\n", - " user_info = store.get((\"users\",), user_id) # (7)!\n", - " return str(user_info.value) if user_info else \"Unknown user\"\n", - " \n", - " agent = create_react_agent(\n", - " model=\"anthropic:claude-3-7-sonnet-latest\",\n", - " tools=[get_user_info],\n", - " # highlight-next-line\n", - " store=store # (8)!\n", - " )\n", - " \n", - " # Run the agent\n", - " agent.invoke(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": \"look up user information\"}]},\n", - " # highlight-next-line\n", - " config={\"configurable\": {\"user_id\": \"user_123\"}}\n", - " )\n", - " ```\n", - " \n", - " 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [store documentation](../reference/store.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you.\n", - " 2. For this example, we write some sample data to the store using the `put` method. Please see the [BaseStore.put][langgraph.store.base.BaseStore.put] API reference for more details.\n", - " 3. The first argument is the namespace. This is used to group related data together. In this case, we are using the `users` namespace to group user data.\n", - " 4. A key within the namespace. This example uses a user ID for the key.\n", - " 5. The data that we want to store for the given user.\n", - " 6. The `get_store` function is used to access the store. You can call it from anywhere in your code, including tools and prompts. This function returns the store that was passed to the agent when it was created.\n", - " 7. The `get` method is used to retrieve data from the store. The first argument is the namespace, and the second argument is the key. This will return a `StoreValue` object, which contains the value and metadata about the value.\n", - " 8. The `store` is passed to the agent. This enables the agent to access the store when running tools. You can also use the `get_store` function to access the store from anywhere in your code." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Update\n", - "\n", - "```python\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langchain_core.tools import tool\n", - "from langgraph.graph import StateGraph\n", - "# highlight-next-line\n", - "from langgraph.config import get_store\n", - "\n", - "@tool\n", - "def save_user_info(user_info: str, config: RunnableConfig) -> str:\n", - " \"\"\"Save user info.\"\"\"\n", - " # Same as that provided to `builder.compile(store=store)` \n", - " # or `create_react_agent`\n", - " # highlight-next-line\n", - " store = get_store()\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " # highlight-next-line\n", - " store.put((\"users\",), user_id, user_info)\n", - " return \"Successfully saved user info.\"\n", - "\n", - "builder = StateGraph(...)\n", - "...\n", - "graph = builder.compile(store=store)\n", - "```\n", - "\n", - "??? example \"Update long-term memory\"\n", - "\n", - " ```python\n", - " from typing_extensions import TypedDict\n", - "\n", - " from langchain_core.tools import tool\n", - " from langgraph.config import get_store\n", - " from langgraph.prebuilt import create_react_agent\n", - " from langgraph.store.memory import InMemoryStore\n", - " \n", - " store = InMemoryStore() # (1)!\n", - " \n", - " class UserInfo(TypedDict): # (2)!\n", - " name: str\n", - "\n", - " @tool\n", - " def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str: # (3)!\n", - " \"\"\"Save user info.\"\"\"\n", - " # Same as that provided to `create_react_agent`\n", - " # highlight-next-line\n", - " store = get_store() # (4)!\n", - " user_id = config[\"configurable\"].get(\"user_id\")\n", - " # highlight-next-line\n", - " store.put((\"users\",), user_id, user_info) # (5)!\n", - " return \"Successfully saved user info.\"\n", - " \n", - " agent = create_react_agent(\n", - " model=\"anthropic:claude-3-7-sonnet-latest\",\n", - " tools=[save_user_info],\n", - " # highlight-next-line\n", - " store=store\n", - " )\n", - " \n", - " # Run the agent\n", - " agent.invoke(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": \"My name is John Smith\"}]},\n", - " # highlight-next-line\n", - " config={\"configurable\": {\"user_id\": \"user_123\"}} # (6)!\n", - " )\n", - " \n", - " # You can access the store directly to get the value\n", - " store.get((\"users\",), \"user_123\").value\n", - " ```\n", - " \n", - " 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [store documentation](../reference/store.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you.\n", - " 2. The `UserInfo` class is a `TypedDict` that defines the structure of the user information. The LLM will use this to format the response according to the schema.\n", - " 3. The `save_user_info` function is a tool that allows an agent to update user information. This could be useful for a chat application where the user wants to update their profile information.\n", - " 4. The `get_store` function is used to access the store. You can call it from anywhere in your code, including tools and prompts. This function returns the store that was passed to the agent when it was created.\n", - " 5. The `put` method is used to store data in the store. The first argument is the namespace, and the second argument is the key. This will store the user information in the store.\n", - " 6. The `user_id` is passed in the config. This is used to identify the user whose information is being updated." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Attach tools to a model\n", - "\n", - "To attach tool schemas to a [chat model](https://python.langchain.com/docs/concepts/chat_models) you need to use `model.bind_tools()`:\n", - "\n", - "```python\n", - "from langchain_core.tools import tool\n", - "from langchain.chat_models import init_chat_model\n", - "\n", - "@tool\n", - "def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " return a * b\n", - "\n", - "model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", - "# highlight-next-line\n", - "model_with_tools = model.bind_tools([multiply])\n", - "\n", - "model_with_tools.invoke(\"what's 42 x 7?\")\n", - "```\n", - "\n", - "```\n", - "AIMessage(\n", - " content=[{'text': \"I'll help you calculate that by using the multiply function.\", 'type': 'text'}, {'id': 'toolu_01GhULkqytMTFDsNv6FsXy3Y', 'input': {'a': 42, 'b': 7}, 'name': 'multiply', 'type': 'tool_use'}]\n", - " tool_calls=[{'name': 'multiply', 'args': {'a': 42, 'b': 7}, 'id': 'toolu_01GhULkqytMTFDsNv6FsXy3Y', 'type': 'tool_call'}]\n", - ")\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Use tools\n", - "\n", - "LangChain tools conform to the [Runnable interface](https://python.langchain.com/docs/concepts/runnables/), which means that you can execute them using `.invoke()` / `.ainvoke()` methods:\n", - "\n", - "```python\n", - "from langchain_core.tools import tool\n", - "\n", - "@tool\n", - "def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " return a * b\n", - "\n", - "# highlight-next-line\n", - "multiply.invoke({\"a\": 42, \"b\": 7})\n", - "```\n", - "\n", - "```\n", - "294\n", - "```\n", - "\n", - "If you want the tool to return a [ToolMessage](https://python.langchain.com/docs/concepts/messages/#toolmessage), invoke it with the tool call:\n", - "\n", - "```python\n", - "tool_call = {\n", - " \"type\": \"tool_call\",\n", - " \"id\": \"1\",\n", - " \"args\": {\"a\": 42, \"b\": 7}\n", - "}\n", - "multiply.invoke(tool_call)\n", - "```\n", - "\n", - "```\n", - "ToolMessage(content='294', name='multiply', tool_call_id='1')\n", - "```\n", - "\n", - "??? example \"Use with a chat model\"\n", - "\n", - " ```python\n", - " from langchain_core.tools import tool\n", - " from langchain.chat_models import init_chat_model\n", - " \n", - " @tool\n", - " def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " return a * b\n", - " \n", - " model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", - " # highlight-next-line\n", - " model_with_tools = model.bind_tools([multiply])\n", - " \n", - " response_message = model_with_tools.invoke(\"what's 42 x 7?\")\n", - " tool_call = response_message.tool_calls[0]\n", - "\n", - " # highlight-next-line\n", - " multiply.invoke(tool_call)\n", - " ```\n", - "\n", - " ```\n", - " ToolMessage(content='294', name='multiply', tool_call_id='toolu_0176DV4YKSD8FndkeuuLj36c')\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Use prebuilt agent\n", - "\n", - "To create a tool-calling agent, you can use the prebuilt [create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent]\n", - "\n", - "```python\n", - "from langchain_core.tools import tool\n", - "# highlight-next-line\n", - "from langgraph.prebuilt import create_react_agent\n", - "\n", - "@tool\n", - "def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " return a * b\n", - "\n", - "# highlight-next-line\n", - "agent = create_react_agent(\n", - " model=\"anthropic:claude-3-7-sonnet\",\n", - " tools=[multiply]\n", - ")\n", - "graph.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"what's 42 x 7?\"}]})\n", - "```\n", - "\n", - "See this [guide](../../agents/overview) to learn more." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Use prebuilt `ToolNode`\n", - "\n", - "[`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] is a prebuilt LangGraph [node](../../concepts/low_level#nodes) for executing tool calls.\n", - "\n", - "**Why use `ToolNode`?**\n", - "\n", - "* support for both sync and async tools\n", - "* concurrent execution of the tools\n", - "* error handling during tool execution. You can enable / disable this by setting `handle_tool_errors=True` (enabled by default). See [this section](#handle-errors) for more details on handling errors\n", - "\n", - "ToolNode operates on [MessagesState](../../concepts/low_level#messagesstate):\n", - "\n", - "* input: `MessagesState` where the last message is an `AIMessage` with `tool_calls` parameter\n", - "* output: `MessagesState` with [`ToolMessage`](https://python.langchain.com/docs/concepts/messages/#toolmessage) the result of tool calls\n", - "\n", - "!!! tip\n", - "\n", - " `ToolNode` is designed to work well out-of-box with LangGraph's prebuilt [agent](../../agents/agents), but can also work with any `StateGraph` that uses `MessagesState.`\n", - "\n", - "```python\n", - "# highlight-next-line\n", - "from langgraph.prebuilt import ToolNode\n", - "\n", - "def get_weather(location: str):\n", - " \"\"\"Call to get the current weather.\"\"\"\n", - " if location.lower() in [\"sf\", \"san francisco\"]:\n", - " return \"It's 60 degrees and foggy.\"\n", - " else:\n", - " return \"It's 90 degrees and sunny.\"\n", - "\n", - "def get_coolest_cities():\n", - " \"\"\"Get a list of coolest cities\"\"\"\n", - " return \"nyc, sf\"\n", - "\n", - "# highlight-next-line\n", - "tool_node = ToolNode([get_weather, get_coolest_cities])\n", - "tool_node.invoke({\"messages\": [...]})\n", - "```\n", - "\n", - "??? example \"Single tool call\"\n", - "\n", - " ```python\n", - " from langchain_core.messages import AIMessage\n", - " from langgraph.prebuilt import ToolNode\n", - " \n", - " # Define tools\n", - " @tool\n", - " def get_weather(location: str):\n", - " \"\"\"Call to get the current weather.\"\"\"\n", - " if location.lower() in [\"sf\", \"san francisco\"]:\n", - " return \"It's 60 degrees and foggy.\"\n", - " else:\n", - " return \"It's 90 degrees and sunny.\"\n", - " \n", - " # highlight-next-line\n", - " tool_node = ToolNode([get_weather])\n", - " \n", - " message_with_single_tool_call = AIMessage(\n", - " content=\"\",\n", - " tool_calls=[\n", - " {\n", - " \"name\": \"get_weather\",\n", - " \"args\": {\"location\": \"sf\"},\n", - " \"id\": \"tool_call_id\",\n", - " \"type\": \"tool_call\",\n", - " }\n", - " ],\n", - " )\n", - " \n", - " tool_node.invoke({\"messages\": [message_with_single_tool_call]})\n", - " ```\n", - " \n", - " ```\n", - " {'messages': [ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='tool_call_id')]}\n", - " ```\n", - "\n", - "??? example \"Multiple tool calls\"\n", - "\n", - " ```python\n", - " from langchain_core.messages import AIMessage\n", - " from langgraph.prebuilt import ToolNode\n", - " \n", - " # Define tools\n", - " \n", - " def get_weather(location: str):\n", - " \"\"\"Call to get the current weather.\"\"\"\n", - " if location.lower() in [\"sf\", \"san francisco\"]:\n", - " return \"It's 60 degrees and foggy.\"\n", - " else:\n", - " return \"It's 90 degrees and sunny.\"\n", - " \n", - " def get_coolest_cities():\n", - " \"\"\"Get a list of coolest cities\"\"\"\n", - " return \"nyc, sf\"\n", - " \n", - " # highlight-next-line\n", - " tool_node = ToolNode([get_weather, get_coolest_cities])\n", - "\n", - " message_with_multiple_tool_calls = AIMessage(\n", - " content=\"\",\n", - " tool_calls=[\n", - " {\n", - " \"name\": \"get_coolest_cities\",\n", - " \"args\": {},\n", - " \"id\": \"tool_call_id_1\",\n", - " \"type\": \"tool_call\",\n", - " },\n", - " {\n", - " \"name\": \"get_weather\",\n", - " \"args\": {\"location\": \"sf\"},\n", - " \"id\": \"tool_call_id_2\",\n", - " \"type\": \"tool_call\",\n", - " },\n", - " ],\n", - " )\n", - "\n", - " # highlight-next-line\n", - " tool_node.invoke({\"messages\": [message_with_multiple_tool_calls]}) # (1)!\n", - " ```\n", - "\n", - " 1. `ToolNode` will execute both tools in parallel\n", - "\n", - " ```\n", - " {\n", - " 'messages': [\n", - " ToolMessage(content='nyc, sf', name='get_coolest_cities', tool_call_id='tool_call_id_1'),\n", - " ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='tool_call_id_2')\n", - " ]\n", - " }\n", - " ```\n", - "\n", - " \n", - "\n", - "??? example \"Use with a chat model\"\n", - "\n", - " ```python\n", - " from langchain.chat_models import init_chat_model\n", - " from langgraph.prebuilt import ToolNode\n", - " \n", - " def get_weather(location: str):\n", - " \"\"\"Call to get the current weather.\"\"\"\n", - " if location.lower() in [\"sf\", \"san francisco\"]:\n", - " return \"It's 60 degrees and foggy.\"\n", - " else:\n", - " return \"It's 90 degrees and sunny.\"\n", - " \n", - " # highlight-next-line\n", - " tool_node = ToolNode([get_weather])\n", - " \n", - " model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", - " # highlight-next-line\n", - " model_with_tools = model.bind_tools([get_weather]) # (1)!\n", - " \n", - " \n", - " # highlight-next-line\n", - " response_message = model_with_tools.invoke(\"what's the weather in sf?\")\n", - " tool_node.invoke({\"messages\": [response_message]})\n", - " ```\n", - "\n", - " 1. Use `.bind_tools()` to attach the tool schema to the chat model\n", - "\n", - " ```\n", - " {'messages': [ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='toolu_01Pnkgw5JeTRxXAU7tyHT4UW')]}\n", - " ```\n", - "\n", - "??? example \"Use in a tool-calling agent\"\n", - "\n", - " This is an example of creating a tool-calling agent from scratch using `ToolNode`. You can also use LangGraph's prebuilt [agent](../../agents/agents).\n", - "\n", - " ```python\n", - " from langchain.chat_models import init_chat_model\n", - " from langgraph.prebuilt import ToolNode\n", - " from langgraph.graph import StateGraph, MessagesState, START, END\n", - " \n", - " def get_weather(location: str):\n", - " \"\"\"Call to get the current weather.\"\"\"\n", - " if location.lower() in [\"sf\", \"san francisco\"]:\n", - " return \"It's 60 degrees and foggy.\"\n", - " else:\n", - " return \"It's 90 degrees and sunny.\"\n", - " \n", - " # highlight-next-line\n", - " tool_node = ToolNode([get_weather])\n", - " \n", - " model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", - " # highlight-next-line\n", - " model_with_tools = model.bind_tools([get_weather])\n", - " \n", - " def should_continue(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " if last_message.tool_calls:\n", - " return \"tools\"\n", - " return END\n", - " \n", - " def call_model(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " response = model_with_tools.invoke(messages)\n", - " return {\"messages\": [response]}\n", - " \n", - " builder = StateGraph(MessagesState)\n", - " \n", - " # Define the two nodes we will cycle between\n", - " builder.add_node(\"call_model\", call_model)\n", - " # highlight-next-line\n", - " builder.add_node(\"tools\", tool_node)\n", - " \n", - " builder.add_edge(START, \"call_model\")\n", - " builder.add_conditional_edges(\"call_model\", should_continue, [\"tools\", END])\n", - " builder.add_edge(\"tools\", \"call_model\")\n", - " \n", - " graph = builder.compile()\n", - " \n", - " graph.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf?\"}]})\n", - " ```\n", - " \n", - " ```\n", - " {\n", - " 'messages': [\n", - " HumanMessage(content=\"what's the weather in sf?\"),\n", - " AIMessage(\n", - " content=[{'text': \"I'll help you check the weather in San Francisco right now.\", 'type': 'text'}, {'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'input': {'location': 'San Francisco'}, 'name': 'get_weather', 'type': 'tool_use'}],\n", - " tool_calls=[{'name': 'get_weather', 'args': {'location': 'San Francisco'}, 'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'type': 'tool_call'}]\n", - " ),\n", - " ToolMessage(content=\"It's 60 degrees and foggy.\"),\n", - " AIMessage(content=\"The current weather in San Francisco is 60 degrees and foggy. Typical San Francisco weather with its famous marine layer!\")\n", - " ]\n", - " }\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Handle errors\n", - "\n", - "By default, the `ToolNode` will catch all exceptions raised during tool calls and will return those as tool messages. To control how the errors are handled, you can use `ToolNode`'s `handle_tool_errors` parameter:\n", - "\n", - "=== \"Enable error handling (default)\"\n", - "\n", - " ```python\n", - " from langchain_core.messages import AIMessage\n", - " from langgraph.prebuilt import ToolNode\n", - " \n", - " def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " if a == 42:\n", - " raise ValueError(\"The ultimate error\")\n", - " return a * b\n", - " \n", - " tool_node = ToolNode([multiply])\n", - " \n", - " # Run with error handling (default)\n", - " message = AIMessage(\n", - " content=\"\",\n", - " tool_calls=[\n", - " {\n", - " \"name\": \"multiply\",\n", - " \"args\": {\"a\": 42, \"b\": 7},\n", - " \"id\": \"tool_call_id\",\n", - " \"type\": \"tool_call\",\n", - " }\n", - " ],\n", - " )\n", - " \n", - " tool_node.invoke({\"messages\": [message]})\n", - " ```\n", - "\n", - " ```\n", - " {'messages': [ToolMessage(content=\"Error: ValueError('The ultimate error')\\n Please fix your mistakes.\", name='multiply', tool_call_id='tool_call_id', status='error')]}\n", - " ```\n", - "\n", - "=== \"Disable error handling\"\n", - "\n", - " ```python\n", - " from langchain_core.messages import AIMessage\n", - " from langgraph.prebuilt import ToolNode\n", - "\n", - " def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " if a == 42:\n", - " raise ValueError(\"The ultimate error\")\n", - " return a * b\n", - "\n", - " tool_node = ToolNode(\n", - " [multiply],\n", - " # highlight-next-line\n", - " handle_tool_errors=False # (1)!\n", - " )\n", - " message = AIMessage(\n", - " content=\"\",\n", - " tool_calls=[\n", - " {\n", - " \"name\": \"multiply\",\n", - " \"args\": {\"a\": 42, \"b\": 7},\n", - " \"id\": \"tool_call_id\",\n", - " \"type\": \"tool_call\",\n", - " }\n", - " ],\n", - " )\n", - " tool_node.invoke({\"messages\": [message]})\n", - " ```\n", - "\n", - " 1. This disables error handling (enabled by default). See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].\n", - "\n", - "=== \"Custom error handling\"\n", - "\n", - " ```python\n", - " from langchain_core.messages import AIMessage\n", - " from langgraph.prebuilt import ToolNode\n", - "\n", - " def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiply two numbers.\"\"\"\n", - " if a == 42:\n", - " raise ValueError(\"The ultimate error\")\n", - " return a * b\n", - "\n", - " # highlight-next-line\n", - " tool_node = ToolNode(\n", - " [multiply],\n", - " # highlight-next-line\n", - " handle_tool_errors=(\n", - " \"Can't use 42 as a first operand, you must switch operands!\" # (1)!\n", - " )\n", - " )\n", - " tool_node.invoke({\"messages\": [message]})\n", - " ```\n", - "\n", - " 1. This provides a custom message to send to the LLM in case of an exception. See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].\n", - "\n", - " ```\n", - " {'messages': [ToolMessage(content=\"Can't use 42 as a first operand, you must switch operands!\", name='multiply', tool_call_id='tool_call_id', status='error')]}\n", - " ```\n", - "\n", - "See [API reference][langgraph.prebuilt.tool_node.ToolNode] for more information on different tool error handling options." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Handle large numbers of tools" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As the number of available tools grows, you may want to limit the scope of the LLM's selection, to decrease token consumption and to help manage sources of error in LLM reasoning.\n", - "\n", - "To address this, you can dynamically adjust the tools available to a model by retrieving relevant tools at runtime using semantic search.\n", - "\n", - "See [`langgraph-bigtool`](https://github.com/langchain-ai/langgraph-bigtool) prebuilt library for a ready-to-use implementation and this [how-to guide](../many-tools) for more details." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/tool-calling.md b/docs/docs/how-tos/tool-calling.md new file mode 100644 index 000000000..e60a2190d --- /dev/null +++ b/docs/docs/how-tos/tool-calling.md @@ -0,0 +1,1006 @@ +# Call tools + +[Tools](../concepts/tools.md) encapsulate a callable function and its input schema. These can be passed to compatible [chat models](https://python.langchain.com/docs/concepts/chat_models), allowing the model to decide whether to invoke a tool and determine the appropriate arguments. + +You can [define your own tools](#define-a-tool) or use [prebuilt tools](#prebuilt-tools) + +## Define a tool + +Define a basic tool with the [@tool](https://python.langchain.com/api_reference/core/tools/langchain_core.tools.convert.tool.html) decorator: + +```python +from langchain_core.tools import tool + +# highlight-next-line +@tool +def multiply(a: int, b: int) -> int: + """Multiply two numbers.""" + return a * b +``` + +## Run a tool + +Tools conform to the [Runnable interface](https://python.langchain.com/docs/concepts/runnables/), which means you can run a tool using the `invoke` method: + +```python +multiply.invoke({"a": 6, "b": 7}) # returns 42 +``` + +If the tool is invoked with `type="tool_call"`, it will return a [ToolMessage](https://python.langchain.com/docs/concepts/messages/#toolmessage): + +```python +tool_call = { + "type": "tool_call", + "id": "1", + "args": {"a": 42, "b": 7} +} +multiply.invoke(tool_call) # returns a ToolMessage object +``` + +Output: + +```pycon +ToolMessage(content='294', name='multiply', tool_call_id='1') +``` + + +## Use in an agent + +To create a tool-calling agent, you can use the prebuilt [create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent]: + +```python +from langchain_core.tools import tool +# highlight-next-line +from langgraph.prebuilt import create_react_agent + +@tool +def multiply(a: int, b: int) -> int: + """Multiply two numbers.""" + return a * b + +# highlight-next-line +agent = create_react_agent( + model="anthropic:claude-3-7-sonnet", + tools=[multiply] +) +agent.invoke({"messages": [{"role": "user", "content": "what's 42 x 7?"}]}) +``` + +## Use in a workflow + +If you are writing a custom workflow, you will need to: + +1. register the tools with the chat model +2. call the tool if the model decides to use it + +Use `model.bind_tools()` to register the tools with the model. + +```python +from langchain.chat_models import init_chat_model + +model = init_chat_model(model="claude-3-5-haiku-latest") + +# highlight-next-line +model_with_tools = model.bind_tools([multiply]) +``` + +LLMs automatically determine if a tool invocation is necessary and handle calling the tool with the appropriate arguments. + +??? example "Extended example: attach tools to a chat model" + + ```python + from langchain_core.tools import tool + from langchain.chat_models import init_chat_model + + @tool + def multiply(a: int, b: int) -> int: + """Multiply two numbers.""" + return a * b + + model = init_chat_model(model="claude-3-5-haiku-latest") + # highlight-next-line + model_with_tools = model.bind_tools([multiply]) + + response_message = model_with_tools.invoke("what's 42 x 7?") + tool_call = response_message.tool_calls[0] + + multiply.invoke(tool_call) + ``` + + ```pycon + ToolMessage( + content='294', + name='multiply', + tool_call_id='toolu_0176DV4YKSD8FndkeuuLj36c' + ) + ``` +#### ToolNode + +To execute tools in custom workflows, use the prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] or implement your own custom node. + +`ToolNode` is a specialized node for executing tools in a workflow. It provides the following features: + +* Supports both synchronous and asynchronous tools. +* Executes multiple tools concurrently. +* Handles errors during tool execution (`handle_tool_errors=True`, enabled by default). See [handling tool errors](#handle-errors) for more details. + +`ToolNode` operates on [`MessagesState`](../concepts/low_level.md#messagesstate): + +* **Input**: `MessagesState`, where the last message is an `AIMessage` containing the `tool_calls` parameter. +* **Output**: `MessagesState` updated with the resulting [`ToolMessage`](https://python.langchain.com/docs/concepts/messages/#toolmessage) from executed tools. + + +```python +# highlight-next-line +from langgraph.prebuilt import ToolNode + +def get_weather(location: str): + """Call to get the current weather.""" + if location.lower() in ["sf", "san francisco"]: + return "It's 60 degrees and foggy." + else: + return "It's 90 degrees and sunny." + +def get_coolest_cities(): + """Get a list of coolest cities""" + return "nyc, sf" + +# highlight-next-line +tool_node = ToolNode([get_weather, get_coolest_cities]) +tool_node.invoke({"messages": [...]}) +``` + +??? example "Single tool call" + + ```python + from langchain_core.messages import AIMessage + from langgraph.prebuilt import ToolNode + + # Define tools + @tool + def get_weather(location: str): + """Call to get the current weather.""" + if location.lower() in ["sf", "san francisco"]: + return "It's 60 degrees and foggy." + else: + return "It's 90 degrees and sunny." + + # highlight-next-line + tool_node = ToolNode([get_weather]) + + message_with_single_tool_call = AIMessage( + content="", + tool_calls=[ + { + "name": "get_weather", + "args": {"location": "sf"}, + "id": "tool_call_id", + "type": "tool_call", + } + ], + ) + + tool_node.invoke({"messages": [message_with_single_tool_call]}) + ``` + + ``` + {'messages': [ToolMessage(content="It's 60 degrees and foggy.", name='get_weather', tool_call_id='tool_call_id')]} + ``` + +??? example "Multiple tool calls" + + ```python + from langchain_core.messages import AIMessage + from langgraph.prebuilt import ToolNode + + # Define tools + + def get_weather(location: str): + """Call to get the current weather.""" + if location.lower() in ["sf", "san francisco"]: + return "It's 60 degrees and foggy." + else: + return "It's 90 degrees and sunny." + + def get_coolest_cities(): + """Get a list of coolest cities""" + return "nyc, sf" + + # highlight-next-line + tool_node = ToolNode([get_weather, get_coolest_cities]) + + message_with_multiple_tool_calls = AIMessage( + content="", + tool_calls=[ + { + "name": "get_coolest_cities", + "args": {}, + "id": "tool_call_id_1", + "type": "tool_call", + }, + { + "name": "get_weather", + "args": {"location": "sf"}, + "id": "tool_call_id_2", + "type": "tool_call", + }, + ], + ) + + # highlight-next-line + tool_node.invoke({"messages": [message_with_multiple_tool_calls]}) # (1)! + ``` + + 1. `ToolNode` will execute both tools in parallel + + ``` + { + 'messages': [ + ToolMessage(content='nyc, sf', name='get_coolest_cities', tool_call_id='tool_call_id_1'), + ToolMessage(content="It's 60 degrees and foggy.", name='get_weather', tool_call_id='tool_call_id_2') + ] + } + ``` + + + +??? example "Use with a chat model" + + ```python + from langchain.chat_models import init_chat_model + from langgraph.prebuilt import ToolNode + + def get_weather(location: str): + """Call to get the current weather.""" + if location.lower() in ["sf", "san francisco"]: + return "It's 60 degrees and foggy." + else: + return "It's 90 degrees and sunny." + + # highlight-next-line + tool_node = ToolNode([get_weather]) + + model = init_chat_model(model="claude-3-5-haiku-latest") + # highlight-next-line + model_with_tools = model.bind_tools([get_weather]) # (1)! + + + # highlight-next-line + response_message = model_with_tools.invoke("what's the weather in sf?") + tool_node.invoke({"messages": [response_message]}) + ``` + + 1. Use `.bind_tools()` to attach the tool schema to the chat model + + ``` + {'messages': [ToolMessage(content="It's 60 degrees and foggy.", name='get_weather', tool_call_id='toolu_01Pnkgw5JeTRxXAU7tyHT4UW')]} + ``` + +??? example "Use in a tool-calling agent" + + This is an example of creating a tool-calling agent from scratch using `ToolNode`. You can also use LangGraph's prebuilt [agent](../agents/agents.md). + + ```python + from langchain.chat_models import init_chat_model + from langgraph.prebuilt import ToolNode + from langgraph.graph import StateGraph, MessagesState, START, END + + def get_weather(location: str): + """Call to get the current weather.""" + if location.lower() in ["sf", "san francisco"]: + return "It's 60 degrees and foggy." + else: + return "It's 90 degrees and sunny." + + # highlight-next-line + tool_node = ToolNode([get_weather]) + + model = init_chat_model(model="claude-3-5-haiku-latest") + # highlight-next-line + model_with_tools = model.bind_tools([get_weather]) + + def should_continue(state: MessagesState): + messages = state["messages"] + last_message = messages[-1] + if last_message.tool_calls: + return "tools" + return END + + def call_model(state: MessagesState): + messages = state["messages"] + response = model_with_tools.invoke(messages) + return {"messages": [response]} + + builder = StateGraph(MessagesState) + + # Define the two nodes we will cycle between + builder.add_node("call_model", call_model) + # highlight-next-line + builder.add_node("tools", tool_node) + + builder.add_edge(START, "call_model") + builder.add_conditional_edges("call_model", should_continue, ["tools", END]) + builder.add_edge("tools", "call_model") + + graph = builder.compile() + + graph.invoke({"messages": [{"role": "user", "content": "what's the weather in sf?"}]}) + ``` + + ``` + { + 'messages': [ + HumanMessage(content="what's the weather in sf?"), + AIMessage( + content=[{'text': "I'll help you check the weather in San Francisco right now.", 'type': 'text'}, {'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'input': {'location': 'San Francisco'}, 'name': 'get_weather', 'type': 'tool_use'}], + tool_calls=[{'name': 'get_weather', 'args': {'location': 'San Francisco'}, 'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'type': 'tool_call'}] + ), + ToolMessage(content="It's 60 degrees and foggy."), + AIMessage(content="The current weather in San Francisco is 60 degrees and foggy. Typical San Francisco weather with its famous marine layer!") + ] + } + ``` + + +## Tool customization + +### Parameter descriptions + +Auto-generate descriptions from docstrings: + +```python +# highlight-next-line +from langchain_core.tools import tool + +# highlight-next-line +@tool("multiply_tool", parse_docstring=True) +def multiply(a: int, b: int) -> int: + """Multiply two numbers. + + Args: + a: First operand + b: Second operand + """ + return a * b +``` + +### Explicit input schema + +Define schemas using `args_schema`: + +```python +from pydantic import BaseModel, Field +from langchain_core.tools import tool + +class MultiplyInputSchema(BaseModel): + """Multiply two numbers""" + a: int = Field(description="First operand") + b: int = Field(description="Second operand") + +# highlight-next-line +@tool("multiply_tool", args_schema=MultiplyInputSchema) +def multiply(a: int, b: int) -> int: + return a * b +``` + +### Tool name + +Override the default tool name (function name) using the first argument: + +```python +from langchain_core.tools import tool + +# highlight-next-line +@tool("multiply_tool") +def multiply(a: int, b: int) -> int: + """Multiply two numbers.""" + return a * b +``` + +## Context management + +Tools within LangGraph sometimes require context data, such as runtime-only arguments (e.g., user IDs or session details), that should not be controlled by the model. LangGraph provides three methods for managing such context: + +| Type | Usage Scenario | Mutable | Lifetime | +|-----------------------------------------|------------------------------------------|---------|--------------------------| +| [Configuration](#configuration) | Static, immutable runtime data | ❌ | Single invocation | +| [Short-term memory](#short-term-memory) | Dynamic, changing data during invocation | ✅ | Single invocation | +| [Long-term memory](#long-term-memory) | Persistent, cross-session data | ✅ | Across multiple sessions | + +### Configuration + +Use configuration when you have **immutable** runtime data that tools require, such as user identifiers. You pass these arguments via [`RunnableConfig`](https://python.langchain.com/docs/concepts/runnables/#runnableconfig) at invocation and access them in the tool: + +```python +from langchain_core.tools import tool +from langchain_core.runnables import RunnableConfig + +@tool +# highlight-next-line +def get_user_info(config: RunnableConfig) -> str: + """Retrieve user information based on user ID.""" + user_id = config["configurable"].get("user_id") + return "User is John Smith" if user_id == "user_123" else "Unknown user" + +# Invocation example with an agent +agent.invoke( + {"messages": [{"role": "user", "content": "look up user info"}]}, + # highlight-next-line + config={"configurable": {"user_id": "user_123"}} +) +``` + +??? example "Extended example: Access config in tools" + + ```python + from langchain_core.runnables import RunnableConfig + from langchain_core.tools import tool + from langgraph.prebuilt import create_react_agent + + def get_user_info( + # highlight-next-line + config: RunnableConfig, + ) -> str: + """Look up user info.""" + # highlight-next-line + user_id = config["configurable"].get("user_id") + return "User is John Smith" if user_id == "user_123" else "Unknown user" + + agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[get_user_info], + ) + + agent.invoke( + {"messages": [{"role": "user", "content": "look up user information"}]}, + # highlight-next-line + config={"configurable": {"user_id": "user_123"}} + ) + ``` + +### Short-term memory + +Short-term memory maintains **dynamic** state that changes during a single execution. + +To **access** (read) the graph state inside the tools, you can use a special parameter **annotation** — [`InjectedState`][langgraph.prebuilt.InjectedState]: + +```python +from typing import Annotated, NotRequired +from langchain_core.tools import tool +from langgraph.prebuilt import InjectedState, create_react_agent +from langgraph.prebuilt.chat_agent_executor import AgentState + +class CustomState(AgentState): + # The user_name field in short-term state + user_name: NotRequired[str] + +@tool +def get_user_name( + # highlight-next-line + state: Annotated[CustomState, InjectedState] +) -> str: + """Retrieve the current user-name from state.""" + # Return stored name or a default if not set + return state.get("user_name", "Unknown user") + +# Example agent setup +agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[get_user_name], + state_schema=CustomState, +) + +# Invocation: reads the name from state (initially empty) +agent.invoke({"messages": "what's my name?"}) +``` + +Use a tool that returns a `Command` to **update** `user_name` and append a confirmation message: + +```python +from typing import Annotated +from langgraph.types import Command +from langchain_core.messages import ToolMessage +from langchain_core.tools import tool, InjectedToolCallId + +@tool +def update_user_name( + new_name: str, + tool_call_id: Annotated[str, InjectedToolCallId] +) -> Command: + """Update user name in short-term memory.""" + # highlight-next-line + return Command(update={ + # highlight-next-line + "user_name": new_name, + # highlight-next-line + "messages": [ + # highlight-next-line + ToolMessage(f"Updated user name to {new_name}", tool_call_id=tool_call_id) + # highlight-next-line + ] + # highlight-next-line + }) +``` + +!!! important + + If you want to use tools that return `Command` and update graph state, you can either use prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] / [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] components, or implement your own tool-executing node that collects `Command` objects returned by the tools and returns a list of them, e.g.: + + ```python + def call_tools(state): + ... + commands = [tools_by_name[tool_call["name"]].invoke(tool_call) for tool_call in tool_calls] + return commands + ``` + + +### Long-term memory + +Use [long-term memory](../concepts/memory.md#long-term-memory) to store user-specific or application-specific data across conversations. This is useful for applications like chatbots, where you want to remember user preferences or other information. + +To use long-term memory, you need to: + +1. [Configure a store](memory/add-memory.md#add-long-term-memory) to persist data across invocations. +2. Use the [`get_store`][langgraph.config.get_store] function to access the store from within tools or prompts. + +To **access** information in the store: + +```python +from langchain_core.runnables import RunnableConfig +from langchain_core.tools import tool +from langgraph.graph import StateGraph +# highlight-next-line +from langgraph.config import get_store + +@tool +def get_user_info(config: RunnableConfig) -> str: + """Look up user info.""" + # Same as that provided to `builder.compile(store=store)` + # or `create_react_agent` + # highlight-next-line + store = get_store() + user_id = config["configurable"].get("user_id") + # highlight-next-line + user_info = store.get(("users",), user_id) + return str(user_info.value) if user_info else "Unknown user" + +builder = StateGraph(...) +... +graph = builder.compile(store=store) +``` + +??? example "Access long-term memory" + + ```python + from langchain_core.runnables import RunnableConfig + from langchain_core.tools import tool + from langgraph.config import get_store + from langgraph.prebuilt import create_react_agent + from langgraph.store.memory import InMemoryStore + + # highlight-next-line + store = InMemoryStore() # (1)! + + # highlight-next-line + store.put( # (2)! + ("users",), # (3)! + "user_123", # (4)! + { + "name": "John Smith", + "language": "English", + } # (5)! + ) + + @tool + def get_user_info(config: RunnableConfig) -> str: + """Look up user info.""" + # Same as that provided to `create_react_agent` + # highlight-next-line + store = get_store() # (6)! + user_id = config["configurable"].get("user_id") + # highlight-next-line + user_info = store.get(("users",), user_id) # (7)! + return str(user_info.value) if user_info else "Unknown user" + + agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[get_user_info], + # highlight-next-line + store=store # (8)! + ) + + # Run the agent + agent.invoke( + {"messages": [{"role": "user", "content": "look up user information"}]}, + # highlight-next-line + config={"configurable": {"user_id": "user_123"}} + ) + ``` + + 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [store documentation][../reference/store.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you. + 2. For this example, we write some sample data to the store using the `put` method. Please see the [BaseStore.put][langgraph.store.base.BaseStore.put] API reference for more details. + 3. The first argument is the namespace. This is used to group related data together. In this case, we are using the `users` namespace to group user data. + 4. A key within the namespace. This example uses a user ID for the key. + 5. The data that we want to store for the given user. + 6. The `get_store` function is used to access the store. You can call it from anywhere in your code, including tools and prompts. This function returns the store that was passed to the agent when it was created. + 7. The `get` method is used to retrieve data from the store. The first argument is the namespace, and the second argument is the key. This will return a `StoreValue` object, which contains the value and metadata about the value. + 8. The `store` is passed to the agent. This enables the agent to access the store when running tools. You can also use the `get_store` function to access the store from anywhere in your code. + +To **update** information in the store: + +```python +from langchain_core.runnables import RunnableConfig +from langchain_core.tools import tool +from langgraph.graph import StateGraph +# highlight-next-line +from langgraph.config import get_store + +@tool +def save_user_info(user_info: str, config: RunnableConfig) -> str: + """Save user info.""" + # Same as that provided to `builder.compile(store=store)` + # or `create_react_agent` + # highlight-next-line + store = get_store() + user_id = config["configurable"].get("user_id") + # highlight-next-line + store.put(("users",), user_id, user_info) + return "Successfully saved user info." + +builder = StateGraph(...) +... +graph = builder.compile(store=store) +``` + +??? example "Update long-term memory" + + ```python + from typing_extensions import TypedDict + + from langchain_core.tools import tool + from langgraph.config import get_store + from langgraph.prebuilt import create_react_agent + from langgraph.store.memory import InMemoryStore + + store = InMemoryStore() # (1)! + + class UserInfo(TypedDict): # (2)! + name: str + + @tool + def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str: # (3)! + """Save user info.""" + # Same as that provided to `create_react_agent` + # highlight-next-line + store = get_store() # (4)! + user_id = config["configurable"].get("user_id") + # highlight-next-line + store.put(("users",), user_id, user_info) # (5)! + return "Successfully saved user info." + + agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[save_user_info], + # highlight-next-line + store=store + ) + + # Run the agent + agent.invoke( + {"messages": [{"role": "user", "content": "My name is John Smith"}]}, + # highlight-next-line + config={"configurable": {"user_id": "user_123"}} # (6)! + ) + + # You can access the store directly to get the value + store.get(("users",), "user_123").value + ``` + + 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [store documentation](../reference/store.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you. + 2. The `UserInfo` class is a `TypedDict` that defines the structure of the user information. The LLM will use this to format the response according to the schema. + 3. The `save_user_info` function is a tool that allows an agent to update user information. This could be useful for a chat application where the user wants to update their profile information. + 4. The `get_store` function is used to access the store. You can call it from anywhere in your code, including tools and prompts. This function returns the store that was passed to the agent when it was created. + 5. The `put` method is used to store data in the store. The first argument is the namespace, and the second argument is the key. This will store the user information in the store. + 6. The `user_id` is passed in the config. This is used to identify the user whose information is being updated. + +## Advanced tool features + +### Immediate return + +Use `return_direct=True` to immediately return a tool's result without executing additional logic. + +This is useful for tools that should not trigger further processing or tool calls, allowing you to return results directly to the user. + +```python +# highlight-next-line +@tool(return_direct=True) +def add(a: int, b: int) -> int: + """Add two numbers""" + return a + b +``` + +??? example "Extended example: Using return_direct in a prebuilt agent" + + ```python + from langchain_core.tools import tool + from langgraph.prebuilt import create_react_agent + + # highlight-next-line + @tool(return_direct=True) + def add(a: int, b: int) -> int: + """Add two numbers""" + return a + b + + agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[add] + ) + + agent.invoke( + {"messages": [{"role": "user", "content": "what's 3 + 5?"}]} + ) + ``` + + +!!! important "Using without prebuilt components" + + If you are building a custom workflow and are not relying on `create_react_agent` or `ToolNode`, you will also + need to implement the control flow to handle `return_direct=True`. + +### Force tool use + +If you need to force a specific tool to be used, you will need to configure this +at the **model** level using the `tool_choice` parameter in the `bind_tools` method. + +Force specific tool usage via tool_choice: + +```python +@tool(return_direct=True) +def greet(user_name: str) -> int: + """Greet user.""" + return f"Hello {user_name}!" + +tools = [greet] + +configured_model = model.bind_tools( + tools, + # Force the use of the 'greet' tool + # highlight-next-line + tool_choice={"type": "tool", "name": "greet"} +) + +``` + +??? example "Extended example: Force tool usage in an agent" + + To force the agent to use specific tools, you can set the `tool_choice` option in `model.bind_tools()`: + + ```python + from langchain_core.tools import tool + + # highlight-next-line + @tool(return_direct=True) + def greet(user_name: str) -> int: + """Greet user.""" + return f"Hello {user_name}!" + + tools = [greet] + + agent = create_react_agent( + # highlight-next-line + model=model.bind_tools(tools, tool_choice={"type": "tool", "name": "greet"}), + tools=tools + ) + + agent.invoke( + {"messages": [{"role": "user", "content": "Hi, I am Bob"}]} + ) + ``` + +!!! Warning "Avoid infinite loops" + + Forcing tool usage without stopping conditions can create infinite loops. Use one of the following safeguards: + + - Mark the tool with [`return_direct=True`](#immediate-return to end the loop after execution. + - Set [`recursion_limit`](../concepts/low_level.md#recursion-limit) to restrict the number of execution steps. + + +!!! tip "Tool choice configuration" + + The `tool_choice` parameter is used to configure which tool should be used by the model when it decides to call a tool. This is useful when you want to ensure that a specific tool is always called for a particular task or when you want to override the model's default behavior of choosing a tool based on its internal logic. + + Note that not all models support this feature, and the exact configuration may vary depending on the model you are using. + +### Disable parallel calls + +For supported providers, you can disable parallel tool calling by setting `parallel_tool_calls=False` via the `model.bind_tools()` method: + +```python +model.bind_tools( + tools, + # highlight-next-line + parallel_tool_calls=False +) +``` + +??? example "Extended example: disable parallel tool calls in a prebuilt agent" + + ```python + from langchain.chat_models import init_chat_model + + def add(a: int, b: int) -> int: + """Add two numbers""" + return a + b + + def multiply(a: int, b: int) -> int: + """Multiply two numbers.""" + return a * b + + model = init_chat_model("anthropic:claude-3-5-sonnet-latest", temperature=0) + tools = [add, multiply] + agent = create_react_agent( + # disable parallel tool calls + # highlight-next-line + model=model.bind_tools(tools, parallel_tool_calls=False), + tools=tools + ) + + agent.invoke( + {"messages": [{"role": "user", "content": "what's 3 + 5 and 4 * 7?"}]} + ) + ``` + +### Handle errors + +LangGraph provides built-in error handling for tool execution through the prebuilt [ToolNode][langgraph.prebuilt.tool_node.ToolNode] component, used both independently and in prebuilt agents. + +By **default**, `ToolNode` catches exceptions raised during tool execution and returns them as `ToolMessage` objects with a status indicating an error. + +```python +from langchain_core.messages import AIMessage +from langgraph.prebuilt import ToolNode + +def multiply(a: int, b: int) -> int: + if a == 42: + raise ValueError("The ultimate error") + return a * b + +# Default error handling (enabled by default) +tool_node = ToolNode([multiply]) + +message = AIMessage( + content="", + tool_calls=[{ + "name": "multiply", + "args": {"a": 42, "b": 7}, + "id": "tool_call_id", + "type": "tool_call" + }] +) + +result = tool_node.invoke({"messages": [message]}) +``` + +Output: + +```pycon +{'messages': [ + ToolMessage( + content="Error: ValueError('The ultimate error')\n Please fix your mistakes.", + name='multiply', + tool_call_id='tool_call_id', + status='error' + ) +]} +``` + +#### Disable error handling + +To propagate exceptions directly, disable error handling: + +```python +tool_node = ToolNode([multiply], handle_tool_errors=False) +``` + +With error handling disabled, exceptions raised by tools will propagate up, requiring explicit management. + +#### Custom error messages + +Provide a custom error message by setting `handle_tool_errors` to a string: + +```python +tool_node = ToolNode( + [multiply], + handle_tool_errors="Can't use 42 as the first operand, please switch operands!" +) +``` + +Example output: + +```python +{'messages': [ + ToolMessage( + content="Can't use 42 as the first operand, please switch operands!", + name='multiply', + tool_call_id='tool_call_id', + status='error' + ) +]} +``` + +#### Error handling in agents + +Error handling in prebuilt agents (`create_react_agent`) leverages `ToolNode`: + +```python +from langgraph.prebuilt import create_react_agent + +agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[multiply] +) + +# Default error handling +agent.invoke({"messages": [{"role": "user", "content": "what's 42 x 7?"}]}) +``` + +To disable or customize error handling in prebuilt agents, explicitly pass a configured `ToolNode`: + +```python +custom_tool_node = ToolNode( + [multiply], + handle_tool_errors="Cannot use 42 as a first operand!" +) + +agent_custom = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=custom_tool_node +) + +agent_custom.invoke({"messages": [{"role": "user", "content": "what's 42 x 7?"}]}) +``` + +### Handle large numbers of tools + +As the number of available tools grows, you may want to limit the scope of the LLM's selection, to decrease token consumption and to help manage sources of error in LLM reasoning. + +To address this, you can dynamically adjust the tools available to a model by retrieving relevant tools at runtime using semantic search. + +See [`langgraph-bigtool`](https://github.com/langchain-ai/langgraph-bigtool) prebuilt library for a ready-to-use implementation. + +## Prebuilt tools + +### LLM provider tools + +You can use prebuilt tools from model providers by passing a dictionary with tool specs to the `tools` parameter of `create_react_agent`. For example, to use the `web_search_preview` tool from OpenAI: + +```python +from langgraph.prebuilt import create_react_agent + +agent = create_react_agent( + model="openai:gpt-4o-mini", + tools=[{"type": "web_search_preview"}] +) +response = agent.invoke( + {"messages": ["What was a positive news story from today?"]} +) +``` + +Please consult the documentation for the specific model you are using to see which tools are available and how to use them. + +### LangChain tools + +Additionally, LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development. + +You can browse the full list of available integrations in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/tools/). + +Some commonly used tool categories include: + +- **Search**: Bing, SerpAPI, Tavily +- **Code interpreters**: Python REPL, Node.js REPL +- **Databases**: SQL, MongoDB, Redis +- **Web data**: Web scraping and browsing +- **APIs**: OpenWeatherMap, NewsAPI, and others + +These integrations can be configured and added to your agents using the same `tools` parameter shown in the examples above. + diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 87b5cf2f3..3fc89c979 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -166,8 +166,7 @@ nav: - Set breakpoints: how-tos/human_in_the_loop/breakpoints.ipynb - Use Server API: cloud/how-tos/human_in_the_loop_breakpoint.md - Tools: - - Use tools: agents/tools.md - - Customize tools: how-tos/tool-calling.ipynb + - Call tools: how-tos/tool-calling.md - Subgraphs: - Use subgraphs: how-tos/subgraph.ipynb - Multi-agent: