如何为Chat API添加一个新的大模型上游?渠道适配器开发实战教程
【免费下载链接】chat-apiOpenAI 接口聚合管理,我们致力于提供优质的API接入服务,让您可以轻松集成先进的AI模型至您的产品和服务。项目地址: https://gitcode.com/gh_mirrors/ch/chat-api
Chat API 是一个OpenAI 接口聚合管理平台,它把各家大模型厂商的接口统一封装成 OpenAI 兼容格式,让开发者用一把 Token 就能调用 Gemini、Claude、文心一言等上游模型。如果你想把新的上游(比如 Ollama、Cohere、DeepSeek)接入 Chat API,核心工作就是开发一个渠道适配器(Channel Adaptor):它负责把统一的 OpenAI 请求"翻译"成目标上游的私有协议,再把响应翻译回来。本教程将以真实源码为例,带你走完从定义渠道编号、实现适配器、注册系统到控制台测试的完整流程。
一、先搞懂:渠道适配器在整个项目中扮演什么角色
Chat API 的转发逻辑集中在relay/目录,一次请求的处理链路大致是:
用户请求 → 路由与中间件(router/relay-router.go)→ 选择渠道(middleware/distributor.go)→渠道适配器(
relay/channel/下的各家子目录)→ 上游模型
每个上游厂商的 API 协议都不同(鉴权方式、请求体字段、流式返回格式各不相同),而 Chat API 对外只暴露统一的 OpenAI 格式。渠道适配器就是中间的"翻译官",所有协议差异都被隔离在适配器内部。
relay/channel/下已经内置了几十种渠道,可以作为现成参考:
| 适配器目录 | 对接的上游 |
|---|---|
| relay/channel/openai/ | OpenAI / Azure / 各种 OpenAI 兼容服务 |
| relay/channel/anthropic/ | Claude |
| relay/channel/gemini/ | Google Gemini |
| relay/channel/baidu/ | 百度文心一言 |
| relay/channel/ollama/ | Ollama 本地大模型 |
| relay/channel/coze/ | 字节 Coze |
💡新手建议:写新适配器前,先找一个和目标上游"协议最像"的现有适配器通读一遍,比看文档快得多。
二、新渠道接入的完整路径:一共要改哪 5 处
| 步骤 | 文件 | 做什么 |
|---|---|---|
| ① 定义渠道类型 | common/constants.go | 新增ChannelTypeXxx编号,并加入ChannelBaseURLs列表 |
| ② 映射 API 类型 | relay/constant/api_type.go | 在ChannelType2APIType中把渠道号映射为APITypeXxx |
| ③ 实现适配器 | relay/channel/ 下新建目录 | 实现Adaptor接口,完成请求/响应转换 |
| ④ 注册适配器 | relay/helper/main.go | 在GetAdaptor的 switch 中返回你的适配器实例 |
| ⑤ 控制台配置测试 | 管理后台"渠道管理" | 添加渠道、填写 BaseURL 与 API Key、点击测试 |
以渠道编号为例,在 common/constants.go 中可以清晰看到编号是顺序分配的:
ChannelTypeOllama = 33 ChannelTypeAwsClaude = 35 ChannelTypeCoze = 36 // 新增渠道时取下一个未使用的编号即可同时需要把新渠道的默认 BaseURL 追加到同文件的ChannelBaseURLs数组中,这样前端创建渠道时会自动带出正确的默认地址。
三、适配器接口详解:需要实现的 9 个方法
所有适配器都要实现统一接口,定义在 relay/channel/interface.go:
type Adaptor interface { Init(meta *util.RelayMeta) GetRequestURL(meta *util.RelayMeta) (string, error) SetupRequestHeader(c *gin.Context, req *http.Request, meta *util.RelayMeta) error ConvertRequest(c *gin.Context, meta *util.RelayMeta, request *model.GeneralOpenAIRequest) (any, error) ConvertImageRequest(request *model.ImageRequest) (any, error) DoRequest(c *gin.Context, meta *util.RelayMeta, requestBody io.Reader) (*http.Response, error) DoResponse(c *gin.Context, resp *http.Response, meta *util.RelayMeta) (aitext string, usage *model.Usage, err *model.ErrorWithStatusCode) GetModelList() []string GetChannelName() string }各方法的职责可以这样记忆:
Init:初始化,比如按模型名选择不同协议版本GetRequestURL:根据meta.Mode(对话/向量化/图像生成等,定义见 relay/constant/relay_mode.go)拼出上游完整 URLSetupRequestHeader:设置鉴权头(Bearer、AK/SK 签名等)ConvertRequest/ConvertImageRequest:把 OpenAI 请求体转成上游私有格式DoRequest:发送 HTTP 请求(一般直接调用通用辅助函数)DoResponse:解析上游响应,回填 token 用量usage(这是计费的关键)GetModelList/GetChannelName:返回模型清单与渠道名称
📌 其中DoRequest几乎不需要自己写,直接复用 relay/channel/common.go 中的DoRequestHelper即可,它会自动处理 URL 拼接、请求头设置和代理转发(配合common/client/proxy.go的代理能力)。
四、以 Ollama 为例:写出一个最小可用适配器
Ollama 适配器(relay/channel/ollama/)是代码量最少的完整样例,非常适合新手仿写。它的目录结构就是新渠道的"标准模板":
adaptor.go—— 实现Adaptor接口constants.go—— 定义ModelList模型清单model.go—— 定义上游的请求/响应结构体main.go—— 响应解析(流式与非流式)
① 核心逻辑只有几十行,看 relay/channel/ollama/adaptor.go 的两个关键方法:
func (a *Adaptor) GetRequestURL(meta *util.RelayMeta) (string, error) { fullRequestURL := fmt.Sprintf("%s/api/chat", meta.BaseURL) if meta.Mode == constant.RelayModeEmbeddings { fullRequestURL = fmt.Sprintf("%s/api/embeddings", meta.BaseURL) } return fullRequestURL, nil } func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *util.RelayMeta) error { channel.SetupCommonRequestHeader(c, req, meta) req.Header.Set("Authorization", "Bearer "+meta.APIKey) return nil }② 用结构体描述上游协议,在 relay/channel/ollama/model.go 中:
type ChatRequest struct { Model string `json:"model,omitempty"` Messages []Message `json:"messages,omitempty"` Stream bool `json:"stream"` Options *Options `json:"options,omitempty"` }③ 在ConvertRequest中做字段映射,把统一的GeneralOpenAIRequest(定义于 relay/model/general.go)逐字段转换成ChatRequest。④ 在DoResponse中按meta.IsStream分支处理流式/非流式响应,并把prompt_eval_count/eval_count换算为usage,保证账单准确。
⚠️ 注意:如果上游的 token 计费口径与 OpenAI 不同,建议在 relay/util/model_mapping.go 中配置模型映射,而不是在适配器里硬编码。
五、把新渠道注册进系统
适配器写好后,还差两步注册:
① 在 relay/helper/main.go 的GetAdaptor中注册——这是系统"根据 API 类型找到适配器"的唯一入口:
case constant.APITypeOllama: return &ollama.Adaptor{}② 在 relay/constant/api_type.go 中完成"渠道号 → API 类型"的映射,并新增对应的APITypeXxx常量。
小技巧:如果你的目标上游兼容 OpenAI 协议,则无需新写适配器!直接在控制台创建"OpenAI"类型渠道、填入它的 BaseURL 即可,这正是 relay/channel/openai/compatible.go 支持的能力。
六、在控制台添加并测试你的新渠道
代码改完、服务重启后,进入管理后台的"渠道管理"页面:
操作步骤:
- 点击右上角"添加渠道",类型选择你新增的渠道类型
- 填写上游BaseURL与API Key(本地模型如 Ollama 通常无需 Key)
- 在"模型"栏粘贴你的模型清单(来自适配器的
ModelList) - 点击"测试"按钮验证连通性,成功后开启渠道并配置分组与权重
测试通过后,该上游的模型就会出现在用户侧的模型列表中,统一以 OpenAI 兼容格式对外服务 🎉
七、最佳实践与避坑清单
- 流式响应是最容易踩坑的部分:不同上游的 SSE 结束标记不同(
[DONE]vsdone: true),务必参考 relay/channel/ollama/main.go 中StreamHandler的逐行解析方式 - 错误码要规范:统一用
model.ErrorWithStatusCode返回,让上游 4xx/5xx 能被正确透传并计入渠道健康度 - 计费别漏:
DoResponse中一定要填充usage,否则该渠道请求无法统计 token 消耗(计费逻辑见 relay/util/billing.go) - 渠道测试失败会触发自动禁用:如果你的上游限流严格,测试接口要选轻量模型
- 参考学习路径:简单渠道看 relay/channel/ollama/,复杂渠道(多协议分支)看 relay/channel/ali/ 和 relay/channel/coze/
小结
为 Chat API 添加新的大模型上游,本质就是**"4 处代码 + 1 次测试"**:
- common/constants.go 中分配渠道编号
- relay/constant/api_type.go 中映射 API 类型
- relay/channel/ 下新建目录实现
Adaptor接口 - relay/helper/main.go 中注册适配器
- 控制台添加渠道并测试
掌握这套适配器开发流程后,你就能把任意协议的大模型服务接入 Chat API,让平台的能力随需求无限扩展。
【免费下载链接】chat-apiOpenAI 接口聚合管理,我们致力于提供优质的API接入服务,让您可以轻松集成先进的AI模型至您的产品和服务。项目地址: https://gitcode.com/gh_mirrors/ch/chat-api
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考