换大模型 API 要改哪些代码:三处必改配置,加四类参数兼容检查

2026-10-12 48 0

先说结论:如果新旧两边都走 OpenAI 兼容协议(用 OpenAI SDK,或者直接请求 /v1/chat/completions),必改的只有三处:客户端初始化时的 base_url 和 api_key,以及请求里的 model。messages 列表、role、content 这套主体结构一般不用动。

不过,改完这三处能不能直接上线,要看代码里有没有用到下面四类东西:

  1. 输出长度参数:max_tokens 还是 max_completion_tokens
  2. 采样参数:temperature、top_p、presence_penalty 等
  3. 流式输出里的 usage 统计和推理过程字段
  4. 工具调用(tools / tool_choice)和结构化输出(response_format)

这四类都没用到,三处配置改完基本就能跑。用到了,就按下面的顺序逐项检查。

换模型时的三层改动:必改的客户端配置,以及需要按情况检查的请求参数和响应解析

先确认:迁移后还在兼容协议里吗

这一点决定了改动量有多大。

  • 新旧都是 OpenAI 兼容的 Chat Completions:属于本文讨论的情况,改动集中在配置和参数上。
  • 代码用的是 Responses API:先确认目标端点支持这条接口路径。如果不支持,要么把调用改回 Chat Completions,要么继续用原来的服务。两套接口的请求和响应结构不同,不是改一个 URL 就能切过去的。
  • 从兼容协议换成某家厂商的原生 SDK:消息格式和返回结构都可能变,相当于重写调用层。建议在业务代码和 SDK 之间加一层自己的封装,以后再换模型就只改这一层。

第一步:改三处配置,并把它们从代码里拿出来

很多项目迁移时最费事的地方,是模型名和地址散落在几十个文件里。建议借这次迁移,把三个值统一改成从环境变量读取:

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.environ["LLM_BASE_URL"],  # 新端点地址,通常带 /v1
    api_key=os.environ["LLM_API_KEY"],
)
MODEL = os.environ["LLM_MODEL"]

resp = client.chat.completions.create(
    model=MODEL,
    messages=[{"role": "user", "content": "你好"}],
)

这样做以后,切换模型和回滚都只需要改配置,不用重新发版。Node.js、LangChain 的写法大同小异,入口参数名略有区别,可以参考 Python 调用 AI API 和 LangChain 怎么改自定义 base_url。地址要不要带 /v1、改完报 404 怎么查,在 OpenAI 兼容接口怎么用 里有说明。

如果目标是 NexAIX,端点是 https://api.nexaix.net/v1,提供的是 OpenAI 兼容接口,把 base_url 换成这个地址、填上新的 Key 即可。model 要填目标模型在平台上的准确名称,不能沿用旧平台的写法。可用模型和名称以 模型清单 为准。每个模型页都标明了供给方式:开源权重模型部署在自有算力上,闭源模型走厂商官方授权渠道。下面几步要核对的参数支持情况,也到对应模型页去看。

第二步:检查输出长度参数

这是换模型后最常见的 400 报错来源。

传统的 Chat Completions 用 max_tokens 限制输出长度。OpenAI 的 o 系列推理模型和一些较新的模型改成了要求 max_completion_tokens,传旧参数会直接报错。改名的原因是推理模型会生成一段用户看不到的思考内容(reasoning tokens),这部分同样消耗额度。

所以这里有两件事要处理:

  • 按模型类型决定传哪个参数名;
  • 给推理模型设上限时,要给思考过程留出余量。上限压得太紧,可能出现思考还没结束就被截断、可见输出很短甚至为空的情况。

第三步:采样参数不要写死

不同模型对采样参数的支持范围不一样。有的模型 temperature 只接受 0 到 1,有的接受 0 到 2。深度推理模型通常把 temperature、top_p、presence_penalty 固定住,或者干脆不接受这些参数。

如果旧代码在每个请求里都写死了 temperature=1.5 这类值,换到推理模型上就可能报错。比较稳妥的做法是集中构造参数,按模型决定传什么:

# 按目标模型的文档填写,不要凭模型名猜
REASONING_MODELS = {"<推理模型名>"}

def build_params(model: str, max_out: int, temperature=None) -> dict:
    params = {}
    if model in REASONING_MODELS:
        params["max_completion_tokens"] = max_out
        # 推理模型通常不接受或固定采样参数,这里直接不传
    else:
        params["max_tokens"] = max_out
        if temperature is not None:
            params["temperature"] = temperature
    return params

resp = client.chat.completions.create(
    model=MODEL,
    messages=messages,
    **build_params(MODEL, 2048, temperature=0.7),
)

第四步:流式输出里的 usage 和推理字段

开启 stream=True 后,usage(Token 消耗)不一定会自动返回。如果监控、计费或限额代码依赖它,迁移后很容易出现「请求正常,统计全是空」的情况。按 OpenAI 的约定,需要显式请求:

stream = client.chat.completions.create(
    model=MODEL,
    messages=messages,
    stream=True,
    stream_options={"include_usage": True},
)

usage = None
for chunk in stream:
    if chunk.choices:  # 携带 usage 的最后一个 chunk,choices 可能为空
        delta = chunk.choices[0].delta
        if delta.content:
            print(delta.content, end="")
    if getattr(chunk, "usage", None):
        usage = chunk.usage

有两点需要注意:

  • 兼容层不一定支持 stream_options。有的会忽略它,有的可能报错,要在目标端点上实际跑一次。
  • 推理模型的思考过程字段、reasoning tokens 统计,不同实现的返回方式不一样。解析代码要容忍字段缺失,不要因为少了一个字段就让整条流中断。

第五步:工具调用和结构化输出

如果代码依赖 tools、tool_choice 或 response_format(JSON Mode / Structured Outputs),要先确认目标模型原生支持这些参数,不能默认「兼容接口就一定支持」。

目标模型只支持纯文本对话时,需要在业务层做降级:在 Prompt 里写明输出格式,再用正则或 JSON 解析取出结果,解析失败就重试或报错。这种方式比原生支持脆弱,在高频或格式要求严格的场景里,最好还是换一个支持工具调用的模型。

上线前怎么验证

能跑通不等于能上线。建议准备一组有代表性的真实输入,在新旧两边各跑一遍,对比以下几项:

  • 报错率:重点看 400,大多是参数名或参数取值不被接受。错误码的含义可以对照 AI API 错误码怎么看。
  • finish_reason:如果大量出现 length,说明长度上限设小了,推理模型尤其要注意。
  • JSON 解析成功率、工具调用成功率:业务依赖结构化结果时,这两项比回答内容本身更关键。
  • usage 是否正常回传:流式和非流式都要检查。
  • 回答质量:为旧模型调好的 Prompt,换到新模型上效果可能不一样,关键链路要人工抽查一部分结果。

验证通过后,用前面抽出来的配置项做灰度:先让一部分流量走新模型,观察一段时间再全量切换。出了问题,把配置改回去就能回滚。如果要在新端点上跑这组回归测试,可以先注册领取测试额度,接入步骤见官网导航中的「文档」。

相关文章

Claude 和 GPT API 对比:协议差异、缓存机制与迁移成本怎么算
gpt-oss-120b API 接入指南:选型判断、reasoning_effort 调档与降配验证
GPT-5.6 Terra API 接入指南:选型判断、推理档位与降配验证
统一AI API 接入 LangChain:langchain-openrouter 专用包与 ChatOpenAI 覆盖 base_url 该怎么选(2...

评论(0)

暂无评论

发布评论