- peterpan1342026-09-11Lv2638元老会员
环境:Windows 11 + WorkBuddy(CodeBuddy 系 CLI)+ New API 架构中转站(Cloudflare 前置)
思路通用:任何「只会 OpenAI 协议的客户端」+「只剩 Anthropic 端点的中转站」 都适用,不限 WorkBuddyTL;DR
中转站的
/v1/chat/completions被 Cloudflare 按路径拉黑(怎么绕都是 403),全站唯一活着的是/v1/messages(Anthropic 协议),而我的 CLI 只会说 OpenAI 协议——看起来是个死局。解法:本机跑一个 LiteLLM 当翻译官,对内开 OpenAI 端点,对外说 Anthropic 话:
CLI ──OpenAI 格式──▶ 127.0.0.1:3456(LiteLLM 桥)──Anthropic 格式──▶ 中转站 /v1/messages全程本地回环,流式、工具调用全能翻,实测三天稳定。总共 4 步,10 分钟搞定。
一、先确认你真是「死局」:路径封锁的判定
同一个 key、同一个 IP,只换路径对比:
请求 结果 GET /v1/models200(key 有效、账号正常) POST /v1/chat/completions403,返回 Cloudflare HTML 拦截页 POST /v1/messages200,正常出内容 路径变体全灭,无一幸免:
路径 结果 /v1/chat/completions/、/v1//chat/completions、?x=1、/openai/v1/chat/completions全 403 /chat/completions(去掉 v1)200 但是 SPA 首页 HTML,没法用 结论:WAF 按路径拉黑了 OpenAI 端点,与 key、UA、额度全都无关。报错文案里那句 "check your account and provider settings" 纯属误导,别去查账号。
二、排查差点翻车:curl 的 403 不一定是真的
这坑必须单独讲,因为我差点被它带沟里。
晚间我用 curl 复测
/v1/messages,全 403 且响应体为空(content-type: application/octet-stream),和被封的 OpenAI 端点表现几乎一样——我以为全站沦陷,方案差点推翻。后来换 Node fetch 和 Python urllib 复测同一端点,全 200,内容正常。
真相:该站的 Cloudflare 除了按路径拉黑,还按 TLS 指纹(JA3)拉黑 curl 这个客户端。
识别特征:403 + 空 body +
application/octet-stream(真路径封锁返回的是 HTML 拦截页)。方法论(重要):测连通性必须用目标客户端的实际协议栈——CLI 跑在 Node 上就用 Node 的
fetch测,桥跑在 Python 上就用urllib测。curl 的结论只代表 curl 自己,--noproxy "*"排除代理干扰后仍要这么干。三、方案原理
┌──────────┐ OpenAI 格式 ┌─────────────────┐ Anthropic 格式 ┌──────────┐ │ CLI │ ───────────────▶ │ LiteLLM 本地桥 │ ────────────────▶ │ 中转站 │ │(只会OpenAI)│ 127.0.0.1:3456 │ (协议翻译层) │ /v1/messages │(只认Anthropic)│ └──────────┘ └─────────────────┘ └──────────┘- 对 CLI 侧:一座标准 OpenAI 兼容网关,baseURL 填
http://127.0.0.1:3456/v1 - 对中转站:一个说 Anthropic 协议的客户端,出站打
/v1/messages - 请求体、SSE 流式帧、
tool_calls↔tool_use,全部双向翻译
四、实施步骤(Windows,可跟做)
Step 0:前置验证(1 分钟,别跳过)
装任何东西之前,先用 Python urllib(不是 curl,理由见第二节)确认 Anthropic 端点活着、且 Python 的 TLS 指纹没被拉黑:
import json, urllib.request req = urllib.request.Request( "https://api.<你的中转站域名>/v1/messages", data=json.dumps({"model": "<模型名>", "max_tokens": 16, "messages": [{"role": "user", "content": "Reply OK"}]}).encode(), headers={"x-api-key": "er-你的key", "anthropic-version": "2023-06-01", "content-type": "application/json"}) print(urllib.request.urlopen(req, timeout=60).status) # 200 才继续这一步同时验证了两件事:端点活着 + Python 栈能过 Cloudflare。后者是本方案唯一的硬前提——如果 Python 也被 TLS 指纹拦,此路不通。
Step 1:建隔离环境装 LiteLLM
& "C:\<你的Python路径>\python.exe" -m venv "C:\litellm-bridge" & "C:\litellm-bridge\Scripts\pip.exe" install -i https://pypi.tuna.tsinghua.edu.cn/simple "litellm[proxy]"独立 venv,不污染系统环境。国内走清华镜像,1 分多钟装完。
Step 2:写桥的配置
C:\litellm-bridge\config.yaml:model_list: - model_name: gpt-5.6-luna # CLI 侧看到的模型名 litellm_params: model: anthropic/gpt-5.6-luna # anthropic/ 前缀 = 出站走 Anthropic 协议(关键!) api_base: https://api.<你的中转站域名> api_key: er-xxxxxxxx # 中转站发给你的 key - model_name: gpt-5.6-sol litellm_params: model: anthropic/gpt-5.6-sol api_base: https://api.<你的中转站域名> api_key: er-xxxxxxxx # 有几个模型抄几段 litellm_settings: drop_params: true # 关键!见踩坑 3 telemetry: false request_timeout: 600 general_settings: master_key: sk-bridge-你自己随便造一个 # 桥自己的 key,CLI 侧填这个Step 3:写启动脚本
C:\litellm-bridge\启动.bat(桌面建个快捷方式,双击就开、关窗就停):@echo off set HTTP_PROXY= set HTTPS_PROXY= set ALL_PROXY= set NO_PROXY=* title LiteLLM Bridge - 127.0.0.1:3456 "C:\litellm-bridge\Scripts\litellm.exe" --config "C:\litellm-bridge\config.yaml" --host 127.0.0.1 --port 3456 pause注意调用的是
litellm.exe,不是python -m litellm——后者已失效,见踩坑 1。
开头清空代理变量也是必须的,见踩坑 2。Step 4:客户端指向桥
任何 OpenAI 兼容客户端,把 baseURL 指到
http://127.0.0.1:3456/v1,key 填 master_key,模型名照旧。WorkBuddy(CodeBuddy 系)为例,
~/.workbuddy/models.json加条目(改完即时生效,无需重启):{ "id": "gpt-5.6-luna", "name": "gpt-5.6-luna(本地桥接)", "vendor": "Custom", "url": "http://127.0.0.1:3456/v1", "apiKey": "sk-bridge-你自己随便造一个", "supportsToolCall": true, "supportsImages": true, "supportsReasoning": true, "useCustomProtocol": false }五、验证清单(全绿才算通)
# 非流式:确认翻译和路由正常 curl.exe --noproxy "*" -sS http://127.0.0.1:3456/v1/chat/completions ` -H "Authorization: Bearer sk-bridge-xxx" -H "Content-Type: application/json" ` -d '{"model":"gpt-5.6-luna","max_tokens":16,"messages":[{"role":"user","content":"Reply OK"}]}' # 流式:确认 SSE 帧正常且以 data: [DONE] 收尾 # 加 "stream": true,检查输出里有 chat.completion.chunk 帧和 [DONE] # 工具调用:确认 tool_calls 翻译正常(agent 类 CLI 的命脉) curl.exe --noproxy "*" -sS http://127.0.0.1:3456/v1/chat/completions ` -H "Authorization: Bearer sk-bridge-xxx" -H "Content-Type: application/json" ` -d '{"model":"gpt-5.6-luna","max_tokens":200,"messages":[{"role":"user","content":"Beijing weather? Use the tool"}],"tools":[{"type":"function","function":{"name":"get_weather","parameters":{"type":"object","properties":{"city":{"type":"string"}}}}},"tool_choice":{"type":"function","function":{"name":"get_weather"}}}'我的实测结果(3 个模型 × 3 项测试):非流式 200 出内容、流式 200 标准 OpenAI SSE +
[DONE]、工具调用 200 且tool_calls参数翻译正确。另外带reasoning_effort参数也不报错(被 drop_params 兜住了)。六、踩坑汇总
# 坑 症状 解法 1 python -m litellm已死No module named litellm.__main__; 'litellm' is a package and cannot be directly executed1.100+ 版本删了 __main__入口,必须用Scripts\litellm.exe2 代理环境变量劫持出站 桥进程启动正常,请求全部超时/连接失败 启动前清空 HTTP_PROXY/HTTPS_PROXY/ALL_PROXY(bat 里set XXX=),设NO_PROXY=*3 CLI 发的 OpenAI 特有参数被 Anthropic 端拒绝 400 报参数不认识(如 reasoning_effort)config 里 drop_params: true,自动丢弃目标端不认的参数4 curl 测出假 403 403 + 空 body + octet-stream TLS 指纹拦截,换 Node fetch/ Pythonurllib复测再下结论5 中转站模型名悄悄变了 503 no available channel/model_not_found桥配置里的 model:用实测 200 的名字,别照抄旧文档6 LiteLLM 首次启动卡一下 日志报拉远程价格表超时 无碍,自动落回本地备份,不用管 七、局限与说明
- 唯一硬前提:Python 栈的 TLS 指纹没被中转站拉黑(Step 0 已验证)
- 桥是个常驻进程,用的时候得开着(双击 bat,黑窗别关);不用就关,零后台占用
- 多一跳本机回环,延迟增加可忽略(<1ms)
- key 安全:master_key 只在本机回环上暴露,中转站真实 key 只存在于桥配置里,不进客户端配置——某种意义上比直连还干净一点
结语
中转站的 Cloudflare 规则你控制不了,但「客户端协议」和「本机 127.0.0.1」都是你的地盘。打不过就绕,绕不过就翻译——LiteLLM 这类网关本来就是干这个的,拿来救「只剩 Anthropic 端点」的场,属于物尽其用。
有更好解法(比如客户端原生支持 Anthropic 协议的,像 opencode 换
@ai-sdk/anthropic就能直连)当然优先原生,本方案是给「客户端协议焊死在 OpenAI 上」的场景兜底的。 - 对 CLI 侧:一座标准 OpenAI 兼容网关,baseURL 填
- peterpan1342026-09-11Lv2638元老会员
测试AgentRouter和Just Worker的模型
点赞