Function Calling(函数调用)

👉就是让 AI 能“使用工具”的能力。

  • 大模型本身不能直接查天气、发邮件、查数据库……但它可以“调用函数”来做到这些。
  • 比如你问:“现在美元兑人民币汇率多少?”
    AI 会识别出需要调用“汇率查询”函数,自动传入参数(如 base=USD, target=CNY),然后拿到真实数据再回答你。
  • 开发者可以预先定义好各种函数(查天气、发消息、查订单等),AI 在需要时就“喊一声”调用它们。

✅ 简单说:Function Calling = AI 的“外挂工具箱”,让它能做真实世界的事。


任务示例:

  • 开发一个“旅行小助手”:用户说“明天北京到上海的天气怎么样?”,AI 自动:
    1. 调用天气 API 查两地天气
    2. 调用日历工具确认“明天”的具体日期
    3. 整合信息生成自然语言回答

​技术栈:

  • 使用 OpenAI / 通义千问 / Ollama 等支持 function calling 的模型
  • 模拟或接入真实 API(如 OpenWeatherMap)

关键收获:
✅ 理解函数声明(function schema)的写法
✅ 掌握模型如何决定是否调用函数
✅ 学会处理函数返回结果并继续对话


实践步骤

🎯 用户输入

“明天北京到上海的天气怎么样?”


🔁 完整交互流程(含模拟 JSON)

第 1 步:用户请求到达 FastAPI

POST /travel-assistant
{
  "message": "明天北京到上海的天气怎么样?"
}

第 2 步:第一次调用硅基流动(带 tools)

发送给模型的 messages,附带的 tools 定义:

# ----------------------------
# 工具定义(供大模型理解)
# ----------------------------
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_tomorrow_date",
            "description": "获取明天的具体日期,格式为 YYYY-MM-DD",
            "parameters": {"type": "object", "properties": {}, "required": []}
        }
    },
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询指定中国城市的当前天气情况",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称,例如 '北京'、'上海'、'广州'"}
                },
                "required": ["city"]
            }
        }
    }
]

# ----------------------------
# 硅基流动 API 调用函数
# ----------------------------
async def call_siliconflow(messages, tools=None, tool_choice="auto"):
    url = "https://api.siliconflow.cn/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {SILICONFLOW_API_KEY}",
        "Content-Type": "application/json"
    }
    payload = {
        "model": MODEL_NAME,
        "messages": messages,
        "temperature": 0.3,
    }
    if tools:
        payload["tools"] = tools
        payload["tool_choice"] = tool_choice

    async with httpx.AsyncClient(timeout=30.0) as client:
        resp = await client.post(url, headers=headers, json=payload)
        if resp.status_code != 200:
            raise HTTPException(status_code=500, detail=f"硅基流动 API 错误: {resp.text}")
        return resp.json()
# ----------------------------
#  第一次调用模型,判断是否需要工具
# ----------------------------
messages = [{"role": "user", "content":"明天北京到上海的天气怎么样?"}]
response = await call_siliconflow(messages, tools=tools)

第 3 步:模型返回 tool_calls

模型理解需要查“明天日期”、“北京天气”、“上海天气”,于是返回:

{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_1",
            "type": "function",
            "function": {
              "name": "get_tomorrow_date",
              "arguments": "{}"
            }
          },
          {
            "id": "call_2",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\": \"北京\"}"
            }
          },
          {
            "id": "call_3",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\": \"上海\"}"
            }
          }
        ]
      }
    }
  ]
}

✅ 注意:

  • content 为 null 表示模型不直接回答,而是请求工具。
  • arguments 是 JSON 字符串,需用 json.loads() 解析。

第 4 步:服务端执行工具函数

程序依次调用:

get_tomorrow_date()        → 返回 "2026-01-27"
get_weather("北京")        → 返回 "北京:2.5°C,晴"
get_weather("上海")        → 返回 "上海:8.1°C,多云"

第 5 步:构造新 messages 并二次调用模型

更新后的 messages:

[
  {
    "role": "user",
    "content": "明天北京到上海的天气怎么样?"
  },
  {
    "role": "assistant",
    "tool_calls": [ /* 上面的三个 tool_calls */ ]
  },
  {
    "role": "tool",
    "tool_call_id": "call_1",
    "name": "get_tomorrow_date",
    "content": "2026-01-27"
  },
  {
    "role": "tool",
    "tool_call_id": "call_2",
    "name": "get_weather",
    "content": "北京:2.5°C,晴"
  },
  {
    "role": "tool",
    "tool_call_id": "call_3",
    "name": "get_weather",
    "content": "上海:8.1°C,多云"
  }
]

⚠️ 这个结构是 OpenAI/硅基流动 Function Calling 的标准格式。


第 6 步:模型生成最终自然语言回答

模型返回:

{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "明天是 2026-01-27。北京天气晴,气温 2.5°C;上海多云,气温 8.1°C。建议您根据温差合理穿衣,旅途愉快!"
      }
    }
  ]
}

第 7 步:FastAPI 返回给用户

{
  "response": "明天是 2026-01-27。北京天气晴,气温 2.5°C;上海多云,气温 8.1°C。建议您根据温差合理穿衣,旅途愉快!"
}

✅ 总结:Function Calling 的核心价值

阶段 谁负责 做什么
意图识别 大模型 判断是否需要外部工具
参数提取 大模型 从自然语言中抽取出函数参数(如城市名)
工具执行 你的代码 调用真实 API 或本地函数
结果整合 大模型 将工具返回的数据转化为人类可读的回答

💡 扩展思考

你可以轻松扩展更多工具,例如:

def search_flight(departure: str, arrival: str, date: str):
    # 调用航班查询 API
    pass

tools.append({
    "type": "function",
    "function": {
        "name": "search_flight",
        "parameters": {
            "type": "object",
            "properties": {
                "departure": {"type": "string"},
                "arrival": {"type": "string"},
                "date": {"type": "string", "format": "date"}
            },
            "required": ["departure", "arrival", "date"]
        }
    }
})

用户说:“帮我查明天从北京到上海的航班”,就能自动触发!


关注【码进制的世界】回复“ai102”获取完整源码

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐