让模型"说话"很容易,让模型"办事"才是分水岭。Function Calling(函数调用)就是那道分水岭:模型不直接给答案,而是告诉你"我想调哪个函数、传什么参数",你的代码执行后把结果回传,模型再组织成自然语言。本文用聚合 API 走通一个最小闭环,这也是所有 Agent 的底层机制。

一、它能解决什么问题

模型再强,也有两件事做不到:不知道实时数据,也不能替你执行操作。

  • 问"北京今天天气"——模型没联网,答不上
  • 说"帮我查下这个订单"——模型碰不到你的数据库

Function Calling 就是给模型开的口子:你告诉模型"我有哪些工具可用",模型决定调哪个、传什么参数,你负责执行,结果回传。

二、最小闭环:查天气

先定义一个"工具"——其实就是描述你的函数签名:

import json
from openai import OpenAI

client = OpenAI(
    base_url="https://api.tokenportal.ai/v1",  # 控制台获取的网关地址
    api_key="YOUR_TOKENPORTAL_KEY",            # 控制台获取的 Key
)

def get_weather(city: str) -> str:
    # 模拟实现:实际接你的天气接口 / 数据库
    return f"{city}今天晴,25°C"

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "查询指定城市的天气",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "城市名,例如 北京"}
            },
            "required": ["city"]
        }
    }
}]

三、两轮调用,走通闭环

def ask(query):
    messages = [{"role": "user", "content": query}]

    # 第一轮:模型决定要不要调工具
    r = client.chat.completions.create(
        model="deepseek-v4-pro",
        messages=messages,
        tools=tools,
    )
    msg = r.choices[0].message

    # 模型没调工具,直接返回文本
    if not msg.tool_calls:
        return msg.content

    # 模型要调工具:先把它的回复塞回上下文
    messages.append(msg)
    for tc in msg.tool_calls:
        args = json.loads(tc.function.arguments)
        result = get_weather(**args)
        # 把工具执行结果回传给模型
        messages.append({
            "role": "tool",
            "tool_call_id": tc.id,
            "content": result,
        })

    # 第二轮:模型结合结果,组织成自然语言
    r2 = client.chat.completions.create(
        model="deepseek-v4-pro",
        messages=messages,
    )
    return r2.choices[0].message.content

print(ask("北京今天天气怎么样?"))
# 输出类似:北京今天晴,25°C,适合出门。

跑一遍,你会看到模型自己决定调 get_weather、传了 city="北京"、拿到结果后总结成一句话。

四、几个容易踩的坑

  1. 要把模型的回复塞回上下文:第一轮返回的 msg(含 tool_calls)必须 append 进 messages,否则第二轮模型不知道发生了什么。
  2. tool_call_id 不能省role="tool" 的消息必须带上对应的 tool_call_id,对不上会报错。
  3. 参数要校验:模型传的参数可能不合法(类型错、缺字段),执行前最好用 try/except 兜底。
  4. 工具描述写清楚descriptionparameters 写得越明确,模型调用越准。这是 Function Calling 准确率的头号因素。

五、能玩到什么程度

把这套闭环扩展开,就是 Agent:

  • 查订单 → 调你的数据库接口
  • 发邮件 → 调你的邮件接口
  • 算报价 → 调你的计价函数
  • 组合多步 → 一个"查库存 → 算价格 → 下单"的任务链

核心都是一样的:定义工具、让模型选、你执行、结果回传。

六、为什么用聚合 API 做 Function Calling

tools 参数是 OpenAI 兼容的标准格式,主流模型都支持,但个别模型的字段名、返回结构有差异。聚合 API 统一成一套格式,你写好一次工具定义,切换模型不用改调用代码。

想给你的应用加上工具调用能力、又不想逐个适配各家格式,来我主页查看一个接口打通主流模型的方案。

更多推荐