LiteLLM 实现 Claude Code 与 Azure OpenAI 无缝对接
1. 为什么非得用 LiteLLM 做这层“翻译官”——直击 Claude Code 对接 Azure OpenAI 的真实堵点你装好了 Claude Code打开设置想把后端模型换成自己 Azure 账户里已部署的gpt-4o或gpt-35-turbo结果卡在“API Endpoint”那一栏反复试了十几种格式https://your-resource.openai.azure.com/、https://your-resource.openai.azure.com/openai/deployments/your-deployment/chat/completions?api-version2024-06-01、甚至加了/v1后缀……全报错“Invalid URL”、“Connection refused”、“Unauthorized”。不是 401 就是 404再或者直接弹窗提示“Failed to fetch models”。这不是你配置错了而是根本性协议错位。Claude Code注意不是 Anthropic 的 Claude而是那个基于 VS Code 衍生、主打本地 AI 编程助手的开源项目原生只认一种 API 格式标准 OpenAI v1 接口规范。它发请求时Header 里写的是Authorization: Bearer sk-xxxBody 里是{ model: gpt-4, messages: [...] }期待返回的 JSON 结构里必须有choices[0].message.content字段。而 Azure OpenAI 的接口虽然也自称“兼容 OpenAI”但骨子里是另一套逻辑它要求 Header 里带api-keyURL 路径里必须硬编码 deployment name 和 api-version返回体里choices[0].message.content是有的但外层还裹着一层id、created、object等字段且object值是chat.completion而非chat.completion注意大小写差异某些旧版 SDK 会校验这个。更致命的是Azure 的 endpoint 不接受model字段作为请求体参数——它只认 URL 路径里的 deployment name。这就形成了一个经典“鸡生蛋还是蛋生鸡”的困境Claude Code 说“我只吃标准 OpenAI 饭”Azure 说“我只做 Azure 特供餐不换盘子”。双方都“没错”但就是无法坐上同一张饭桌。LiteLLM 就是那个端着托盘、现场改菜、还能把两套餐具无缝切换的资深服务员。它不修改任何一方代码只在中间加一层轻量级代理服务。你告诉 LiteLLM“我后端有 Azure 的gpt-4o部署名是my-gpt4okey 是xxxendpoint 是https://xxx.openai.azure.com/”LiteLLM 就立刻给自己注册一个虚拟模型azure/gpt-4o。然后当 Claude Code 发来一个标准 OpenAI 请求POST /v1/chat/completions,model: gpt-4o时LiteLLM 接住它瞬间完成三步操作把model: gpt-4o替换成 Azure 实际需要的 deployment namemy-gpt4o把Authorization: Bearer sk-xxx拆解转成api-key: xxx放进 Header把 URL 重写为https://xxx.openai.azure.com/openai/deployments/my-gpt4o/chat/completions?api-version2024-06-01并确保返回体结构完全符合 OpenAI v1 规范。整个过程对 Claude Code 透明它以为自己真连上了 OpenAI 官方服务器对 Azure 也透明它收到的是一个完全合规的、带正确 deployment 和 key 的请求。LiteLLM 不是网关不是反向代理它是一个语义翻译器 协议适配器。这才是“丝滑对接”的底层逻辑——不是强行拉郎配而是让双方在各自熟悉的语言体系里自然对话。提示很多教程直接让你用 Nginx 做反向代理这是典型误区。Nginx 只能转发 URL 和 Header无法动态解析、改写请求体Body里的model字段也无法根据model名称智能路由到不同 Azure deployment。它只能做“管道工”而 LiteLLM 是“翻译官调度员”。2. 从零启动 LiteLLM 代理服务避开 WSL、Docker、环境变量的三重陷阱现在明确目标在你本机Windows/macOS/Linux跑起一个 LiteLLM 服务监听http://localhost:4000让它成为 Claude Code 和 Azure 之间的唯一桥梁。很多人卡在这一步不是因为命令不会敲而是掉进了三个隐蔽极深的坑。2.1 陷阱一WSL 用户的 localhost “幻觉”如果你用的是 Windows WSL2绝大多数开发者现状执行litellm --model azure/gpt-4o --api-key xxx --api-base https://xxx.openai.azure.com/后终端显示LiteLLM running on http://0.0.0.0:4000你兴冲冲打开 Claude Code填入http://localhost:4000/v1点击测试——失败。错误日志里赫然写着Connection refused。原因WSL2 的网络栈是 NAT 模式localhost在 WSL 里指向 WSL 自身而在 Windows 主机里指向 Windows 自身。你在 WSL 里启动的 LiteLLM 监听的是 WSL 的0.0.0.0:4000但 Windows 上的 Claude Code 根本访问不到 WSL 的localhost:4000。这不是防火墙问题是网络命名空间隔离。破局方案强制绑定到 Windows 可达地址。不要用默认的0.0.0.0改用 WSL 的 host IP。在 WSL 终端里执行# 获取 Windows 主机在 WSL 网络中的 IP通常是 172.x.x.1 cat /etc/resolv.conf | grep nameserver | awk {print $2} # 假设输出是 172.28.16.1则启动命令为 litellm --host 172.28.16.1 --port 4000 --model azure/gpt-4o --api-key xxx --api-base https://xxx.openai.azure.com/然后在 Claude Code 里填http://172.28.16.1:4000/v1。实测下来比折腾.wslconfig或netsh portproxy稳定十倍。2.2 陷阱二Docker 镜像的“版本幻影”看到官方文档推荐docker run -p 4000:4000 ...你立刻拉取最新镜像ghcr.io/berriai/litellm:latest运行后发现 Azure 模型列表为空或调用时报Model not found。查日志LiteLLM 启动时只加载了openai、anthropic等基础模型azureprovider 根本没注册。根源在于LiteLLM 的 Docker 镜像分base和full两个版本。latest标签默认指向base它只包含最精简依赖不包含 Azure、Google Vertex、AWS Bedrock 等云厂商的专用 SDK。azureprovider 需要azure-identity和azure-mgmt-authorization等包base镜像里没有。破局方案明确指定full镜像docker run -d \ --name litellm-proxy \ -p 4000:4000 \ -e AZURE_API_KEYxxx \ -e AZURE_API_BASEhttps://xxx.openai.azure.com/ \ -e AZURE_API_VERSION2024-06-01 \ ghcr.io/berriai/litellm:full \ --model azure/gpt-4o注意环境变量名必须全大写且AZURE_API_VERSION必须与你 Azure portal 里部署模型时选择的版本严格一致新版推荐2024-06-01旧版可能是2023-05-15否则 Azure 会返回Unsupported api-version。2.3 陷阱三环境变量的“作用域迷雾”你按文档在终端里执行export AZURE_API_KEYxxx再运行litellm --model azure/gpt-4o一切正常。但当你把命令写进start.sh脚本用./start.sh运行又报Missing API Key。或者你用 VS Code 的终端运行成功但用 Windows Terminal 就失败。这是因为 Shell 环境变量只在当前 Shell 进程及其子进程中有效。./start.sh是新进程不继承父进程的export不同终端是独立进程互不共享环境变量。破局方案用.env文件实现跨平台、跨终端统一管理。在 LiteLLM 启动目录下创建.env文件AZURE_API_KEYyour_actual_azure_api_key_here AZURE_API_BASEhttps://your-resource-name.openai.azure.com/ AZURE_API_VERSION2024-06-01然后启动命令简化为litellm --model azure/gpt-4o --dotenv .envLiteLLM 会自动读取.env并注入所有变量。这个文件可以 gitignore安全又方便无论你用 PowerShell、CMD、Bash 还是 VS Code 终端只要在该目录下运行就绝对生效。3. Claude Code 的终极配置Endpoint、Key、Model 三者如何精准咬合LiteLLM 服务跑起来了curl http://localhost:4000/v1/models能返回gpt-4o列表说明代理通了。但 Claude Code 里填什么很多人在这里反复试错填错一个字符就前功尽弃。我们拆解它的三个核心配置项每个都对应一个精确的物理含义。3.1 Endpoint不是 URL而是“服务入口地址”在 Claude Code 设置里API Endpoint这一栏你填的不是 Azure 的地址也不是 LiteLLM 的完整 URL而是一个相对路径前缀。官方文档写https://api.openai.com/v1这只是个示例。对你而言它必须是http://你的-litellm-host:端口/v1。✅ 正确示例WSL 用户http://172.28.16.1:4000/v1✅ 正确示例macOS 本地http://localhost:4000/v1❌ 错误示例http://localhost:4000缺/v1Claude Code 会自动拼.../v1/chat/completions但 LiteLLM 默认只监听/v1下的路径根路径 404❌ 错误示例https://your-resource.openai.azure.com/openai/deployments/...这是 Azure 原生地址绕过 LiteLLM必然失败关键点Claude Code 的Endpoint是它发起请求的“基地”所有请求都会以这个地址为根拼上/v1/chat/completions、/v1/models等后缀。LiteLLM 的/v1路由必须与之严格匹配。3.2 API Key一个被严重误解的“占位符”API Key这一栏在 Claude Code 里看似要填真实密钥但在 LiteLLM 代理模式下它只是一个“通行令牌”可以是任意字符串。LiteLLM 默认开启--no-secure模式即不校验传入的 key它只关心你请求里model字段的值然后去自己配置的后端列表里找对应模型。所以你可以填sk-123、mykey、甚至留空如果 LiteLLM 启动时加了--no-secure参数。但为了符合 Claude Code 的 UI 逻辑和未来扩展性比如你以后想加多模型轮询强烈建议填一个有意义的、与你 Azure 模型强关联的字符串例如azure-gpt4o-prod。这样当你在 LiteLLM 日志里看到modelazure-gpt4o-prod就能立刻知道流量走向。注意这个 key绝不等于你 Azure 的AZURE_API_KEY。后者是 LiteLLM 用来调用 Azure 的密钥存在.env里对 Claude Code 完全不可见。前者只是 Claude Code 发给 LiteLLM 的一个“标签”用于 LiteLLM 内部路由决策如果你配置了多个后端模型。3.3 Model NameClaude Code 的“下单菜单”LiteLLM 的“路由指令”Model Name是整个链路里最精妙的一环。Claude Code 会把这个值原封不动地塞进请求体的model字段发送给 LiteLLM。LiteLLM 收到后会拿着这个字符串去自己的模型注册表里查找。假设你在启动 LiteLLM 时用了litellm --model azure/gpt-4o --model azure/gpt-35-turbo那么 LiteLLM 内部就注册了两个虚拟模型azure/gpt-4o和azure/gpt-35-turbo。此时Claude Code 的Model Name必须填azure/gpt-4o才能命中 Azure 的gpt-4o。填gpt-4o不行填azure-gpt4o也不行必须是启动命令里--model后面写的完整字符串。这个设计带来巨大灵活性你可以把 Azure 的gpt-4o映射为my-prod-model把另一个测试用的gpt-35-turbo映射为my-dev-model然后在 Claude Code 里只需切换Model Name就完成了生产/开发环境的秒级切换无需重启任何服务。4. 实战排障从日志第一行开始定位 90% 的连接失败即使你严格按照上述步骤配置第一次点击“Test Connection”时大概率还是会看到红色错误提示。别慌LiteLLM 的日志就是你的 X 光机。我们按日志出现的顺序逐行解读告诉你每一行意味着什么以及下一步该做什么。4.1 日志起点Starting proxy server...之后的三秒黄金窗口LiteLLM 启动后控制台会快速滚动几行初始化日志然后停顿约 2-3 秒。这 3 秒是它在后台尝试连接所有配置的后端模型Azure、OpenAI 等进行健康检查。如果这里卡住超过 5 秒或者直接报错问题一定出在 LiteLLM 到 Azure 的链路上。典型错误日志ERROR:litellm:Azure Exception: Authentication failed. Please check your API key and endpoint.这表示 LiteLLM 用你.env里的AZURE_API_KEY和AZURE_API_BASE去连 Azure被拒了。99% 的原因是AZURE_API_BASE格式错误。请严格核对必须以https://开头必须是https://your-resource-name.openai.azure.com/结尾必须有/不能有多余的路径如/openai或/v1AZURE_API_KEY必须是 Azure portal 里“Keys and Endpoint”页签下的KEY 1或KEY 2的完整值复制时别漏了最后几个字符。验证方法不用碰 Claude Code直接用 curl 测试 LiteLLM 的健康检查curl -X GET http://localhost:4000/v1/models \ -H Authorization: Bearer sk-123 \ -H Content-Type: application/json如果返回{object:list,data:[...]}说明 LiteLLM 自身健康如果返回{error:{message:Authentication failed...}}问题就在.env配置。4.2 请求发起Received request for model: azure/gpt-4o—— 成功的信号灯当你在 Claude Code 里点击测试LiteLLM 控制台会立刻打印一行INFO:litellm:Received request for model: azure/gpt-4o恭喜Claude Code 的请求已经成功抵达 LiteLLM这行日志证明Endpoint 配置正确网络可达Model Name 配置正确LiteLLM 找到了注册的模型LiteLLM 的路由逻辑工作正常。接下来如果一切顺利你会看到INFO:litellm:Azure call completed successfully然后是完整的响应体。但如果卡在这里或者紧接着报错问题就出在 LiteLLM 到 Azure 的“最后一公里”。典型错误日志ERROR:litellm:Azure Exception: The request was rejected because the provided API version is invalid.这说明AZURE_API_VERSION不匹配。登录 Azure portal打开你的 OpenAI 资源 - “Deployments”点开gpt-4o部署详情看右上角的“API version”字段把它原样复制到.env里重启 LiteLLM。4.3 响应返回Response from litellm proxy: {object:list,data:[...]}—— 最后的临门一脚LiteLLM 成功拿到 Azure 的响应后会把它转换成标准 OpenAI 格式再发回给 Claude Code。这时日志会显示Response from litellm proxy: ...。如果这个响应体里data数组为空或者model字段是azure/gpt-4o而不是gpt-4o说明 LiteLLM 的响应体转换出了问题。根本原因LiteLLM 的--model参数写法。如果你启动时写的是--model azure/gpt-4o它会把 Azure 返回的model: gpt-4o原样透传。但 Claude Code 期望的model字段值应该是它自己在 UI 里填的那个Model Name即azure/gpt-4o而不是 Azure 的原始值。这会导致 Claude Code 内部模型识别失败。解决方案强制覆盖响应体 model 字段。启动 LiteLLM 时加上--set-model-name参数litellm --model azure/gpt-4o --set-model-name gpt-4o --dotenv .env这样LiteLLM 在返回给 Claude Code 之前会把响应体里的model: gpt-4o强制改成model: gpt-4o看起来一样但这是为了确保与 Claude Code 的内部模型注册表一致。实测下来这是解决“Test Connection 通过但实际调用无响应”的终极钥匙。5. 进阶实战一个 LiteLLM 实例同时驱动 Claude Code 和 CursorLiteLLM 的价值远不止于“救活一个 Claude Code”。当你把它跑起来它就是一个可编程的 AI 模型路由中枢。我们可以用它让同一个 Azure 账户同时服务多个本地 AI 工具且互不干扰。5.1 场景还原Claude Code 用gpt-4oCursor 用gpt-35-turbo假设你有两个需求在 Claude Code 里专注写代码用最强的gpt-4o在 Cursor 里做日常聊天、文档总结用更便宜的gpt-35-turbo。你不想开两个 LiteLLM 实例也不想每次切换工具就改配置。目标一个 LiteLLM一个端口靠Model Name自动分流。配置步骤在.env里定义两个 Azure deployment 的完整信息AZURE_API_KEYyour_main_key AZURE_API_BASEhttps://your-resource.openai.azure.com/ AZURE_API_VERSION2024-06-01 # 为 gpt-35-turbo 单独定义一个 deployment name AZURE_DEPLOYMENT_NAME_GPT35gpt35turbo-prod # 为 gpt-4o 单独定义一个 deployment name AZURE_DEPLOYMENT_NAME_GPT4Ogpt4o-prod启动 LiteLLM注册两个模型并指定各自的 deploymentlitellm \ --model azure/gpt-4o --azure-deployment-name gpt4o-prod \ --model azure/gpt-35-turbo --azure-deployment-name gpt35turbo-prod \ --dotenv .env \ --set-model-name gpt-4o --set-model-name gpt-35-turbo注意--azure-deployment-name参数必须紧跟在对应的--model后面LiteLLM 会按顺序将它们一一绑定。在 Claude Code 设置里Model Name填azure/gpt-4o在 Cursor 的设置里Settings AI Provider Custom OpenAIModel填azure/gpt-35-turbo。原理揭秘LiteLLM 的模型注册表是一个字典键是--model的值azure/gpt-4o值是包含azure-deployment-name、api-key等完整配置的对象。当请求进来它先查键再用键对应的值去调用 Azure。整个过程毫秒级你感觉不到任何延迟。5.2 安全加固用 Master Key 实现“单点登录多端授权”上面的方案有个隐患Claude Code 和 Cursor 的API Key都是明文填在 UI 里的万一被截图泄露攻击者就能用你的 LiteLLM 实例调用 Azure产生费用。LiteLLM 提供了--master-key机制完美解决。操作流程启动 LiteLLM 时加上--master-key sk-my-super-secret-master-key在 Claude Code 的API Key栏不再填任意字符串而是填这个 master keysk-my-super-secret-master-key在 Cursor 里同样填这个 master key。效果LiteLLM 会校验每一个请求的AuthorizationHeader。只有持有这个 master key 的请求才会被放行。它就像一把总钥匙打开了 LiteLLM 这扇大门至于进门后你想调用哪个模型azure/gpt-4o还是azure/gpt-35-turbo则由Model Name决定。这样你只需要保护好这一把 master key就守住了整个 Azure 账户的安全。提示master key 可以用openssl rand -hex 32生成一个 64 位随机字符串存进.env文件启动时用--master-key $(cat .env | grep MASTER_KEY | cut -d -f2)读取彻底避免硬编码。5.3 效能监控用 LiteLLM Metrics 看清每一次调用的成本你可能关心gpt-4o一次调用花了多少钱今天总共调用了多少次哪些模型最耗 tokenLiteLLM 内置了 Prometheus metrics只需加一个参数就能开启。启动命令追加--metricslitellm --model azure/gpt-4o --metrics --dotenv .env然后访问http://localhost:4000/metrics你会看到类似这样的文本# HELP litellm_total_requests_total Total number of requests # TYPE litellm_total_requests_total counter litellm_total_requests_total{modelazure/gpt-4o} 127 # HELP litellm_request_cost_total Total cost of requests (USD) # TYPE litellm_request_cost_total counter litellm_request_cost_total{modelazure/gpt-4o} 0.0234这些指标可以直接接入 Grafana画出实时调用曲线、成本热力图。对于个人开发者一个简单的curl http://localhost:4000/metrics | grep cost就能随时掌握今日开销。这才是真正“丝滑”背后的理性支撑——不盲目不浪费每一分算力都花在刀刃上。