当前位置: 首页 > news >正文

LangChain 第四课:拒绝“纸上谈兵”,给大模型装上“双手”

在之前的学习中,我们眼中的大模型(LLM)更像是一个博学但封闭的“大脑”。它能陪你聊天、写诗、解释复杂的概念,但它有一个致命的弱点:它无法触及外部世界

它不知道此时此刻北京的天气(因为它只有历史数据),它算不好复杂的加减乘除(因为它是基于概率预测文字,而不是计算器),它更无法帮你查询数据库。

今天这一课,我们将通过 LangChain 的Tools(工具)模块,打破这层次元壁。我们将学习如何将自定义函数变成大模型可以调用的“工具”,让 AI 从“只会聊天”进化为“能干实事”。

为什么需要 Tools?

大模型的核心能力是理解意图和生成文本。当我们把“工具”引入系统时,我们实际上是在通过 Prompt 告诉大模型:

“嘿,我这里有一个查天气的函数和一个做加法的函数。如果用户问的问题涉及到这两个领域,不要自己瞎编,请告诉我你需要用哪个函数,以及参数是什么。”

这就是Function Calling(函数调用)的核心逻辑。

在本文中,我们将构建一个基于 DeepSeek 模型的应用,通过两个具体的工具——天气查询器加法计算器,来演示这一过程。

第一步:定义工具(The “Hands”)

在 LangChain 中,定义一个工具不仅仅是写一个函数,我们还需要告诉大模型这个工具是干什么用的(Description),以及它需要什么参数(Schema)。

我们需要引入zod库来进行参数的类型验证,这是连接自然语言与程序代码的桥梁。

1. 模拟一个天气数据库

首先,因为我们没有真实的 API key,我们用一个对象来模拟数据库:

// 模拟的天气数据库 const fakeWeatherDB = { 北京: { temp: "30摄氏度", condition: "晴", wind: "微风"}, 上海: { temp: "28摄氏度", condition: "多云", wind: "强"}, 广州: { temp: "26摄氏度", condition: "阴", wind: "中"}, }

2. 创建天气工具

我们使用@langchain/core/tools中的tool方法来封装逻辑。

请注意schema部分。我们使用z.object定义了输入必须包含city字段,并且必须是字符串。这非常关键,因为大模型会根据这个定义,从用户的自然语言(如“北京今天咋样”)中提取出{ city: "北京" }

import { tool } from '@langchain/core/tools'; import { z } from 'zod'; 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("要查询天气的城市") // 参数描述 }) } )

3. 创建加法工具

同理,大模型通常不擅长精确数学计算。我们可以给它一个计算器:

const addTool = tool( async ({a, b}) => String(a + b), // 将结果转为字符串返回给模型 { name: 'add', description: '计算两个数字的和', schema: z.object({ a: z.number(), b: z.number() }) } )

第二步:绑定模型(The “Brain”)

有了工具,我们还需要让“大脑”知道它们的存在。我们将使用ChatDeepSeek模型,并通过.bindTools()方法将刚才定义的工具箱挂载到模型上。

import { ChatDeepSeek } from '@langchain/deepseek'; import 'dotenv/config'; const model = new ChatDeepSeek({ model: 'deepseek-chat', temperature: 0 // 设置为0,让模型更理性,专注于任务执行 }).bindTools([addTool, weatherTool]);

.bindTools()是整个流程的点睛之笔。它并不会改变模型的内部权重,而是将工具的描述和 Schema 转换成特定格式的 System Prompt 发送给大模型,让模型进入“待命状态”。

第三步:调用与执行(The Action)

现在,让我们看看当我们向模型提问时,究竟发生了什么。

场景一:用户询问天气

const res = await model.invoke("北京今天的天气怎么样?");

如果是普通的聊天模型,它可能会回答:“作为一个 AI 我无法联网…”。

但因为绑定了工具,模型会分析语意,发现这匹配了 get_weather 的描述。

此时,模型并没有直接执行代码(切记,大模型只是文本生成器,它运行不了 JS 代码)。它返回的res对象中包含了一个特殊的属性:tool_calls

让我们打印看看res.tool_calls[0]长什么样:

{ name: 'get_weather', args: { city: '北京' }, type: 'tool_call', id: 'call_00_xyz...' }

模型准确地提取了函数名和参数!

JavaScript 小贴士:优雅的可选链(Optional Chaining)

在处理模型返回结果时,我们需要非常小心。因为模型不一定总是调用工具。如果用户问“你好”,模型可能只返回文本,此时tool_calls是 undefined。

在传统代码中,我们可能需要这样写防御性代码:

// 繁琐的写法 if (res.tool_calls && res.tool_calls.length > 0) { // 执行逻辑 }

但在 ES6+ 中,我们可以使用可选链操作符 (?.)来让代码更优雅:

// 优雅的写法 if (res.tool_calls?.length) { // 只有当 tool_calls 存在且长度不为 0 时,才执行 }

它的作用是安全地访问嵌套对象的属性,一旦中间某个值为nullundefined,表达式会立即短路返回undefined,而不会报错导致程序崩溃。

第四步:闭环(执行工具逻辑)

最后一步,我们需要在代码中捕获模型的“意图”,并在本地执行真正的函数,然后获取结果。

if(res.tool_calls?.length) { const toolCall = res.tool_calls[0]; // 获取第一个工具调用请求 console.log("模型请求调用工具:", toolCall.name); if (toolCall.name === 'add') { // 调用加法工具 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); } }

当我们运行这段代码时,控制台将输出:

最终结果: 城市北京的天气是30摄氏度, 晴, 风力微风

如果用户问数学题呢?

如果我们把输入改为:model.invoke(“3 + 5等于多少?”)。

模型会返回 name: ‘add’ 和 args: { a: 3, b: 5 }。

我们的代码会命中 add 分支,最终输出 8。

总结与思考

通过今天的课程,我们揭开了 AI Agent(智能体)最基础的雏形:

  1. 定义:利用zodtool定义清晰的函数边界。
  2. 绑定:利用bindTools赋予大模型选择权。
  3. 解析:利用tool_calls获取模型的决策。
  4. 执行:在本地运行代码并获取结果。

为什么这很重要?

这就好比给大脑(LLM)接上了手(Tools)。虽然在这个简单的例子中,我们需要手动写 if/else 来判断执行哪个工具,但在更高级的 LangChain Agent 模块中,这一过程是自动化的——模型会自己“观察”结果,甚至根据结果进行下一轮的思考(ReAct 模式)。

http://www.jsqmd.com/news/268497/

相关文章:

  • rocketMq源码简介
  • 克拉玛依英语雅思辅导机构推荐,2026权威出国雅思课程口碑排行榜 - 老周说教育
  • 德事TEC大中华区布局全景:从北京国贸到上海陆家嘴,240+据点如何满足企业全球化需求 - 资讯焦点
  • 2026适老化拐杖优质厂家推荐榜聚焦安全性能 - 资讯焦点
  • 单机单卡部署
  • Redis 性能问题全解析:90% 的人都把活干错了地方
  • 新疆维吾尔族自治区乌鲁木齐英语雅思辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 老周说教育
  • PW6606 PD Sink受电端快充协议芯片,大幅减少外围元件数量
  • AI开发者必读:Qwen2.5开源模型支持多语言推理的落地实践
  • 2026 年 1 月推荐,中国 AI 智能体获客靠谱老师谁最专业?麟哥不值得优先选?
  • α-MSH (free acid) (Acetyl-ACTH (1-13)) ;Ac-Ser-Tyr-Ser-Met-Glu-His-Phe-Arg-Trp-Gly-Lys-Pro-Val
  • α-MSH (11-13) ;Lys-Pro-Val-NH2
  • α-Helical CRF (9-41) (CRF antagonist) ;H-DLTFHLLREMLEMAKAEQEAEQAALNRLLLEE A-NH₂
  • 厉害了!中科院2区权威顶刊,投稿量激增18000+!
  • ARIMA与SARIMA:时间序列预测的经典基石
  • α-Neoendorphin (1-6) (Leu-Enkephalin-Arg, Dynorphin A (1-6));Tyr-Gly-Gly-Phe-Leu-Arg
  • 智能水控四大优势,改写多场景用水管理格局:精准计量+智能调控!
  • 小程序毕设选题推荐:基于小程序的高校校友会在线交流管理系统基于springboot+小程序的高校学院校友会系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 单片机超市RFID射频安全防盗报警系统+GSM上报设计(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 太阳总辐射传感器:能源、气象领域的关键测量工具
  • 救大命!Legion Go 外接屏变竖屏?两步快速恢复横屏显示!
  • 联想百应账号注销指南:小程序 + PC 端分步操作,这些注意事项必看!
  • 基于MATLAB的球轴承拟静力学计算实现
  • 小程序毕设项目推荐-基于nodejs+微信小程序的垃圾分类管理、垃圾知识管理垃圾分类和回收系统【附源码+文档,调试定制服务】
  • 兽医影像自适应特征选择误诊率直降
  • 联想设备相机异常?台式 / 笔记本 / ThinkPad 通用排查指南来了!
  • 只投影竖直条纹的话,在双目中可以利用极线约束来求解全局相位
  • 手搓HTML模板引擎:比Jinja2快3倍的動態頁面生成器
  • 阅读理解【牛客tracker 每日一题】
  • 深度学习框架YOLOV8模型如何训练苹果小目标检测数据集 建立基于YOLOV8深度学习框架苹果小目标检测系统