工具之所以引人入胜,是因为它们使 AI 智能体(Agent)拥有了更广泛的能力范围。与其让智能体只能执行一组有限的动作,不如通过添加工具,使智能体现在能够执行各种各样的动作。在本章中,我们将研究“工具使用设计模式”,该模式描述了 AI 智能体如何使用特定的工具来实现其目标。
简介
在本课中,我们希望回答以下问题:
- 什么是工具使用设计模式?
- 它可以应用于哪些用例?
- 实现该设计模式需要哪些元素/构建模块?
- 使用工具使用设计模式构建可信 AI 智能体时,有哪些特殊的注意事项?
学习目标
完成本课后,您将能够:
- 定义工具使用设计模式及其目的。
- 识别适用工具使用设计模式的用例。
- 了解实现该设计模式所需的关键元素。
- 认识在使用此设计模式时,确保 AI 智能体具备可信性的相关注意事项。
什么是工具使用设计模式?
工具使用设计模式侧重于赋予大语言模型(LLM)与外部工具交互的能力,以实现特定的目标。工具是可以由智能体执行以完成某些操作的代码。工具可以是一个简单的函数(例如计算器),也可以是向第三方服务发起的 API 调用(例如股票价格查询或天气预报)。在 AI 智能体的语境下,工具被设计为由智能体响应**模型生成的函数调用(function calls)**来执行。
它可以应用于哪些用例?
AI 智能体可以利用工具来完成复杂的任务、检索信息或做出决策。工具使用设计模式通常用于需要与外部系统(例如数据库、Web 服务或代码解释器)进行动态交互的场景。这种能力对于许多不同的用例都非常有用,包括:
- 动态信息检索: 智能体可以查询外部 API 或数据库以获取最新数据(例如,查询 SQLite 数据库进行数据分析,获取股票价格或天气信息)。
- 代码执行和解释: 智能体可以执行代码或脚本来解决数学问题、生成报告或执行模拟。
- 工作流自动化: 通过集成任务调度程序、电子邮件服务或数据管道等工具,实现重复性或多步骤工作流的自动化。
客户支持: 智能体可以与 CRM 系统、工单平台或知识库交互,以解决用户查询。 - 内容生成与编辑: 智能体可以利用语法检查器、文本摘要器或内容安全评估器等工具来协助完成内容创建任务。
实现工具使用设计模式需要哪些元素/构建模块?
这些构建模块使得 AI 智能体能够执行广泛的任务。让我们看看实现工具使用设计模式所需的关键元素:
- 函数/工具模式 (Function/Tool Schemas): 可用工具的详细定义,包括函数名称、目的、所需参数和预期输出。这些模式 (Schemas) 使 LLM 能够理解有哪些可用工具以及如何构建有效的请求。
- 函数执行逻辑 (Function Execution Logic): 管理如何以及何时根据用户的意图和对话上下文调用工具。这可能包括规划器模块、路由机制或动态决定工具使用情况的条件工作流。
- 消息处理系统 (Message Handling System): 管理用户输入、LLM 响应、工具调用和工具输出之间对话流的组件。
工具集成框架 (Tool Integration Framework): 将智能体连接到各种工具(无论是简单的函数还是复杂的外部服务)的基础设施。 - 错误处理与验证 (Error Handling & Validation): 处理工具执行失败、验证参数以及管理意外响应的机制。
- 状态管理 (State Management): 跟踪对话上下文、之前的工具交互以及持久性数据,以确保在多轮交互中保持一致性。
接下来,让我们更详细地了解“函数/工具调用”。
函数/工具调用 (Function/Tool Calling)
函数调用是我们使大语言模型 (LLM) 能够与工具交互的主要方式。您经常会看到“函数 (Function)”和“工具 (Tool)”这两个词被交替使用,因为“函数”(可重用的代码块)正是智能体用来执行任务的“工具”。为了让一段函数的代码被调用,LLM 必须将用户的请求与函数的描述进行比对。为此,需要将包含所有可用函数描述的模式 (Schema) 发送给 LLM。随后,LLM 会为该任务选择最合适的函数,并返回该函数的名称和参数。选定的函数被调用后,其响应会被发回给 LLM,LLM 进而利用这些信息来回答用户的请求。
对于开发人员来说,要为智能体实现函数调用,您需要:
- 一个支持函数调用的 LLM 模型。
- 一个包含函数描述的模式 (Schema)。
- 所描述每个函数的具体代码。
让我们以获取某个城市的当前时间为例进行说明:
1. 初始化一个支持函数调用的 LLM:
并非所有模型都支持函数调用,因此检查您正在使用的 LLM 是否支持这一点很重要。Azure OpenAI 支持函数调用。我们可以首先初始化 Azure OpenAI 客户端。
Python
# 初始化 Azure OpenAI 客户端
client = AzureOpenAI(
azure_endpoint = os.getenv("AZURE_AI_PROJECT_ENDPOINT"),
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
api_version="2024-05-01-preview"
)
2. 创建一个函数模式 (Function Schema):
接下来,我们将定义一个 JSON 模式,其中包含函数名称、函数作用的描述,以及函数参数的名称和描述。然后,我们将把这个模式连同用户想要查询旧金山时间的请求一起,传递给之前创建的客户端。需要重点注意的是,返回的内容是一个工具调用 (tool call),而不是问题的最终答案。如前所述,LLM 返回的是它为任务选择的函数名称以及将传递给该函数的参数。
Python
# 供模型读取的函数描述
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "获取给定位置的当前时间",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,例如 San Francisco",
},
},
"required": ["location"],
},
}
}
]
# 初始用户消息
messages = [{"role": "user", "content": "What's the current time in San Francisco"}]
# 第一次 API 调用:要求模型使用函数
response = client.chat.completions.create(
model=deployment_name,
messages=messages,
tools=tools,
tool_choice="auto",
)
# 处理模型的响应
response_message = response.choices[0].message
messages.append(response_message)
print("模型的响应:")
print(response_message)
Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_pOsKdUlqvdyttYB67MOj434b', function=Function(arguments='{"location":"San Francisco"}', name='get_current_time'), type='function')])
3. 执行任务所需的函数代码:
现在 LLM 已经选择了需要运行的函数,接下来需要实现并执行完成该任务的代码。我们可以用 Python 实现获取当前时间的代码。我们还需要编写代码,从 response_message 中提取名称和参数,以获得最终结果。
Python
def get_current_time(location):
"""获取给定位置的当前时间"""
print(f"get_current_time 收到 location: {location} 的调用")
location_lower = location.lower()
for key, timezone in TIMEZONE_DATA.items():
if key in location_lower:
print(f"找到 {key} 的时区")
current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
return json.dumps({
"location": location,
"current_time": current_time
})
print(f"未找到 {location_lower} 的时区数据")
return json.dumps({"location": location, "current_time": "unknown"})
# 处理函数调用
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
if tool_call.function.name == "get_current_time":
function_args = json.loads(tool_call.function.arguments)
time_response = get_current_time(
location=function_args.get("location")
)
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": "get_current_time",
"content": time_response,
})
else:
print("模型没有进行任何工具调用。")
# 第二次 API 调用:获取模型的最终响应
final_response = client.chat.completions.create(
model=deployment_name,
messages=messages,
)
return final_response.choices[0].message.content
Plaintext
get_current_time 收到 location: San Francisco 的调用
找到 san francisco 的时区
旧金山的当前时间是 09:24 AM。
函数调用是大多数(如果不是全部的话)智能体工具使用设计的核心,然而从头开始实现它有时会具有挑战性。正如我们在第 2 课中所学的,智能体框架为我们提供了预置的构建模块来实现工具的使用。
智能体框架下的工具使用示例 (Tool Use Examples with Agentic Frameworks)
以下是一些关于如何使用不同智能体框架实现工具使用设计模式的示例:
Microsoft 智能体框架 (Microsoft Agent Framework)
Microsoft 智能体框架是一个用于构建 AI 智能体的开源 AI 框架。它通过允许您使用 @tool 装饰器将工具定义为 Python 函数,从而简化了使用函数调用的过程。该框架处理模型与您的代码之间来回的通信。它还允许通过 AzureAIProjectAgentProvider 访问文件搜索和代码解释器等预置工具。
下图说明了 Microsoft 智能体框架中函数调用的过程:

在 Microsoft 智能体框架中,工具被定义为带有装饰器的函数。我们可以通过使用 @tool 装饰器,将我们之前看到的 get_current_time 函数转换为一个工具。该框架将自动序列化函数及其参数,创建模式 (schema) 并发送给 LLM。
Python
from agent_framework import tool
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity import AzureCliCredential
@tool
def get_current_time(location: str) -> str:
"""获取给定位置的当前时间"""
...
# 创建客户端
provider = AzureAIProjectAgentProvider(credential=AzureCliCredential())
# 创建并运行带有该工具的智能体
agent = await provider.create_agent(name="TimeAgent", instructions="使用可用工具回答问题。", tools=get_current_time)
response = await agent.run("What time is it?")
Azure AI 智能体服务 (Azure AI Agent Service)
Azure AI 智能体服务是一个较新的智能体框架,旨在帮助开发人员安全地构建、部署和扩展高质量且可扩展的 AI 智能体,而无需管理底层计算和存储资源。它非常适合企业应用程序,因为它是一个具备企业级安全性的全托管服务。
与直接使用 LLM API 进行开发相比,Azure AI 智能体服务提供了一些优势,包括:
- 自动工具调用 – 无需手动解析工具调用、调用工具并处理响应;所有这些现在都在服务器端完成。
- 安全的数据管理 – 无需管理您自己的对话状态,您可以依靠线程 (threads) 来存储所需的所有信息。
- 开箱即用的工具 – 可用于与您的数据源交互的工具,例如 Bing(必应)、Azure AI Search 和 Azure Functions。
Azure AI 智能体服务中可用的工具可分为两类:
知识工具 (Knowledge Tools):
- 基于 Bing 搜索的数据基座 (Grounding with Bing Search)
- 文件搜索 (File Search)
- Azure AI 搜索 (Azure AI Search)
动作工具 (Action Tools):
- 函数调用 (Function Calling)
- 代码解释器 (Code Interpreter)
- OpenAPI 定义的工具
- Azure Functions
该智能体服务允许我们将这些工具作为一个工具集 (toolset) 组合使用。它还利用线程 (threads) 来记录特定对话中的历史消息。
想象一下您是一家名为 Contoso 公司的销售代理。您希望开发一个对话式智能体,用于回答有关您销售数据的问题。
以下图像说明了您如何使用 Azure AI 智能体服务来分析您的销售数据:

要使用该服务中的任何这些工具,我们可以创建一个客户端并定义一个工具或工具集。为了在实践中实现这一点,我们可以使用以下 Python 代码。LLM 将能够查看工具集,并根据用户的请求决定是使用用户创建的函数 fetch_sales_data_using_sqlite_query,还是使用预置的代码解释器。
Python
import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from fetch_sales_data_functions import fetch_sales_data_using_sqlite_query
# fetch_sales_data_using_sqlite_query 函数可以在 fetch_sales_data_functions.py 文件中找到。
from azure.ai.projects.models import ToolSet, FunctionTool, CodeInterpreterTool
project_client = AIProjectClient.from_connection_string(
credential=DefaultAzureCredential(),
conn_str=os.environ["PROJECT_CONNECTION_STRING"],
)
# 初始化工具集
toolset = ToolSet()
# 将 fetch_sales_data_using_sqlite_query 函数初始化为函数调用工具,并添加到工具集中
fetch_data_function = FunctionTool(fetch_sales_data_using_sqlite_query)
toolset.add(fetch_data_function)
# 初始化代码解释器工具并添加到工具集中
code_interpreter = CodeInterpreterTool()
toolset.add(code_interpreter)
agent = project_client.agents.create_agent(
model="gpt-4o-mini", name="my-agent", instructions="您是一个有用的智能体",
toolset=toolset
)
使用工具使用设计模式构建可信 AI 智能体时,有哪些特殊的注意事项?
对于由 LLM 动态生成的 SQL 语句,一个常见的担忧是安全性,尤其是 SQL 注入风险或恶意行为(例如删库或篡改数据库)。虽然这些担忧是合理的,但可以通过正确配置数据库访问权限来有效缓解。对于大多数数据库,这涉及将数据库配置为只读模式。对于 PostgreSQL 或 Azure SQL 等数据库服务,应为应用程序分配只读 (SELECT) 角色。
在安全环境中运行该应用程序可进一步增强保护。在企业场景中,数据通常从操作系统提取并转换到具有用户友好模式(Schema)的只读数据库或数据仓库中。这种方法可确保数据的安全,针对性能和可访问性进行优化,并保证应用程序仅具有受限的只读访问权限。
你可能也喜欢
- ♥ 探索微软智能代理框架12/26
- ♥ AI 智能体与智能体用例简介03/06
- ♥ AI 智能体协议:MCP, A2A 与 NLWeb09/18
- ♥ 探索 AI Agent(智能体)框架04/26
- ♥ 多智能体设计模式 (Multi-agent design patterns)04/28
- ♥ AI 智能体设计原则01/18

