Skip to content

04-multi-tool.ts

多工具编排示例,createAgent 配 4 个工具,演示 agent 自主选择 + 并行 tool calls。

功能介绍

这个示例演示了如何用 createAgent 构建多工具 agent。4 个工具(天气 / 计算器 / 时间 / 搜索)各有不同输入 schema,agent 根据 description 自主决定调用哪个工具。演示用例会触发 3 个工具并行调用(time + weather + calculator),展示 agent 在一个 turn 里发起多个 tool_calls 的能力。

使用场景

  • 需要结合多种能力的任务(查询 + 计算 + 检索)
  • agent 根据问题自主选择工具
  • 并行调用多个工具提升效率
  • 构建多功能智能助手

学习要点

  1. createAgenttools 参数接受工具数组,agent 按 description 自主选择
  2. agent 能在一个 turn 里并行调用多个工具(同一 AIMessage 多个 tool_calls)
  3. tool() helper 配 zod schema 处理不同输入形态(结构化对象 / 算术 / 无参 / 文本)
  4. 计算器用 switch 而非 Function(),避免代码注入风险
  5. 打印 result.messages 可看到 AIMessage(tool_calls × N) -> ToolMessage × N -> AIMessage(最终) 的轨迹

源码

typescript
import "dotenv/config";
import { ChatOpenAI } from "@langchain/openai";
import { createAgent } from "langchain";
import { tool } from "@langchain/core/tools";
import { z } from "zod";

if (!process.env.ZHIPUAI_API_KEY) {
  throw new Error("ZHIPUAI_API_KEY is not set in environment variables");
}

// 复用 01-tools 的天气工具定义
const weatherTool = tool(
  async ({ city, unit }) => {
    const weatherData: Record<string, { temp: number; condition: string }> = {
      "北京": { temp: 25, condition: "晴天" },
      "上海": { temp: 22, condition: "多云" },
      "广州": { temp: 28, condition: "小雨" },
    };
    const data = weatherData[city] || { temp: 20, condition: "未知" };
    const temp = unit === "fahrenheit" ? Math.round(data.temp * 9/5 + 32) : data.temp;
    return `${city} 的天气: ${data.condition},${temp}°${unit === "celsius" ? "C" : "F"}`;
  },
  {
    name: "get_current_weather",
    description: "获取指定城市的当前天气",
    schema: z.object({
      city: z.string().describe("城市名称"),
      unit: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("温度单位"),
    }),
  }
);

// 计算器工具:用 switch 而非 Function(),避免代码注入风险
const calculatorTool = tool(
  async ({ a, b, op }) => {
    switch (op) {
      case "+": return `${a} + ${b} = ${a + b}`;
      case "-": return `${a} - ${b} = ${a - b}`;
      case "*": return `${a} * ${b} = ${a * b}`;
      case "/": return b === 0 ? "错误:除数不能为 0" : `${a} / ${b} = ${a / b}`;
    }
  },
  {
    name: "calculator",
    description: "执行两个数的四则运算",
    schema: z.object({
      a: z.number().describe("第一个数"),
      b: z.number().describe("第二个数"),
      op: z.enum(["+", "-", "*", "/"]).describe("运算符"),
    }),
  }
);

// 时间工具:获取当前北京时间
const timeTool = tool(
  async () => {
    const now = new Date();
    return `当前时间: ${now.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" })}`;
  },
  {
    name: "get_current_time",
    description: "获取当前时间(北京时间)",
    schema: z.object({}),
  }
);

// 搜索工具:mock 实现,关键词命中返回预设结果
const searchTool = tool(
  async ({ query }) => {
    const searchResults: Record<string, string> = {
      "LangChain": "LangChain 是一个用于开发由语言模型驱动的应用程序的框架",
      "DeepSeek": "DeepSeek 是一家中国 AI 公司,提供大语言模型",
      "agent": "AI agent 是能自主调用工具完成任务的智能体",
    };
    for (const [keyword, result] of Object.entries(searchResults)) {
      if (query.includes(keyword)) {
        return result;
      }
    }
    return `没有找到关于"${query}"的结果`;
  },
  {
    name: "search",
    description: "搜索网络获取信息",
    schema: z.object({
      query: z.string().describe("搜索关键词"),
    }),
  }
);

async function main() {
  try {
    console.log("=== Multi-Tool 示例(createAgent + 4 工具)===\n");

    const model = new ChatOpenAI({
      model: "deepseek-v3-1",
      temperature: 0,
      configuration: {
        baseURL: "https://ark.cn-beijing.volces.com/api/coding/v3/",
        apiKey: process.env.ZHIPUAI_API_KEY,
      },
    });

    const agent = createAgent({
      model,
      tools: [weatherTool, calculatorTool, timeTool, searchTool],
    });

    const question = "帮我查一下:现在几点?北京天气怎么样?15 加 27 是多少?";
    console.log("问题:", question);
    console.log("\n---\n");

    const result = await agent.invoke({
      messages: [{ role: "user", content: question }],
    });

    // 打印消息历史,让并行 tool calls 可见
    console.log("消息历史(共", result.messages.length, "条):");
    for (const msg of result.messages) {
      console.log(`  [${msg._getType()}]`, msg.content);
    }
    console.log("\n---\n");

    console.log("最终回答:", result.messages.at(-1)?.content);
  } catch (error) {
    console.error("Error during multi-tool example:", error);
    process.exit(1);
  }
}

main().catch(console.error);

运行方式

bash
npm run dev src/05-agents/04-multi-tool.ts