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是在调用工具时被调用的。
请记住,准确定义name 和description 对于语言模型正确准备调用非常重要。
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
您也可以使用Tool 与 Agent 组件一起使用。在内部,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"))
其他参考资料
🧑🍳食谱
更新于 6 个月前
