大模型无法处理精确计算和实时信息,通过LangChainTool定义加法、天气查询等功能,借助Zod规范参数,将工具绑定到模型后,模型可识别任务并调用对应工具获取结果,实现从文本生成到真实世界操作的跨越。
在正式动手写代码之前,先聊一个关键问题:为什么 ChatGPT 连简单的加减法都搞不定?为什么它不知道今天北京的天气?
答案很简单:大模型的本质是概率预测,它是基于训练数据生成下一个字,而不是基于逻辑运算或实时数据库。说白了,它更像一个“文科生”——擅长模仿,不擅长精确计算。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
LangChain Tool 的出现,就是为了解决这个短板。它的核心思路是:当用户问“1234 + 5678 等于几?”时,大模型不再自己瞎猜,而是分析出“哦,这是一个计算任务”,然后告诉程序:“请帮我调用 add 工具,参数是 a=1234, b=5678”。程序运行完代码后,把结果反馈给用户。
听起来很酷?接下来,我们一步步通过代码把这个过程落地。
先从最基础的讲起:如何定义一个工具。
在 LangChain 中,tool 函数是核心入口。我们需要引入它,并配合 zod 库来定义参数结构。
import { ChatDeepSeek } from "@langchain/deepseek";
import 'dotenv/config';
import { tool } from "@langchain/core/tools";
import { z } from "zod"; // 关键:用于定义函数参数的类型 schema
这里重点聊聊 zod。大模型输出的是文本(JSON 字符串),而我们的函数需要的是具体变量(比如数字、字符串)。Zod 的作用就是建立一个“契约”:它告诉大模型,“如果你要调用这个工具,你必须给我传什么样的参数,是数字还是字符串”。这能大大提升工具调用的准确性和健壮性。
addTool)先从最简单的加法开始,让大模型学会算术。
// 函数 定义一个加法工具
const addTool = tool(
// 1. 工具的具体逻辑(函数体)
// 这里接收一个对象,解构出 a 和 b
// 注意:所有工具函数的参数通常都会被包装成一个对象
async ({a, b}) => String(a + b),
{
// 2. 工具的元数据(Metadata)
name: "add", // 工具名称,大模型通过这个名字识别工具
description: "计算两个数字的和", // 工具描述,非常重要!这相当于写给大模型的 Prompt,告诉它什么时候用这个工具
// 3. 参数 Schema 定义
schema: z.object({
a: z.number().describe("加数 a"), // 明确告诉模型,a 必须是一个数字
b: z.number().describe("加数 b") // b 也必须是一个数字
})
}
)
代码深度解析:
tool(function, options):这是定义工具的标准范式。第一个参数是实际执行的 Ja vaScript 函数,第二个参数是配置对象。async ({a, b}):LangChain 的工具调用通常是异步的。参数被设计为解构形式,这是为了配合 Zod 定义的 Object Schema。description:千万不要忽视描述!大模型正是通过这段文字来判断用户的问题是否需要使用该工具。如果描述写得含糊,模型可能就不会调用它。z.number():这里限制了 a 和 b 必须是数字。如果模型抽风传了字符串,Zod 会在底层进行校验或报错,保证程序的健壮性。学会了简单的加法,我们来模拟一个更贴近真实场景的业务——查询天气。由于没有连接真实的气象局 API,这里用了一个“伪数据库”来模拟。
const fakeWeatherDB = {
北京: { temp: "30°C", condition: "晴", wind: "微风" },
上海: { temp: "28°C", condition: "多云", wind: "东风 3 级" },
广州: { temp: "32°C", condition: "阵雨", wind: "南风 2 级" }
}
weatherTool)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({
// z.string() 规定参数 city 必须是字符串
// .describe() 进一步解释参数含义,帮助模型提取正确的实体
city: z.string().describe("要查询天气的城市")
})
}
)
知识点延伸:在 weatherTool 中,我们看到工具不仅仅是计算,还可以是查表、请求 API、读取文件。
if(!weather)。在真实开发中,工具内部做好错误处理非常重要,否则一个异常可能导致整个对话崩塌。工具定义好了,就像家里买了吸尘器和洗碗机,但如果作为“管家”的大模型不知道它们的存在,也是白搭。我们需要将工具**绑定(Bind)**到模型上。
// 实例化 DeepSeek 模型
const model = new ChatDeepSeek({
model: 'deepseek-chat',
temperature: 0 // 设置为 0,让模型更理性、逻辑更严密,减少胡言乱语
}).bindTools([addTool, weatherTool]) // 核心步骤:绑定工具数组
解析:
.bindTools([...]):这一步发生了很多魔法。LangChain 会自动将我们定义的 addTool 和 weatherTool 的 name、description 以及 zod schema 转换成 OpenAI 兼容的 JSON 格式,并发送给 DeepSeek 模型。万事俱备,只欠东风。我们向模型提问,看看它如何反应。
// 发起提问
const res = await model.invoke('北京今天的天气怎么样');
当这句话发出去后,DeepSeek 会进行如下思考:
get_weather 工具吗?有。.) 的妙用模型返回的 res 对象中,包含了很多信息。如果模型决定调用工具,res.tool_calls 属性就会有值。
// 可选链运算符 es6 新增 代码的简洁和优雅
// 传统写法(繁琐):
// if(res.tool_calls){
// if(res.tool_calls.length){
// // ...
// }
// }
// 现代写法(推荐):
if(res.tool_calls.length){
console.log("模型决定调用工具:", res.tool_calls);
// 获取第一个工具调用的指令
const toolCall = res.tool_calls[0];
// 根据工具名称,分发执行逻辑
if(toolCall.name === 'add'){
// 执行加法工具
// toolCall.args 包含了模型提取好的参数 {a: ..., b: ...}
const result = await addTool.invoke(toolCall.args);
console.log("加法工具运行结果:", result);
}
else if(toolCall.name === 'get_weather'){
// 执行天气工具
const result = await weatherTool.invoke(toolCall.args);
console.log("天气工具运行结果:", result);
}
}
res.tool_calls 看看:[图片占位]
知识点详解:可选链运算符 (.)
在 Ja vaScript 中,处理深层嵌套的对象属性时,经常会遇到 Cannot read property of undefined 的报错。
res.tool_calls 可能不存在(如果模型认为不需要调用工具,只是普通聊天)。.,我们需要写多层 if 判断来确保安全。res.tool_calls.length 的意思是:如果 res.tool_calls 存在(不为 null 或 undefined),则读取 .length;否则,直接返回 undefined,不会报错。配合 if 语句,undefined 会被视为 false,逻辑非常通顺。这一小小的语法糖,极大地提升了代码的简洁性和优雅度,是现代 JS 开发的必备技巧。
让我们回顾一下这段代码运行的完整生命周期:
tool() 和 zod 精确描述了 add 和 get_weather 两个工具的功能和参数格式。.bindTools() 将这些能力的“说明书”发给了 DeepSeek 大模型。get_weather 工具,并精准提取出 city: "北京"。tool_calls 的响应对象。. 安全地检测到调用请求,并在本地运行了 weatherTool 函数,通过查阅 fakeWeatherDB 得到了结果。当你运行这段代码(node index.js),控制台会输出:
[{name: 'get_weather',args: { city: '北京' },id: 'call_xxxxxxxxx'}]
最终结果: 当前北京的天气是30°C,晴, 风力微风
如果你把问题改成 model.invoke('100 加 200 等于几'),它会自动切换逻辑:
[{name: 'add',args: { a: 100, b: 200 },id: 'call_yyyyyyyyy'}]
最终结果: 300
通过这篇文章,我们不仅学习了 LangChain 中 tool 的基础用法,还掌握了如何利用 zod 进行数据验证,以及使用 ES6+ 的可选链运算符编写健壮的代码。
Tools 模块彻底改变了大模型的应用形态。它让大模型从一个“只读”的百科全书,进化成了一个能“读写”现实世界的智能袋里(Agent)。
赶快打开你的编辑器,试着定义属于你自己的工具吧!不管是查询股票、发送邮件,还是控制智能家居,LangChain 都能帮你实现。
本文代码示例基于 LangChain.js 最新版本。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述