chore: import upstream snapshot with attribution
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
Docker image release / Build base image (push) Has been cancelled
Sync docs with Docusaurus / sync (push) Has been cancelled
Tests / Check if changed (push) Has been cancelled
Tests / format (push) Has been cancelled
Tests / check-imports (push) Has been cancelled
Tests / Unit / macos-latest (push) Has been cancelled
Tests / Unit / ubuntu-latest (push) Has been cancelled
Tests / Unit / windows-latest (push) Has been cancelled
Tests / mypy (push) Has been cancelled
Tests / Integration / ubuntu-latest (push) Has been cancelled
Tests / Integration / macos-latest (push) Has been cancelled
Tests / Integration / windows-latest (push) Has been cancelled
Tests / notify-slack-on-failure (push) Has been cancelled
Tests / Mark tests as completed (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
Docker image release / Build base image (push) Has been cancelled
Sync docs with Docusaurus / sync (push) Has been cancelled
Tests / Check if changed (push) Has been cancelled
Tests / format (push) Has been cancelled
Tests / check-imports (push) Has been cancelled
Tests / Unit / macos-latest (push) Has been cancelled
Tests / Unit / ubuntu-latest (push) Has been cancelled
Tests / Unit / windows-latest (push) Has been cancelled
Tests / mypy (push) Has been cancelled
Tests / Integration / ubuntu-latest (push) Has been cancelled
Tests / Integration / macos-latest (push) Has been cancelled
Tests / Integration / windows-latest (push) Has been cancelled
Tests / notify-slack-on-failure (push) Has been cancelled
Tests / Mark tests as completed (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
---
|
||||
title: "Toolset"
|
||||
id: toolset
|
||||
slug: "/toolset"
|
||||
description: "Group multiple Tools into a single unit."
|
||||
---
|
||||
|
||||
# Toolset
|
||||
|
||||
Group multiple Tools into a single unit.
|
||||
|
||||
<div className="key-value-table">
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| **Mandatory init variables** | `tools`: A list of tools |
|
||||
| **API reference** | [Toolset](/reference/tools-api#toolset) |
|
||||
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/tools/toolset.py |
|
||||
| **Package name** | `haystack-ai` |
|
||||
|
||||
</div>
|
||||
|
||||
## Overview
|
||||
|
||||
A `Toolset` groups multiple Tool instances into a single manageable unit. It simplifies passing tools to components like Chat Generators, [`ToolInvoker`](../pipeline-components/tools/toolinvoker.mdx), or [`Agent`](../pipeline-components/agents-1/agent.mdx), and supports filtering, serialization, and reuse.
|
||||
|
||||
Additionally, by subclassing `Toolset`, you can create implementations that dynamically load tools from external sources like OpenAPI URLs, MCP servers, or other resources.
|
||||
|
||||
### Initializing Toolset
|
||||
|
||||
Here’s how to initialize `Toolset` with [Tool](tool.mdx). Alternatively, you can use [ComponentTool](componenttool.mdx) or [MCPTool](mcptool.mdx) in `Toolset` as Tool instances.
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
from haystack.tools import Toolset, tool
|
||||
|
||||
|
||||
@tool
|
||||
def add_numbers(
|
||||
a: Annotated[int, "first number"],
|
||||
b: Annotated[int, "second number"],
|
||||
) -> int:
|
||||
"""Add two numbers."""
|
||||
return a + b
|
||||
|
||||
|
||||
@tool
|
||||
def subtract_numbers(
|
||||
a: Annotated[int, "first number"],
|
||||
b: Annotated[int, "second number"],
|
||||
) -> int:
|
||||
"""Subtract b from a."""
|
||||
return a - b
|
||||
|
||||
|
||||
math_toolset = Toolset([add_numbers, subtract_numbers])
|
||||
```
|
||||
|
||||
### Adding New Tools to Toolset
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
from haystack.tools import tool
|
||||
|
||||
|
||||
@tool
|
||||
def multiply_numbers(
|
||||
a: Annotated[int, "first number"],
|
||||
b: Annotated[int, "second number"],
|
||||
) -> int:
|
||||
"""Multiply two numbers."""
|
||||
return a * b
|
||||
|
||||
|
||||
math_toolset.add(multiply_numbers)
|
||||
|
||||
# or, you can merge toolsets together
|
||||
math_toolset.add(another_toolset)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
You can use `Toolset` wherever you can use Tools in Haystack.
|
||||
|
||||
:::tip
|
||||
The recommended way to use a `Toolset` in Haystack is with the [`Agent`](../pipeline-components/agents-1/agent.mdx) component, which manages the tool call loop for you. The examples below also show how to wire `ChatGenerator` and `ToolInvoker` together manually for cases where you need fine-grained control.
|
||||
:::
|
||||
|
||||
### With the Agent
|
||||
|
||||
```python
|
||||
from haystack.components.agents import Agent
|
||||
from haystack.dataclasses import ChatMessage
|
||||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||||
|
||||
agent = Agent(
|
||||
system_prompt="You are a helpful assistant that can do math using the tools at your disposal.",
|
||||
chat_generator=OpenAIChatGenerator(model="gpt-5.4-nano"),
|
||||
tools=math_toolset,
|
||||
)
|
||||
|
||||
response = agent.run(messages=[ChatMessage.from_user("What is 4 + 2?")])
|
||||
|
||||
print(response["messages"][-1].text)
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
4 + 2 equals 6.
|
||||
```
|
||||
|
||||
### With ChatGenerator and ToolInvoker
|
||||
|
||||
```python
|
||||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||||
from haystack.components.tools import ToolInvoker
|
||||
from haystack.dataclasses import ChatMessage
|
||||
|
||||
chat_generator = OpenAIChatGenerator(model="gpt-5.4-nano", tools=math_toolset)
|
||||
tool_invoker = ToolInvoker(tools=math_toolset)
|
||||
|
||||
user_message = ChatMessage.from_user("What is 10 minus 5?")
|
||||
|
||||
replies = chat_generator.run(messages=[user_message])["replies"]
|
||||
print(f"assistant message: {replies}")
|
||||
|
||||
# If the assistant message contains a tool call, run the tool invoker
|
||||
if replies[0].tool_calls:
|
||||
tool_messages = tool_invoker.run(messages=replies)["tool_messages"]
|
||||
print(f"tool result: {tool_messages[0].tool_call_result.result}")
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
assistant message: [ChatMessage(
|
||||
_role=<ChatRole.ASSISTANT: 'assistant'>,
|
||||
_content=[ToolCall(tool_name='subtract', arguments={'a': 10, 'b': 5}, id='call_awGa5q7KtQ9BrMGPTj6IgEH1')],
|
||||
_meta={'model': 'gpt-5.4-nano', 'index': 0, 'finish_reason': 'tool_calls', 'usage': {'completion_tokens': 18, 'prompt_tokens': 75, 'total_tokens': 93}}
|
||||
)]
|
||||
tool result: 5
|
||||
```
|
||||
|
||||
### In a Pipeline
|
||||
|
||||
```python
|
||||
from haystack import Pipeline
|
||||
from haystack.components.converters import OutputAdapter
|
||||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||||
from haystack.components.tools import ToolInvoker
|
||||
from haystack.dataclasses import ChatMessage
|
||||
|
||||
pipeline = Pipeline()
|
||||
pipeline.add_component(
|
||||
"llm",
|
||||
OpenAIChatGenerator(model="gpt-5.4-nano", tools=math_toolset),
|
||||
)
|
||||
pipeline.add_component("tool_invoker", ToolInvoker(tools=math_toolset))
|
||||
pipeline.add_component(
|
||||
"adapter",
|
||||
OutputAdapter(
|
||||
template="{{ initial_msg + initial_tool_messages + tool_messages }}",
|
||||
output_type=list[ChatMessage],
|
||||
unsafe=True,
|
||||
),
|
||||
)
|
||||
pipeline.add_component("response_llm", OpenAIChatGenerator(model="gpt-5.4-nano"))
|
||||
pipeline.connect("llm.replies", "tool_invoker.messages")
|
||||
pipeline.connect("llm.replies", "adapter.initial_tool_messages")
|
||||
pipeline.connect("tool_invoker.tool_messages", "adapter.tool_messages")
|
||||
pipeline.connect("adapter.output", "response_llm.messages")
|
||||
|
||||
user_input_msg = ChatMessage.from_user(text="What is 2+2?")
|
||||
|
||||
result = pipeline.run(
|
||||
{
|
||||
"llm": {"messages": [user_input_msg]},
|
||||
"adapter": {"initial_msg": [user_input_msg]},
|
||||
},
|
||||
)
|
||||
|
||||
print(result["response_llm"]["replies"][0].text)
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
2 + 2 equals 4.
|
||||
```
|
||||
Reference in New Issue
Block a user