本文是【大模型API中转站】系列篇。本系列致力于用最低的成本、最清晰的方法,帮你打通多模型 API 的任督二脉。建议先收藏,随用随查。


1. 开篇:我为什么需要这个方案

不止生图生视频,做"AI 智能体"同样绕不开多模型 API:你要一个能**看图(多模态)+ 会决策调工具(function calling)**的 LLM。直连官方依旧是老问题——网络、注册、按量计费贵、还得为 GPT-4o / Gemini 各写一套对接。

本文用一套真实的"电商图片智能体"后端(看产品图 → 按目标电商平台风格写营销提示词 → 调生图工具出图),讲清楚怎么通过中转站(如 4SAPI)用一把 Key、一个 OpenAI SDK同时跑通:多模态看图、function calling 工具编排、JSON 结构化输出。


2. 原理速览

智能体的 LLM 调用全部走 OpenAI 标准的 /v1/chat/completions,中转站负责把它翻译成各家模型协议。三种用法共用一个端点:

你的智能体
   ├─ 看图写词   chat.completions(messages 带 image_url)      ← 多模态
   ├─ 指挥决策   chat.completions(tools + tool_choice=auto)   ← function calling
   └─ 结构化输出 chat.completions → 解析返回的 JSON           ← 套图规划
            ▼
        中转站(4sapi) → GPT-4o / Gemini / ...

前提:选的模型要同时支持 function-calling 和多模态(如 gpt-4o-mini、gemini)。


3. 接入实战(参考 4SAPI chat/completions)

① 配置:base_url 自动补 /v1

智能体复用"AI 模型"表里 feature_type=llm 的那条配置,凭证不另存。一个易踩的小坑:OpenAI SDK 需要 .../v1 才能命中 /v1/chat/completions,所以管理员只填 https://4sapi.com,代码自动补 /v1

# ecommerce_agent_service.py
base_url = (rt["base_url"] or "").rstrip("/")
if base_url and not base_url.endswith("/v1"):
    base_url += "/v1"          # 管理员填 host 即可,代码补全
return base_url, rt["api_key"], rt["provider_model_name"]

② 多模态:messages 里塞一张图

看图写词,就是把文本和 image_url 放进同一条 user message 的 content 数组:

client = OpenAI(api_key=api_key, base_url=base_url, timeout=90)
resp = client.chat.completions.create(
    model=model,
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": user_text},
            {"type": "image_url", "image_url": {"url": image_data_url}},  # 可传 data URI
        ],
    }],
    temperature=0.7, max_tokens=2000,
)
return resp.choices[0].message.content.strip()

注意 image_url 既能传 http 链接,也能传 data:image/...;base64,xxx 的 Base64 Data URI —— 前端上传的产品图不落盘也能直接喂给模型。

③ function calling:让模型自己决定调哪个工具

"指挥官"模式:把"发问卷、写提示词、生成图片、改图"四个能力定义成 tools,tool_choice="auto" 让模型按对话自己决定调哪个:

COMMANDER_TOOLS = [
    {"type": "function", "function": {
        "name": "write_product_prompt",
        "description": "看产品图,按目标电商平台风格写营销海报图生图提示词。",
        "parameters": {"type": "object", "properties": {
            "brief": {"type": "string", "description": "产品描述+核心卖点"},
            "mode":  {"type": "string", "enum": ["single", "set"]},
            "count": {"type": "integer", "minimum": 1, "maximum": 8},
        }, "required": ["brief", "mode", "count"]},
    }},
    # ask_requirements / generate_images / modify_image ...
]

resp = client.chat.completions.create(
    model=model, messages=messages,
    tools=COMMANDER_TOOLS, tool_choice="auto",
    temperature=0.4, max_tokens=800,
)
message = resp.choices[0].message     # 可能含 message.tool_calls

模型决定调工具时,返回的 message.tool_calls 里就带着结构化参数,你的代码据此执行真实动作(如冻结积分 → 投 Celery 生图)。

④ 结构化输出:宽松解析 JSON

让模型输出套图规划(N 个镜头角色)时,要求它返回 JSON。但模型有时会画蛇添足包一层 ```json,所以解析要"宽松"——裸 JSON、代码块、首尾大括号都认:

def _extract_json(text: str) -> dict:
    try: return json.loads(text)                       # 裸 JSON
    except Exception: pass
    m = re.search(r"```(?:json)?\s*([\s\S]*?)\s*```", text)  # ```json``` 包裹
    if m:
        try: return json.loads(m.group(1))
        except Exception: pass
    a, b = text.find("{"), text.rfind("}")             # 首尾大括号兜底
    if a >= 0 and b > a:
        return json.loads(text[a:b+1])
    raise ValueError("LLM 返回的 JSON 无法解析")

4. 成本与风险提示


5. 总结与系列导航

一句话总结:做多模态智能体不用为每家模型写代码 —— 一个 OpenAI SDK + 中转站一把 Keymessages 塞图就是多模态,挂 tools 就是 function calling,再配个宽松 JSON 解析器,看图、决策、结构化输出全齐活。

适用人群:要做 AI 智能体、Agent、多模态应用的开发者与团队。

中转站与 chat/completions 文档可参考 4SAPI。欢迎在评论区分享你的 Agent 编排心得。