工具之所以有趣,是因为它们允许 AI 智能体拥有更广泛的能力。通过添加工具,智能体不再局限于其可以执行的有限操作集合,而是可以执行各种各样的操作。在本章中,我们将探讨工具使用设计模式,该模式描述了 AI 智能体如何使用特定工具来实现其目标。
简介
在本课程中,我们希望回答以下问题:
- 什么是工具使用设计模式?
- 它可以应用于哪些用例?
- 实现该设计模式需要哪些元素/构建块?
- 使用工具使用设计模式构建可信赖的 AI 智能体有哪些特殊注意事项?
学习目标
完成本课程后,你将能够:
- 定义工具使用设计模式及其目的。
- 识别适用工具使用设计模式的用例。
- 了解实现该设计模式所需的关键元素。
- 认识到在使用此设计模式时确保 AI 智能体可信赖性的注意事项。
什么是工具使用设计模式?
工具使用设计模式 侧重于赋予大语言模型 (LLMs) 与外部工具交互以实现特定目标的能力。工具是智能体可以执行以执行操作的代码。工具可以是简单的函数 (例如计算器),也可以是第三方服务 (例如股票价格查询或天气预报) 的 API 调用。在 AI 智能体的上下文中,工具被设计为由智能体执行,以响应 模型生成的函数调用。
它可以应用于哪些用例?
AI 智能体可以利用工具来完成复杂的任务、检索信息或做出决策。工具使用设计模式通常用于需要与外部系统 (例如数据库、Web 服务或代码解释器) 进行动态交互的场景。此功能对于许多不同的用例都很有用,包括:
- 动态信息检索: 智能体可以查询外部 API 或数据库以获取最新数据 (例如,查询 SQLite 数据库进行数据分析,获取股票价格或天气信息)。
- 代码执行和解释: 智能体可以执行代码或脚本来解决数学问题、生成报告或执行模拟。
- 工作流自动化: 通过集成任务调度程序、电子邮件服务或数据管道等工具来自动化重复或多步骤工作流。
- 客户支持: 智能体可以与 CRM 系统、工单平台或知识库交互以解决用户查询。
- 内容生成和编辑: 智能体可以利用语法检查器、文本摘要器或内容安全评估器等工具来协助内容创建任务。
实现工具使用设计模式需要哪些元素/构建块?
这些构建块允许 AI 智能体执行各种各样的任务。让我们看看实现工具使用设计模式所需的关键元素:
- 函数/工具调用:这是使大语言模型 (LLMs) 能够与工具交互的主要方式。函数或工具是智能体用来执行任务的可重用代码块。这些函数可以是简单的函数 (如计算器),也可以是第三方服务 (如股票价格查询或天气预报 1) 的 API 调用。
- 动态信息检索:智能体可以查询外部 API 或数据库以获取最新数据。这对于数据分析、获取股票价格或天气信息 1 等任务非常有用。
- 代码执行和解释:智能体可以执行代码或脚本来解决数学问题、生成报告或执行模拟 1。
- 工作流自动化:这涉及通过集成任务调度程序、电子邮件服务或数据管道 1 等工具来自动化重复或多步骤工作流。
- 客户支持:智能体可以与 CRM 系统、工单平台或知识库交互以解决用户查询 1。
- 内容生成和编辑:智能体可以利用语法检查器、文本摘要器或内容安全评估器等工具来协助内容创建任务。
接下来,让我们更详细地了解函数/工具调用。
函数/工具调用
函数调用是我们使大语言模型 (LLMs) 能够与工具交互的主要方式。你经常会看到“函数”和“工具”互换使用,因为“函数”(可重用代码块) 是智能体用来执行任务的“工具”。为了调用函数的代码,大语言模型 (LLM) 必须将用户的请求与函数的描述进行比较。为此,包含所有可用函数描述的模式将发送到大语言模型 (LLM)。然后,大语言模型 (LLM) 选择最适合该任务的函数并返回其名称和参数。选定的函数被调用,其响应被发送回大语言模型 (LLM),大语言模型 (LLM) 使用该信息来响应用户的请求。
对于开发人员为智能体实现函数调用,你需要:
- 支持函数调用的大语言模型 (LLM) 模型
- 包含函数描述的模式
- 每个描述的函数的代码
让我们以获取城市当前时间的示例来说明:
- 初始化支持函数调用的大语言模型 (LLM):
并非所有模型都支持函数调用,因此检查你正在使用的大语言模型 (LLM) 是否支持非常重要。Azure OpenAI 支持函数调用。我们可以首先初始化 Azure OpenAI 客户端。# Initialize the Azure OpenAI client client = AzureOpenAI( azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"), api_key=os.getenv("AZURE_OPENAI_API_KEY"), api_version="2024-05-01-preview" )
- 创建函数模式:
接下来,我们将定义一个 JSON 模式,其中包含函数名称、函数功能的描述以及函数参数的名称和描述。然后,我们将采用此模式并将其与用户的请求一起传递给先前创建的客户端,以查找旧金山的时间。需要注意的是,返回的是 工具调用,而不是 问题的最终答案。如前所述,大语言模型 (LLM) 返回它为任务选择的函数的名称,以及将传递给它的参数。
# Function description for the model to read
tools = [
{
"type": "function",
"function": {
"name": "get_current_time",
"description": "Get the current time in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name, e.g. San Francisco",
},
},
"required": ["location"],
},
}
}
]
# Initial user message
messages = [{"role": "user", "content": "What's the current time in San Francisco"}]
# First API call: Ask the model to use the function
response = client.chat.completions.create(
model=deployment_name,
messages=messages,
tools=tools,
tool_choice="auto",
)
# Process the model's response
response_message = response.choices[0].message
messages.append(response_message)
print("Model's response:")
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')])
- 执行任务所需的函数代码:
现在大语言模型 (LLM) 已经选择了需要运行的函数,需要实现并执行执行任务的代码。我们可以实现代码以获取 Python 中的当前时间。我们还需要编写代码以从 response_message 中提取名称和参数以获取最终结果。def get_current_time(location): """Get the current time for a given location""" print(f"get_current_time called with location: {location}") location_lower = location.lower() for key, timezone in TIMEZONE_DATA.items(): if key in location_lower: print(f"Timezone found for {key}") current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p") return json.dumps({ "location": location, "current_time": current_time }) print(f"No timezone data found for {location_lower}") return json.dumps({"location": location, "current_time": "unknown"})
# Handle function calls 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("No tool calls were made by the model.") # Second API call: Get the final response from the model final_response = client.chat.completions.create( model=deployment_name, messages=messages, ) return final_response.choices[0].message.content
get_current_time called with location: San Francisco Timezone found for san francisco The current time in San Francisco is 09:24 AM.
函数调用是大多数 (如果不是全部) 智能体工具使用设计的核心,但是从头开始实现它有时可能具有挑战性。正如我们在 第 2 课 中学到的那样,Agentic 框架为我们提供了预构建的构建块来实现工具使用。
使用 Agentic 框架的工具使用示例
以下是一些如何使用不同的 agentic 框架实现工具使用设计模式的示例:
Semantic Kernel
Semantic Kernel 是一个开源 AI 框架,适用于使用大语言模型 (LLMs) 的 .NET、Python 和 Java 开发人员。它通过称为 序列化 的过程自动向模型描述你的函数及其参数,从而简化了使用函数调用的过程。它还处理模型和你的代码之间的来回通信。使用像 Semantic Kernel 这样的 agentic 框架的另一个优点是,它允许你访问预构建的工具,例如 文件搜索 和 代码解释器。
下图说明了使用 Semantic Kernel 进行函数调用的过程:
在 Semantic Kernel 中,函数/工具被称为 插件。我们可以通过将我们之前看到的 get_current_time
函数转换为一个类,并将该函数放在其中,从而将其转换为插件。我们还可以导入 kernel_function
装饰器,该装饰器接受函数的描述。然后,当你使用 GetCurrentTimePlugin 创建内核时,内核将自动序列化函数及其参数,从而创建要在此过程中发送到大语言模型 (LLM) 的模式。
from semantic_kernel.functions import kernel_function
class GetCurrentTimePlugin:
async def __init__(self, location):
self.location = location
@kernel_function(
description="Get the current time for a given location"
)
def get_current_time(location: str = ""):
...
from semantic_kernel import Kernel
# Create the kernel
kernel = Kernel()
# Create the plugin
get_current_time_plugin = GetCurrentTimePlugin(location)
# Add the plugin to the kernel
kernel.add_plugin(get_current_time_plugin)
Azure AI Agent Service
Azure AI Agent Service 是一个较新的 agentic 框架,旨在使开发人员能够安全地构建、部署和扩展高质量、可扩展的 AI 智能体,而无需管理底层计算和存储资源。它对于企业应用程序特别有用,因为它是一个具有企业级安全性的完全托管服务。
与直接使用大语言模型 (LLM) API 进行开发相比,Azure AI Agent Service 提供了一些优势,包括:
- 自动工具调用 – 无需解析工具调用、调用工具和处理响应;所有这些现在都在服务器端完成
- 安全管理的数据 – 你可以依赖线程来存储所需的所有信息,而不是管理自己的对话状态
- 开箱即用的工具 – 你可以用来与数据源交互的工具,例如 Bing、Azure AI 搜索和 Azure Functions。
Azure AI Agent Service 中可用的工具可以分为两类:
- 知识工具:
- 使用 Bing 搜索进行基础处理
- 文件搜索
- Azure AI 搜索
- 操作工具:
- 函数调用
- 代码解释器
- OpenAI 定义的工具
- Azure Functions
Agent Service 允许我们将这些工具一起用作 toolset
。它还利用 threads
来跟踪来自特定对话的消息历史记录。
假设你是 Contoso 公司的销售代理。你想开发一个可以回答有关你的销售数据的问题的对话代理。
下图说明了如何使用 Azure AI Agent Service 来分析你的销售数据:
要将这些工具中的任何一个与服务一起使用,我们可以创建一个客户端并定义一个工具或工具集。为了实际实现这一点,我们可以使用以下 Python 代码。大语言模型 (LLM) 将能够查看工具集并决定是使用用户创建的函数 fetch_sales_data_using_sqlite_query
还是预构建的代码解释器,具体取决于用户请求。
import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from fecth_sales_data_functions import fetch_sales_data_using_sqlite_query # fetch_sales_data_using_sqlite_query function which can be found in a fetch_sales_data_functions.py file.
from azure.ai.projects.models import ToolSet, FunctionTool, CodeInterpreterTool
project_client = AIProjectClient.from_connection_string(
credential=DefaultAzureCredential(),
conn_str=os.environ["PROJECT_CONNECTION_STRING"],
)
# Initialize function calling agent with the fetch_sales_data_using_sqlite_query function and adding it to the toolset
fetch_data_function = FunctionTool(fetch_sales_data_using_sqlite_query)
toolset = ToolSet()
toolset.add(fetch_data_function)
# Initialize Code Interpreter tool and adding it to the toolset.
code_interpreter = code_interpreter = CodeInterpreterTool()
toolset = ToolSet()
toolset.add(code_interpreter)
agent = project_client.agents.create_agent(
model="gpt-4o-mini", name="my-agent", instructions="You are helpful agent",
toolset=toolset
)
使用工具使用设计模式构建可信赖的 AI 智能体有哪些特殊注意事项?
大语言模型 (LLMs) 动态生成的 SQL 的一个常见问题是安全性,特别是 SQL 注入或恶意操作 (例如删除或篡改数据库) 的风险。虽然这些担忧是合理的,但可以通过正确配置数据库访问权限来有效地缓解这些担忧。对于大多数数据库,这涉及将数据库配置为只读。对于 PostgreSQL 或 Azure SQL 等数据库服务,应为应用程序分配只读 (SELECT) 角色。
在安全环境中运行应用程序可进一步增强保护。在企业场景中,数据通常从操作型系统提取并转换为具有用户友好模式的只读数据库或数据仓库。这种方法可确保数据安全、针对性能和可访问性进行优化,并且应用程序具有受限的只读访问权限。