Tool 与 Function Calling

Tool 是 LangChain Agent 调用外部世界的方式。Function Calling 是 LLM 调 Tool 的底层协议。


什么是 Tool?

Tool = 让 LLM 能够执行外部动作的函数封装。

1
2
3
4
5
6
传统 LLM:
输入 → LLM → 输出文本

带 Tool 的 LLM:
输入 → LLM → [需要执行 search] → search() → 结果 → LLM → 最终回答
↑ 工具调用 ↑ 工具返回

定义 Tool

方式 1:@tool 装饰器(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain_core.tools import tool

@tool
def search_wiki(query: str) -> str:
"""在维基百科搜索相关词条"""
# 真实实现中这里调用 Wikipedia API
return f"关于'{query}'的搜索结果..."

@tool
def calculate(expression: str) -> float:
"""执行数学计算"""
return eval(expression) # 注意:真实场景要用安全计算器

tools = [search_wiki, calculate]

方式 2:StructuredTool(更正式)

1
2
3
4
5
6
7
8
from langchain_core.tools import StructuredTool

search_tool = StructuredTool.from_function(
name="search_wiki",
description="在维基百科搜索相关词条",
func=lambda query: wikipedia.search(query),
return_direct=False
)

绑定 Tool 到模型

1
2
3
4
5
6
7
8
9
10
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

llm = ChatOpenAI(model="gpt-4o")

# 方式1:bind_tools(推荐,简洁)
llm_with_tools = llm.bind_tools(tools)

# 方式2:with_configurable_tools
llm_with_tools = llm.with_configurable_tools(tools=[search_wiki, calculate])

调用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 第一次调用:LLM 判断需要调用哪个 Tool
response = llm_with_tools.invoke("查一下水的沸点是多少")

print(response) # AIMessage with tool_calls
# AIMessage(
# content='',
# tool_calls=[
# {
# 'name': 'search_wiki',
# 'args': {'query': '水的沸点'},
# 'id': 'call_xxx'
# }
# ]
# )

解析 Tool 调用结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from langchain_core.messages import HumanMessage, AIMessage, ToolMessage

# 用户问题
messages = [HumanMessage(content="水的沸点是多少")]

# 1. LLM 判断调用 Tool
ai_response = llm_with_tools.invoke(messages)
messages.append(ai_response)

# 2. 执行 Tool,获取结果
tool_result = search_wiki.invoke(ai_response.tool_calls[0].args)
messages.append(ToolMessage(content=tool_result, tool_call_id=ai_response.tool_calls[0].id))

# 3. 再次调用 LLM,传入 Tool 结果
final_response = llm.invoke(messages)
print(final_response.content) # "水的沸点是100°C..."

create_react_agent(自动完成上述循环)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain.agents import create_react_agent

llm = ChatOpenAI(model="gpt-4o")
agent = create_react_agent(llm, tools)

# 一次性调用,Agent 自动完成推理→调用→再推理→返回
result = agent.invoke({"input": "水的沸点是多少摄氏度?加上273.15转成开尔文"})

print(result["output"])
# Agent 会自动:
# 1. 搜索"水的沸点" → 100°C
# 2. 计算 100 + 273.15 = 373.15K
# 3. 返回结果

Tool 的输入输出设计

输入设计原则

原则说明
名字清晰search_wikisearch 更明确
描述详细描述会发给 LLM,帮助它判断何时调用
类型严格用 Pydantic 或类型注解限定输入
单一职责一个 Tool 做一件事
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@tool
def search_flights(
origin: str,
destination: str,
date: str,
max_price: float | None = None
) -> str:
"""搜索航班信息

Args:
origin: 出发地机场代码(如 PEK, SHA)
destination: 目的地机场代码
date: 出发日期,格式 YYYY-MM-DD
max_price: 最高票价(可选)
"""
...

输出设计原则

原则说明
返回字符串Tool 的返回必须是字符串
信息完整包含 LLM 回答所需的所有信息
结构化尽量返回 JSON 或格式化文本

并行 Tool 调用

多个独立 Tool 可以并行执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@tool
def get_weather(city: str) -> str:
"""获取城市天气"""
...

@tool
def get_news(topic: str) -> str:
"""获取新闻"""
...

# 模型可以同时决定调用两个工具
llm_with_tools = llm.bind_tools([get_weather, get_news])
response = llm_with_tools.invoke("北京今天天气和最新科技新闻")
# response.tool_calls 可能有多个 ToolCall

Agent 类型选择

Agent特点适用场景
create_react_agentReAct(推理+行动交替)通用场景,最常用
create_conversational_agent对话式,有记忆聊天机器人
create_openai_functions_agentOpenAI Function Calling需要精确工具选择
create_self_ask_agentSelf-Ask with Search需要搜索验证的场景

MCP + LangChain(扩展)

MCP(Model Context Protocol)是新标准,让 Tool 调用更统一:

1
2
3
4
5
6
7
8
9
# LangChain MCP 适配器
from langchain_mcp_adapters import MCPClient

# 连接到 MCP Server
client = MCPClient.from_config_file("servers_config.json")

# 工具自动注册到 LangChain
tools = client.get_tools()
agent = create_react_agent(llm, tools)

详见 11-新兴协议/MCP协议