ByteNoteByteNote
AI 工作流专栏 09:LLM API 接入与统一适配层
字

字节笔记本

2026年10月6日 · 约 48 分钟读完

AI 工作流专栏 09:LLM API 接入与统一适配层

API中转
¥120

本文是《从零成为 AI 工作流工程师》系列第 9 篇,主题是把大模型正式接进你自己的系统。Prompt 写得再好也只是"台词",你还得先把模型这个"演员"请上台。本文把 OpenAI、Claude、阿里通义、DeepSeek 四家主流大模型的 API 全部接通一遍,更关键的是带你设计一个统一模型适配层:一套代码,改一行配置就能切换模型。这是招聘 JD 里明确要求的能力("熟悉多家大模型 API、能做模型切换与降级"),也是生产级 AI 系统的标配架构。

本篇你将学到:

  1. 四家主流模型 API 的注册、Key 获取、价格档位与国内访问注意事项
  2. OpenAI SDK 的标准调用方式与核心参数(model / messages / temperature / max_tokens / top_p)
  3. messages 三种 role(system / user / assistant)的作用
  4. Claude API 的差异(system 是顶层参数)与通义、DeepSeek 兼容 OpenAI 协议的关键洞察
  5. 设计统一模型适配层:LLMClient 抽象加四个实现,业务代码只调 client.chat()
  6. 多模型对比与选型决策表
  7. 用 tenacity 做指数退避重试,处理 429 限流与超时
  8. API Key 安全管理(.env 加 python-dotenv)与成本核算

一、先把四把"钥匙"领到手:API Key 获取

在写代码之前,你得先有四把"钥匙":各家模型的 API Key。这一步看着简单,但国内开发者在这里卡半天的不在少数。逐家说明。

1.1 OpenAI(GPT 系列)

生活类比:OpenAI 就像 iPhone:产品最成熟,但有点"高冷",国内直连不通。

  • 注册入口:https://platform.openai.com
  • Key 获取:登录后进入 Dashboard → API Keys → Create new secret key。Key 只在创建时显示一次,务必立刻复制保存。
  • 国内访问注意:OpenAI 不对中国大陆开放注册(需海外手机号加信用卡),且 API 域名 api.openai.com 在国内无法直连。两种解法:
    1. 走代理或中转网关:很多团队用自建的海外代理节点,或第三方中转服务(把请求转发到 OpenAI,只需改 base_url)。
    2. 用 Azure OpenAI:微软提供的 OpenAI 服务,企业可正经签合同、走合规通道,国内可用,但需要企业资质。
  • 价格档位(2026 参考):gpt-4o 输入 $2.5/M tokens、输出 $10/M;推理模型 o3 更贵。轻量任务可用 gpt-4o-mini(约便宜 30 倍)。

1.2 Anthropic Claude

生活类比:Claude 像"文科加编程的双料学霸",长文和代码特别强,但脾气(协议)和 OpenAI 不太一样。

  • 注册入口:https://console.anthropic.com
  • Key 获取:Console → API Keys → Create Key。
  • 国内访问注意:Anthropic 同样不直接对中国大陆开放,需要海外手机号验证,国内访问通常也走代理。好消息是阿里云、AWS Bedrock 都提供了 Claude 的合规托管,国内企业可以通过百炼、Bedrock 正经调用,走的是国内或合规通道。
  • 价格档位:claude-sonnet-4 输入 $3/M、输出 $15/M;旗舰 claude-opus-4 更贵。长文本、代码任务性价比高。

1.3 阿里通义千问(Qwen)

生活类比:通义是"家门口的便利店":中文好、合规顺、人民币结算,国内项目首选之一。

  • 注册入口:阿里云百炼平台 https://bailian.console.aliyun.com
  • Key 获取:登录后进模型广场 / API-KEY 管理创建。国内手机号、实名认证即可,无门槛。
  • 国内访问注意:完全无障碍,国内直连,毫秒级延迟。新用户通常送免费额度。
  • 价格档位:qwen-plus 输入 ¥0.8/M、输出 ¥2/M;旗舰 qwen-max 略贵,还有开源版 qwen-turbo 极便宜。关键:通义兼容 OpenAI 协议,代码几乎不用改。

1.4 DeepSeek

生活类比:DeepSeek 是"国产性价比之王":能力接近 GPT-4o,价格只有它的 1/20。

  • 注册入口:https://platform.deepseek.com
  • Key 获取:登录后进 API Keys 创建。国内手机号注册即可。
  • 国内访问注意:国内直连,速度快。模型开源(V3、R1 权重公开),你也可以本地部署。
  • 价格档位:deepseek-chat(V3)输入 ¥1/M、输出 ¥2/M;deepseek-reasoner(R1 推理模型)略贵但仍是白菜价。完全兼容 OpenAI 协议。

1.5 一个表格速记

厂商国内直连注册门槛协议适合场景
OpenAI需代理海外卡、手机号OpenAI(原生)海外项目、质量优先
Claude需代理海外卡、手机号独立协议长文、代码、写作
通义 Qwen可直连国内实名兼容 OpenAI国内企业、中文场景
DeepSeek可直连国内手机号兼容 OpenAI国内项目、性价比

关键洞察:四家里三家(OpenAI、通义、DeepSeek)用同一套协议,只有 Claude 是"另类"。所以先学 OpenAI 协议,性价比最高,这也是本文后面默认用 OpenAI SDK 风格的原因。

四家主流模型 API 的协议兼容关系:OpenAI 协议是事实标准,通义与 DeepSeek 直接兼容,Claude 是独立协议


二、OpenAI SDK 调用:行业"普通话"

先装 SDK:

bash
pip install openai python-dotenv

2.1 生活类比:打电话

调用大模型 API,就像给一个聪明但没记忆的接线员打电话:

  • 你要先告诉它"你是谁、扮演什么角色"(system)
  • 再问它问题(user)
  • 它回答你(assistant)
  • 如果是多轮对话,把"你问、它答、你再问"的完整历史都重新念给它听(因为它每次都"失忆",靠 messages 列表重建记忆)

2.2 messages 三种 role

role谁在说话作用
system系统设定给模型"定调子":身份、风格、规则。一般放第一条
user用户提问、下指令
assistant模型模型之前的回答。多轮对话时必须带上,模型才记得"刚才说了什么"

为什么 system 单独拎出来? 因为它对模型的影响是全局的:优先级高于 user 消息,能稳定地约束模型行为(比如"只回答医疗问题、闲聊就拒绝")。

2.3 标准调用代码(可跑)

python
# llm_basic.py
import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()  # 从 .env 读取环境变量

client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    # 如用中转服务,取消下一行注释并填中转地址
    # base_url="https://your-proxy.com/v1",
)

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "你是一位资深 Python 程序员,回答简洁、带代码示例。"},
        {"role": "user", "content": "用一句话解释什么是装饰器。"},
    ],
    temperature=0.7,
    max_tokens=500,
    top_p=1.0,
)

print(response.choices[0].message.content)

2.4 参数详解

参数作用推荐值
model用哪个模型,如 gpt-4o、gpt-4o-mini按任务选
messages对话历史,role 加 content 组成的列表必填
temperature创造力,0 最稳定,1 以上更发散生产用 0 到 0.3
max_tokens输出最多生成多少 token(防超长)按需,默认够用
top_p核采样,和 temperature 二选一调节随机性默认 1.0,一般不动
stream是否流式输出先按 False 处理,流式属于进阶玩法

小白常踩的坑:temperature 和 top_p 一般只调一个,两个都动容易乱。生产环境锁 temperature=0,保证可复现。

2.5 多轮对话:记得带上历史

python
# 模拟多轮对话
history = [
    {"role": "system", "content": "你是友好助手。"},
    {"role": "user", "content": "我叫小明。"},
    {"role": "assistant", "content": "你好小明!很高兴认识你。"},
    {"role": "user", "content": "我刚才说我叫什么?"},  # 测试它"记不记得"
]

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=history,
    temperature=0,
)
print(resp.choices[0].message.content)
# 输出:你刚才说你叫小明。

模型本身是无记忆的,它能"记得",是因为你每次都把之前的对话原样塞进 messages。所以做聊天机器人时,你要自己维护这份 history(存数据库或 Redis)。


三、Claude API:那个"另类"

Claude 用自己的 SDK,而且有个最容易踩的坑:它的 system 不是 messages 里的第一条,而是和 messages 平级的顶层参数。

bash
pip install anthropic
python
# claude_basic.py
import os
from anthropic import Anthropic
from dotenv import load_dotenv

load_dotenv()

client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=500,
    system="你是一位资深 Python 程序员,回答简洁、带代码示例。",  # 注意:放在顶层
    messages=[
        {"role": "user", "content": "用一句话解释什么是装饰器。"},
    ],
)

print(response.content[0].text)

两个关键差异:

  1. system 是顶层参数,不放进 messages。如果你照搬 OpenAI 的写法把 system 塞进 messages[0],Claude 会忽略它(或表现奇怪)。
  2. 必须指定 max_tokens,否则报错。OpenAI 是可选的,Claude 是必填的。

其余几乎一样:messages 列表、多轮对话、temperature 都类似。所以适配层主要处理这两个差异点。


四、通义、DeepSeek:兼容 OpenAI 协议的"惊喜"

这是本篇最实用的一个洞察:通义和 DeepSeek 都能直接用 OpenAI SDK 调用,只需改 base_url 和 api_key。

python
# qwen_via_openai_sdk.py,通义千问
import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),                  # 通义的 Key
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",  # 通义的兼容端点
)

resp = client.chat.completions.create(
    model="qwen-plus",
    messages=[{"role": "user", "content": "你好,介绍一下自己。"}],
)
print(resp.choices[0].message.content)
python
# deepseek_via_openai_sdk.py,DeepSeek
import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com/v1",   # DeepSeek 的兼容端点
)

resp = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "你好,介绍一下自己。"}],
)
print(resp.choices[0].message.content)

看出来了吗?这两段代码和第二节 OpenAI 的代码几乎一模一样,只差 base_url、api_key、model 三个值。这就是"兼容 OpenAI 协议"的威力:你掌握了一套调用方式,就掌握了 3 家模型。

行业现状:因为 OpenAI 协议成了事实标准,几乎所有国产模型(智谱 GLM、月之暗面 Kimi、百川、零一万物)都提供了 OpenAI 兼容端点。学会 OpenAI SDK,国产模型你都能调。


五、核心:设计统一模型适配层

现在到了本篇精华。前面四家 API 各有差异(Claude 的 system 在顶层、必填 max_tokens;OpenAI、通义、DeepSeek 协议一致),如果业务代码里到处写 if model == "openai": ...,会乱成一锅粥。

工程上的标准解法是适配器模式(Adapter Pattern):定义一个抽象类 LLMClient,规定"所有模型都必须实现 chat() 方法",然后给每家模型写一个子类实现。上层业务只面向抽象,不关心底层是哪家模型。

统一模型适配层架构:业务代码只调 client.chat(),LLMClient 抽象基类之下一套实现,切换模型只改一个字符串

5.1 生活类比:万能遥控器

想象你家有 4 台不同品牌的电视(索尼、三星、LG、小米),每台遥控器按键布局都不一样。你买了一个万能遥控器,只定义了"开机、换台、调音量"三个通用按键,里面再适配每台电视的具体红外码。

  • LLMClient = 万能遥控器(定义通用接口)
  • 4 个子类 = 4 个适配器(把通用按键翻译成各品牌的具体信号)
  • 你的手 = 业务代码(只按通用按键,不管底下是哪台电视)

5.2 完整实现(可跑、有注释)

python
# llm_client.py,统一模型适配层
import os
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional
from dotenv import load_dotenv

load_dotenv()


@dataclass
class ChatResult:
    """统一的返回结构,屏蔽各家的差异"""
    content: str               # 模型输出的文本
    model: str                 # 实际用的模型名
    prompt_tokens: int = 0     # 输入 token 数(用于算钱)
    completion_tokens: int = 0 # 输出 token 数
    total_tokens: int = 0


class LLMClient(ABC):
    """抽象基类:所有模型适配器都要实现 chat()"""

    @abstractmethod
    def chat(
        self,
        messages: list[dict],
        system: Optional[str] = None,
        temperature: float = 0.7,
        max_tokens: int = 1024,
    ) -> ChatResult:
        """
        统一的对话接口。
        :param messages: [{"role": "user"/"assistant", "content": "..."}]
        :param system: 系统提示词(单独抽出,方便适配 Claude 的顶层参数)
        """
        ...


class OpenAIClient(LLMClient):
    """OpenAI 官方 + 所有兼容 OpenAI 协议的模型(通义、DeepSeek)"""

    def __init__(self, model: str, api_key: str, base_url: Optional[str] = None):
        from openai import OpenAI
        kwargs = {"api_key": api_key}
        if base_url:
            kwargs["base_url"] = base_url
        self.client = OpenAI(**kwargs)
        self.model = model

    def chat(self, messages, system=None, temperature=0.7, max_tokens=1024):
        # OpenAI 协议:system 放进 messages 第一条
        full_messages = []
        if system:
            full_messages.append({"role": "system", "content": system})
        full_messages.extend(messages)

        resp = self.client.chat.completions.create(
            model=self.model,
            messages=full_messages,
            temperature=temperature,
            max_tokens=max_tokens,
        )
        usage = resp.usage
        return ChatResult(
            content=resp.choices[0].message.content,
            model=self.model,
            prompt_tokens=usage.prompt_tokens if usage else 0,
            completion_tokens=usage.completion_tokens if usage else 0,
            total_tokens=usage.total_tokens if usage else 0,
        )


class ClaudeClient(LLMClient):
    """Claude:system 是顶层参数,max_tokens 必填"""

    def __init__(self, model: str, api_key: str):
        from anthropic import Anthropic
        self.client = Anthropic(api_key=api_key)
        self.model = model

    def chat(self, messages, system=None, temperature=0.7, max_tokens=1024):
        kwargs = {
            "model": self.model,
            "max_tokens": max_tokens,   # Claude 必填
            "messages": messages,       # system 不在这里
            "temperature": temperature,
        }
        if system:
            kwargs["system"] = system   # system 作为顶层参数

        resp = self.client.messages.create(**kwargs)
        usage = resp.usage
        return ChatResult(
            content=resp.content[0].text,
            model=self.model,
            prompt_tokens=usage.input_tokens,
            completion_tokens=usage.output_tokens,
            total_tokens=usage.input_tokens + usage.output_tokens,
        )


def create_client(provider: str = "openai") -> LLMClient:
    """工厂函数:根据 provider 名字创建对应适配器。
    切换模型 = 改这一个字符串。"""
    if provider == "openai":
        return OpenAIClient(
            model="gpt-4o-mini",
            api_key=os.getenv("OPENAI_API_KEY"),
        )
    elif provider == "qwen":
        return OpenAIClient(                          # 通义复用 OpenAIClient
            model="qwen-plus",
            api_key=os.getenv("DASHSCOPE_API_KEY"),
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        )
    elif provider == "deepseek":
        return OpenAIClient(                          # DeepSeek 也复用
            model="deepseek-chat",
            api_key=os.getenv("DEEPSEEK_API_KEY"),
            base_url="https://api.deepseek.com/v1",
        )
    elif provider == "claude":
        return ClaudeClient(
            model="claude-sonnet-4-20250514",
            api_key=os.getenv("ANTHROPIC_API_KEY"),
        )
    else:
        raise ValueError(f"未知的 provider: {provider}")

5.3 业务代码:怎么用

python
# app.py,上层业务,完全不知道底层是哪家模型
from llm_client import create_client

# 切换模型只改这一行!openai / claude / qwen / deepseek
client = create_client("deepseek")

result = client.chat(
    messages=[{"role": "user", "content": "用一句话解释什么是闭包。"}],
    system="你是一位资深程序员,回答简洁。",
    temperature=0,
)

print(f"[{result.model}] {result.content}")
print(f"token 用量:输入 {result.prompt_tokens} + 输出 {result.completion_tokens} = {result.total_tokens}")

看出威力了吗? 业务代码里没有任何 if provider == ...,切换模型只需把 "deepseek" 改成 "qwen"。这就是适配器模式的价值:解耦。

5.4 小结:为什么这么设计

设计决策理由
system 单独作为参数兼容 Claude 的顶层 system,又能在 OpenAI 协议里自动拼进 messages
统一返回 ChatResult业务代码不关心 Claude 是 resp.content[0].text 还是 OpenAI 是 resp.choices[0].message.content
通义、DeepSeek 复用 OpenAIClient它们协议一致,只需传 base_url,避免重复代码
工厂函数 create_client集中管理创建逻辑,切换、新增模型只改一处
抽象基类 LLMClient强制所有实现遵循同一接口,未来加新模型(如 Gemini)只需写一个子类

进阶提示:生产环境还可以在适配层加入重试、限流、降级、缓存、日志、计费埋点。本文先讲重试,其余能力思路相同,都可以在这层逐步加上。


六、多模型对比与选型策略

有了适配层,你可以用同一个问题跑 4 家模型,横向对比:

python
# compare.py,同一问题问 4 家
import time
from llm_client import create_client

question = [{"role": "user", "content": "用 100 字解释什么是 RAG。"}]

for provider in ["openai", "claude", "qwen", "deepseek"]:
    try:
        client = create_client(provider)
        t0 = time.time()
        result = client.chat(question, system="你是 AI 技术专家。", temperature=0)
        elapsed = time.time() - t0
        print(f"\n=== {provider}({elapsed:.1f}s,{result.total_tokens} tokens)===")
        print(result.content[:120], "...")
    except Exception as e:
        print(f"\n=== {provider} 调用失败:{e} ===")

跑完你会得到一张"质量、速度、成本"三维对比表。基于经验,给你一份选型决策表:

任务类型国内推荐海外推荐理由
日常对话 / 客服Qwen-Plus / DeepSeek-ChatGPT-4o-mini便宜、够用、快
复杂推理 / 数学DeepSeek-R1o3 / Claude推理模型强
长文分析 / 合同Qwen-Max(长上下文)Claude(200K 窗口)上下文长、准确
代码生成 / ReviewDeepSeek-V3 / Qwen-CoderClaude Sonnet代码能力强
中文写作 / 营销Qwen / DeepSeek不作重点中文母语级
多模态(看图)Qwen-VLGPT-4o / Gemini视觉理解

选型三原则:

  1. 先按"国内、海外"筛(合规第一)
  2. 再按预算定档位(能用 mini 就别用 max)
  3. 最后按任务类型微调(推理任务才上推理模型)

别迷信"旗舰就是最好"。日常任务用 gpt-4o-mini、deepseek-chat,又快又便宜,效果未必差。


七、错误处理与重试:让调用"皮实"

线上调 API,一定会遇到这些错:

错误原因处理
429 Too Many Requests限流(QPS、配额超了)指数退避重试
500 / 503服务端临时故障重试
超时网络抖动、模型慢重试 + 缩短 max_tokens
401 UnauthorizedKey 失效、写错不重试,直接报警

7.1 用 tenacity 做指数退避

bash
pip install tenacity
python
# llm_retry.py,给适配层加重试
from tenacity import (
    retry,
    stop_after_attempt,
    wait_exponential,
    retry_if_exception_type,
)
from openai import RateLimitError, APIConnectionError, APITimeoutError
from llm_client import create_client


class RobustClient:
    """包装一层,自动对可恢复错误做指数退避重试"""

    def __init__(self, provider: str, max_attempts: int = 5):
        self.inner = create_client(provider)
        self.max_attempts = max_attempts

        # 用 tenacity 装饰:遇到这三类错误才重试
        self._chat = retry(
            stop=stop_after_attempt(max_attempts),            # 最多重试 5 次
            wait=wait_exponential(multiplier=1, min=1, max=16),  # 1,2,4,8,16 秒
            retry=retry_if_exception_type(
                (RateLimitError, APIConnectionError, APITimeoutError)
            ),
            reraise=True,  # 重试用尽后抛原异常
        )(self.inner.chat)

    def chat(self, *args, **kwargs):
        return self._chat(*args, **kwargs)


# 使用
client = RobustClient("deepseek")
result = client.chat([{"role": "user", "content": "你好"}])

指数退避的意思:第一次失败等 1 秒重试,再失败等 2 秒,再 4 秒、8 秒,越等越久,给服务端喘息时间,避免一堆请求同时重试把服务打挂。

7.2 降级策略

重试 5 次还失败怎么办?降级到备用模型,而不是直接让用户看到报错:

python
def chat_with_fallback(question: str, primary="deepseek", fallback="qwen") -> str:
    """主模型挂了,自动切备用模型"""
    providers = [primary, fallback]
    for p in providers:
        try:
            client = RobustClient(p)
            return client.chat([{"role": "user", "content": question}]).content
        except Exception as e:
            print(f"[降级] {p} 失败:{e},尝试下一个...")
    raise RuntimeError("所有模型都不可用")

生产 AI 系统标配:主用 → 重试 → 降级 → 兜底(规则、缓存)。这样即使一家模型全线故障,你的产品也不至于瘫掉。


八、API Key 安全管理

这是新手最容易犯的致命错误:把 API Key 写死在代码里,然后 push 到 GitHub。结果 Key 一夜被盗刷几千美金(真事,每周都在发生)。

8.1 正确做法:.env 加 python-dotenv

在项目根目录建一个 .env 文件:

bash
# .env,这个文件绝不能提交到 Git!
OPENAI_API_KEY=sk-xxxxxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxx
DASHSCOPE_API_KEY=sk-xxxxxxxxxxxx
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxx

然后在 .gitignore 里加上:

.env

代码里用 python-dotenv 加载:

python
from dotenv import load_dotenv
load_dotenv()  # 把 .env 的内容读进环境变量

import os
key = os.getenv("DEEPSEEK_API_KEY")  # 永远从环境变量取

8.2 生产环境:用密钥管理服务

.env 适合本地开发。生产环境别用 .env,改用专业的密钥管理服务:

  • 阿里云 KMS、AWS Secrets Manager、HashiCorp Vault:集中存密钥,按权限下发,自动轮转。
  • 应用启动时从 KMS 拉取 Key,内存里用,绝不落盘。

核心原则:Key 永远不出现在代码仓库里。任何能 git log 的人都不应该看到 Key。


九、成本意识:每次调用都要算账

调 API 不是免费的,合格的 AI 工程师对每一分钱心里有数。

9.1 从响应里读 usage

每家 API 的响应都带 token 用量(第五节 ChatResult 已经封装好了):

python
result = client.chat([{"role": "user", "content": "解释量子力学"}])
print(f"输入 {result.prompt_tokens} tokens,输出 {result.completion_tokens} tokens")

9.2 算钱

python
# cost.py,按各家价格算单次费用
# 单价:每百万 token 多少美元(输入 / 输出)
PRICING = {
    "gpt-4o-mini": (0.15, 0.60),
    "gpt-4o":      (2.5, 10.0),
    "deepseek-chat": (0.14, 0.28),    # 折算成美元,1 元约 0.14 美元
    "qwen-plus":     (0.11, 0.28),
    "claude-sonnet-4-20250514": (3.0, 15.0),
}

def calc_cost(model, prompt_tokens, completion_tokens):
    in_price, out_price = PRICING.get(model, (0, 0))
    cost = (prompt_tokens / 1_000_000) * in_price + (completion_tokens / 1_000_000) * out_price
    return cost

# 示例:一次调用
cost = calc_cost("deepseek-chat", prompt_tokens=500, completion_tokens=200)
print(f"本次调用花费:${cost:.5f}")  # 约 $0.00013,几乎免费

把 cost 记进日志(每次调用都记),月底你就能画出"每个功能、每个用户花了多少钱"。这是成本治理的核心:不可观测的成本就是失控的成本。

9.3 省钱的三个习惯

  1. 能用小模型别用大模型:分类、提取、简单问答用 mini、turbo 版。
  2. 控制 max_tokens:别让模型"喋喋不休",按需截断。
  3. 缓存重复请求:同一问题直接返回缓存结果(适合 FAQ 场景)。

十、本章小结

  1. 四家模型 API:OpenAI、Claude 是海外加代理,通义、DeepSeek 国内直连。通义和 DeepSeek 兼容 OpenAI 协议,这是最重要的洞察。
  2. OpenAI SDK 是行业普通话:掌握它,3 家国产模型都能调。核心是 client.chat.completions.create 加 messages 三种 role(system 定调、user 提问、assistant 历史)。
  3. Claude 是"另类":system 是顶层参数、max_tokens 必填,适配时要注意。
  4. 统一模型适配层:抽象基类 LLMClient 加工厂函数 create_client,业务代码只调 client.chat(),切换模型只改一个字符串。这是生产 AI 系统的标配。
  5. 选型三步:地区、预算、任务类型。日常别迷信旗舰,mini、chat 版够用。
  6. 错误处理:用 tenacity 做指数退避重试,主模型挂了降级到备用模型。
  7. Key 安全:本地 .env 加 .gitignore,生产用 KMS,永不写死在代码里。
  8. 成本意识:每次调用读 usage 算钱并记日志,对小模型、缓存养成习惯。

十一、动手练习

练习 1(基础):注册 DeepSeek、通义其中一家(国内免费),用本篇的适配层代码跑通一次 client.chat(),把输出和 token 用量打印出来。

练习 2(进阶):用 compare.py 脚本,对同一个问题(如"用 200 字介绍杭州")分别调通义和 DeepSeek,记录两者的:响应内容、耗时、token 数、估算成本,写一份对比小结。

练习 3(挑战):给适配层加一个自动降级功能:主模型用 DeepSeek,调用失败自动切通义。再用 time.sleep 模拟一次 DeepSeek 超时,验证降级是否生效。(提示:参考第七节的 chat_with_fallback,把它做成适配层的一个方法。)


十二、延伸阅读

相关文章

分享: