mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-06 15:13:56 +00:00
Note: includes links to API reference pages for ToolCall and other objects that currently don't exist (e.g., https://api.python.langchain.com/en/latest/messages/langchain_core.messages.tool.ToolCall.html#langchain_core.messages.tool.ToolCall).
327 lines
13 KiB
Plaintext
327 lines
13 KiB
Plaintext
---
|
|
sidebar_position: 2
|
|
title: Tool/function calling
|
|
---
|
|
|
|
# Tool calling
|
|
|
|
:::info
|
|
We use the term tool calling interchangeably with function calling. Although
|
|
function calling is sometimes meant to refer to invocations of a single function,
|
|
we treat all models as though they can return multiple tool or function calls in
|
|
each message.
|
|
:::
|
|
|
|
# Calling Tools
|
|
|
|
Tool calling allows a model to respond to a given prompt by generating output that
|
|
matches a user-defined schema. While the name implies that the model is performing
|
|
some action, this is actually not the case! The model is coming up with the
|
|
arguments to a tool, and actually running the tool (or not) is up to the user -
|
|
for example, if you want to [extract output matching some schema](/docs/use_cases/extraction/)
|
|
from unstructured text, you could give the model an "extraction" tool that takes
|
|
parameters matching the desired schema, then treat the generated output as your final
|
|
result.
|
|
|
|
A tool call includes a name, arguments dict, and an optional identifier. The
|
|
arguments dict is structured `{argument_name: argument_value}`.
|
|
|
|
Many LLM providers, including [Anthropic](https://www.anthropic.com/),
|
|
[Cohere](https://cohere.com/), [Google](https://cloud.google.com/vertex-ai),
|
|
[Mistral](https://mistral.ai/), [OpenAI](https://openai.com/), and others,
|
|
support variants of a tool calling feature. These features typically allow requests
|
|
to the LLM to include available tools and their schemas, and for responses to include
|
|
calls to these tools. For instance, given a search engine tool, an LLM might handle a
|
|
query by first issuing a call to the search engine. The system calling the LLM can
|
|
receive the tool call, execute it, and return the output to the LLM to inform its
|
|
response. LangChain includes a suite of [built-in tools](/docs/integrations/tools/)
|
|
and supports several methods for defining your own [custom tools](/docs/modules/tools/custom_tools).
|
|
Tool-calling is extremely useful for building [tool-using chains and agents](/docs/use_cases/tool_use),
|
|
and for getting structured outputs from models more generally.
|
|
|
|
Providers adopt different conventions for formatting tool schemas and tool calls.
|
|
For instance, Anthropic returns tool calls as parsed structures within a larger content block:
|
|
```
|
|
[
|
|
{
|
|
"text": "<thinking>\nI should use a tool.\n</thinking>",
|
|
"type": "text"
|
|
},
|
|
{
|
|
"id": "id_value",
|
|
"input": {"arg_name": "arg_value"},
|
|
"name": "tool_name",
|
|
"type": "tool_use"
|
|
}
|
|
]
|
|
```
|
|
whereas OpenAI separates tool calls into a distinct parameter, with arguments as JSON strings:
|
|
```
|
|
{
|
|
"tool_calls": [
|
|
{
|
|
"id": "id_value",
|
|
"function": {
|
|
"arguments": '{"arg_name": "arg_value"}',
|
|
"name": "tool_name"
|
|
},
|
|
"type": "function"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
LangChain implements standard interfaces for defining tools, passing them to LLMs,
|
|
and representing tool calls.
|
|
|
|
## Passing tools to LLMs
|
|
|
|
Chat models supporting tool calling features implement a `.bind_tools` method, which
|
|
receives a list of LangChain [tool objects](https://api.python.langchain.com/en/latest/tools/langchain_core.tools.BaseTool.html#langchain_core.tools.BaseTool)
|
|
and binds them to the chat model in its expected format. Subsequent invocations of the
|
|
chat model will include tool schemas in its calls to the LLM.
|
|
|
|
For example, we can define the schema for custom tools using the `@tool` decorator
|
|
on Python functions:
|
|
|
|
```python
|
|
from langchain.tools import tool
|
|
|
|
|
|
@tool
|
|
def add(a: int, b: int) -> int:
|
|
"""Adds a and b."""
|
|
return a + b
|
|
|
|
|
|
@tool
|
|
def multiply(a: int, b: int) -> int:
|
|
"""Multiplies a and b."""
|
|
return a * b
|
|
|
|
|
|
tools = [add, multiply]
|
|
```
|
|
|
|
Or below, we define the schema using Pydantic:
|
|
```python
|
|
from langchain_core.pydantic_v1 import BaseModel, Field
|
|
|
|
|
|
# Note that the docstrings here are crucial, as they will be passed along
|
|
# to the model along with the class name.
|
|
class Add(BaseModel):
|
|
"""Add two integers together."""
|
|
|
|
a: int = Field(..., description="First integer")
|
|
b: int = Field(..., description="Second integer")
|
|
|
|
|
|
class Multiply(BaseModel):
|
|
"""Multiply two integers together."""
|
|
|
|
a: int = Field(..., description="First integer")
|
|
b: int = Field(..., description="Second integer")
|
|
|
|
|
|
tools = [Add, Multiply]
|
|
```
|
|
|
|
We can bind them to chat models as follows:
|
|
|
|
import Tabs from "@theme/Tabs";
|
|
import TabItem from "@theme/TabItem";
|
|
|
|
import ChatModelTabs from "@theme/ChatModelTabs";
|
|
|
|
<ChatModelTabs
|
|
customVarName="llm"
|
|
fireworksParams={`model="accounts/fireworks/models/firefunction-v1", temperature=0`}
|
|
hideGoogle={true}
|
|
hideAnthropic={false}
|
|
/>
|
|
|
|
We can use the `bind_tools()` method to handle converting
|
|
`Multiply` to a "tool" and binding it to the model (i.e.,
|
|
passing it in each time the model is invoked).
|
|
|
|
```python
|
|
llm_with_tools = llm.bind_tools(tools)
|
|
```
|
|
|
|
## Tool calls
|
|
|
|
If tool calls are included in a LLM response, they are attached to the corresponding
|
|
[message](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.ai.AIMessage.html#langchain_core.messages.ai.AIMessage)
|
|
or [message chunk](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.ai.AIMessageChunk.html#langchain_core.messages.ai.AIMessageChunk)
|
|
as a list of [tool call](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.tool.ToolCall.html#langchain_core.messages.tool.ToolCall)
|
|
objects in the `.tool_calls` attribute. A `ToolCall` is a typed dict that includes a
|
|
tool name, dict of argument values, and (optionally) an identifier. Messages with no
|
|
tool calls default to an empty list for this attribute.
|
|
|
|
Example:
|
|
|
|
```python
|
|
query = "What is 3 * 12? Also, what is 11 + 49?"
|
|
|
|
llm_with_tools.invoke(query).tool_calls
|
|
```
|
|
```text
|
|
[{'name': 'Multiply',
|
|
'args': {'a': 3, 'b': 12},
|
|
'id': 'call_viACG45wBz9jYzljHIwHamXw'},
|
|
{'name': 'Add',
|
|
'args': {'a': 11, 'b': 49},
|
|
'id': 'call_JMFUqoi5L27rGeMuII4MJMWo'}]
|
|
```
|
|
|
|
The `.tool_calls` attribute should contain valid tool calls. Note that on occasion,
|
|
model providers may output malformed tool calls (e.g., arguments that are not
|
|
valid JSON). When parsing fails in these cases, instances
|
|
of [InvalidToolCall](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.tool.InvalidToolCall.html#langchain_core.messages.tool.InvalidToolCall)
|
|
are populated in the `.invalid_tool_calls` attribute. An `InvalidToolCall` can have
|
|
a name, string arguments, identifier, and error message.
|
|
|
|
If desired, [output parsers](/docs/modules/model_io/output_parsers) can further
|
|
process the output. For example, we can convert back to the original Pydantic class:
|
|
|
|
```python
|
|
from langchain_core.output_parsers.openai_tools import PydanticToolsParser
|
|
|
|
chain = llm_with_tools | PydanticToolsParser(tools=[Multiply, Add])
|
|
chain.invoke(query)
|
|
```
|
|
```text
|
|
[Multiply(a=3, b=12), Add(a=11, b=49)]
|
|
```
|
|
|
|
### Streaming
|
|
|
|
When tools are called in a streaming context,
|
|
[message chunks](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.ai.AIMessageChunk.html#langchain_core.messages.ai.AIMessageChunk)
|
|
will be populated with [tool call chunk](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.tool.ToolCallChunk.html#langchain_core.messages.tool.ToolCallChunk)
|
|
objects in a list via the `.tool_call_chunks` attribute. A `ToolCallChunk` includes
|
|
optional string fields for the tool `name`, `args`, and `id`, and includes an optional
|
|
integer field `index` that can be used to join chunks together. Fields are optional
|
|
because portions of a tool call may be streamed across different chunks (e.g., a chunk
|
|
that includes a substring of the arguments may have null values for the tool name and id).
|
|
|
|
Because message chunks inherit from their parent message class, an
|
|
[AIMessageChunk](https://api.python.langchain.com/en/latest/messages/langchain_core.messages.ai.AIMessageChunk.html#langchain_core.messages.ai.AIMessageChunk)
|
|
with tool call chunks will also include `.tool_calls` and `.invalid_tool_calls` fields.
|
|
These fields are parsed best-effort from the message's tool call chunks.
|
|
|
|
Note that not all providers currently support streaming for tool calls.
|
|
|
|
Example:
|
|
|
|
```python
|
|
async for chunk in llm_with_tools.astream(query):
|
|
print(chunk.tool_call_chunks)
|
|
```
|
|
|
|
```text
|
|
[]
|
|
[{'name': 'Multiply', 'args': '', 'id': 'call_Al2xpR4uFPXQUDzGTSawMOah', 'index': 0}]
|
|
[{'name': None, 'args': '{"a"', 'id': None, 'index': 0}]
|
|
[{'name': None, 'args': ': 3, ', 'id': None, 'index': 0}]
|
|
[{'name': None, 'args': '"b": 1', 'id': None, 'index': 0}]
|
|
[{'name': None, 'args': '2}', 'id': None, 'index': 0}]
|
|
[{'name': 'Add', 'args': '', 'id': 'call_VV6ck8JSQ6joKtk2xGtNKgXf', 'index': 1}]
|
|
[{'name': None, 'args': '{"a"', 'id': None, 'index': 1}]
|
|
[{'name': None, 'args': ': 11,', 'id': None, 'index': 1}]
|
|
[{'name': None, 'args': ' "b": ', 'id': None, 'index': 1}]
|
|
[{'name': None, 'args': '49}', 'id': None, 'index': 1}]
|
|
[]
|
|
```
|
|
|
|
Note that adding message chunks will merge their corresponding tool call chunks. This is the principle by which LangChain's various [tool output parsers](/docs/modules/model_io/output_parsers/types/openai_tools/) support streaming.
|
|
|
|
For example, below we accumulate tool call chunks:
|
|
|
|
```python
|
|
first = True
|
|
async for chunk in llm_with_tools.astream(query):
|
|
if first:
|
|
gathered = chunk
|
|
first = False
|
|
else:
|
|
gathered = gathered + chunk
|
|
|
|
print(gathered.tool_call_chunks)
|
|
```
|
|
|
|
```text
|
|
[]
|
|
[{'name': 'Multiply', 'args': '', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}]
|
|
[{'name': 'Multiply', 'args': '{"a"', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, ', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 1', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 12}', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 12}', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}, {'name': 'Add', 'args': '', 'id': 'call_uGot9MOHDcz67Bj0h13c7QA5', 'index': 1}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 12}', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}, {'name': 'Add', 'args': '{"a"', 'id': 'call_uGot9MOHDcz67Bj0h13c7QA5', 'index': 1}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 12}', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}, {'name': 'Add', 'args': '{"a": 11,', 'id': 'call_uGot9MOHDcz67Bj0h13c7QA5', 'index': 1}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 12}', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}, {'name': 'Add', 'args': '{"a": 11, "b": ', 'id': 'call_uGot9MOHDcz67Bj0h13c7QA5', 'index': 1}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 12}', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}, {'name': 'Add', 'args': '{"a": 11, "b": 49}', 'id': 'call_uGot9MOHDcz67Bj0h13c7QA5', 'index': 1}]
|
|
[{'name': 'Multiply', 'args': '{"a": 3, "b": 12}', 'id': 'call_2MG1IGft6WmgMooqZgJ07JX6', 'index': 0}, {'name': 'Add', 'args': '{"a": 11, "b": 49}', 'id': 'call_uGot9MOHDcz67Bj0h13c7QA5', 'index': 1}]
|
|
```
|
|
|
|
```python
|
|
print(type(gathered.tool_call_chunks[0]["args"]))
|
|
```
|
|
|
|
```text
|
|
<class 'str'>
|
|
```
|
|
|
|
And below we accumulate tool calls to demonstrate partial parsing:
|
|
|
|
```python
|
|
first = True
|
|
async for chunk in llm_with_tools.astream(query):
|
|
if first:
|
|
gathered = chunk
|
|
first = False
|
|
else:
|
|
gathered = gathered + chunk
|
|
|
|
print(gathered.tool_calls)
|
|
```
|
|
|
|
```text
|
|
[]
|
|
[]
|
|
[{'name': 'Multiply', 'args': {}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 1}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}, {'name': 'Add', 'args': {}, 'id': 'call_zPAyMWr8hN1q083GWGX2dSiB'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}, {'name': 'Add', 'args': {'a': 11}, 'id': 'call_zPAyMWr8hN1q083GWGX2dSiB'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}, {'name': 'Add', 'args': {'a': 11}, 'id': 'call_zPAyMWr8hN1q083GWGX2dSiB'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}, {'name': 'Add', 'args': {'a': 11, 'b': 49}, 'id': 'call_zPAyMWr8hN1q083GWGX2dSiB'}]
|
|
[{'name': 'Multiply', 'args': {'a': 3, 'b': 12}, 'id': 'call_z3B4o82SQDY5NCnmrXIcVQo4'}, {'name': 'Add', 'args': {'a': 11, 'b': 49}, 'id': 'call_zPAyMWr8hN1q083GWGX2dSiB'}]
|
|
```
|
|
|
|
```python
|
|
print(type(gathered.tool_calls[0]["args"]))
|
|
```
|
|
|
|
```text
|
|
<class 'dict'>
|
|
```
|
|
|
|
|
|
## Next steps
|
|
|
|
- **Output parsing**: See [OpenAI Tools output
|
|
parsers](/docs/modules/model_io/output_parsers/types/openai_tools/)
|
|
and [OpenAI Functions output
|
|
parsers](/docs/modules/model_io/output_parsers/types/openai_functions/)
|
|
to learn about extracting the function calling API responses into
|
|
various formats.
|
|
- **Structured output chains**: [Some models have constructors](/docs/modules/model_io/chat/structured_output/) that
|
|
handle creating a structured output chain for you.
|
|
- **Tool use**: See how to construct chains and agents that actually
|
|
call the invoked tools in [these
|
|
guides](/docs/use_cases/tool_use/).
|