← 返回文章列表 / Back to list
usage

用 OpenAI SDK 兼容层调用免费 API

Calling Free APIs via the OpenAI SDK Compatibility Layer

⚠️ 待更新·2026-08-29核验 · 更新时间待核验 · 本文信息可能已过期,请以官方文档为准 更新时间:2026-08-29 · 核验状态:待更新 · 官方溯源待补

简介

Groq、Together AI、DeepSeek、NVIDIA NIM、OpenRouter 都遵循 OpenAI Chat Completions 协议。这意味着一套 openai SDK 代码,只换 base_urlapi_key,就能在所有这些平台之间无缝切换。本篇给出统一封装,并演示流式与异步两种进阶用法。

架构图

flowchart TD A[OpenAI SDK codebase] --> B{Switch base_url + api_key} B -->|groq.com| C[Groq LPU] B -->|together.xyz| D[Together AI] B -->|deepseek.com| E[DeepSeek] B -->|integrate.api.nvidia.com| F[NVIDIA NIM] C --> G[Same SDK shape] D --> G E --> G F --> G

安装

pip install openai python-dotenv

统一封装

import os
from dataclasses import dataclass
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

@dataclass
class Provider:
    name: str
    base_url: str
    api_key_env: str
    model: str

PROVIDERS = {
    "groq":       Provider("Groq",       "https://api.groq.com/openai/v1",       "GROQ_API_KEY",      "llama-3.3-70b-versatile"),
    "together":   Provider("Together",   "https://api.together.xyz/v1",          "TOGETHER_API_KEY",  "meta-llama/Llama-3.3-70B-Instruct-Turbo"),
    "deepseek":   Provider("DeepSeek",   "https://api.deepseek.com/v1",          "DEEPSEEK_API_KEY",  "deepseek-chat"),
    "nim":        Provider("NIM",        "https://integrate.api.nvidia.com/v1",  "NVIDIA_API_KEY",    "meta/llama-3.1-8b-instruct"),
    "openrouter": Provider("OpenRouter", "https://openrouter.ai/api/v1",         "OPENROUTER_API_KEY","meta-llama/llama-3.3-70b-instruct:free"),
}

def client_for(name: str) -> OpenAI:
    p = PROVIDERS[name]
    return OpenAI(api_key=os.environ[p.api_key_env], base_url=p.base_url)

def chat(name: str, prompt: str, system: str = "你是简洁的中文助手") -> str:
    p = PROVIDERS[name]
    resp = client_for(name).chat.completions.create(
        model=p.model,
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": prompt},
        ],
        temperature=0.3,
        max_tokens=256,
    )
    return resp.choices[0].message.content

if __name__ == "__main__":
    for name in PROVIDERS:
        try:
            print(f"[{name}] {chat(name, '用一句话解释什么是反向索引')}")
        except Exception as e:
            print(f"[{name}] ERROR: {e}")

流式封装

def chat_stream(name: str, prompt: str):
    p = PROVIDERS[name]
    stream = client_for(name).chat.completions.create(
        model=p.model,
        messages=[{"role": "user", "content": prompt}],
        stream=True,
    )
    for chunk in stream:
        delta = chunk.choices[0].delta.content
        if delta:
            yield delta

for piece in chat_stream("groq", "写一首秋天的诗"):
    print(piece, end="", flush=True)
print()

异步并发(Async)

跑批处理时,AsyncOpenAI 能并发请求多家 provider:

import asyncio
from openai import AsyncOpenAI

async def achat(name, prompt):
    p = PROVIDERS[name]
    client = AsyncOpenAI(api_key=os.environ[p.api_key_env], base_url=p.base_url)
    r = await client.chat.completions.create(
        model=p.model,
        messages=[{"role":"user","content":prompt}],
        max_tokens=64,
    )
    return name, r.choices[0].message.content

async def main():
    results = await asyncio.gather(*[achat(n, "hi") for n in PROVIDERS])
    for name, text in results:
        print(f"[{name}] {text}")

asyncio.run(main())

选型策略

  • 最低延迟:Groq(LPU)
  • 最便宜:OpenRouter :free 模型
  • 中文最强:DeepSeek
  • 本地化部署:NIM 容器
  • 多 provider 容灾:OpenRouter 的 fallback 字段

容灾与降级

生产环境推荐组合使用:主链路用付费稳定 provider(如 OpenAI/Anthropic),备份链路配置多家免费 provider,主链路异常时自动切换。可借助 OpenRouter 的 fallback 字段实现零代码容灾,也可在外层包 try/except 手动切换。并发场景下用 asyncio.Semaphore 控制并发度,批处理时把请求存到队列,worker 按各家限速消费,避免触发 429。跨时区场景下,境外 provider 在中国早晚高峰延迟波动大,可加连接池复用与本地代理。

流式输出封装

所有 provider 都支持 OpenAI 风格的流式响应,封装一个统一的生成器即可复用。下面这段代码把流式 token 转成 Python 生成器,业务侧无需关心是哪家 provider:

def chat_stream(name: str, prompt: str):
    p = PROVIDERS[name]
    stream = client_for(name).chat.completions.create(
        model=p.model,
        messages=[{"role": "user", "content": prompt}],
        stream=True,
    )
    for chunk in stream:
        delta = chunk.choices[0].delta.content
        if delta:
            yield delta

for piece in chat_stream("groq", "写一首秋天的诗"):
    print(piece, end="", flush=True)
print()

这样前端 SSE 推送、命令行打字机效果都能复用同一份生成器。

常见问题

  • 401:对应 provider 的环境变量没设或拼错,检查 api_key_env
  • model not found:不同平台的模型 ID 不同,以各自 /v1/models 返回为准。
  • 想加自动 fallback:在外层包 try/except,失败时切换到下一个 provider。
  • token 计费口径不一:各家对 system prompt 是否计入缓存不同,成本对比需统一基准。

掌握这套模式后,切换模型只需改一个字符串。

最佳实践

  • 抽象一个 make_client(provider) 工厂:统一返回 OpenAI(base_url, api_key),业务代码不关心 provider。
  • 环境变量按 provider 命名GROQ_API_KEYTOGETHER_API_KEYDEEPSEEK_API_KEY 等分开存。
  • base_url 末尾要带 /v1:少了 /v1 会 404,所有兼容层都遵循 OpenAI 路径约定。
  • 错误码语义统一:不同 provider 的 429 含义可能不同(RPM vs TPM),网关层要归一化。

相关文章 / Related

Gemini API 免费层调用在本地 IDE 中集成免费 APIOpenRouter API Key 申请与费率OpenCode 接入免费模型实战免费 OCR 与文档解析 API 实战