[智能体设计模式] 第五章 :函数调用

目录

工具使用模式:智能体的外部交互核心机制

典型流程

实践应用与场景

[1. 外部信息检索](#1. 外部信息检索)

[2. 与数据库和 API 交互](#2. 与数据库和 API 交互)

[3. 计算与数据分析](#3. 计算与数据分析)

[4. 发送通讯](#4. 发送通讯)

[5. 执行代码](#5. 执行代码)

[6. 控制其他系统或设备](#6. 控制其他系统或设备)

实战代码示例(LangChain)

代码解析


工具使用模式:智能体的外部交互核心机制

工具使用模式通常通过"函数调用"机制实现,使智能体能够与外部 API、数据库、服务甚至执行代码进行交互。它允许智能体核心的 LLM 根据用户请求或任务当前状态,决定何时以及如何调用特定的外部函数。

典型流程

  1. 工具定义:向 LLM 描述外部函数或能力,包括函数用途、名称、参数类型及说明。
  2. LLM 决策:LLM 接收用户请求和可用工具定义,根据理解判断是否需要调用一个或多个工具来完成请求。
  3. 函数调用生成:如果 LLM 决定使用工具,会生成结构化输出(通常为 JSON),指定要调用的工具名称及参数(从用户请求中提取)。
  4. 工具执行:智能体框架或编排层拦截结构化输出,识别请求的工具并用提供的参数实际执行外部函数。
  5. 观察/结果:工具执行的输出或结果返回给智能体。
  6. LLM 处理(可选但常见):LLM 将工具输出作为上下文,用于生成最终回复或决定下一步(可能再次调用工具、反思或直接答复)。

实践应用与场景

工具使用模式几乎适用于所有智能体需要超越文本生成、执行动作或获取动态信息的场景:

1. 外部信息检索

获取 LLM 训练数据之外的实时数据或信息。

  • 案例:天气智能体
  • 工具:天气 API,输入地点返回当前天气
  • 流程:用户问"伦敦天气如何?",LLM 识别需要天气工具,调用工具,工具返回数据,LLM 格式化回复。

2. 与数据库和 API 交互

查询、更新或操作结构化数据。

  • 案例:电商智能体
  • 工具:查询库存、订单状态、支付等 API
  • 流程:用户问"X 产品有货吗?",LLM 调用库存 API,工具返回库存数,LLM 告知用户。

3. 计算与数据分析

使用外部计算器、数据分析库或统计工具。

  • 案例:金融智能体
  • 工具:计算器函数、股票数据 API、表格工具
  • 流程:用户问"AAPL 当前价格及买入 100 股的潜在利润",LLM 调用股票 API,再调用计算器工具,整合结果回复。

4. 发送通讯

发送邮件、消息或调用外部通讯服务 API。

  • 案例:个人助理智能体
  • 工具:邮件发送 API
  • 流程:用户说"给 John 发会议邮件",LLM 提取收件人、主题、正文,调用邮件工具。

5. 执行代码

在安全环境中运行代码片段完成特定任务。

  • 案例:编程助手智能体
  • 工具:代码解释器
  • 流程:用户提供 Python 代码并问"这段代码做什么?",LLM 用解释器工具运行并分析输出。

6. 控制其他系统或设备

操作智能家居、物联网平台等。

  • 案例:智能家居智能体
  • 工具:控制智能灯的 API
  • 流程:用户说"关闭客厅灯",LLM 调用智能家居工具,传递命令和目标设备。

工具使用让语言模型从文本生成器转变为具备感知、推理和行动能力的智能体(见图1)。


实战代码示例(LangChain)

在 LangChain 框架中实现工具使用分为两步:首先定义工具(通常封装现有 Python 函数或可运行组件),然后将工具绑定到语言模型,使模型在需要时能生成结构化的工具调用请求。

以下代码演示了如何定义一个信息检索工具,并构建一个能使用该工具的智能体。运行需安装 LangChain 核心库和模型相关包,并配置 API 密钥。

python 复制代码
import os
import getpass
import asyncio
import nest_asyncio
from typing import List
from dotenv import load_dotenv
import logging

from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool as langchain_tool
from langchain.agents import create_tool_calling_agent, AgentExecutor

# 安全输入 API 密钥并设置为环境变量
os.environ["GOOGLE_API_KEY"] = getpass.getpass("输入你的 Google API 密钥:")
os.environ["OPENAI_API_KEY"] = getpass.getpass("输入你的 OpenAI API 密钥:")

try:
    # 初始化具备工具调用能力的模型
    llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", temperature=0)
    print(f" 语言模型已初始化:{llm.model}")
except Exception as e:
    print(f" 初始化语言模型出错:{e}")
    llm = None

# --- 定义工具 ---
@langchain_tool
def search_information(query: str) -> str:
    """
    根据主题提供事实信息。用于回答如"法国首都"或"伦敦天气?"等问题。
    """
    print(f"\n---  工具调用:search_information, 查询:'{query}' ---")
    # 用预设结果模拟搜索工具
    simulated_results = {
        "weather in london": "伦敦当前天气多云,气温 15°C。",
        "capital of france": "法国的首都是巴黎。",
        "population of earth": "地球人口约 80 亿。",
        "tallest mountain": "珠穆朗玛峰是世界最高的山峰。",
        "default": f"模拟搜索 '{query}':未找到具体信息,但该主题很有趣。"
    }
    result = simulated_results.get(query.lower(), simulated_results["default"])
    print(f"--- 工具结果:{result} ---")
    return result

tools = [search_information]

# --- 创建工具调用 Agent ---
if llm:
    agent_prompt = ChatPromptTemplate.from_messages([
        ("system", "你是一个乐于助人的助手。"),
        ("human", "{input}"),
        ("placeholder", "{agent_scratchpad}"),
    ])

    agent = create_tool_calling_agent(llm, tools, agent_prompt)
    agent_executor = AgentExecutor(agent=agent, verbose=True, tools=tools)

    async def run_agent_with_tool(query: str):
        """用 Agent 执行查询并打印最终回复。"""
        print(f"\n---  Agent 运行查询:'{query}' ---")
        try:
            response = await agent_executor.ainvoke({"input": query})
            print("\n--- ✅ Agent 最终回复 ---")
            print(response["output"])
        except Exception as e:
            print(f"\n Agent 执行出错:{e}")

    async def main():
        """并发运行多个 Agent 查询。"""
        tasks = [
            run_agent_with_tool("法国的首都是什么?"),
            run_agent_with_tool("伦敦天气如何?"),
            run_agent_with_tool("说说狗的相关信息。")  # 触发默认工具回复
        ]
        await asyncio.gather(*tasks)

    nest_asyncio.apply()
    asyncio.run(main())

代码解析

该代码使用 LangChain 和 Google Gemini 模型创建了一个工具调用智能体,核心逻辑如下:

  1. 环境配置与模型初始化 :通过 getpass 安全输入 Google API 密钥和 OpenAI API 密钥,初始化 ChatGoogleGenerativeAI 模型(选用 gemini-2.0-flash,低温度保证输出确定性)。
  2. 工具定义 :使用 @langchain_tool 装饰器定义 search_information 工具,功能是根据查询提供事实信息。内部通过预设的 simulated_results 字典模拟搜索结果,支持常见查询(如天气、首都)和默认回复。
  3. 智能体创建
    • 定义 agent_prompt 模板,包含系统提示、用户输入占位符和智能体草稿区(agent_scratchpad,用于记录工具调用过程);
    • create_tool_calling_agent 绑定模型、工具和提示模板,生成具备工具调用能力的智能体;
    • AgentExecutor 管理智能体的执行流程,开启 verbose=True 可查看详细调用日志。
  1. 运行与测试
    • run_agent_with_tool 异步函数接收用户查询,调用智能体并输出最终回复;
    • main 函数并发运行多个测试查询,验证工具对特定请求的精准响应和默认回复逻辑;
    • 通过 nest_asyncio.apply() 解决异步嵌套问题,确保并发任务正常执行。

整体实现了"用户查询 → LLM 决策 → 工具调用 → 结果整合 → 最终回复"的完整工具使用流程,展示了智能体如何通过外部工具扩展自身能力。

相关推荐
编码者卢布9 小时前
【Azure Developer】中国区Azure环境中查看用户账号是否可用(accountEnabled)的操作步骤
microsoft·flask·azure
YigAin10 小时前
Unity23种设计模式之 命令模式
设计模式·命令模式
twj_one11 小时前
java中23种设计模式
java·开发语言·设计模式
编码者卢布11 小时前
【Azure App Service】部署在应用服务上的WebJob中,为何会多出一个名为“DaaS“的 WebJob呢?
microsoft·azure
香芋Yu12 小时前
【深度学习教程——01_深度基石(Foundation)】05_数据太多怎么吃?Mini-batch训练的设计模式
深度学习·设计模式·batch
晚霞的不甘12 小时前
Flutter for OpenHarmony构建全功能视差侧滑菜单系统:从动效设计到多页面导航的完整实践
前端·学习·flutter·microsoft·前端框架·交互
逻极14 小时前
Claude Code实战——打造智能研报 CLI 工具:45分钟零构建智能研报助手CLI,解锁AI编程效率革命
microsoft·ai编程·ai辅助编程·claude code·python实战·cli开发
xixixi7777714 小时前
Prompt脱敏——不损失(或尽量少损失)原文本语义和上下文价值的前提下,防止原始敏感数据暴露给模型服务方、潜在的攻击者或出现在模型训练数据中
人工智能·microsoft·ai·大模型·数据安全·提示词·敏感信息
进击的小头15 小时前
设计模式组合应用:传感器数据采集与处理系统
c语言·设计模式
茶本无香16 小时前
设计模式之十一—桥接模式:解耦抽象与实现的艺术
设计模式·桥接模式