提供工具给大模型,大模型会在适当的时候,自主决定是否要使用工具,让大模型自主决定的流程,是一种agentic workflows或者reasoning-heavy workflows.
LLM能够解析自然语言并按正确顺序使用合适的工具,以完成各种不同的任务
LLM说: 给我Tools我来安排工作流(Agentic workflow)
🎉注意
选择合适的模型很重要:对于简单任务,较小的模型更快、更便宜;而对于推理密集型工作流reasoning-heavy workflows,更强的模型则表现更佳。
大模型使用工具
这里大模型不知道当前系统的时间,我们提供一个工具(这里是一个函数)给大模型。
让大模型自主决定是否使用工具中的任何一个
- 当大模型需要使用工具的时候,它会告诉我们去调用工具,这里要知道时间,它需要让我们去执行
get_current_time,执行之后,我们再把结果给LLM - 当大模型不需要使用工具,它就没有使用工具,尽管我们给他了时间的工具,说明它能够自主判断是否需要使用工具
Agentic应用开发
所以作为一个开发者,在开发一个Agentic App智能体应用时,应该考虑要实现哪些功能?然后创建相应的函数(工具),为大模型实现并开放不同的工具,大模型会自己决定是否要使用工具。
比如要创建一个日历智能体助手。给模型提供一系列操作日历的工具,比如:检查日历,预约事项,删除预约等。大模型会在可用的工具列表中判断。
大模型进行决定最先要用的可能是checkCalendar,于是调用check_calendar,将执行结果反馈给大模型,接下来它决定选择一个时间段,比如下午三点,然后调用make_appointment创建预约,同样将操作的结果反馈给大模型。
🔔需要注意的时候,整个任务的拆分和调用工具的流程完全由LLM自主决定,也许他可能跳过check_calendar直接执行make_appointment也说不定。这不是一个工业级别严格执行的workflow,而是一个agentic workflow。
🎉LLM使用工具的原理
- 大模型LLM只是被训练用来输出文本(输出token)的。它本身并不会执行工具。
- 工具(Tools): LLM能够请求要执行的代码。
LLM并不会直接调用函数,而是以特定格式输出内容:
- 在提示词中告诉LLM有哪些工具,并且告诉他如果决定要使用工具时,要输出的格式(要调用的函数名称,甚至函数的参数信息)。
- 接着我们的代码进行拦截处理,判断LLM请求要执行工具,我们就调用函数执行代码
- 将执行结果再反馈给LLM
来自我另一篇文章【 Agent的ReAct(推理+行动)模式】 这里拦截LLM的输出,然后进行反射调用方法。
代码角度理解工具执行的原理
get_current_time会将自己的注释提供给LLM,告诉LLM这个工具是干什么用的,让LLM自主决定什么时候使用
from datetime import datetime
def get_current_time():
"""
Returns the current time as a string.
"""
return datetime.now().strftime("%H:%M:%S")
aisuite这个框架封装了提示词,并且
tools=[get_current_time]将工具列表解析出来:工具名称以及描述(这里是注释)
此时框架的作用就体现出来了: 🎉Turning function into an LLM tool🎉,在抽象层面将函数转化成LLM可执行的工具。
尽管我们知道底层是通过提示词引导,输出结果拦截解析,然后执行具体的函数。AISuite 处理了所有复杂流程:提取包含工具调用的消息、在本地执行该调用。
但是在上层,这已经可以理解为给LLM赋能,提供脚和手的工具,增强了LLM对这个世界的认知。
import aisuite as ai
# Create an instance of the AISuite client
client = ai.Client()
# Message structure
prompt = "What time is it?"
messages = [
{
"role": "user",
"content": prompt,
}
]
response = client.chat.completions.create(
model="openai:gpt-4o",
messages=messages, # 历史消息
tools=[get_current_time], # 🎉工具列表
max_turns=5 # ReAct限制大模型连续请求的次数
)
内部执行深入了解
函数成工具的处理
在aisuite这个包中,底层会生成一个详细描述函数(工具)的JSON结构,每个工具都带有其预期的固定模式(schema)
tools = [{
"type": "function",
"function": {
"name": "get_current_time", # <--- Your functions name
"description": "Returns the current time as a string.", # <--- a description for the LLM
"parameters": {}
}
}]
如果是带有参数,JSON的Schema长这样。
模型返回需要调用工具
这里只让Agent与LLM循环一次,方便查看LLM的输出结果
import json
# Message structure
prompt = "What time is it?"
messages = [
{
"role": "user",
"content": prompt,
}
]
response = client.chat.completions.create(
model="openai:gpt-4o",
messages=messages,
tools=tools, # <-- Your list of tools with get_current_time
# max_turns=5 # <-- When defining tools manually, you must handle calls yourself and cannot use max_turns
)
print(json.dumps(response.model_dump(), indent=2, default=str))
注意,在响应中,你可以在 message 下看到 tool_calls。LLM 的此响应表示它现在想要调用一个工具,具体来说是 get_current_time。你可以添加一些逻辑来处理这种情况,然后将结果传回模型,并获取最终响应。
{
"id": "chatcmpl-DUbu4GSDZ3XPDdOP1ei6ufJj7X6Nu",
"choices": [
{
"finish_reason": "tool_calls",
"index": 0,
"logprobs": null,
"message": {
"content": null,
"refusal": null,
"role": "assistant",
"annotations": [],
"audio": null,
"function_call": null,
"tool_calls": [
{
"id": "call_hEZFo8JLKq1p9bcoVJykkhWu",
"function": {
"arguments": "{}",
"name": "get_current_time"
},
"type": "function"
}
]
}
}
],
"created": 1776187912,
"model": "gpt-4o-2024-08-06",
"object": "chat.completion",
"service_tier": "default",
"system_fingerprint": "fp_071222c984",
"usage": {
"completion_tokens": 11,
"prompt_tokens": 45,
"total_tokens": 56,
"completion_tokens_details": {
"accepted_prediction_tokens": 0,
"audio_tokens": 0,
"reasoning_tokens": 0,
"rejected_prediction_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0
}
}
}
手动处理函数执行
现在手动执行函数,然后将执行结果添加到messages中,再反馈给LLM
response2 = None
# Create a condition in case tool_calls is in response object
if response.choices[0].message.tool_calls:
# Pull out the specific tool metadata from the response
tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
# Run the tool locally
tool_result = get_current_time()
# Append the result to the messages list
messages.append(response.choices[0].message)
messages.append({
"role": "tool", "tool_call_id": tool_call.id, "content": str(tool_result)
})
# Send the list of messages with the newly appended results back to the LLM
response2 = client.chat.completions.create(
model="openai:gpt-4o",
messages=messages,
tools=tools,
)
print(response2.choices[0].message.content) # The current time is 06:20:57.
查看完整的messages流程
[
{
"role": "user",
"content": "What time is it?"
},
"ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_hEZFo8JLKq1p9bcoVJykkhWu', function=Function(arguments='{}', name='get_current_time'), type='function')])",
{
"role": "tool",
"tool_call_id": "call_hEZFo8JLKq1p9bcoVJykkhWu",
"content": "06:33:02"
}
]
有意思的是我将此时的messages粘贴给deepseek,它真的能够根据上下文,推断出来的了上下文的时间,尽管当时我执行的时间是北京14:25
小结
整个过程的消息角色:"user", "assistant", "system",还有一个"tool"
LLM自主决策选择工具
定义工具
提供了三个工具给LLM
| 工具名 | 参数 | 描述 |
|---|---|---|
get_weather_from_ip | 无(自动检测IP) | 检测用户IP地址,通过外部API调用获取当前位置的当前温度、最高温和最低温。 |
write_txt_file | file_path(文件路径), content(内容) | 在本地环境中创建指定内容的文本文件。 |
generate_qr_code | data(数据), filename(文件名), img_path(图片路径,可选) | 根据数据生成二维码图像,并可选择嵌入图片。 |
import requests
import qrcode
from qrcode.image.styledpil import StyledPilImage
def get_weather_from_ip():
"""
Gets the current, high, and low temperature in Fahrenheit for the user's
location and returns it to the user.
"""
# Get location coordinates from the IP address
lat, lon = requests.get('https://ipinfo.io/json').json()['loc'].split(',')
# Set parameters for the weather API call
params = {
"latitude": lat,
"longitude": lon,
"current": "temperature_2m",
"daily": "temperature_2m_max,temperature_2m_min",
"temperature_unit": "fahrenheit",
"timezone": "auto"
}
# Get weather data
weather_data = requests.get("https://api.open-meteo.com/v1/forecast", params=params).json()
# Format and return the simplified string
return (
f"Current: {weather_data['current']['temperature_2m']}°F, "
f"High: {weather_data['daily']['temperature_2m_max'][0]}°F, "
f"Low: {weather_data['daily']['temperature_2m_min'][0]}°F"
)
# Write a text file
def write_txt_file(file_path: str, content: str):
"""
Write a string into a .txt file (overwrites if exists).
Args:
file_path (str): Destination path.
content (str): Text to write.
Returns:
str: Path to the written file.
"""
with open(file_path, "w", encoding="utf-8") as f:
f.write(content)
return file_path
# Create a QR code
def generate_qr_code(data: str, filename: str, image_path: str):
"""Generate a QR code image given data and an image path.
Args:
data: Text or URL to encode
filename: Name for the output PNG file (without extension)
image_path: Path to the image to be used in the QR code
"""
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H)
qr.add_data(data)
img = qr.make_image(image_factory=StyledPilImage, embedded_image_path=image_path)
output_file = f"{filename}.png"
img.save(output_file)
return f"QR code saved as {output_file} containing: {data[:50]}..."
执行任务
给提示词Can you get the weather for my location?
prompt = "Can you get the weather for my location?"
response = client.chat.completions.create(
model="openai:o4-mini",
messages=[{"role": "user", "content": (
prompt
)}],
tools=[
get_current_time,
get_weather_from_ip,
write_txt_file,
generate_qr_code
],
max_turns=5
)
display_functions.pretty_print_chat_completion(response)
可以看到LLM能够在众多的工具集中能够选择,正确的工具进行执行。
🎉Agentic Workflow的体现
将LLM的推理能力与外部工具相结合,以完成更复杂的任务,不仅能自主安排了流程,而且自己选择了相应的工具。
提示词
Can you help me create a qr code that goes to www.deeplearning.com from the image dl_logo.jpg? Also write me a txt note with the current weather please.
这个提示需要相当多的逻辑才能理解何时调用哪个工具。例如,虽然你要求它先写文本笔记再描述内容,但LLM需要先获取信息才能传给文本笔记。如果LLM先调用文件写入工具,它就会缺少从天气工具获取的信息。但是LLM能够自己拆分任务顺序,它知道先查询天气,然后再写入文本。这很好地体现了LLM的能力:解析自然语言并按正确顺序使用合适的工具,以完成各种不同的任务。
LLM说: 给我Tools我来安排工作流(Agentic workflow)
import display_functions
prompt = "Can you help me create a qr code that goes to www.deeplearning.com from the image dl_logo.jpg? Also write me a txt note with the current weather please."
response = client.chat.completions.create(
model="openai:o4-mini",
messages=[{"role": "user", "content": (
prompt
)}],
tools=[ # 🎉给你工具,让LLM你自己捣鼓去吧
get_weather_from_ip,
get_current_time,
write_txt_file,
generate_qr_code
],
max_turns=10
)
display_functions.pretty_print_chat_completion(response)
执行结果:
get_weather_from_ip → generate_qr_code → write_txt_file
LLM自己安排顺序,选择相应的执行工具。(我们知道get_weather_from_ip → write_txt_file是有严格先后顺序的,generate_qr_code则是一个独立的步骤)。