在 LangChain 构建的智能体(Agent)系统中,Tool 是赋予大语言模型(LLM)执行具体操作能力的核心组件。LLM 本身仅擅长理解和生成文本,而通过 Tool,它可以调用外部 API、查询数据库、执行计算或与物理世界交互。LangChain 提供了灵活的机制,允许开发者将任意 Python 函数封装为标准化的 Tool,从而扩展 Agent 的能力边界。

自定义 Tool 的核心要素与标准结构
一个有效的自定义 Tool 在 LangChain 中必须满足三个基本要素:可调用的函数逻辑、清晰的功能描述(description)和明确的输入参数规范(schema)。这些要素共同构成了 LLM 理解和正确使用该工具的基础。
早期版本的 LangChain 允许通过简单的装饰器 @tool 将函数快速转换为 Tool。然而,在当前推荐的架构中,更强调使用 Pydantic 模型来严格定义输入参数的 Schema。这种强类型约束不仅提高了代码的健壮性,也使得 LLM 能更准确地生成符合要求的参数,减少因格式错误导致的工具调用失败。
Tool 的描述(description)尤为重要。它并非简单的功能说明,而是需要以 LLM 能理解的方式,清晰阐述该工具的用途、适用场景以及输入输出的语义。一个模糊的描述如“获取数据”远不如“根据用户提供的城市名称,查询并返回该城市当前的实时天气状况,包括温度、湿度和天气描述”有效。
使用装饰器快速创建基础 Tool
对于逻辑简单、输入参数明确的函数,LangChain 提供了便捷的 @tool 装饰器。这是最快速的自定义方式。
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""将两个整数相乘,并返回它们的乘积。"""
return a * b
在此示例中,函数签名中的类型注解(int)会被自动解析为输入 Schema,而 docstring 则成为工具的 description。这种方式适用于大多数 CRUD 操作或简单的计算任务。
然而,当输入参数较为复杂,例如包含嵌套对象、枚举类型或需要特定格式验证时,仅依赖函数签名就显得力不从心。此时,必须采用更强大的 Pydantic 模型来定义 Schema。
基于 Pydantic 模型定义复杂输入 Schema
Pydantic 是 Python 中广泛使用的数据验证和设置管理库。LangChain 深度集成了 Pydantic,允许开发者通过定义模型类来精确控制 Tool 的输入结构。
from pydantic import BaseModel, Field
from langchain_core.tools import StructuredTool
class WeatherInput(BaseModel):
city: str = Field(description="要查询天气的城市名称,例如 '北京' 或 'New York'")
unit: str = Field(default="celsius", description="温度单位,可选 'celsius' 或 'fahrenheit'")
def get_weather(city: str, unit: str = "celsius") -> str:
# 此处应替换为真实的天气 API 调用
return f"城市 {city} 的当前温度是 20°{unit[0].upper()},天气晴朗。"
weather_tool = StructuredTool.from_function(
func=get_weather,
name="get_weather",
description="根据城市名称和温度单位,获取该城市的实时天气信息。",
args_schema=WeatherInput,
)
通过 StructuredTool.from_function,我们将一个普通函数与一个 Pydantic 模型绑定,创建了一个功能完备的 Tool。LLM 在决定调用此工具时,会尝试生成一个符合 WeatherInput 模型的 JSON 对象作为参数。这种结构化的方式极大地提升了工具调用的成功率和可靠性。
集成自定义 Tool 到 Agent 执行器
创建好 Tool 后,下一步是将其集成到 Agent 中。LangChain 的 create_tool_calling_agent 工厂函数是构建现代 Agent 的标准方法,它能自动处理 OpenAI、Anthropic 等支持原生工具调用的模型。
from langchain import hub
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_openai import ChatOpenAI
# 1. 加载预设的提示词模板
prompt = hub.pull("hwchase17/openai-functions-agent")
# 2. 初始化 LLM(需支持工具调用)
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
# 3. 创建 Agent
agent = create_tool_calling_agent(llm, [multiply, weather_tool], prompt)
# 4. 创建执行器
agent_executor = AgentExecutor(agent=agent, tools=[multiply, weather_tool], verbose=True)
# 执行查询
response = agent_executor.invoke({"input": "纽约现在的天气怎么样?"})
print(response["output"])
AgentExecutor 是整个流程的驱动者,它负责管理对话历史、调用 LLM、解析其工具调用请求、执行相应的 Tool,并将结果反馈给 LLM 以生成最终回答。verbose=True 参数可以在开发阶段打印详细的执行日志,便于调试。
高级自定义:异步 Tool 与状态管理
对于涉及网络 I/O 或耗时计算的 Tool,应实现为异步函数以避免阻塞事件循环。LangChain 完全支持异步 Tool,只需在函数定义前加上 async 关键字,并在调用时使用 ainvoke。
此外,某些 Tool 可能需要访问或修改外部状态(如数据库会话、用户配置)。最佳实践是避免在 Tool 内部直接持有状态,而是通过依赖注入的方式,在创建 AgentExecutor 时传入必要的上下文。这保证了 Tool 的无状态性和可测试性。