2026/5/20 11:27:15
网站建设
项目流程
创办一个网站需要多少费用,网页图片高清,网站规划的原则有哪些,网站开发过程记录在之前的学习中#xff0c;我们眼中的大模型#xff08;LLM#xff09;更像是一个博学但封闭的“大脑”。它能陪你聊天、写诗、解释复杂的概念#xff0c;但它有一个致命的弱点#xff1a;它无法触及外部世界。
它不知道此时此刻北京的天气#xff08;因为它只有历史数据…在之前的学习中我们眼中的大模型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 时才执行 }它的作用是安全地访问嵌套对象的属性一旦中间某个值为null或undefined表达式会立即短路返回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智能体最基础的雏形定义利用zod和tool定义清晰的函数边界。绑定利用bindTools赋予大模型选择权。解析利用tool_calls获取模型的决策。执行在本地运行代码并获取结果。为什么这很重要这就好比给大脑LLM接上了手Tools。虽然在这个简单的例子中我们需要手动写 if/else 来判断执行哪个工具但在更高级的 LangChain Agent 模块中这一过程是自动化的——模型会自己“观察”结果甚至根据结果进行下一轮的思考ReAct 模式。