Docs · App Dev Guide

大模型应用开发

从 Prompt 工程到 AI Agent,一站式覆盖大模型应用开发全链路 —— 让你能在 1 周内跑出生产级 MVP。

Function Call · OpenAI 实战

OpenAI 是 Function Call 的开创者,API 设计也是事实标准 —— DeepSeek / Qwen / Moonshot 等国内模型都兼容这套协议。

完整 5 步代码

任务:让模型查询天气并回答用户问题。

Step 1:定义工具

from openai import OpenAI
      import json
      
      client = OpenAI()  # 自动读 OPENAI_API_KEY 环境变量
      
      tools = [{
          "type": "function",
          "function": {
              "name": "get_weather",
              "description": "查询指定城市的当前天气情况",
              "parameters": {
                  "type": "object",
                  "properties": {
                      "city": {
                          "type": "string",
                          "description": "城市名称,如「北京」「San Francisco」"
                      },
                      "unit": {
                          "type": "string",
                          "enum": ["celsius", "fahrenheit"],
                          "description": "温度单位",
                          "default": "celsius"
                      }
                  },
                  "required": ["city"]
              },
              "strict": True  # 启用严格模式(推荐)
          }
      }]
💡

strict: True 是 OpenAI 2024 推出的「保证 100% 符合 schema」模式 —— 强烈推荐打开。模型生成的参数不再可能出现拼写错误、漏字段等问题。

Step 2:实现真实函数

def get_weather(city: str, unit: str = "celsius") -> dict:
          """这是你真实的业务函数 —— 模型不会执行它"""
          # 真实实现会调气象 API
          fake_data = {
              "北京": {"temp": 32, "condition": "晴"},
              "San Francisco": {"temp": 18, "condition": "Cloudy"}
          }
          result = fake_data.get(city, {"temp": 20, "condition": "未知"})
          if unit == "fahrenheit":
              result["temp"] = result["temp"] * 9/5 + 32
          return result

Step 3:第一轮 —— 模型决策

messages = [
          {"role": "user", "content": "北京今天热吗?建议穿什么?"}
      ]
      
      resp = client.chat.completions.create(
          model="gpt-5",
          messages=messages,
          tools=tools,
          tool_choice="auto"  # auto / none / required / {specific}
      )
      
      msg = resp.choices[0].message
      # msg.tool_calls 是个列表(可能并行调多个)
      tool_call = msg.tool_calls[0]
      print(tool_call.function.name)       # "get_weather"
      print(tool_call.function.arguments)  # '{"city": "北京", "unit": "celsius"}'

Step 4:执行工具

args = json.loads(tool_call.function.arguments)
      result = get_weather(**args)
      # {"temp": 32, "condition": "晴"}

Step 5:第二轮 —— 模型综合结果

# 把工具调用 + 结果都加进消息历史
      messages.append(msg)  # 模型的 tool_calls 消息
      messages.append({
          "role": "tool",
          "tool_call_id": tool_call.id,
          "content": json.dumps(result)
      })
      
      resp2 = client.chat.completions.create(
          model="gpt-5",
          messages=messages,
          tools=tools
      )
      final_answer = resp2.choices[0].message.content
      print(final_answer)
      # "北京今天 32°C 晴天,比较热。建议穿轻薄透气的衣物,记得防晒。"

通用调度循环

实际应用中,模型可能多轮调用工具(先查天气再查穿搭推荐)。封装成循环:

def chat_with_tools(user_message: str, tools: list, tool_handlers: dict,
                          max_iterations: int = 5):
          """通用调度循环:处理多轮 FC"""
          messages = [{"role": "user", "content": user_message}]
      
          for _ in range(max_iterations):
              resp = client.chat.completions.create(
                  model="gpt-5",
                  messages=messages,
                  tools=tools,
                  tool_choice="auto"
              )
              msg = resp.choices[0].message
              messages.append(msg)
      
              # 没有工具调用 → 模型给出最终答案
              if not msg.tool_calls:
                  return msg.content
      
              # 有工具调用 → 执行所有调用
              for tc in msg.tool_calls:
                  fn = tool_handlers[tc.function.name]
                  args = json.loads(tc.function.arguments)
                  result = fn(**args)
                  messages.append({
                      "role": "tool",
                      "tool_call_id": tc.id,
                      "content": json.dumps(result, ensure_ascii=False)
                  })
      
          raise RuntimeError(f"超过 {max_iterations} 轮仍未结束")
      
      # 使用
      answer = chat_with_tools(
          user_message="北京今天热吗?建议穿什么?",
          tools=tools,
          tool_handlers={"get_weather": get_weather}
      )

tool_choice 的 4 种模式

取值行为
"auto" (默认)模型自主判断要不要调
"none"强制不调用,只生成文本
"required"强制必须调一个工具
{"type":"function","function":{"name":"..."}}强制调指定工具

实战场景:

  • 客服意图分类tool_choice="required" + 多个分类工具,强制必须分类
  • 闲聊tool_choice="none",不让模型乱调工具
  • 复杂任务tool_choice="auto",让模型自由决策

多工具并行调用

GPT-4o / GPT-5 默认支持一次调多个工具。例如「查北京和上海的天气」 → 模型一次返回 2 个 tool_calls。

# 模型可能一次返回:
      [
          {name: "get_weather", arguments: '{"city": "北京"}'},
          {name: "get_weather", arguments: '{"city": "上海"}'}
      ]
      
      # 并行执行
      import asyncio
      
      async def run_tool(tc):
          args = json.loads(tc.function.arguments)
          return await tool_handlers[tc.function.name](**args)
      
      results = await asyncio.gather(*[run_tool(tc) for tc in msg.tool_calls])

详见 并行调用与错误处理

国内模型兼容性

OpenAI Function Call 协议是事实标准,以下都兼容:

模型兼容性备注
DeepSeek-V3⭐⭐⭐⭐⭐完全兼容,价格 1/10
Qwen3⭐⭐⭐⭐⭐完全兼容
Moonshot Kimi⭐⭐⭐⭐⭐完全兼容,长上下文
智谱 GLM-4.5⭐⭐⭐⭐基本兼容,schema 严格度略低

切换 base_url 就能直接用 OpenAI SDK 调国内模型:

client = OpenAI(
          api_key=os.getenv("DEEPSEEK_API_KEY"),
          base_url="https://api.deepseek.com/v1"
      )
      # 代码其他都不用改

常见坑

解决方案
arguments 是字符串不是对象始终 json.loads() 一下
大模型乱传参数strict: True
一直循环调用max_iterations 上限
多轮历史太长截断或用 Prompt Caching
description 不够清晰写明用例 + 边界条件

下一节:Anthropic Tool Use —— Claude 的实现差异。