Skip to main content
许多人工智能应用通过自然语言与用户交互。然而,某些用例要求模型能够直接通过结构化输入与外部系统(如API、数据库或文件系统)进行接口。 工具是智能体([智能体](/oss/javascript/langchain/agents))调用来执行操作的组件。它们通过允许智能体通过定义良好的输入和输出与世界交互来扩展模型的能力。工具封装了一个可调用的函数及其输入模式。这些可以传递给兼容的聊天模型,使模型能够决定是否调用工具以及使用哪些参数。在这些场景中,工具调用使模型能够生成符合指定输入模式的请求。
服务器端工具使用一些聊天模型(例如,OpenAIAnthropicGemini)具有内置工具,这些工具在服务器端执行,例如网页搜索和代码解释器。请参阅提供商概述了解如何使用您的特定聊天模型访问这些工具。

创建工具

基本工具定义

创建工具的最简单方法是通过从 langchain 包中导入 tool 函数。您可以使用 zod 来定义工具的输入模式:
import * as z from "zod"
import { tool } from "langchain"

const searchDatabase = tool(
  ({ query, limit }) => `Found ${limit} results for '${query}'`,
  {
    name: "search_database",
    description: "Search the customer database for records matching the query.",
    schema: z.object({
      query: z.string().describe("Search terms to look for"),
      limit: z.number().describe("Maximum number of results to return"),
    }),
  }
);

访问上下文

为什么这很重要: 工具在能够访问智能体状态、运行时上下文和长期记忆时最为强大。这使得工具能够做出上下文感知的决策、个性化响应并在对话中保持信息。
工具可以通过 ToolRuntime 参数访问运行时信息,该参数提供:
  • 状态 - 在执行过程中流动的可变数据(消息、计数器、自定义字段)
  • 上下文 - 如用户ID、会话详情或特定于应用的配置等不可变配置
  • 存储 - 横跨对话的持久长期内存
  • 流写入器 - 在工具执行时流式传输自定义更新
  • 配置 - 可运行的执行配置
  • 工具调用ID - 当前工具调用的ID

工具运行时

使用 ToolRuntime 通过单个参数访问所有运行时信息。只需将 runtime: ToolRuntime 添加到您的工具签名中,它将自动注入而无需暴露给LLM。
ToolRuntime:一个统一的参数,为工具提供访问状态、上下文、存储、流、配置和工具调用ID的功能。这取代了使用单独的@[InjectedState]、@[InjectedStore]、@[get_runtime]和@[InjectedToolCallId]注解的较老模式。

上下文

通过 runtime.context 访问不可变配置和上下文数据,如用户ID、会话详情或特定应用的配置。 工具可以通过 config 参数访问智能体的运行时上下文:
import * as z from "zod"
import { ChatOpenAI } from "@langchain/openai"
import { createAgent } from "langchain"

const getUserName = tool(
  (_, config) => {
    return config.context.user_name
  },
  {
    name: "get_user_name",
    description: "Get the user's name.",
    schema: z.object({}),
  }
);

const contextSchema = z.object({
  user_name: z.string(),
});

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

const result = await agent.invoke(
  {
    messages: [{ role: "user", content: "What is my name?" }]
  },
  {
    context: { user_name: "John Smith" }
  }
);

记忆(存储)

使用存储来跨对话访问持久数据。存储通过 runtime.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();

// Access memory
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: "Look up user info.",
    schema: z.object({
      user_id: z.string(),
    }),
  }
);

// Update memory
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 "Successfully saved user info.";
  },
  {
    name: "save_user_info",
    description: "Save user info.",
    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,
});

// First session: save user info
await agent.invoke({
  messages: [
    {
      role: "user",
      content: "Save the following user: userid: abc123, name: Foo, age: 25, email: foo@langchain.dev",
    },
  ],
});

// Second session: get user info
const result = await agent.invoke({
  messages: [
    { role: "user", content: "Get user info for user with id 'abc123'" },
  ],
});

console.log(result);
// Here is the user info for user with ID "abc123":
// - Name: Foo
// - Age: 25
// - Email: foo@langchain.dev

流写入器

使用 runtime.stream_writer 流式传输工具在执行过程中的自定义更新。这有助于向用户提供实时反馈,了解工具正在做什么。
import * as z from "zod";
import { tool } from "langchain";

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

    // Stream custom updates as the tool executes
    writer(`Looking up data for city: ${city}`);
    writer(`Acquired data for city: ${city}`);

    return `It's always sunny in ${city}!`;
  },
  {
    name: "get_weather",
    description: "Get weather for a given city.",
    schema: z.object({
      city: z.string(),
    }),
  }
);