一行环境变量,让任何 AI 服务变成 OpenAI:base_url 配置与本地网关实战(2026)

调 AI 的 API 这件事,10 个教程里 9 个用 OpenAI 的写法。创建客户端、填密钥、发消息,代码长得都差不多。问题是你要调的不一定是 OpenAI:可能是本地的 Ollama,可能是 DeepSeek 或者智谱,也可能是自己搭的网关。

大多数人这时候选择改代码,把 SDK 换掉,把调用逻辑重写一遍。其实不用。几乎所有主流服务商都留了同一扇门:把 OpenAI 的 SDK 指向另一个地址,剩下的代码一行不改。这扇门在配置里通常叫 base_url,而给它传值的最好方式,是环境变量。

这篇文章把两件事一次讲清:base_url 环境变量怎么配,以及本地服务怎么假装成 OpenAI。

为什么环境变量比写死在代码里好

先说结论:密钥和接口地址这类会变的东西,都别写死在代码里。

原因很实际。密钥写进代码,一提交 Git 就进了历史记录,哪怕下个版本删掉,历史里还在,翻出来就能盗刷你的余额。地址写进代码,测试环境和生产环境来回切换就得改代码,改完忘了提交又是一轮排查。

环境变量解决的就是这个问题。它是操作系统层面的配置,进程启动时读进去,代码里只管取。官方 SDK 默认就是这么设计的:Python 的 openai 库初始化时,api_key 不填就去读 OPENAI_API_KEY;Anthropic 的 SDK 同理,读 ANTHROPIC_API_KEY。密钥本来就该这么传。

地址也一样,而且更容易被忽略。openai 库会读 OPENAI_BASE_URL,Anthropic 的 SDK 会读 ANTHROPIC_BASE_URL,不设置就走官方默认地址。这个变量平时感觉不到存在,一旦你要换服务商或者接本地服务,它就是那扇门。

顺带一提优先级:如果代码里显式传了参数,参数优先;没传参数,SDK 才去找环境变量。所以老项目里 if base_url 不生效,先查是不是代码里已经写死了。

三行代码切换服务商

配置方法简单到不像话。以 Linux 和 macOS 为例:

export OPENAI_API_KEY="sk-你的密钥"
export OPENAI_BASE_URL="https://api.deepseek.com"
python your_script.py

Windows PowerShell 的写法:

$env:OPENAI_API_KEY="sk-你的密钥"
$env:OPENAI_BASE_URL="https://api.deepseek.com"
python your_script.py

然后是你的 Python 代码,注意看,里面没有任何服务商的名字:

from openai import OpenAI

client = OpenAI()  # 密钥和地址都从环境变量读

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

export 到哪家,这段代码就调哪家。DeepSeek 官方文档里给的 OpenAI 兼容地址就是这个:api.deepseek.com。换成智谱,把地址换成 open.bigmodel.cn 那一套,模型名换掉,代码还是这段代码。

想让配置长期生效,把 export 那两行写进 ~/.bashrc 或 ~/.zshrc,重开终端即可。别把密钥提交进项目仓库,写在系统配置里就行。

Anthropic 系的工具怎么办

Anthropic 的接口是另一套格式(/v1/messages),不过思路完全一样:ANTHROPIC_API_KEY 配密钥,ANTHROPIC_BASE_URL 配地址。我在 Anthropic Python SDK 的源码里确认过读取逻辑:显式传参最优先,其次是 ANTHROPIC_BASE_URL,再往后是 profile 配置文件。

有意思的是,DeepSeek 还提供了 Anthropic 格式的兼容地址 api.deepseek.com/anthropic。也就是说 Claude Code 这类只认 Anthropic 协议的工具,理论上也能通过改这两个变量接到 DeepSeek 上。这一招在需要特定工具链但想换便宜模型的时候特别好用。

本地模型怎么假装成 OpenAI

环境变量解决「换云服务商」,另一件事是「接本地服务」。你的电脑上跑着 Ollama,模型就在本地,怎么用熟悉的 OpenAI SDK 调它?

Ollama 官方文档给过答案:它内置了 OpenAI 兼容接口,地址是 http://localhost:11434/v1。把 OPENAI_BASE_URL 指过去就行:

export OPENAI_BASE_URL="http://localhost:11434/v1"
export OPENAI_API_KEY="ollama"

那个 "ollama" 是占位密钥。openai 库要求必须有密钥,否则报错,但 Ollama 本地服务根本不校验它的值。官方示例里就写着 api_key='ollama',注释原话是 "required but ignored",必填但被忽略。随便填个字符串都能通。

模型名换成你本地拉过的:

from openai import OpenAI

client = OpenAI()  # 读环境变量,指向本地 Ollama

resp = client.chat.completions.create(
    model="qwen3:8b",
    messages=[{"role": "user", "content": "你好"}],
    stream=True,
)
for chunk in resp:
    print(chunk.choices[0].delta.content or "", end="")

流式输出的写法和调云端完全一样,SSE 格式逐段吐字。云端和本地在你眼里只剩下两个环境变量的区别,工具链、重试逻辑、解析代码全部复用。

进阶:模型多到管不过来,就架个网关

环境变量切一两家服务商够用了。如果你的场景是:代码里要用五六个模型、团队里每个人都要配密钥、还想统计每个人花了多少钱,一家家配很快就乱了。

这时候该上 API 网关,比如开源的 LiteLLM。它把自己部署成本地服务(官方 Docker 快速开始文档里一行 docker compose 就能起,默认端口 4000),把 100 多家服务商收到同一个 OpenAI 兼容接口后面。你的应用只认网关,网关去认各家:

model_list:
  - model_name: gpt-5.6-terra
    litellm_params:
      model: openai/gpt-5.6-terra
      api_key: os.environ/OPENAI_API_KEY

这段配置的意思是:用户请求 gpt-5.6-terra,网关转给 OpenAI,密钥从网关自己的环境变量里读。应用侧拿着网关发的虚拟密钥,OPENAI_BASE_URL 指向 http://localhost:4000,剩下的用法一模一样。

密钥管理也收敛了:真正的服务商密钥只存在于网关服务器上,开发人员手里是可随时吊销的虚拟密钥,花销有记录,额度能设上限。之前写过一篇 LiteLLM 的实测部署指南,感兴趣可以深入看。

一张表记住所有地址

服务 OPENAI_BASE_URL 的值 说明
OpenAI 官方 不设置 SDK 默认值
DeepSeek https://api.deepseek.com 官方 OpenAI 兼容
智谱 https://open.bigmodel.cn/api/paas/v4 官方 OpenAI 兼容
本地 Ollama http://localhost:11434/v1 密钥占位随便填
LiteLLM 网关 http://localhost:4000 配虚拟密钥

常见坑就三个:地址少了 /v1 或者多了 /v1(各家要求不同,报 404 先查这个);环境变量设了但没生效(开了新终端没重新 export,或者代码里写死了参数);模型名写错(模型名不跟着地址走,地址对了名字错了照样报错,各家模型命名规则之前专门写过)。

写在最后

base_url 环境变量的价值,说穿了就一句话:把「连到哪里」从代码里抽出来,变成一行配置。云上、本地、网关,对代码来说都是同一个 OpenAI 接口,变的只是那两个变量。

下次再看到「支持 OpenAI 兼容接口」这句话,你就知道该干什么了:找地址,export,跑。

相关阅读:改一行 base_url,换一家大模型:API 兼容层使用指南讲了云上各家兼容层的更多细节;Ollama 本地部署完整教程带你把本地模型跑起来;遇到 401、404、429 先翻这篇 API 报错排查指南。

发表评论