本文目录导读:

LangChain 的工具调用是其核心功能之一,它允许 LLM 与外部系统(API、数据库、自定义函数等)进行交互,其底层原理核心是 Function Calling(函数调用)能力。
以下是实现 LangChain 工具调用的完整指南,从最简单的自定义函数到复杂的多工具链。
核心概念
- Tool(工具): 一个被 LLM 调用的函数,它需要有一个清晰的名称、描述和参数定义。
- 模型绑定: 将工具的定义(通过 JSON Schema)传给 LLM。
- 执行循环: LLM 决定调用哪个工具 -> 提取参数 -> 执行工具函数 -> 将结果返回给 LLM -> LLM 生成最终答案。
使用 @tool 装饰器(推荐,最简单)
这是最常用的方式,只需将一个普通 Python 函数转化为工具。
安装依赖:
pip install langchain langchain-openai
代码实现:
from langchain_openai import ChatOpenAI
from langchain.agents import tool
# 1. 定义工具 - 使用 @tool 装饰器
@tool
def calculate_sum(a: int, b: int) -> int:
"""计算两个整数的和。"""
return a + b
@tool
def get_weather(location: str) -> str:
"""获取指定地点的天气情况(模拟数据)。"""
# 这里应该调用真实的天气 API
return f"{location} 今天天气晴朗,温度25°C。"
# 2. 初始化模型
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# 3. 将工具绑定到模型
tools = [calculate_sum, get_weather]
llm_with_tools = llm.bind_tools(tools)
# 4. 调用模型
response = llm_with_tools.invoke("北京天气怎么样?")
print(response)
# 5. 检查模型是否想调用了工具
if response.tool_calls:
for tool_call in response.tool_calls:
# tool_call 包含 'name' 和 'args'
print(f"调用工具: {tool_call['name']}, 参数: {tool_call['args']}")
# 手动执行工具(更常见的做法是用 Agent)
if tool_call['name'] == 'get_weather':
result = get_weather.invoke(tool_call['args'])
print(f"工具返回: {result}")
输出示例:
content='' additional_kwargs={'tool_calls': [{'id': 'call_...', 'function': {'name': 'get_weather', 'arguments': '{"location": "北京"}'}}]}
调用工具: get_weather, 参数: {'location': '北京'}
工具返回: 北京 今天天气晴朗,温度25°C。
使用 Tool 类(手动定义,更灵活)
当需要更精细控制时(例如指定返回格式、处理异常),可以使用 Tool 类。
from langchain.tools import Tool
from langchain_openai import ChatOpenAI
def multiply(a: int, b: int) -> int:
"""乘法函数"""
return a * b
# 使用 Tool 类包装
multiply_tool = Tool(
name="multiply",
func=multiply,
description="非常有用,当你需要将两个整数相乘时。",
# 可选:定义参数架构(如果不定义,LLM 可能不准确)
args_schema=None # 通常可以留空,依赖 LLM 的理解
)
# 另一个例子:输入参数更复杂的
from pydantic import BaseModel, Field
class CalculatorInput(BaseModel):
a: int = Field(description="第一个数字")
b: int = Field(description="第二个数字")
calculator_tool = Tool(
name="calculator",
func=multiply, # 假设乘法
description="当需要计算两个数字的乘积时使用。",
args_schema=CalculatorInput # 提供 Pydantic schema 帮助 LLM 理解参数
)
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools([calculator_tool])
response = llm_with_tools.invoke("3 * 5 等于多少?")
print(response.tool_calls)
使用 Agent(自动执行循环)
手动解析 tool_calls 很麻烦,LangChain Agent 可以自动处理这个循环:调用 LLM -> 解析工具调用 -> 执行工具 -> 结果反馈给 LLM -> 生成最终答案。
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain.agents import tool
from langchain_core.prompts import ChatPromptTemplate
@tool
def search_web(query: str) -> str:
"""搜索网络获取信息(模拟)"""
return f"'{query}' 的搜索结果:这是模拟数据。"
@tool
def get_current_time() -> str:
"""获取当前时间"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 1. 创建 Agent
tools = [search_web, get_current_time]
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个聪明的助手,请通过调用必要的工具来回答用户的问题。"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"), # 这是关键,Agent 的内部工作空间
])
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# 创建 agent(使用 tool-calling 能力)
agent = create_tool_calling_agent(llm, tools, prompt)
# 2. 创建 AgentExecutor 来自动执行循环
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 打印运行过程,便于调试
handle_parsing_errors=True
)
# 3. 运行
result = agent_executor.invoke({"input": "现在几点了?顺便帮我搜一下今天的新闻。"})
print("\n最终答案:", result['output'])
输出示例(verbose=True):
> Entering new AgentExecutor chain...
Invoking: `get_current_time` with `{}`
2024-12-20 10:30:00
Invoking: `search_web` with `{'query': '今天的热点新闻'}`
'今天的热点新闻' 的搜索结果:这是模拟数据。
> Finished chain.
最终答案: 现在是 2024-12-20 10:30:00,关于今天的新闻,这是模拟搜索结果...
进阶技巧与最佳实践
工具描述的“玄学”
LLM 选择工具主要靠描述,描述要清晰、具体。
- ❌ 不好:
get_user_info,描述:“获取信息”。 - ✅ 好:
get_user_info,描述:“当用户想查看自己的账户信息、余额或用户名时使用,接受一个 user_id 参数。”
错误处理
工具可能会失败(如 API 超时),让工具返回明确的错误字符串,LLM 会理解并尝试重试或告知用户。
@tool
def get_stock_price(symbol: str) -> str:
"""获取股票实时价格"""
try:
# 模拟 API 调用
if symbol == "ERROR":
raise ValueError("API 调用失败")
price = 100.0
return f"{symbol} 当前价格为 ${price}"
except Exception as e:
return f"查询失败:{str(e)}"
结构化输出(Tools 返回复杂对象)
通过 Pydantic 定义返回结构。
from pydantic import BaseModel
from typing import Optional
class MovieInfo(BaseModel): str
year: Optional[int] = None
rating: float
@tool(args_schema=..., return_direct=True)
def search_movie(query: str) -> MovieInfo:
"""搜索电影信息"""
return MovieInfo(title="Inception", year=2010, rating=8.8)
多模态工具(非文本输入)
工具可以接受图片、文件等输入。
@tool
def analyze_image(image_path: str) -> str:
"""分析图片内容(路径由 LLM 参数提供)"""
# 这里可以调用图像识别 API
return "图片中包含一只猫"
总结选型
| 场景 | 推荐方法 | 理由 |
|---|---|---|
| 简单查询 / 单次计算 | @tool + bind_tools + 手动解析 |
轻量级,控制力强,适合无状态调用 |
| 多步骤推理 / 复杂任务 | create_tool_calling_agent + AgentExecutor |
自动处理循环、错误重试、中间步骤 |
| 不希望 LLM 有权决定调用 | Tool 类 + invoke 直接调用 |
手动调用工具,绕过 LLM 决策 |
| 需要异步 / 流式输出 | astream_events 或 RunnableLambda |
高级用法,适合实时交互 |
建议从 方法一(@tool) 和 方法三(Agent) 开始,它们覆盖了 90% 的需求。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播