Continue.dev 接自定义端点:私有部署与非标准网关踩坑指南
Continue.dev 官方文档把”接第三方中转”和”接自建端点”混在一起讲,导致很多人以为只要 apiBase 填对了就万事大吉。实际上,公开的中转服务(比如 Continue.dev 国内 API 配置完整教程 里讲的那种)和你自己搭的网关、私有部署模型,在 Continue.dev 里走的是同一套 provider: openai 适配器,但兼容性问题完全不是一个量级。本文只讲后者——当你的端点不是一个成熟商业中转、而是自己搭的网关、内网私有部署、或者非标准实现时,该怎么接、怎么排错。
如果你还没装过 Continue.dev、不熟悉 config.yaml 的基本结构,建议先看上面那篇打好基础,本文默认你已经能跑通一个标准中转端点。
一、先搞清楚”自定义端点”到底是哪一种
Continue.dev 里能塞进 apiBase 的端点,大致分三类,排错思路完全不同:
| 类型 | 例子 | 兼容性 |
|---|---|---|
| 成熟商业中转 | 按 OpenAI 协议完整实现的中转服务 | 高,照抄官方示例基本能跑 |
| 自建网关 | 公司内部用 FastAPI/Nginx 包装的转发层 | 中,取决于自己实现了多少 OpenAI 协议细节 |
| 本地/私有部署 | Ollama、vLLM、LM Studio、TGI | 中低,流式格式、字段命名经常和 OpenAI 有细微差异 |
第一类基本不用看这篇文章。后两类是本文的重点,问题几乎都出在”自己实现的端点没有 100% 复刻 OpenAI 协议”。
二、provider 该填 openai 还是自定义值
Continue.dev 的 provider 字段决定了它用哪套请求/响应解析逻辑,不是随便填的标签:
models:
- name: 内网网关
provider: openai # 只要端点是 OpenAI Chat Completions 协议,一律填 openai
model: internal-qwen-72b
apiBase: http://gateway.internal.company.com/v1
apiKey: internal-token
roles: [chat, edit]
关键认知:provider: openai 不代表”调用 OpenAI 官方”,而是代表”按 OpenAI 协议格式解析”。Ollama、vLLM 起的 OpenAI 兼容服务、你自己写的转发层,只要暴露的是 /v1/chat/completions 这套接口形状,都应该填 openai,而不是去找一个不存在的”custom”值。
Ollama 本地服务是例外——Continue.dev 给它单独做了 provider: ollama,走的是 Ollama 原生协议而不是 OpenAI 兼容层,两者不能混填,否则会报字段解析错误。
三、自定义鉴权头:不是所有网关都用 Bearer Token
标准 OpenAI 协议用 Authorization: Bearer <key>,但很多自建网关会用自定义 header(比如内部单点登录签发的 token、自定义的 X-API-Key)。Continue.dev 支持通过 requestOptions.headers 覆盖或追加请求头:
models:
- name: 内网网关
provider: openai
model: internal-qwen-72b
apiBase: http://gateway.internal.company.com/v1
apiKey: placeholder-not-used
requestOptions:
headers:
X-API-Key: your-internal-token
X-Team-Id: infra-team
roles: [chat]
注意:即使鉴权走自定义 header,apiKey 字段也建议填一个非空占位符,部分版本的 Continue.dev 在 apiKey 为空时会跳过整个请求头组装逻辑,导致自定义 header 也一起丢失。
四、流式响应格式不一致是最常见的报错源
自建网关和本地部署最容易在流式返回上和标准 OpenAI 协议出现细微偏差,典型症状:
- Continue.dev 侧栏卡住不动,网络面板能看到数据在传但 UI 不刷新 → 大概率是 SSE 的
data:前缀或[DONE]结束标记没有严格对齐 - 输出内容被截断或重复 → 网关把多个 chunk 合并/拆分的方式和 OpenAI 官方不一致
- Autocomplete 完全没反应 → 很多自建网关只实现了 Chat Completions,没实现 Completions(legacy)接口,而 Continue.dev 的自动补全默认走 legacy 接口
针对最后一种情况,Continue.dev 提供了强制切换开关:
models:
- name: 自建补全模型
provider: openai
model: internal-coder
apiBase: http://gateway.internal.company.com/v1
apiKey: placeholder
useLegacyCompletionsEndpoint: false # 强制走 chat/completions 而不是 completions
roles: [autocomplete]
排查流式问题最快的办法不是直接调 Continue.dev,而是先用 curl 手动测试端点是否符合协议:
curl http://gateway.internal.company.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: your-internal-token" \
-d '{
"model": "internal-qwen-72b",
"messages": [{"role": "user", "content": "hello"}],
"stream": true
}'
如果 curl 返回的流式数据本身就不规范(缺 data: 前缀、没有 [DONE]),问题在网关侧,不在 Continue.dev,先修网关再回来调插件配置能少走很多弯路。
五、多个自定义端点同时接入:按角色路由而不是按端点二选一
企业内部常见场景是”公司网关跑对话、本地小模型跑补全、另一个私有部署跑 embedding”,这时不要纠结用哪一个端点,Continue.dev 的 roles 机制本来就是为多端点路由设计的:
models:
- name: 公司网关-对话
provider: openai
model: internal-qwen-72b
apiBase: http://gateway.internal.company.com/v1
apiKey: placeholder
roles: [chat, edit]
- name: 本地-补全
provider: ollama
model: qwen2.5-coder:7b
apiBase: http://localhost:11434
roles: [autocomplete]
- name: 私有-embedding
provider: openai
model: internal-embedding-v2
apiBase: http://embed.internal.company.com/v1
apiKey: placeholder
roles: [embed]
三个端点互不干扰,各自只承担自己声明的角色。出问题时也更好定位——先看是哪个角色报错,就去查对应端点,不用把整个配置当成一个黑盒排查。
六、私有部署模型名不匹配的坑
vLLM/TGI 起服务时,model 字段通常要求填服务端实际加载的模型路径或别名,和你在 config.yaml 里习惯性填的”友好名字”经常对不上,报错通常是 model not found 或 404。排查顺序:
- 先用
curl <apiBase>/models看服务端实际暴露的模型列表(大多数 OpenAI 兼容服务都实现了这个只读接口) - 把返回列表里的
id原样填进config.yaml的model字段,不要自己编 - 如果服务端没实现
/models接口,去问维护网关的人要准确的模型标识,不要靠猜