工具调用与 Agent
构建真正的智能体:让 LLM 学会使用工具(Tool Calling)
📚 学习目标
学完这篇文章后,你将能够:
- 使用
@langchain/core/tools定义自定义工具 - 使用
bindTools将工具能力赋予 LLM - 使用预构建的 ToolNode 执行工具调用
- 复现经典的 ReAct(Reasoning + Acting)Agent 模式
前置知识
在开始学习之前,建议先阅读:
1️⃣ 什么是 Agent?
简单来说,Agent = LLM + Tools + Loop。
- LLM 负责思考:理解用户意图,决定是否需要使用工具,以及使用哪个工具。
- Tools 负责行动:执行具体任务(查天气、算数学、搜网页)。
- Loop 负责循环:思考 → 行动 → 再思考 → 再行动,直到任务完成。
2️⃣ 定义工具 (Define Tools)
我们使用 tool 函数和 zod schema 来定义工具。Schema 非常重要,因为它告诉 LLM 该如何正确调用这个工具。
import { tool } from "@langchain/core/tools";
import z from "zod";
// 定义天气查询工具
const getWeather = tool(
async (input) => {
// 工具实现的实际逻辑(例如调用 API)
return `查询结果:${input.city} 今天晴,25°C`;
},
{
name: 'getWeather',
description: '获取指定城市的天气',
// 参数 Schema
schema: z.object({
city: z.string().describe('城市名称,如北京'),
})
}
);
const tools = [getWeather];3️⃣ 赋予 LLM 工具能力
LangChain 提供了 bindTools 方法,将工具定义转换为 LLM 能理解的 JSON Schema 格式。
// 1. 实例化 LLM
const llm = new ChatOpenAI({ model: 'qwen3-max' });
// 2. 绑定工具
const llmWithTools = llm.bindTools(tools);
// 3. 节点逻辑
const agentNode = async (state) => {
// LLM 会智能决定是返回普通文本,还是返回工具调用请求
const result = await llmWithTools.invoke(state.messages);
return { messages: [result] };
}4️⃣ 执行工具调用 (ToolNode)
LangGraph 提供了一个预构建的节点 ToolNode,它能自动解析 LLM 的工具调用请求,执行对应的工具,并将结果返回。
import { ToolNode } from '@langchain/langgraph/prebuilt';
const toolNode = new ToolNode(tools);5️⃣ 构建 ReAct 循环
我们需要一个条件路由逻辑:
- 如果 LLM 想要调用工具 (
tool_calls) → 去tools节点。 - 如果 LLM 只是普通回复 → 结束。
// 路由函数
const shouldContinue = (state) => {
const lastMessage = state.messages[state.messages.length - 1];
// 检查是否有工具调用请求
if (lastMessage.tool_calls?.length) {
return 'tools';
}
return END;
}
// 构建图
const graph = new StateGraph(StateAnnotation)
.addNode('agent', agentNode)
.addNode('tools', toolNode)
.addEdge(START, 'agent')
// 条件边
.addConditionalEdges('agent', shouldContinue, {
tools: 'tools',
[END]: END
})
// 工具执行完后,必须回到 agent 节点,让 LLM 看到结果并继续思考
.addEdge('tools', 'agent')
.compile();下面的 Mermaid 图展示了这个经典的循环:
💡 练习题
- 实操题:向你的 Agent 添加一个
calculate工具(可以使用 JavaScript 的eval或mathjs),试着问它:"北京的天气怎么样?然后计算 123 * 456 是多少?"。观察它是否能连续调用两个工具。 - 思考:
ToolNode执行完具后,为什么要连回agent节点?如果连向END会发生什么?(参考答案:连回 agent 是为了让 LLM 能够基于工具的返回结果生成最终的自然语言回复,或者决定是否需要进行下一步操作。直接连向 END 会导致用户只看到工具的原始输出,而不是 LLM 的解读。)
📚 参考资源
官方文档
项目代码
- 查看本节完整代码:quick-start/6.tools.ts
✅ 总结
核心要点:
- Schema 定义了一切:工具的描述和参数定义决定了 LLM 能否正确使用它。
- bindTools 是链接 LLM 和代码实现的桥梁。
- ReAct 循环(Agent → Tools → Agent)是现代 AI Agent 的基石。
下一步:在下一篇文章《记忆与持久化》中,我们将学习如何让 Agent 记住上下文,实现多轮连续对话。
登录以继续阅读
解锁完整文档、代码示例及更多高级功能。