掘金 人工智能 4小时前
LangChain.js学习笔记(三)函数调用
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了LangChain中工具调用的概念和使用方法,通过工具抽象将TypeScript函数与名称、描述和输入模式关联,使AI模型能够调用代码以增强自身能力。文章详细讲解了如何使用`tool`函数创建工具、绑定工具到模型,以及模型如何根据输入的相关性决定何时调用工具。同时,还介绍了如何将工具执行的工件传递给链或代理中的下游组件,以及如何利用`RunnableConfig`对象将自定义运行时值传递给工具。最后,通过一个完整的示例,演示了如何利用工具调用来执行函数,并将结果返回给模型,最终生成针对原始问题的答案。

🧰LangChain中的工具抽象将TypeScript函数与定义函数名称、描述和输入的模式关联起来,工具可以传递给支持工具调用的聊天模型,允许模型请求执行具有特定输入的特定函数,以此增强AI模型的能力。

🛠️使用`tool`函数可以简化工具的创建过程,该函数支持定义返回工件/artifacts(如图像等)的工具,并支持使用注入的工具参数从模式中隐藏输入参数,同时,LangChain 提供了标准化的接口,用于将工具连接到模型,`.bindTools()`方法可用于指定模型可以调用哪些工具。

🤖模型根据输入的相关性决定何时使用工具,并非总是需要调用。当模型选择调用工具时,其响应将包含工具调用的参数,这些参数可以直接传递给工具执行,且工具实现了Runnable接口,可以直接被调用。

🔄为了将工具输出传递给聊天模型,需要利用模型生成的参数来调用工具函数,并使用LangChain的ToolCall调用Tool,它会自动返回一个可以反馈给模型的ToolMessage,每个ToolMessage必须包含与模型原始工具调用中id相匹配的tool_call_id,以便模型将工具响应与工具调用关联起来。

前面学了如何构建提示词、加载文档/网页内容、检索、嵌入等等,实现简单的RAG,下面再来继续学一下函数调用,让ai调用代码能力实现对ai能力的增强

工具概念

概述

LangChain 中的工具抽象将 TypeScript 函数与定义函数名称描述输入模式关联起来。

工具可以传递给支持工具调用的聊天模型,允许模型请求执行具有特定输入的特定函数。

核心概念

工具接口

工具接口在 StructuredTool 类中定义,该类是 Runnable 接口的子类。

与工具模式对应的关键属性:

工具关联的执行函数的关键方法:

使用 tool 函数创建工具

推荐使用 tool 函数创建工具。该函数旨在简化工具创建过程,在大多数情况下应使用此方法。

import { tool } from "@langchain/core/tools";import { z } from "zod";const multiply = tool(  ({ a, b }: { a: number; b: number }): number => {    /**     * 两个数字相乘。     */    return a * b;  },  {    name: "multiply",    description: "两个数字相乘",    schema: z.object({      a: z.number(),      b: z.number(),    }),  });

有关如何创建工具的更多详细信息,请参阅如何创建自定义工具指南。

LangChain 还有其他几种创建工具的方法;例如,通过子类化 StructuredTool 类或使用 StructuredTool。这些方法在如何创建自定义工具指南中展示,但我们通常推荐在大多数情况下使用 tool 函数。

直接使用工具

定义工具后,可以通过调用函数直接使用它。例如,使用上面定义的 multiply 工具:

await multiply.invoke({ a: 2, b: 3 });

检查

您还可以检查工具的模式和其他属性:

console.log(multiply.name); // multiplyconsole.log(multiply.description); // 两个数字相乘。

如果您使用预构建的 LangChain 或 LangGraph 组件,如 createReactAgent,可能不需要直接与工具交互。然而,了解如何使用它们对于调试和测试非常有价值。此外,在构建自定义 LangGraph 工作流时,您可能会发现有必要直接使用工具。

配置模式

tool 函数提供了额外的选项来配置工具的模式(例如,修改名称、描述或解析函数的文档字符串以推断模式)。

请参阅 tool 的 API 参考 获取更多详细信息,并查看如何创建自定义工具指南中的示例。

工具工件

工具是模型可以调用的实用程序,其输出设计为反馈给模型。然而,有时我们希望将工具执行的工件传递给链或代理中的下游组件,但不希望将其暴露给模型本身。例如,如果工具返回自定义对象、数据框或图像,我们可能希望将有关此输出的一些元数据传递给模型,而不将实际输出传递给模型。同时,我们可能希望在其他地方访问此完整输出,例如在下游工具中。

const someTool = tool(({ ... }) => {    // 执行某些操作}, {  // ... 工具模式参数  // 将 returnType 设置为 "content_and_artifact"  responseFormat: "content_and_artifact"});

有关更多详细信息,请参阅如何从工具返回工件

RunnableConfig

您可以使用 RunnableConfig 对象将自定义运行时值传递给工具。

如果需要从工具内部访问 RunnableConfig 对象,可以通过在工具的函数签名中使用 RunnableConfig 来实现。

import { RunnableConfig } from "@langchain/core/runnables";const someTool = tool(    async (args: any, config: RunnableConfig): Promise<[string, any]> => {        /**         * 执行某些操作的工具。         */    },    {        name: "some_tool",        description: "执行某些操作的工具",        schema: z.object({ ... }),        returnType: "content_and_artifact"    });await someTool.invoke(..., { configurable: { value: "some_value" } });

config 不会成为工具模式的一部分,将在运行时注入适当的值。

最佳实践

设计供模型使用的工具时,请记住以下几点:

工具包

LangChain 有工具包的概念。这是一个非常薄的抽象,将设计用于特定任务一起使用的工具分组。

接口

所有工具包都公开了一个 getTools 方法,该方法返回工具列表。因此,您可以执行以下操作:

// 初始化工具包const toolkit = new ExampleTookit(...)// 获取工具列表const tools = toolkit.getTools()

相关资源

有关更多信息,请参阅以下资源:

函数调用

概述

许多AI应用直接与人类交互。在这些情况下,模型以自然语言响应是合适的。但如果我们希望模型也能直接与系统(如数据库或API)交互呢?这些系统通常有特定的输入模式;例如,API经常需要特定的负载结构。这种需求催生了工具调用的概念。你可以使用工具调用来请求模型响应符合特定模式。

有时你会听到术语function calling / 函数调用。我们将其与tool calling / 工具调用互换使用。

关键概念

(1) 工具创建: 使用tool函数创建一个工具。工具是函数与其模式之间的关联。
(2) 工具绑定: 工具需要连接到支持工具调用的模型。这使模型能够了解工具及其所需的输入模式。
(3) 工具调用: 在适当的时候,模型可以决定调用工具并确保其响应符合工具的输入模式。
(4) 工具执行: 可以使用模型提供的参数执行工具。

推荐用法

以下伪代码展示了使用工具调用的推荐工作流程。创建的工具作为列表传递给.bindTools()方法。可以像往常一样调用此模型。如果进行了工具调用,模型的响应将包含工具调用的参数。工具调用的参数可以直接传递给工具。

// 工具创建const tools = [myTool];// 工具绑定const modelWithTools = model.bindTools(tools);// 工具调用const response = await modelWithTools.invoke(userInput);

工具创建

推荐使用tool函数创建工具。

import { tool } from "@langchain/core/tools";const multiply = tool(  ({ a, b }: { a: number; b: number }): number => {    /**     * 两个数字相乘。     */    return a * b;  },  {    name: "multiply",    description: "将两个数字相乘",    schema: z.object({      a: z.number(),      b: z.number(),    }),  });

进一步阅读

    查看我们的工具概念指南以获取更多细节。查看支持工具调用的模型集成。查看关于工具调用的操作指南。

对于不需要执行函数的工具调用,你也可以只定义工具模式:

const multiplyTool = {  name: "multiply",  description: "将两个数字相乘",  schema: z.object({    a: z.number(),    b: z.number(),  }),};

工具绑定

许多 模型提供商支持工具调用。

需要理解的核心概念是,LangChain提供了一个标准化的接口,用于将工具连接到模型。.bindTools()方法可用于指定模型可以调用哪些工具。

const llmWithTools = model.bindTools([toolsList]);

作为一个具体示例,让我们将一个函数multiply作为工具绑定到支持工具调用的模型。

const multiply = tool(  ({ a, b }: { a: number; b: number }): number => {    /**     * 将a和b相乘。     *     * @param a - 第一个数字     * @param b - 第二个数字     * @returns a和b的乘积     */    return a * b;  },  {    name: "multiply",    description: "将两个数字相乘",    schema: z.object({      a: z.number(),      b: z.number(),    }),  });const llmWithTools = model.bindTools([multiply]);

工具调用

工具调用的一个关键原则是,模型根据输入的相关性决定何时使用工具。模型并不总是需要调用工具。例如,给定一个不相关的输入,模型不会调用工具:

const result = await llmWithTools.invoke("Hello world!");
AIMessage {  "content": "Hello! How can I assist you today?",  "additional_kwargs": {},  "tool_calls": [],   "invalid_tool_calls": [],  // 省略其他不重要的信息...}

结果将是一个包含模型自然语言响应(例如“Hello!”)的AIMessage。然而,如果我们传递一个与工具相关的输入,模型应该选择调用它:

const result = await llmWithTools.invoke("2乘以3等于多少?");
AIMessage {  "content": "",  "additional_kwargs": {    "tool_calls": [      {        "function": "[Object]",        "id": "call_wft9unvz0nufdxsvjd2n0fdd",        "type": "function"      }    ]  },  "response_metadata": {    "tokenUsage": {      "promptTokens": 176,      "completionTokens": 22,      "totalTokens": 198    },    "finish_reason": "tool_calls",    "model_name": "deepseek-v3-250324"  },  "tool_calls": [    {      "name": "multiply",      "args": {        "a": 2,        "b": 3      },      "type": "tool_call",      "id": "call_wft9unvz0nufdxsvjd2n0fdd"    }  ],  "invalid_tool_calls": []}

和之前一样,输出result将是一个AIMessage。但如果工具被调用,result将有一个tool_calls属性。此属性包括执行工具所需的一切,包括工具名称和输入参数:

result.tool_calls
{'name': 'multiply', 'args': {'a': 2, 'b': 3}, 'id': 'xxx', 'type': 'tool_call'}

有关用法的更多细节,请参阅我们的操作指南

工具执行

工具实现了Runnable接口,这意味着它们可以直接被调用(例如tool.invoke(args))。

LangGraph提供了预构建的组件(例如ToolNode),通常会代表用户调用工具。

进一步阅读

    查看我们的工具调用操作指南。查看LangGraph关于使用ToolNode的文档。

最佳实践

在设计模型使用的工具时,重要的是要记住:

如何将工具输出传递给聊天模型

本指南将演示如何利用这些工具调用来实际执行函数,并将结果正确返回给模型。

import { z } from "zod";import { tool } from "@langchain/core/tools";const addTool = tool(async ({ a, b }) => {  return a + b;}, {  name: "add",  schema: z.object({    a: z.number(),    b: z.number(),  }),  description: "将两个数字相加",});const multiplyTool = tool(async ({ a, b }) => {  return a * b;}, {  name: "multiply",  schema: z.object({    a: z.number(),    b: z.number(),  }),  description: "将两个数字相乘",});const tools = [addTool, multiplyTool];

现在,我们将让模型调用工具。我们会将其添加到作为对话历史记录的消息列表中:

import { HumanMessage } from "@langchain/core/messages";const llmWithTools = model.bindTools(tools);const messages = [  new HumanMessage("3乘以12是多少? 还有, 11+49是多少?"),];const aiMessage = await llmWithTools.invoke(messages);console.log(aiMessage);messages.push(aiMessage);

接下来,让我们使用模型生成的参数来调用工具函数!

方便的是,如果我们用 ToolCall 调用 LangChain 的 Tool,它会自动返回一个可以反馈给模型的 ToolMessage

const toolsByName = {  add: addTool,  multiply: multiplyTool,}for (const toolCall of aiMessage.tool_calls) {  const selectedTool = toolsByName[toolCall.name];  const toolMessage = await selectedTool.invoke(toolCall);  messages.push(toolMessage);}console.log(messages);
[  HumanMessage {    "content": "3乘以12是多少? 还有, 11+49是多少?",    "additional_kwargs": {},    "response_metadata": {}  },  AIMessage {    "id": "02174850158423247ec89029d8000ca2c3a009559e9dc1ae84b31",    "content": "",    "additional_kwargs": {      "tool_calls": [        {          "function": "[Object]",          "id": "call_b88swfz7zqiyquph399jkp9t",          "type": "function"        },        {          "function": "[Object]",          "id": "call_fl3bxokzdjtjsy2tqtxwr25u",          "type": "function"        }      ]    },    "response_metadata": {      "tokenUsage": {        "promptTokens": 334,        "completionTokens": 48,        "totalTokens": 382      },      "finish_reason": "tool_calls",      "model_name": "deepseek-v3-250324"    },    "tool_calls": [      {        "name": "multiply",        "args": {          "a": 3,          "b": 12        },        "type": "tool_call",        "id": "call_b88swfz7zqiyquph399jkp9t"      },      {        "name": "add",        "args": {          "a": 11,          "b": 49        },        "type": "tool_call",        "id": "call_fl3bxokzdjtjsy2tqtxwr25u"      }    ],    "invalid_tool_calls": [],    "usage_metadata": {      "output_tokens": 48,      "input_tokens": 334,      "total_tokens": 382,      "input_token_details": {        "cache_read": 0      },      "output_token_details": {        "reasoning": 0      }    }  },  ToolMessage {    "content": "36",    "name": "multiply",    "additional_kwargs": {},    "response_metadata": {},    "tool_call_id": "call_b88swfz7zqiyquph399jkp9t"  },  ToolMessage {    "content": "60",    "name": "add",    "additional_kwargs": {},    "response_metadata": {},    "tool_call_id": "call_fl3bxokzdjtjsy2tqtxwr25u"  }]

最后,我们将使用工具调用的结果再次调用模型。模型会基于这些信息生成针对原始问题的最终回答:

await llmWithTools.invoke(messages);
AIMessage {  "id": "021748501676873032f7ddc5f9cefd0e01af52376a34c5388dcbc",  "content": "3乘以12是36,11加49是60。",  "additional_kwargs": {},  "response_metadata": {    "tokenUsage": {      "promptTokens": 386,      "completionTokens": 12,      "totalTokens": 398    },    "finish_reason": "stop",    "model_name": "deepseek-v3-250324"  },  "tool_calls": [],  "invalid_tool_calls": [],  "usage_metadata": {    "output_tokens": 12,    "input_tokens": 386,    "total_tokens": 398,    "input_token_details": {      "cache_read": 0    },    "output_token_details": {      "reasoning": 0    }  }}

请注意,每个 ToolMessage 必须包含与模型原始工具调用中 id 相匹配的 tool_call_id。这有助于模型将工具响应与工具调用关联起来。

像 LangGraph 中的工具调用代理,就是使用这种基础流程来回答问题并完成任务。

相关内容

您已了解如何将工具调用结果传回模型。

接下来可能会对这些指南感兴趣:

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LangChain 工具调用 AI增强
相关文章