工具 (Tools)

工具扩展了智能体的能力,使其能够与外部系统交互、检索信息或执行操作。每个工具都是一个带有名称、描述和参数模式的函数。

创建工具

使用 tool() 函数定义工具。模式描述了工具期望的输入参数:

import { tool } from "langchain";
import * as z from "zod";

const getWeather = tool(
  (input) => `${input.city}的天气是晴天!`,
  {
    name: "get_weather",
    description: "获取指定城市的天气",
    schema: z.object({
      city: z.string().describe("要查询天气的城市"),
    }),
  }
);

访问运行时

工具可以访问运行时功能,例如上下文、存储和流写入器。这些功能通过传递给工具的第二个参数(配置对象)来访问。

上下文

上下文允许工具访问调用时提供的配置数据。这对于需要会话特定信息的工具非常有用。

import { tool, ToolRuntime } from "langchain";
import * as z from "zod";

type AgentContext = { user_id: string };

const getUserLocation = tool(
  (_, config: ToolRuntime<unknown, AgentContext>) => {
    const { user_id } = config.context;
    // 根据用户 ID 返回位置
    return user_id === "1" ? "北京" : "上海";
  },
  {
    name: "get_user_location",
    description: "获取用户的位置",
  }
);

存储 (Store)

使用存储在对话之间访问持久化数据。通过 config.store 访问存储,允许你保存和检索用户特定或应用特定的数据。

import * as z from "zod";
import { createAgent, tool } from "langchain";
import { InMemoryStore } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";

const store = new InMemoryStore();

// 访问存储
const getUserInfo = tool(
  async ({ user_id }) => {
    const value = await store.get(["users"], user_id);
    console.log("get_user_info", user_id, value);
    return value;
  },
  {
    name: "get_user_info",
    description: "查询用户信息",
    schema: z.object({
      user_id: z.string(),
    }),
  }
);

// 更新存储
const saveUserInfo = tool(
  async ({ user_id, name, age, email }) => {
    console.log("save_user_info", user_id, name, age, email);
    await store.put(["users"], user_id, { name, age, email });
    return "用户信息保存成功";
  },
  {
    name: "save_user_info",
    description: "保存用户信息",
    schema: z.object({
      user_id: z.string(),
      name: z.string(),
      age: z.number(),
      email: z.string(),
    }),
  }
);

const agent = createAgent({
  model: new ChatOpenAI({ model: "gpt-4o" }),
  tools: [getUserInfo, saveUserInfo],
  store,
});

// 第一个会话:保存用户信息
await agent.invoke({
  messages: [
    {
      role: "user",
      content: "保存以下用户:userid: abc123, name: 张三, age: 25, email: zhangsan@example.com",
    },
  ],
});

// 第二个会话:获取用户信息
const result = await agent.invoke({
  messages: [
    { role: "user", content: "获取 ID 为 'abc123' 的用户信息" },
  ],
});

console.log(result);
// 用户 ID 为 "abc123" 的信息:
// - 姓名:张三
// - 年龄:25
// - 邮箱:zhangsan@example.com

流写入器 (Stream Writer)

使用 config.writer 在工具执行时流式传输自定义更新。这对于向用户提供工具正在执行的实时反馈非常有用。

import * as z from "zod";
import { tool, ToolRuntime } from "langchain";

const getWeather = tool(
  ({ city }, config: ToolRuntime) => {
    const writer = config.writer;

    // 在工具执行时流式传输自定义更新
    if (writer) {
      writer(`正在查询城市数据:${city}`);
      writer(`已获取城市数据:${city}`);
    }

    return `${city}总是阳光明媚!`;
  },
  {
    name: "get_weather",
    description: "获取指定城市的天气",
    schema: z.object({
      city: z.string(),
    }),
  }
);

工具类型

基础工具

最简单的工具形式,接收输入并返回输出:

const add = tool(
  ({ a, b }) => a + b,
  {
    name: "add",
    description: "两数相加",
    schema: z.object({
      a: z.number().describe("第一个数字"),
      b: z.number().describe("第二个数字"),
    }),
  }
);

异步工具

工具可以是异步的,适用于调用外部 API 或执行 I/O 操作:

const fetchData = tool(
  async ({ url }) => {
    const response = await fetch(url);
    return await response.json();
  },
  {
    name: "fetch_data",
    description: "从 URL 获取数据",
    schema: z.object({
      url: z.string().url().describe("要获取数据的 URL"),
    }),
  }
);

无模式工具

对于不需要任何输入的工具,可以省略模式:

const getCurrentTime = tool(
  () => new Date().toISOString(),
  {
    name: "get_current_time",
    description: "获取当前时间",
  }
);

最佳实践

下一步