工具调用
让 LangGraph 代理具备调用外部 API 和执行操作的能力
📚 学习目标
学完这篇文章后,你将能够:
- 定义可被 LLM 识别的工具(基于 Zod Schema)
- 将工具绑定到 LLM 模型
- 使用
ToolNode和条件边自动执行工具调用
前置知识
在开始学习之前,建议先阅读:
1 什么是工具调用?
工具调用(Function Calling)是现代 LLM(如 GPT-4, Claude 3)的核心能力。它允许模型:
- 识别用户意图需要使用工具。
- 生成符合工具 Schema 的参数。
- 暂停生成,等待外部运行工具。
- 接收工具运行结果,由于 Context 得到增强,模型能生成最终回答。
在 LangGraph 中,这对应 ReAct 循环。
2 定义工具
我们使用 @langchain/core/tools 中的 tool 函数。
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const weatherTool = tool(
async ({ city }) => {
// 模拟 API 调用
if (city === "Shanghai") return "Sunny, 25°C";
return "Unknown city";
},
{
name: "get_weather",
description: "Get current weather for a city",
schema: z.object({
city: z.string().describe("The city name, e.g. Shanghai"),
}),
}
);代码解析:
name/description不是“装饰品”,它们会直接影响模型是否愿意调用、以及怎么调用。schema越清晰,模型越不容易编造字段或传错类型。
3 设计一个“好用”的工具 Schema
一个常见误区是把工具参数设计得太自由,导致模型每次传参风格都不同。
✅ 推荐:
- 参数字段少而清晰(能拆就拆)
describe()写清楚示例与约束- 输出尽量结构化(JSON),而不是长自然语言
例如,把“搜索工具”设计为结构化输出:
const searchDocs = tool(
async ({ query, topK }) => {
return {
query,
hits: [
{ title: '...', url: '...', snippet: '...' },
],
};
},
{
name: 'search_docs',
description: 'Search internal docs and return topK hits.',
schema: z.object({
query: z.string().min(1).describe('Search query'),
topK: z.number().int().min(1).max(10).default(5),
}),
}
);4 绑定到 LLM
模型必须知道有哪些工具可用。
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({ model: "gpt-4o" });
const llmWithTools = llm.bindTools([weatherTool]);如果你有多个工具,直接都绑上去即可:
const llmWithTools = llm.bindTools([weatherTool, searchDocs]);5 构建 Graph:ToolNode + 条件循环
LangGraph 提供了内置的 ToolNode 来简化工具执行。
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { StateGraph, START, END } from "@langchain/langgraph";
import { MessagesAnnotation } from "@langchain/langgraph";
// 1. 定义节点
const agentNode = async (state) => {
const { messages } = state;
// 调用绑定了工具的 LLM
const response = await llmWithTools.invoke(messages);
return { messages: [response] };
};
const toolNode = new ToolNode([weatherTool]);
// 2. 定义条件路由
const shouldContinue = (state) => {
const lastMessage = state.messages.at(-1);
// 如果 LLM 想要调用工具,转到 'tools' 节点
if (lastMessage.tool_calls?.length) {
return "tools";
}
return END;
};
// 3. 组装 Graph
const app = new StateGraph(MessagesAnnotation)
.addNode("agent", agentNode)
.addNode("tools", toolNode)
.addEdge(START, "agent")
.addConditionalEdges("agent", shouldContinue)
.addEdge("tools", "agent") // 工具执行后回到 agent
.compile();[!TIP] 这段循环结构一旦连上了
tools -> agent,就应该在调用invoke/stream时设置recursionLimit,防止“无限调用工具”。
6 MCP (Model Context Protocol)
MCP 是 Anthropic 提出的一个开放标准,旨在标准化工具的定义和连接。LangGraph 支持通过适配器连接 MCP 服务器。
// 伪代码示例
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
const client = new MultiServerMCPClient({ ... });
const mcpTools = await client.getTools();
// 像普通工具一样使用
const llmWithMCP = llm.bindTools(mcpTools);你可以把 MCP 理解为“工具生态的统一接口”:
- 你不需要为每一种工具都写一套绑定逻辑
- 工具提供方按协议暴露能力,你只需要拉取工具清单并绑定到模型
💡 练习题
-
实战题:编写一个
calculator工具,支持加减乘除。将其集成到一个 Agent 中,测试问它是 "33 * 44 等于多少"。点击查看答案
核心是定义一个带参数校验的
calculatortool,并在 Agent 节点绑定该工具后让模型决定是否调用。 测试 "33 * 44" 时应触发工具调用并返回1452,最后答案里可同时给出计算过程与结果。 -
工程题:给
weatherTool加超时(例如 3s)和失败降级:如果失败,返回 "天气服务暂不可用",并让模型在最终回答中说明原因。点击查看答案
可用
Promise.race包装 3 秒超时,异常统一捕获并返回固定兜底文案。 同时在 tool 返回结构里加errorReason字段,让模型在最终回复中明确说明“数据因超时/服务故障不可用”。
✅ 总结
本章要点:
- Schema:清晰的 Zod 定义是 LLM 正确调用工具的关键。
- ToolNode:LangGraph 内置的
ToolNode帮你处理了参数解析和结果回传。 - Cycle:Agent -> Tools -> Agent 是最经典的循环。
下一步:如何保存应用状态,实现“断点续传”?学习持久化。
登录以继续阅读
解锁完整文档、代码示例及更多高级功能。