Function Calling 是什么?从概念到实战

发表于 2026/07/07 21:30
🌺 摘要
纯对话拿不到实时数据、容易编造;Function Calling 让模型输出工具使用意图,由本地执行后回传结果。一文按「为什么 → 是什么 → Demo」讲清。

Function Calling 解决的是:大模型如何安全、可控地用到你的数据和接口。本文按三个问题展开——为什么需要它、它到底是什么、怎么写出一个能跑的 Demo

1. 为什么需要 Function Calling

大模型只会根据训练数据和当前对话生成文本。它不知道你数据库里今天的订单数,调不到内网 HTTP 接口,训练数据也有时效 cutoff。

只靠纯对话,常见两条路都不理想:

做法问题
让模型直接答实时数据只能,容易编造
把所有数据塞进 prompt贵、易超长、难维护

Function Calling 提供第三条路:用户用自然语言提问 → 模型判断要不要用工具、填什么参数 → 你的程序去查库 / 调 API → 结果回传给模型 → 模型组织成最终回答

典型用途:查天气/股价、查订单、创建工单、多步串联(先查用户 ID,再查订单)。副作用操作(写库、发邮件)仍要在本地做鉴权——模型只负责「建议动作」,不负责「执行动作」。

2. Function Calling 是什么

Function Calling 是 OpenAI 系 API 的惯用叫法;更准确说是 Tool Use(工具使用)。名字容易让人以为「模型在执行你的函数」——实际上模型只生成一段结构化文本tool_calls),真正 call 的是你的代码

一次完整的 Tool Use 长这样:

用户提问
  → 请求里带上 tools(能用什么)
  → 模型返回 tool_calls(建议用哪个、参数是什么)
  → 本地执行对应函数
  → 追加 role: tool 消息(执行结果)
  → 再请求,模型输出自然语言回答

Function Calling 流程示意

需要调多个工具时,中间「执行 → 回传」循环,直到模型不再返回 tool_calls

几个 API 字段:

  • tools — 工具清单,每项含 namedescriptionparameters(JSON Schema)。这里的 function 不会自动绑定你项目里的 TS 函数,靠同名约定自己对接。
  • tool_calls — 模型输出的使用意图,例如:
{
  "id": "call_abc123",
  "type": "function",
  "function": {
    "name": "get_weather",
    "arguments": "{\"city\":\"北京\"}"
  }
}

arguments字符串,需 JSON.parse,且可能非法或语义错误,必须本地校验。

  • role: tool — 把执行结果塞回 messagestool_call_id 要对上上面的 id
{
  "role": "tool",
  "tool_call_id": "call_abc123",
  "content": "晴,28°C"
}

和普通 API 的区别:调哪个接口、参数从哪来,由模型从用户话里预测;但 HTTP 请求、数据库读写仍发生在你的服务。它是「自然语言 → 结构化动作」的中间层,不是 REST 的替代品。

3. Demo:用 DeepSeek 查天气

下面用 DeepSeek 把第 2 节串起来。DeepSeek 兼容 OpenAI Chat Completions,安装 openai 包、改 baseURL 即可;OpenAI、通义等接口写法相同。

流程对应关系:

步骤代码里
声明 toolstools 数组 + get_weather schema
第一次请求,拿 tool_callsclient.chat.completions.createfirst
本地执行getWeather(city)
回传结果messages.push({ role: "tool", ... })
第二次请求,拿人话second
import "dotenv/config";
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com",
});

const MODEL = process.env.DEEPSEEK_MODEL ?? "deepseek-chat";

const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
  {
    type: "function",
    function: {
      name: "get_weather",
      description: "查询指定城市的当前天气",
      parameters: {
        type: "object",
        properties: {
          city: { type: "string", description: "城市名称,如:北京、上海" },
        },
        required: ["city"],
      },
    },
  },
];

function getWeather(city: string): string {
  const data: Record<string, string> = {
    北京: "晴,28°C",
    上海: "多云,32°C",
  };
  return data[city] ?? "暂无该城市数据";
}

async function main() {
  const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
    { role: "user", content: "北京今天天气怎么样?" },
  ];

  const first = await client.chat.completions.create({
    model: MODEL,
    messages,
    tools,
  });

  const assistantMsg = first.choices[0].message;
  messages.push(assistantMsg);

  const toolCall = assistantMsg.tool_calls?.[0];
  if (toolCall?.type !== "function") {
    console.log("助手:", assistantMsg.content);
    return;
  }

  const { city } = JSON.parse(toolCall.function.arguments) as { city: string };
  const weather = getWeather(city);
  console.log(`执行: get_weather("${city}") → ${weather}`);

  messages.push({
    role: "tool",
    tool_call_id: toolCall.id,
    content: weather,
  });

  const second = await client.chat.completions.create({
    model: MODEL,
    messages,
  });

  console.log("助手:", second.choices[0].message.content);
}

main().catch(console.error);

环境变量:DEEPSEEK_API_KEYDEEPSEEK_MODEL(可选,默认 deepseek-chat)。运行:

$ tsx src/index.ts

执行: get_weather("北京")  晴,28°C
助手: 北京今天天气晴朗,气温为 **28°C**,祝您生活愉快!

写 Demo 时注意: description 写清何时用;参数名语义化;副作用要鉴权;模型不调工具就改描述,JSON 解析失败就 try/catch,仍返回 tool_calls 就继续循环。

4. 小结

Function Calling 解决的是大模型够不着真实世界的问题;本质是 tools 声明 → tool_calls 意图 → 本地执行 → role: tool 回灌 → 再请求。Demo 跑通后,换任何兼容 OpenAI 格式的接口都能复用同一套写法。

文章发表于 2026/07/07 21:30
没有上一篇文章
下一篇 Vue3 弹窗状态抽离:一个 TypeScript 泛型 Hooks 实践