让大模型“动手”:用 LangChain 工具扩展 AI 能力

68 阅读4分钟

让大模型“动手”:用 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()
    })
  }
);
  • 函数体:接收 ab,返回它们的和(转成字符串)。
  • 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 不仅能聊天,还能在需要时自动调用 addget_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) { ... }

可选链让代码更简洁安全。

运行后,你会看到输出:

image.png

完美! 我们再问模型一个问题:

const res = await model.invoke("3 + 5等于多少?");

模型分析这句哈,并决定调用add工具 运行一下,看到输出:

image.png

大模型会根据对用户输入的理解,自主决定是否需要调用工具,并生成相应的工具调用请求(tool call)


🧠 总结:Tool 的工作流程

  1. 定义工具:用 tool() 包装函数,加上名字、描述和参数规则。
  2. 绑定工具:通过 .bindTools() 告诉模型“你有这些技能”。
  3. 模型推理:用户提问 → 模型判断是否需要调用工具。
  4. 执行调用:程序检查 tool_calls,手动运行对应函数,获取真实结果。
  5. 返回答案:把结果组装成自然语言,回复用户。

🌟 写在最后

LangChain 的 Tool 机制,就像是给大模型配上了“外挂大脑”——它不再局限于训练数据中的知识,而是能实时与外部世界互动。无论是查数据库、调 API,还是控制智能家居,只要封装成 Tool,AI 就能“动手”完成。

下一步,你可以尝试接入真实 API、数据库,甚至让 AI 控制你的智能家居——想象力是唯一边界。