连续工具调用¶
在实际的 AI Agent 开发中,LLM 连续使用多个工具来完成任务是很常见的场景。本示例演示了如何处理这种情况。
我们让 LLM 查询某个地点的最新天气(模拟 API 调用),天气信息通常以摄氏度返回,然后让它将温度转换为华氏度。
OpenAI 客户端实现¶
本示例演示了与 OpenAI API 的集成。如前文所述,我们需要手动处理连续的工具调用。
import os
from dotenv import load_dotenv
from openai import OpenAI
# Load environment variables from .env file
load_dotenv()
from toolregistry import ToolRegistry
# Initialize ToolRegistry
tool_registry = ToolRegistry()
# Register tools using decorator
@tool_registry.register
def get_weather(location: str):
"""Get the weather for a specific location"""
return f"Weather in {location}: Sunny, 25°C"
@tool_registry.register
def c_to_f(celsius: float) -> float:
"""Convert Celsius to Fahrenheit"""
fahrenheit = (celsius * 1.8) + 32
return f"{celsius} celsius degree == {fahrenheit} fahrenheit degree"
# Set up OpenAI client
client = OpenAI(
api_key=os.getenv("API_KEY", "your-api-key"),
base_url=os.getenv("BASE_URL", "https://api.deepseek.com/"),
)
messages = [
{
"role": "user",
"content": "What's the temperature of Shanghai, reply using Fahrenheit?",
}
]
# Make the chat completion request
response = client.chat.completions.create(
model="deepseek-v3",
messages=messages,
tools=tool_registry.get_schemas(),
tool_choice="auto",
)
def handle_tool_calls(response, messages):
"""Handle tool calls in a loop until no more tool calls are needed"""
while response.choices[0].message.tool_calls:
tool_calls = response.choices[0].message.tool_calls
print("Tool calls:", tool_calls)
# Execute tool calls
tool_responses = tool_registry.execute_tool_calls(tool_calls)
# Construct assistant messages with results
assistant_tool_messages = tool_registry.build_tool_call_messages(
tool_calls, tool_responses
)
messages.extend(assistant_tool_messages)
# Send the results back to the model
response = client.chat.completions.create(
model="deepseek-v3",
messages=messages,
tools=tool_registry.get_schemas(),
tool_choice="auto",
)
return response
# Handle tool calls using the new function (without iteration limit)
response = handle_tool_calls(response, messages)
# Print final response
if response.choices[0].message.content:
print(response.choices[0].message.content)
响应输出如下:
Tool calls: [ChatCompletionMessageToolCall(id='call_qcb10odnylzts5qhae9jvt7v', function=Function(arguments='{"location":"Shanghai"}', name='get_weather'), type='function', index=0)]
location='Shanghai'
Tool calls: [ChatCompletionMessageToolCall(id='call_ew7cm09z893u57102aeny2zp', function=Function(arguments='{"celsius":25}', name='c_to_f'), type='function', index=0)]
celsius=25.0
The temperature in Shanghai is 77°F.
Cicada MultiModalModel 实现¶
本示例展示了如何将 ToolRegistry 与 Cicada 的 MultiModalModel 配合使用。
它的一个优点是可以自动处理连续的工具调用。
import os
from cicada.core.model import MultiModalModel
from cicada.core.utils import cprint
from toolregistry import ToolRegistry
# Initialize Cicada model
model_name = os.getenv("MODEL", "deepseek-v3")
stream = os.getenv("STREAM", "True").lower() == "true"
llm = MultiModalModel(
api_key="your-api-key",
api_base_url="https://api.deepseek.com/",
model_name=model_name,
stream=stream,
)
# Initialize ToolRegistry
tool_registry = ToolRegistry()
# Register tools
@tool_registry.register
def get_weather(location: str):
return f"Weather in {location}: Sunny, 25°C"
@tool_registry.register
def c_to_f(celsius: float) -> float:
fahrenheit = (celsius * 1.8) + 32
return f"{celsius} celsius degree == {fahrenheit} fahrenheit degree"
# Query the model with tools
response = llm.query(
"What's the temperature of Shanghai, reply using Fahrenheit?",
tools=tool_registry,
stream=llm.stream,
)
print(response["content"])
cprint(json.dumps(response,indent=2))
响应输出如下:
{
"content": "The current temperature in Shanghai is 77\u00b0F.",
"formatted_response": "[Response]: The current temperature in Shanghai is 77\u00b0F.",
"tool_chain": [
{
"content": "",
"tool_responses": {
"call_mOnZUGqQhhmvj0lIKEUcncAn": "Weather in Shanghai: Sunny, 25\u00b0C"
}
},
{
"content": "",
"tool_responses": {
"call_lDQ0Nq0HRXHnmhoX6PJzmBHo": "25.0 celsius degree == 77.0 fahrenheit degree"
}
}
]
}