如何设计优秀的AI代理

工具使用设计模式

工具的引入使得AI代理具备了更广泛的能力。相比于仅限于执行有限动作的代理,添加工具后,代理能够执行更多样化的操作。本章将介绍工具使用设计模式,阐述AI代理如何通过调用特定工具来实现目标。

课程介绍

本课将解答以下问题:

  • 什么是工具使用设计模式?
  • 它适用于哪些应用场景?
  • 实现该设计模式需要哪些核心元素?
  • 在构建可信赖的AI代理时,使用该设计模式有哪些特别注意事项?

学习目标

完成本课后,您将能够:

  • 定义工具使用设计模式及其目的。
  • 识别适用该设计模式的使用场景。
  • 理解实现该设计模式的关键组成部分。
  • 认识确保使用该设计模式构建的AI代理可信赖性的考虑因素。

什么是工具使用设计模式?

工具使用设计模式主要赋予大型语言模型(LLM)与外部工具交互的能力,以达成特定目标。工具是代理可执行的代码,可执行各种操作。工具可以是简单的函数(如计算器),也可以是调用第三方服务的API(如股票价格查询、天气预报)。在AI代理中,工具通过模型生成的函数调用被执行。

适用场景

AI代理利用工具可以完成复杂任务、获取信息或辅助决策。该设计模式常用于需要动态交互外部系统的场景,如数据库、网络服务或代码解释器。具体应用包括:

  • 动态信息检索:通过调用外部API或数据库获取最新数据,如查询SQLite数据库、股票价格或天气信息。
  • 代码执行与解释:执行代码或脚本解决数学问题、生成报告或进行模拟。
  • 工作流自动化:整合任务调度器、邮件服务或数据管道,实现重复或多步骤流程自动化。
  • 客户支持:与CRM系统、工单平台或知识库交互,解决用户问题。
  • 内容生成与编辑:使用语法检查、文本摘要或内容安全评估工具辅助内容创作。

实现工具使用设计模式的核心元素

以下构件使AI代理能够执行多样任务:

  • 函数/工具模式定义:详细描述可用工具,包括函数名称、用途、参数及输出,帮助LLM理解工具及构造有效调用。
  • 函数执行逻辑:根据用户意图和对话上下文决定何时调用工具,可能包含规划模块、路由机制或条件流程。
  • 消息处理系统:管理用户输入、LLM响应、工具调用及工具输出之间的对话流程。
  • 工具集成框架:连接代理与各种工具,无论是简单函数还是复杂外部服务。
  • 错误处理与验证:处理工具执行失败、参数验证及异常响应。
  • 状态管理:跟踪对话上下文、历史工具交互及持久数据,保证多轮交互一致性。

函数/工具调用详解

函数调用是实现LLM与工具交互的主要方式。函数(可复用代码块)即为代理执行任务的工具。LLM通过对比用户请求与函数描述,选择最合适的函数并返回函数名及参数。随后执行该函数,将结果返回给LLM,LLM据此回复用户。

开发者实现函数调用需准备:

  1. 支持函数调用的LLM模型。
  2. 包含函数描述的模式(schema)。
  3. 各函数的实现代码。

以获取某城市当前时间为例:

  1. 初始化支持函数调用的LLM客户端(如Azure OpenAI)。
# 初始化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"
)
  1. 定义函数模式,描述函数名称、功能及参数。
# 函数描述
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": "旧金山现在几点了?"}]

# 请求模型调用函数
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)
  1. 实现函数代码并处理函数调用结果。
def get_current_time(location):
    """获取指定地点当前时间"""
    location_lower = location.lower()
    for key, timezone in TIMEZONE_DATA.items():
        if key in location_lower:
            current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
            return json.dumps({"location": location, "current_time": current_time})
    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("模型未调用任何工具。")

# 获取最终回复
final_response = client.chat.completions.create(
    model=deployment_name,
    messages=messages,
)

print(final_response.choices[0].message.content)

函数调用是工具使用设计的核心,但从零实现较为复杂。正如第二课所述,代理框架提供了预构建组件,简化工具使用实现。

使用代理框架的工具使用示例

Microsoft代理框架

Microsoft代理框架是开源AI框架,简化函数调用实现。通过@tool装饰器定义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("现在几点了?")

Azure AI代理服务

Azure AI代理服务是托管式框架,帮助开发者安全构建、部署和扩展高质量AI代理,适合企业级应用。相比直接调用LLM API,优势包括:

  • 自动工具调用,服务器端处理调用和响应。
  • 安全管理数据,利用线程存储对话历史。
  • 内置多种工具,如Bing搜索、Azure AI搜索、Azure函数。

工具分为两类:

  1. 知识工具:Bing搜索、文件搜索、Azure AI搜索。
  2. 操作工具:函数调用、代码解释器、OpenAPI定义工具、Azure函数。

代理服务支持将工具组合成工具集,并通过线程管理对话历史。

示例:假设您是Contoso公司的销售代理,想开发一个能回答销售数据问题的对话代理。

代理服务示意

示例代码:

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
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_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代理的特别注意事项

动态生成SQL时,安全性是常见关注点,尤其是SQL注入或恶意操作(如删除数据库)。这些风险可通过配置数据库访问权限有效防范。通常将数据库设为只读,应用程序使用只读(SELECT)权限角色。

在安全环境中运行应用进一步提升保护。企业场景中,数据通常从运营系统抽取并转换至只读数据库或数据仓库,结构友好且性能优化,应用仅具有限制性只读访问权限。

相关资源

课程链接