【LangChain】 预定义工具与 Toolkits 详解:从单独使用到混合编排
LangChain 预定义工具与 Toolkits 详解:从单独使用到混合编排
一、引言
在上一篇博客中,我们深入探讨了 LangChain 中自定义工具(Custom Tools)的实现方式,包括如何使用 @tool 装饰器和 BaseTool 类来封装业务逻辑。然而,LangChain 的强大之处不仅在于支持自定义扩展,更在于它提供了一套开箱即用的预定义工具(Prebuilt Tools)和工具集(Toolkits),能够让我们快速构建具备搜索、计算、数据库操作等能力的智能 Agent。
本文将围绕以下几个核心问题展开:
- LangChain 提供了哪些常用的预定义工具?
- 如何单独使用预定义工具?
- 如何将预定义工具与自定义工具混合使用?
- Toolkit 是什么?它如何简化复杂场景的工具管理?
二、预定义工具 vs 自定义工具
在 LangChain 的 Agent 架构中,工具是 Agent 执行外部操作的"手脚"。从来源上看,工具可以分为两大类:
| 维度 | 预定义工具 | 自定义工具 |
|---|---|---|
| 开发成本 | 低,开箱即用 | 高,需要自行实现逻辑 |
| 灵活性 | 受限于官方实现 | 完全可控,可对接内部系统 |
| 适用场景 | 通用任务(搜索、计算、数据库等) | 特定业务(内部 API、私有数据等) |
| 使用方式 | load_tools() 或直接实例化 |
@tool 装饰器或继承 BaseTool |
最佳实践:先用预定义工具满足通用需求,再通过自定义工具补充业务特定能力,两者相辅相成。
三、预定义工具的分类与典型代表
LangChain 的预定义工具覆盖了大量常见场景,以下是主要分类:
3.1 搜索类工具
| 工具名 | 功能说明 |
|---|---|
DuckDuckGoSearchRun |
通过 DuckDuckGo 进行网页搜索 |
SerpAPI |
通过 SerpAPI 调用 Google 搜索 |
WikipediaQueryRun |
查询维基百科词条 |
ArxivQueryRun |
检索 arXiv 学术论文 |
3.2 数据操作与计算类
| 工具名 | 功能说明 |
|---|---|
PythonREPL / PythonAstREPLTool |
执行 Python 代码(后者使用 AST 更安全) |
MathTool |
执行数学计算 |
JsonListKeysTool |
从 JSON 中提取键名 |
3.3 文件与系统类
| 工具名 | 功能说明 |
|---|---|
ReadFileTool |
读取文件内容 |
WriteFileTool |
写入文件内容 |
ListDirectoryTool |
列出目录文件 |
3.4 数据库类
| 工具名 | 功能说明 |
|---|---|
QuerySQLDataBaseTool |
执行 SQL 查询 |
SQLDatabaseToolkit |
一整套数据库操作工具集 |
3.5 API 集成类
| 工具名 | 功能说明 |
|---|---|
OpenWeatherMapQueryRun |
查询天气数据 |
RequestsWrapper |
发送 HTTP 请求 |
3.6 向量存储类
| 工具名 | 功能说明 |
|---|---|
VectorStoreQATool |
基于向量存储的问答 |
VectorStoreQAWithSourcesTool |
带来源信息的向量问答 |
四、预定义工具的使用方式
4.1 方式一:通过 load_tools 快速加载(传统方式)
这是最简单的方式,适合快速上手和单独使用预定义工具:
from langchain_community.agent_toolkits.load_tools import load_tools
# 加载单个或多个工具
tools = load_tools(["arxiv", "llm-math"], llm=llm)
# 查看所有可用工具名
from langchain_community.agent_toolkits.load_tools import get_all_tool_names
print(get_all_tool_names())
4.2 方式二:直接导入具体工具类(推荐,混用时必需)
更灵活,可以精细配置参数,也是混用自定义工具时的必要方式:
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
# 初始化维基百科工具(指定中文、返回1条结果)
wiki_tool = WikipediaQueryRun(
api_wrapper=WikipediaAPIWrapper(lang="zh", top_k_results=1)
)
# 直接调用
result = wiki_tool.invoke("马斯克")
print(result[:200])
五、核心差异:load_tools vs 直接实例化
很多开发者困惑:为什么单独使用时可以用 load_tools,混用时却要实例化对象?
| 对比项 | load_tools |
直接实例化 |
|---|---|---|
| 返回值 | 工具列表(黑盒) | 单个工具对象 |
| 配置灵活性 | 低,只能传字符串名 | 高,可自定义构造参数 |
| 混用支持 | 不方便与自定义工具组合 | 可与自定义工具统一放入列表 |
| 本质 | 封装了 import + new 的过程 | 手动 import 类并实例化 |
核心原理:load_tools 本质上也是根据字符串名字去 import 对应的类然后实例化。混用时跳过这个"中介",直接拿到对象,就能和自定义工具平起平坐了。
一句话总结:
- 单独用预定义工具 ->
load_tools一键加载- 混用自定义+预定义 -> 预定义工具也要实例化对象,统一组装列表
六、重点详解:Arxiv 工具与科研助理
Arxiv 是一个免费的学术论文预印本平台。ArxivQueryRun 让 Agent 能够按关键词搜索论文、获取标题摘要等信息,是构建科研助理的核心工具。
6.1 单独使用 Arxiv
import os
from langchain.chat_models import ChatOpenAI
from langchain.agents import load_tools, initialize_agent, AgentType
os.environ['OPENAI_API_KEY'] = 'Your Key'
llm = ChatOpenAI(temperature=0.0)
# 单独加载
tools = load_tools(["arxiv"])
agent_chain = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
)
agent_chain.run("介绍一下2005.14165这篇论文的创新点")
6.2 混用 Arxiv + 自定义工具
from langchain_community.tools import ArxivQueryRun
from langchain.tools import tool
from langchain.agents import initialize_agent, AgentType
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(temperature=0.0)
# 预定义工具:实例化对象
arxiv = ArxivQueryRun()
# 自定义工具:论文摘要翻译
@tool
def translate_abstract(text: str, target_lang: str = 'zh') -> str:
"""将论文摘要翻译成目标语言。输入:英文摘要文本"""
# 实际项目中调用翻译 API
return f"[翻译结果] {text[:100]}..."
# 混用:统一放入列表
all_tools = [arxiv, translate_abstract]
agent = initialize_agent(
all_tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
)
agent.run("搜索最近关于 LLM Agent 的论文,并把摘要翻译成中文")
七、Toolkit:工具的组合包
7.1 什么是 Toolkit?
Toolkit 是 LangChain 中针对特定领域预打包的一组工具集合。与单个工具相比,Toolkit 提供了更完整的解决方案。
7.2 最经典的 Toolkit:SQLDatabaseToolkit
当 Agent 需要操作数据库时,单个 SQL 执行工具远远不够。Agent 需要:
- 查看有哪些表(
sql_db_list_tables) - 查看表结构(
sql_db_schema) - 检查 SQL 语法(
sql_db_query_checker) - 执行 SQL 查询(
sql_db_query)
SQLDatabaseToolkit 正好打包了这全套能力:
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
from langchain_community.utilities.sql_database import SQLDatabase
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langchain import hub
# 连接数据库
db = SQLDatabase.from_uri("sqlite:///Chinook.db")
llm = ChatOpenAI(temperature=0)
# 初始化 Toolkit
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
# 获取工具列表(包含4个SQL工具)
tools = toolkit.get_tools()
# 创建 Agent
prompt_template = hub.pull("langchain-ai/sql-agent-system-prompt")
system_message = prompt_template.format(dialect="SQLite", top_k=5)
agent_executor = create_react_agent(
llm, tools, state_modifier=system_message
)
# 查询
events = agent_executor.stream(
{"messages": [("user", "Which country's customers spent the most?")]},
stream_mode="values",
)
for event in events:
event["messages"][-1].pretty_print()
7.3 SQLDatabaseToolkit 工具清单
| 工具 | 作用 |
|---|---|
sql_db_list_tables |
列出数据库中所有表 |
sql_db_schema |
查看指定表的结构(字段、类型、关系) |
sql_db_query_checker |
检查 SQL 语句的语法正确性 |
sql_db_query |
执行 SQL 查询并返回结果 |
这种"组合拳"让 Agent 能够自主探索数据库结构、生成并验证 SQL,最终完成复杂的数据查询任务。
八、完整实战:预定义工具与自定义工具混用
假设我们要构建一个电商智能助手,它需要:
- 用 ArxivQueryRun 查最新的 AI 技术论文
- 用 SQLDatabaseToolkit 查订单数据库
- 用 自定义工具 调用公司内部的价格计算 API
import os
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
from langchain.tools import tool, BaseTool
from langchain_community.tools import ArxivQueryRun
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
from langchain_community.utilities.sql_database import SQLDatabase
from pydantic import BaseModel, Field
# ========== 1. 初始化 LLM ==========
os.environ["OPENAI_API_KEY"] = "your-api-key"
llm = ChatOpenAI(temperature=0, model="gpt-4")
# ========== 2. 预定义工具:Arxiv 论文搜索 ==========
arxiv_tool = ArxivQueryRun()
# ========== 3. 预定义工具:SQL 数据库工具集 ==========
db = SQLDatabase.from_uri("sqlite:///orders.db")
sql_toolkit = SQLDatabaseToolkit(db=db, llm=llm)
sql_tools = sql_toolkit.get_tools()
# ========== 4. 自定义工具:公司内部价格计算 API ==========
class PriceInput(BaseModel):
product_id: str = Field(description="商品ID")
quantity: int = Field(description="购买数量")
coupon_code: str = Field(description="优惠券代码,没有则填空字符串")
class PriceCalculatorTool(BaseTool):
name = "price_calculator"
description = "计算商品最终价格,支持优惠券折扣。输入格式:product_id, quantity, coupon_code"
args_schema = PriceInput
def _run(self, product_id: str, quantity: int, coupon_code: str):
base_price = 100
discount = 0.8 if coupon_code == "SAVE20" else 1.0
final_price = base_price * quantity * discount
return f"商品 {product_id} 购买 {quantity} 件,使用优惠券 {coupon_code},最终价格:{final_price}元"
async def _arun(self, **kwargs):
raise NotImplementedError("不支持异步")
price_tool = PriceCalculatorTool()
# ========== 5. 自定义工具:查询物流状态 ==========
@tool
def logistics_tracker(order_id: str) -> str:
"""查询订单物流状态。输入:订单号"""
return f"订单 {order_id} 当前状态:已发货,预计明天送达"
# ========== 6. 混合所有工具(核心!)==========
all_tools = [
arxiv_tool, # 预定义:Arxiv
*sql_tools, # 预定义:SQL Toolkit(展开4个工具)
price_tool, # 自定义:价格计算
logistics_tracker, # 自定义:物流查询
]
print(f"共加载 {len(all_tools)} 个工具:")
for t in all_tools:
print(f" - {t.name}: {t.description[:50]}...")
# ========== 7. 创建 Agent ==========
agent = initialize_agent(
all_tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
handle_parsing_errors=True,
)
# ========== 8. 测试不同场景 ==========
# 场景1:查论文(触发 Arxiv)
agent.run("最近有没有关于大语言模型微调的论文?")
# 场景2:查数据库(触发 SQL Toolkit)
agent.run("上个月销售额最高的商品是什么?请查一下数据库")
# 场景3:算价格(触发自定义 price_calculator)
agent.run("商品ID为PHONE-001,买3个,用优惠券SAVE20,最终多少钱?")
# 场景4:查物流(触发自定义 logistics_tracker)
agent.run("帮我查一下订单 ORD-2024-001 的物流状态")
# 场景5:复杂问题(可能触发多个工具)
agent.run("帮我查一下订单 ORD-2024-002 买了什么商品,然后算一下如果再加2件用SAVE20优惠券要多少钱")
九、混用时的关键要点
| 要点 | 说明 |
|---|---|
| 统一列表 | 自定义和预定义工具放在同一个 tools 列表里 |
| 描述要清晰 | Agent 靠 description 决定调用哪个工具,描述写不好会选错工具 |
| 输入规范 | 自定义工具建议用 args_schema(Pydantic)定义参数,和预定义工具保持一致 |
| 命名不冲突 | 确保 name 唯一,不要和预定义工具重名 |
| 权限控制 | 自定义工具可能涉及敏感操作,注意权限和异常处理 |
十、使用 LangGraph 的 ReAct Agent 混用
如果你使用新版 LangGraph,混用方式完全一致:
from langgraph.prebuilt import create_react_agent
# 同样的 all_tools 列表
agent = create_react_agent(llm, all_tools)
# 流式输出
for chunk in agent.stream({"messages": [("user", "查一下订单表有哪些字段")]}):
print(chunk)
LangGraph 的 create_react_agent 会自动处理工具调用,混用逻辑和传统 Agent 完全一致。
十一、总结
LangChain 的预定义工具和 Toolkits 是 Agent 能力的重要基石:
- 预定义工具覆盖搜索、计算、文件、数据库、API 等常见场景,通过
load_tools()或直接实例化即可使用。 - 单独使用预定义工具时,可以用
load_tools(["arxiv"])一键加载。 - 混用自定义+预定义工具时,预定义工具也需要实例化为对象,然后统一放入工具列表。
- Arxiv 工具是科研类 Agent 的典型代表,让 LLM 具备文献检索能力。
- Toolkit 是工具的"组合拳",如
SQLDatabaseToolkit提供完整的数据库操作能力,让 Agent 能自主探索 schema、生成 SQL、执行查询。
核心心法:Agent 不区分工具的来源,只关心每个工具是否有 name、description 和 invoke() 方法。只要满足这个契约,预定义工具和自定义工具就能无缝协作。
介绍了自定义工具的完整实现方式。后续还将深入探讨工具调用链的调试与优化,敬请期待!
更多推荐


所有评论(0)