让大模型“动手”:用 LangChain 工具扩展 AI 能力
你有没有想过,如果大语言模型(LLM)不仅能“说”,还能“做”点什么,那该多酷?比如,让它帮你查天气、算账单,甚至订机票——这些能力背后,其实依赖一种叫 工具调用(Tool Calling) 的技术。,我们可以赋予大模型调用外部函数的能力,就像给它装上一双“手”。
今天我们就通过一个简单又实用的例子,来初步理解 LangChain 中的 Tool 是怎么工作的。
🧰 什么是 Tool?
在 LangChain 里,Tool 就是一个可以被大模型调用的函数。你可以把它想象成一个“技能卡”:模型看到问题后,会判断是否需要使用某张技能卡来完成任务。
比如:
- 用户问:“3 加 5 等于多少?” → 模型决定调用
add工具。 - 用户问:“北京今天天气怎么样?” → 模型决定调用
get_weather工具。
关键在于:不是我们硬编码让模型去调用,而是模型自己判断要不要调、调哪个。这种“自主决策”能力,正是智能代理(Agent)的核心。
🛠️ 定义你的第一个 Tool
LangChain 提供了 tool 函数,让我们轻松把普通函数包装成模型能理解的“工具”。来看两个例子:
1. 加法工具:addTool
const addTool = tool(
async ({ a, b }) => String(a + b),
{
name: "add",
description: "计算两个数字的和",
schema: z.object({
a: z.number(),
b: z.number()
})
}
);
- 函数体:接收
a和b,返回它们的和(转成字符串)。 - name:工具的名字,模型靠它识别。
- description:告诉模型这个工具是干啥的。
- schema:用
zod定义输入参数的格式,确保模型传参合法。
2. 天气工具:weatherTool
const fakeWeatherDB = {
北京: { temp: "30°C", condition: "晴", wind: "微风" },
上海: { temp: "28°C", condition: "多云", wind: "东风 3 级" },
广州: { temp: "32°C", condition: "阵雨", wind: "南风 2 级" },
};
const weatherTool = tool(
async ({ city }) => {
const weather = fakeWeatherDB[city];
if (!weather) {
return `暂无${city}的天气信息`;
}
return `当前${city}的天气是${weather.temp}, ${weather.condition}, 风力${weather.wind}`;
},
{
name: "get_weather",
description: "查询指定城市的今日天气情况",
schema: z.object({
city: z.string().describe("要查询天气的城市")
})
}
);
这里我们模拟了一个“天气数据库”,工具根据城市名返回天气信息。如果城市不在库里,就友好提示“暂无信息”。
🌦️ 这就像给 AI 配了个“天气预报小助手”,它不用背数据,只需知道怎么问。
🔗 把工具“绑”给大模型
定义好工具后,下一步是让大模型知道它有这些“技能”。这一步叫 绑定(bind) :
const model = new ChatDeepSeek({
model: "deepseek-chat",
temperature: 0
}).bindTools([addTool, weatherTool]);
现在,这个 model 不仅能聊天,还能在需要时自动调用 add 或 get_weather。
🧪 实际调用:看模型如何“动手”
我们让模型回答一个问题:
const res = await model.invoke("北京今天的天气怎么样?");
模型内部会分析这句话,发现涉及“天气”和“北京”,于是决定调用 get_weather 工具,并传入 { city: "北京" }。
但注意:模型不会直接返回结果,而是先返回一个“工具调用请求” 。我们需要手动执行这个请求:
if (res.tool_calls?.length) {
const call = res.tool_calls[0];
if (call.name === 'get_weather') {
const result = await weatherTool.invoke(call.args);
console.log("最终结果", result);
}
}
🔍 这里的
?.是 JavaScript 的可选链操作符(ES2020 引入),意思是:“如果res.tool_calls存在,再取它的length;否则直接返回undefined,不报错。”
没它的话,代码就得写成:if (res.tool_calls && res.tool_calls.length) { ... }可选链让代码更简洁安全。
运行后,你会看到输出:
完美! 我们再问模型一个问题:
const res = await model.invoke("3 + 5等于多少?");
模型分析这句哈,并决定调用add工具 运行一下,看到输出:
大模型会根据对用户输入的理解,自主决定是否需要调用工具,并生成相应的工具调用请求(tool call)
🧠 总结:Tool 的工作流程
- 定义工具:用
tool()包装函数,加上名字、描述和参数规则。 - 绑定工具:通过
.bindTools()告诉模型“你有这些技能”。 - 模型推理:用户提问 → 模型判断是否需要调用工具。
- 执行调用:程序检查
tool_calls,手动运行对应函数,获取真实结果。 - 返回答案:把结果组装成自然语言,回复用户。
🌟 写在最后
LangChain 的 Tool 机制,就像是给大模型配上了“外挂大脑”——它不再局限于训练数据中的知识,而是能实时与外部世界互动。无论是查数据库、调 API,还是控制智能家居,只要封装成 Tool,AI 就能“动手”完成。
下一步,你可以尝试接入真实 API、数据库,甚至让 AI 控制你的智能家居——想象力是唯一边界。