工具定义与使用
工具是 Agent 与外部世界交互的桥梁。工具的 name、description 和 args_schema 决定了模型是否及如何选择调用工具。
多工具组合
多个工具可以一起使用:
from langchain.agents import create_agent
from langchain_core.tools import tool
@tool
def get_weather(city: str) -> str:
"""获取指定城市的天气信息"""
data = {"北京": "晴,25°C", "上海": "多云,28°C"}
return f"{city}:{data.get(city, '未知')}"
@tool
def calculate(expression: str) -> str:
"""计算数学表达式"""
try:
return str(eval(expression))
except:
return "计算出错"
# 传入工具列表
agent = create_agent(
model=model,
tools=[get_weather, calculate],
system_prompt="你是多功能助手"
)
工具定义方式
@tool 装饰器
适合快速原型开发和简单工具实现。
技术特点:
- 自动参数推断
- 代码简洁,一行装饰器完成
- 无需复杂配置
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiplies a and b."""
return a * b
StructuredTool.from_function
适合需要参数校验的生产环境。
技术特点:
- 强类型校验:Pydantic 模型进行参数验证
- 异步支持:
coroutine参数支持异步 - 完整元数据:name、description、return_direct 等配置
- 生产就绪:内置错误处理和参数校验
from pydantic import BaseModel, Field
from langchain_core.tools import StructuredTool
# 定义参数校验模型
class DivideInput(BaseModel):
dividend: float = Field(description="被除数")
divisor: float = Field(description="除数,不能为零")
def divide(dividend: float, divisor: float) -> float:
if divisor == 0:
raise ValueError("除数不能为零")
return dividend / divisor
# 创建工具
division_tool = StructuredTool.from_function(
func=divide,
name="DivisionTool",
description="安全执行除法运算,自动处理除零错误",
args_schema=DivideInput,
return_direct=False,
)
继承 StructuredTool
适合复杂业务逻辑和状态管理。
技术特点:
- 完全自定义工具行为
- 支持工具内部状态维护
- 适合复杂业务逻辑封装
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field
from typing import Type
class OrderQueryInput(BaseModel):
order_id: str = Field(description="订单编号")
include_details: bool = Field(default=False, description="是否包含商品明细")
class OrderQueryTool(StructuredTool):
name: str = "query_order"
description: str = "查询电商平台订单状态"
args_schema: Type[BaseModel] = OrderQueryInput
return_direct: bool = False
def _run(self, order_id: str, include_details: bool = False) -> dict:
order_db = {"ORD-2024-1234": {"status": "已发货", "express": "顺丰"}}
if order_id not in order_db:
return {"error": f"订单 {order_id} 不存在"}
result = order_db[order_id]
if include_details:
result["items"] = ["商品A × 2"]
return result
# 使用
agent = create_agent(model=model, tools=[OrderQueryTool()])
三种方式对比
| 特性 | @tool | from_function | 继承 |
|---|---|---|---|
| 代码简洁度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| 参数控制 | 自动推断 | args_schema 强校验 | 完全自定义 |
| 异步支持 | ❌ | ✅ | ✅ |
| 适用场景 | 快速原型 | 生产环境 | 复杂业务 |
通过强制化 Schema 和规范化提示词,建立统一的工具使用规范。
规范要求:
- 工具名称必须动词开头
- 每个工具使用标准化 schema
- 工具描述必须包含三件事:能干什么、不能干什么、典型输入示例
工具描述
描述规范
# ❌ 描述不清晰
@tool
def query(sql):
"""查询数据库"""
# ✅ 描述清晰
@tool
def query_database(sql: str) -> str:
"""
执行 SQL 查询,仅限内部业务数据库。
参数:sql SQL语句
示例:select * from users limit 5
"""
好的描述应包含:
- 工具能干什么
- 工具不能干什么
- 典型输入示例
return_direct
return_direct=True:工具结果直接返回(不经过 LLM 处理)return_direct=False(默认):工具结果经过 LLM 处理后返回
内置工具
LangChain 提供了丰富的内置工具,无需自己定义:
| 工具 | 类 | 作用 |
|---|---|---|
| python_repl | PythonREPLTool | 执行 Python 代码 |
| shell | ShellTool | 执行命令行 |
| human | HumanTool | 人工输入 |
| requests_get | RequestsGetTool | GET 请求 |
| requests_post | RequestsPostTool | POST 请求 |
| tavily_search | TavilySearchResults | 搜索 |
| web_loader | WebBaseLoader | 网页加载 |
| read_file | ReadFileTool | 读取文件 |
| write_file | WriteFileTool | 写入文件 |
| sql_db_query | QuerySQLDatabaseTool | SQL 查询 |
| retriever | VectorStoreTool | RAG 检索 |
更多内置工具:LangChain 官方文档
工具调用优化
当工具较多时,Agent 可能选错工具。
Tool Router
使用意图分类器精确匹配工具。
INTENT_PROMPT = """
你是意图分类器,只返回:search | pdf | database | math
"""
def classify_intent(query):
return llm.invoke([("system", INTENT_PROMPT), ("user", query)]).content
动态加载工具
按需加载工具,避免上下文过长。
TOOL_GROUPS = {
"search": [search_web],
"pdf": [extract_pdf_text],
"database": [query_database],
}
def create_agent_for_intent(user_query: str):
intent = classify_intent(user_query)
return create_agent(model, TOOL_GROUPS.get(intent, []))
层次化架构
Router Agent(意图识别)
↓
Search Agent | PDF Agent | Math Agent
统一工具规范
- 工具名称必须动词开头
- 描述必须包含:功能、限制、示例