[智能体设计模式] 第五章 :函数调用
目录
工具使用模式:智能体的外部交互核心机制
典型流程
实践应用与场景
1. 外部信息检索
2. 与数据库和 API 交互
3. 计算与数据分析
4. 发送通讯
5. 执行代码
6. 控制其他系统或设备
实战代码示例(LangChain)
代码解析
工具使用模式:智能体的外部交互核心机制
工具使用模式通常通过“函数调用”机制实现,使智能体能够与外部 API、数据库、服务甚至执行代码进行交互。它允许智能体核心的 LLM 根据用户请求或任务当前状态,决定何时以及如何调用特定的外部函数。
典型流程
- 工具定义:向 LLM 描述外部函数或能力,包括函数用途、名称、参数类型及说明。
- LLM 决策:LLM 接收用户请求和可用工具定义,根据理解判断是否需要调用一个或多个工具来完成请求。
- 函数调用生成:如果 LLM 决定使用工具,会生成结构化输出(通常为 JSON),指定要调用的工具名称及参数(从用户请求中提取)。
- 工具执行:智能体框架或编排层拦截结构化输出,识别请求的工具并用提供的参数实际执行外部函数。
- 观察/结果:工具执行的输出或结果返回给智能体。
- 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 密钥。
import os
import getpass
import asyncio
import nest_asyncio
from typing import List
from dotenv import load_dotenv
import loggingfrom 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 resulttools = [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 模型创建了一个工具调用智能体,核心逻辑如下:
- 环境配置与模型初始化:通过
getpass安全输入 Google API 密钥和 OpenAI API 密钥,初始化ChatGoogleGenerativeAI模型(选用gemini-2.0-flash,低温度保证输出确定性)。 - 工具定义:使用
@langchain_tool装饰器定义search_information工具,功能是根据查询提供事实信息。内部通过预设的simulated_results字典模拟搜索结果,支持常见查询(如天气、首都)和默认回复。 - 智能体创建:
-
- 定义
agent_prompt模板,包含系统提示、用户输入占位符和智能体草稿区(agent_scratchpad,用于记录工具调用过程); - 用
create_tool_calling_agent绑定模型、工具和提示模板,生成具备工具调用能力的智能体; - 用
AgentExecutor管理智能体的执行流程,开启verbose=True可查看详细调用日志。
- 定义
- 运行与测试:
-
run_agent_with_tool异步函数接收用户查询,调用智能体并输出最终回复;main函数并发运行多个测试查询,验证工具对特定请求的精准响应和默认回复逻辑;- 通过
nest_asyncio.apply()解决异步嵌套问题,确保并发任务正常执行。
整体实现了“用户查询 → LLM 决策 → 工具调用 → 结果整合 → 最终回复”的完整工具使用流程,展示了智能体如何通过外部工具扩展自身能力。
