文档API 参考📓 教程🧑‍🍳 食谱🤝 集成💜 Discord🎨 Studio
文档

Tool

Tool 是一个数据类,表示语言模型可以为其准备调用的函数。

越来越多的语言模型现在支持在提示词中同时传递工具定义。

工具调用是指语言模型在响应用户查询时生成对工具(无论是函数还是 API)的调用的能力。模型准备工具调用,但不执行它。

如果您正在寻找这个数据类的详细方法和参数,请访问我们的 API 文档

工具类

Tool 是一个简单统一的抽象,用于表示 Haystack 框架中的工具。

工具是语言模型可以为其准备调用的函数。

Tool 类用于聊天生成器,并为不同模型提供一致的体验。Tool 也用于 ToolInvoker 组件,该组件执行语言模型准备的调用。

@dataclass
class Tool:
    name: str
    description: str
    parameters: Dict[str, Any]
    function: Callable
  • name 是工具的名称。
  • description 是一个描述工具作用的字符串。
  • parameters 是一个描述预期参数的 JSON schema。
  • function 是在调用工具时被调用的。

请记住,准确定义namedescription 对于语言模型正确准备调用非常重要。

Tool 公开了一个 tool_spec 属性,返回语言模型使用的工具规范。

它还有一个 invoke 方法,该方法使用提供的参数执行底层函数。

工具初始化

以下是如何初始化一个工具以使用特定函数

from haystack.tools import Tool

def add(a: int, b: int) -> int:
    return a + b

parameters = {
    "type": "object",
    "properties": {
        "a": {"type": "integer"},
        "b": {"type": "integer"}
    },
    "required": ["a", "b"]
}

add_tool = Tool(name="addition_tool",
            description="This tool adds two numbers",
            parameters=parameters,
            function=add)

print(add_tool.tool_spec)

print(add_tool.invoke(a=15, b=10))
{'name': 'addition_tool',
    'description': 'This tool adds two numbers',
    'parameters':{'type': 'object',
        'properties':{'a':{'type': 'integer'}, 'b':{'type': 'integer'}},
        'required':['a', 'b']}}
        
25        

@tool 装饰器

@tool 装饰器简化了将函数转换为工具的过程。它从函数中推断工具名称、描述和参数,并自动生成 JSON schema。它使用 Python 的typing.Annotated 来描述参数。如果您需要自定义工具名称和描述,请改用create_tool_from_function

from typing import Annotated, Literal
from haystack.tools import tool

@tool
def get_weather(
  city: Annotated[str, "the city for which to get the weather"] = "Munich",
  unit: Annotated[Literal["Celsius", "Fahrenheit"], "the unit for the temperature"] = "Celsius"):
  '''A simple function to get the current weather for a location.'''
  return f"Weather report for {city}: 20 {unit}, sunny"

print(get_weather)
Tool(name='get_weather', description='A simple function to get the current weather for a location.',
parameters={
'type': 'object',
'properties': {
    'city': {'type': 'string', 'description': 'the city for which to get the weather', 'default': 'Munich'},
    'unit': {
        'type': 'string',
        'enum': ['Celsius', 'Fahrenheit'],
        'description': 'the unit for the temperature',
        'default': 'Celsius',
    },
    }
},
function=<function get_weather at 0x7f7b3a8a9b80>)  

create_tool_from_function

create_tool_from_function 方法比@tool 装饰器提供了更大的灵活性,并允许设置工具名称和描述。它以与@tool 装饰器相同的方式自动推断工具参数并生成 JSON schema。

from typing import Annotated, Literal
from haystack.tools import create_tool_from_function

def get_weather(
  city: Annotated[str, "the city for which to get the weather"] = "Munich",
  unit: Annotated[Literal["Celsius", "Fahrenheit"], "the unit for the temperature"] = "Celsius"):
  '''A simple function to get the current weather for a location.'''
  return f"Weather report for {city}: 20 {unit}, sunny"

tool = create_tool_from_function(get_weather)

print(tool)
Tool(name='get_weather', description='A simple function to get the current weather for a location.',
parameters={
'type': 'object',
'properties': {
    'city': {'type': 'string', 'description': 'the city for which to get the weather', 'default': 'Munich'},
    'unit': {
        'type': 'string',
        'enum': ['Celsius', 'Fahrenheit'],
        'description': 'the unit for the temperature',
        'default': 'Celsius',
    },
    }
},
function=<function get_weather at 0x7f7b3a8a9b80>)  

Toolkits (工具集)

工具集 (Toolset) 将多个工具实例分组到一个可管理单元中。它简化了将工具传递给 Chat Generators 或ToolInvoker 等组件的过程,并支持过滤、序列化和重用。

from haystack.tools import Toolset

math_toolset = Toolset([add_tool, subtract_tool])

有关更多详细信息和示例,请参阅 工具集文档页面

用法

为了更好地理解本节内容,请确保您也熟悉 Haystack 的 ChatMessage 数据类。

将工具传递给聊天生成器

使用tools 参数,您可以在初始化时或在run 方法中,将工具作为工具实例列表或单个工具集传递。在运行时传递的工具将覆盖在初始化时设置的工具。

📘

聊天生成器支持

并非所有聊天生成器目前都支持工具,但我们正在积极扩展对更多模型的工具支持。

请留意特定聊天生成器的__init__run 方法中的tools 参数。

from haystack.dataclasses import ChatMessage
from haystack.components.generators.chat import OpenAIChatGenerator

# Initialize the Chat Generator with the addition tool
chat_generator = OpenAIChatGenerator(model="gpt-4o-mini", tools=[add_tool])

# here we expect the Tool to be invoked
res=chat_generator.run([ChatMessage.from_user("10 + 238")])
print(res)

# here the model can respond without using the Tool
res=chat_generator.run([ChatMessage.from_user("What is the habitat of a lion?")])
print(res)
{'replies':[ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>,
            _content=[ToolCall(tool_name='addition_tool',
                    arguments={'a':10, 'b':238},
                    id='call_rbYtbCdW0UbWMfy2x0sgF1Ap'
)],
            _meta={...})]}

            
{'replies':[ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>,
            _content=[TextContent(text='Lions primarily inhabit grasslands, savannas, and open woodlands. ...'
)],
            _meta={...})]}            

通过在运行时传递工具,可以实现与上一次运行相同的結果

# Initialize the Chat Generator without tools
chat_generator = OpenAIChatGenerator(model="gpt-4o-mini")

# pass tools in the run method
res_w_tool_call=chat_generator.run([ChatMessage.from_user("10 + 238")], tools=math_toolset)
print(res_w_tool_call)

执行工具调用

要执行准备好的工具调用,您可以使用 ToolInvoker 组件。该组件充当工具的执行引擎,处理由语言模型准备的调用。

这是一个示例

import random
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.tools import ToolInvoker
from haystack.tools import Tool

# Define a dummy weather toolimport random

def dummy_weather(location: str):
    return {"temp": f"{random.randint(-10,40)} °C",
            "humidity": f"{random.randint(0,100)}%"}

weather_tool = Tool(
    name="weather",
    description="A tool to get the weather",
    function=dummy_weather,
    parameters={
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"],
    },
)

# Initialize the Chat Generator with the weather tool
chat_generator = OpenAIChatGenerator(model="gpt-4o-mini", tools=[weather_tool])

# Initialize the Tool Invoker with the weather tool
tool_invoker = ToolInvoker(tools=[weather_tool])

user_message = ChatMessage.from_user("What is the weather in Berlin?")

replies = chat_generator.run(messages=[user_message])["replies"]
print(f"assistant messages: {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 messages: {tool_messages}")
assistant messages:[ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[ToolCall(tool_name='weather',
arguments={'location': 'Berlin'}, id='call_YEvCEAmlvc42JGXV84NU8wtV')], _meta={'model': 'gpt-4o-mini-2024-07-18',
'index':0, 'finish_reason': 'tool_calls', 'usage':{'completion_tokens':13, 'prompt_tokens':50, 'total_tokens':
63}})]

tool messages: [ChatMessage(_role=<ChatRole.TOOL: 'tool'>, _content=[ToolCallResult(result="{'temp': '22 °C', 
'humidity': '35%'}", origin=ToolCall(tool_name='weather', arguments={'location': 'Berlin'}, 
id='call_YEvCEAmlvc42JGXV84NU8wtV'), error=False)], _meta={})]

使用聊天生成器处理工具结果

在某些情况下,来自工具的原始输出可能不直接适用于最终用户。

您可以将工具的响应传回聊天生成器来优化其输出。这将生成一个用户友好且具有对话风格的消息。

在此示例中,我们将工具的响应传回聊天生成器以进行最终处理

from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.tools import ToolInvoker
from haystack.tools import Tool

# Define a dummy weather toolimport random

def dummy_weather(location: str):
    return {"temp": f"{random.randint(-10,40)} °C",
            "humidity": f"{random.randint(0,100)}%"}

weather_tool = Tool(
    name="weather",
    description="A tool to get the weather",
    function=dummy_weather,
    parameters={
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"],
    },
)

chat_generator = OpenAIChatGenerator(model="gpt-4o-mini", tools=[weather_tool])
tool_invoker = ToolInvoker(tools=[weather_tool])

user_message = ChatMessage.from_user("What is the weather in Berlin?")

replies = chat_generator.run(messages=[user_message])["replies"]
print(f"assistant messages: {replies}")

if replies[0].tool_calls:
    tool_messages = tool_invoker.run(messages=replies)["tool_messages"]
    print(f"tool messages: {tool_messages}")
    # we pass all the messages to the Chat Generator
    messages = [user_message] + replies + tool_messages
    final_replies = chat_generator.run(messages=messages)["replies"]
    print(f"final assistant messages: {final_replies}")
assistant messages:[ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[ToolCall(tool_name='weather',
arguments={'location': 'Berlin'}, id='call_jHX0RCDHRKX7h8V9RrNs6apy')], _meta={'model': 'gpt-4o-mini-2024-07-18',
'index':0, 'finish_reason': 'tool_calls', 'usage':{'completion_tokens':13, 'prompt_tokens':50, 'total_tokens':
63}})]

tool messages: [ChatMessage(_role=<ChatRole.TOOL: 'tool'>, _content=[ToolCallResult(result="{'temp': '2 °C', 
'humidity': '15%'}", origin=ToolCall(tool_name='weather', arguments={'location': 'Berlin'}, 
id='call_jHX0RCDHRKX7h8V9RrNs6apy'), error=False)], _meta={})]

final assistant messages: [ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[TextContent(text='The 
current weather in Berlin is 2 °C with a humidity level of 15%.')], _meta={'model': 'gpt-4o-mini-2024-07-18', 
'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 19, 'prompt_tokens': 85, 'total_tokens': 
104}})]

将工具传递给 Agent

您也可以使用ToolAgent 组件一起使用。在内部,Agent 组件包含一个ToolInvoker 和您选择的 ChatGenerator 来执行工具调用并处理工具结果。

from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack.tools.tool import Tool
from haystack.components.agents import Agent
from typing import List

# Tool Function
def calculate(expression: str) -> dict:
    try:
        result = eval(expression, {"__builtins__": {}})
        return {"result": result}
    except Exception as e:
        return {"error": str(e)}

# Tool Definition
calculator_tool = Tool(
    name="calculator",
    description="Evaluate basic math expressions.",
    parameters={
        "type": "object",
        "properties": {
            "expression": {"type": "string", "description": "Math expression to evaluate"}
        },
        "required": ["expression"]
    },
    function=calculate,
    outputs_to_state={"calc_result": {"source": "result"}}
)

# Agent Setup
agent = Agent(
    chat_generator=OpenAIChatGenerator(),
    tools=[calculator_tool],
    exit_conditions=["calculator"],
    state_schema={
        "calc_result": {"type": int},
    }
)

# Run the Agent
agent.warm_up()
response = agent.run(messages=[ChatMessage.from_user("What is 7 * (4 + 2)?")])

# Output
print(response["messages"])
print("Calc Result:", response.get("calc_result"))

其他参考资料

🧑‍🍳食谱