第 9 章:工具调用 Tool Calling:让 AI 调用函数

5 阅读2分钟

第 9 章:工具调用 Tool Calling:让 AI 调用函数

本章目标

这一章让模型从“只会回答”变成“可以调用函数”。这是 Agent 的基础。

本章效果

工具 Agent 页面展示了最终回答和工具调用轨迹。演示模式会直接显示本地工具执行结果;真实模型模式下,模型会根据工具描述决定是否调用。

工具 Agent 调用轨迹转存失败,建议直接上传图片文件

什么是工具调用

工具调用的核心是:你把可用函数告诉模型,模型根据用户问题决定是否调用。

例如用户问:

帮我算一下 499 元打 8 折是多少钱

模型可以调用:

calculate_discount({ price: 499, rate: 0.8 })

然后基于结果回答用户。

定义一个工具

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

export const calculateDiscount = tool(
  ({ price, rate }) => {
    const result = price * rate;
    return `折后价格是 ${result.toFixed(2)} 元`;
  },
  {
    name: "calculate_discount",
    description: "根据商品原价和折扣率计算折后价格",
    schema: z.object({
      price: z.number().describe("商品原价"),
      rate: z.number().describe("折扣率,例如 0.8 表示八折")
    })
  }
);

工具名建议使用 snake_case,兼容性更好。

创建 Agent

import { createAgent } from "langchain";
import { createChatModel } from "@/lib/ai/model";
import { calculateDiscount } from "@/lib/ai/tools";

export async function createBusinessAgent() {
  const model = await createChatModel();

  return createAgent({
    model,
    tools: [calculateDiscount],
    systemPrompt: "你是业务助手。需要计算时,优先调用工具。"
  });
}

调用:

const agent = await createBusinessAgent();

const result = await agent.invoke({
  messages: [
    {
      role: "user",
      content: "499 元打 8 折是多少钱?"
    }
  ]
});

工具调用适合什么

适合:

  • 计算
  • 查询数据库
  • 调接口
  • 搜索文档
  • 获取实时数据
  • 执行业务操作

不适合:

  • 没有边界的自由操作
  • 直接执行用户给出的任意代码
  • 没权限控制的删除、支付、发消息等高风险动作

工具调用状态怎么展示

前端最好不要只显示“AI 正在思考”。更好的体验是展示工具状态:

正在调用价格计算工具...
已获得计算结果
正在生成回答...

后续可以结合事件流或自定义状态实现。

实战任务

完成:

  • 定义 calculate_discount 工具
  • 创建 createBusinessAgent
  • 新增 /api/agent
  • 在页面上测试一次工具调用

常见坑

工具描述要具体。模型是否会正确调用工具,很大程度取决于工具名、描述和参数说明。

工具返回值不要太随意。返回给模型的信息要足够明确。

高风险工具必须加权限校验和二次确认。

本章小结

工具调用让模型具备执行能力。下一章会专门讲 Zod 参数设计,因为工具稳定性很大程度取决于参数 Schema。