05-工具与MCP
·
第05章:工具与 MCP(Tools)
版本:LangChain v1.3.7 | 讲师:汤姆小白
1. Tools 概述
1.1 什么是工具
大模型只能生成文本,无法与外部世界交互。Tools(工具)为 LLM 装上"手脚",让它能调用 API、搜索互联网、查询数据库、执行代码、操作文件等。
用户提问 → LLM 思考 → 决定调用工具 → 执行工具 → 获取结果 → 继续推理
1.2 工具的构成要素
每个 Tool 包含以下要素:
| 要素 | 说明 | 示例 |
|---|---|---|
name |
唯一标识名称 | "web_search" |
description |
功能描述(LLM 据此判断何时调用) | "搜索互联网获取最新信息" |
args_schema |
参数 JSON Schema(Pydantic 模型) | {"query": "string"} |
func |
实际执行的函数 | 调用搜索 API |
return_direct |
是否直接返回结果给用户 | False(让 Agent 继续) |
Tool 的 name 和 description 至关重要——LLM 完全靠这两项判断何时调用哪个工具。
2. 自定义工具
2.1 @tool 装饰器(最简单)
from langchain_core.tools import tool
@tool
def add(a: int, b: int) -> int:
"""两个整数相加"""
return a + b
print(add.name) # add
print(add.description) # 两个整数相加
print(add.args) # {'a': {'type': 'integer'}, 'b': {'type': 'integer'}}
# 调用
result = add.invoke({"a": 10, "b": 20}) # 30
自定义名称和描述:
@tool("calculator", description="执行数学计算", return_direct=True)
def calculate(expression: str) -> float:
"""计算数学表达式"""
return eval(expression)
使用 Pydantic 完善参数描述:
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(description="搜索关键词")
max_results: int = Field(default=5, description="最大结果数")
@tool(args_schema=SearchInput)
def web_search(query: str, max_results: int = 5) -> str:
"""搜索互联网获取信息"""
# 实际调用搜索 API
return f"关于 '{query}' 的搜索结果..."
2.2 StructuredTool.from_function(更灵活)
from langchain_core.tools import StructuredTool
def get_weather(city: str) -> str:
"""获取城市天气"""
return f"{city}今天晴,28°C"
weather_tool = StructuredTool.from_function(
func=get_weather,
name="get_weather",
description="查询指定城市的天气情况",
)
weather_tool.invoke({"city": "北京"}) # 北京今天晴,28°C
异步工具:
async def fetch_stock_price(symbol: str) -> str:
"""获取股票实时价格"""
await asyncio.sleep(0.5) # 模拟 API 调用
return f"{symbol} 当前价格: ¥128.50"
stock_tool = StructuredTool.from_function(
coroutine=fetch_stock_price, # 用 coroutine 而不是 func
name="stock_price",
description="查询股票实时价格",
)
2.3 两种方式对比
| 特性 | @tool 装饰器 | StructuredTool.from_function |
|---|---|---|
| 简洁度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 灵活性 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 异步支持 | ✅ | ✅ |
| 适用场景 | 大部分自定义工具 | 需要精细控制的工具 |
3. 工具与模型绑定
3.1 bind_tools:将工具绑定到模型
from langchain.chat_models import init_chat_model
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
@tool
def add(a: int, b: int) -> int:
"""两个整数相加"""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""两个整数相乘"""
return a * b
model = init_chat_model("openai:gpt-4o-mini")
model_with_tools = model.bind_tools([add, multiply])
# LLM 会判断需要调用哪个工具
response = model_with_tools.invoke([HumanMessage(content="10 加 20 等于多少?")])
# 查看工具调用
if response.tool_calls:
for tc in response.tool_calls:
print(f"调用工具: {tc['name']}")
print(f"参数: {tc['args']}")
# 手动执行工具
if tc['name'] == 'add':
result = add.invoke(tc['args'])
print(f"结果: {result}")
3.2 工具调用执行循环
完整的工具调用流程:
from langchain_core.messages import HumanMessage, ToolMessage
# 1. 模型判断需要调用工具
response = model_with_tools.invoke([HumanMessage(content="25乘以4是多少?")])
# 2. 执行工具
tool_results = []
for tc in response.tool_calls:
tool_name = tc['name']
if tool_name == 'multiply':
result = multiply.invoke(tc['args'])
tool_results.append(ToolMessage(
content=str(result),
tool_call_id=tc['id']
))
# 3. 将工具结果返回给模型,获得最终回答
final_response = model_with_tools.invoke([
HumanMessage(content="25乘以4是多少?"),
response, # AI 的工具调用消息
*tool_results, # 工具执行结果
])
print(final_response.content) # 25乘以4等于100
3.3 控制工具调用行为
# 强制调用任意工具
model_with_forced_tool = model.bind_tools(
[add, multiply],
tool_choice="any", # 必须调用某个工具
)
# 强制调用指定工具
model_with_specific = model.bind_tools(
[add, multiply],
tool_choice="add", # 必须调用 add
)
# 禁用并行调用(某些模型支持)
model_serial = model.bind_tools(
[add, multiply],
parallel_tool_calls=False,
)
4. MCP 协议
4.1 什么是 MCP
MCP(Model Context Protocol) 是一种开放的标准化协议,让 AI 应用能够通过统一接口连接各种外部工具和数据源。类似 USB 协议统一了外部设备连接——MCP 统一了工具/数据源的接入方式。
LangChain → MCP Server → 外部服务(数据库/API/文件系统/...)
4.2 MCP 的优势
| 传统方式 | MCP 方式 |
|---|---|
| 每个工具自己写胶水代码 | 统一协议,即插即用 |
| 各服务接口不一致 | 标准化接口 |
| 难以复用和共享 | 社区共享 MCP Server |
| 绑死特定框架 | 跨框架通用(Claude/Cursor/Continue…) |
4.3 使用 MCP 工具
from langchain_mcp_adapters.client import MultiServerMCPClient
# 连接 MCP Server
client = MultiServerMCPClient({
"weather": {
"command": "python",
"args": ["-m", "mcp_server_weather"],
},
"database": {
"command": "python",
"args": ["-m", "mcp_server_sqlite", "--db-path", "data.db"],
},
})
# 获取工具列表
tools = client.get_tools()
for t in tools:
print(f"{t.name}: {t.description}")
# 绑定到模型
model = init_chat_model("openai:gpt-4o-mini")
model_with_mcp = model.bind_tools(tools)
# Agent 会自动调用 MCP 工具
MCP Server 可以用 Python、Node.js 等任何语言编写,也可以安装社区已有的各类 MCP Server(文件系统、数据库、搜索引擎等)。
5. 内置工具
LangChain 提供了丰富的内置工具。
5.1 Tavily 搜索引擎
pip install tavily-python
from langchain_community.tools.tavily_search import TavilySearchResults
search = TavilySearchResults(max_results=3, api_key="your_key")
results = search.invoke("2026年AI最新进展")
for r in results:
print(r["content"])
5.2 Wikipedia 查询
pip install wikipedia
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
result = wikipedia.invoke("量子计算")
print(result)
5.3 Python REPL(代码执行)
from langchain_experimental.tools import PythonREPLTool
repl = PythonREPLTool()
result = repl.invoke("print(sum([i**2 for i in range(10)]))")
# 输出: 285
5.4 文件操作工具
from langchain_community.tools.file_management import (
ReadFileTool, WriteFileTool, ListDirectoryTool, MoveFileTool, CopyFileTool
)
reader = ReadFileTool()
content = reader.invoke({"file_path": "./data.txt"})
writer = WriteFileTool()
writer.invoke({"file_path": "./output.txt", "text": "Hello LangChain"})
6. 工具集 Toolkits
Toolkit 是一组紧密相关的工具集合,开箱即用。
6.1 SQL 数据库工具集
pip install pymysql
from langchain_community.agent_toolkits import SQLDatabaseToolkit
from langchain_community.utilities import SQLDatabase
db = SQLDatabase.from_uri("mysql+pymysql://user:pass@localhost/db")
toolkit = SQLDatabaseToolkit(db=db, llm=model)
tools = toolkit.get_tools()
for t in tools:
print(t.name)
# sql_db_query, sql_db_schema, sql_db_list_tables, sql_db_query_checker
6.2 JSON 工具集
from langchain_community.tools.json.tool import JsonSpec
from langchain_community.agent_toolkits import JsonToolkit
json_spec = JsonSpec(dict_={"name": "产品", "price": 99})
toolkit = JsonToolkit(spec=json_spec)
7. 工具最佳实践
- 描述要精准:工具描述直接决定 LLM 能否正确调用。写明"什么时候用"“输入什么”“输出什么”
- 参数用 Pydantic:
args_schema让 LLM 精确理解参数格式和含义 invoke代替run:v1 统一用invoke()方法- 工具要原子化:每个工具只做一件事,复杂流程用多个工具组合
- 异常处理:工具内部做好错误捕获,返回有意义的错误信息而非 traceback
- MCP 优先:系统级操作(数据库、文件系统、API)优先考虑用 MCP 协议接入
本章小结
| 概念 | 说明 |
|---|---|
| @tool | 最简单的自定义工具方式 |
| StructuredTool | 灵活的工具构造器 |
| bind_tools() | 将工具绑定到模型 |
| tool_choice | 控制工具调用的强制行为 |
| MCP | 标准化工具协议,即插即用 |
| Toolkit | 一组相关工具的集合 |
更多推荐




所有评论(0)