部署在 EdgeOne Makers 上的 OpenCode Zen 免费模型网关。它只公开上游 ID 以 -free 结尾的模型,并为客户端提供不带后缀的模型别名。
在线地址:https://oc2api-edgeone.edgeone.dev
GET /v1/models过滤掉非免费模型,并将deepseek-v4-flash-free显示为deepseek-v4-flash。- 上游固定使用 OpenCode 的公开免费 Key
Bearer public。客户端无需提供 API Key,客户端传入的Authorization或x-api-key不会转发。 - 所有请求都会把顶层
model映射回上游*-freeID,并丢弃缺少可解析name的 function 工具(OpenCode CLI 与CLAUDE_CODE_SIMPLE=1客户端会把工具序列化为{"type":"function","function":{}},上游 Console 会以tools[0].function: missing field "name"拒绝)。若清理后tools为空数组,则删除该字段。
三个推理接口统一内部转为 Chat Completions 协议转发上游,再把响应转回各自的协议:
/v1/chat/completions:天生就是 Chat 协议,请求仅做模型映射、工具清理与 reasoning 兜底,响应(含 SSE 流)直接透传,不做额外改写。/v1/messages(Claude):请求把system、thinking、tool_use、tool_result、image内容块转为 Chat 消息与工具;响应反向转回 Claudemessage格式——文本、thinking块和tool_use输出,SSE 流则重写为message_start/content_block_start/content_block_delta/message_stop事件。/v1/responses(OpenAI Responses API):请求把input、instructions、function_call_output、内置apply_patch/shell工具等转为 Chat 消息;响应反向转回 Responses 的message/reasoning/function_call输出项,SSE 流重写为response.created/output_text.delta/function_call_arguments.delta/response.completed事件。
转换时保持 reasoning_content 与 thinking 的对应(Claude 侧显示为 thinking 块,Responses 侧显示为 reasoning 摘要),并修复缺失的 tool_result(无响应的 tool call 会补占位消息)。上游的错误响应和 4xx/5xx 状态码原样返回,不参与改写。
上游在 thinking 模式下要求历史中每条 assistant 消息都必须携带 reasoning_content,否则返回
[invalid_request_error] The reasoning_content in the thinking mode must be passed back to the API。
但 Claude Code、Cherry Studio 等多轮回传时往往只带回文本、丢掉了 thinking 块。网关对此做两层处理:
-
先还原真实推理内容:Claude 路径把客户端回传的
thinking内容块提取回reasoning_content;Responses 路径把reasoning条目累积回对应的 assistant 消息。 -
再以空串兜底:仍缺
reasoning_content(字段缺失或显式为null)的 assistant 历史消息补成""——上游会把"传了空推理"当作合法,只有字段整体缺失才拒绝。三条入口均已挂载:/v1/messages与/v1/responses:在请求转成 Chat 消息后调用ensureReasoningContent。/v1/chat/completions:走透传不进转换器,故在mapRequestBody内做同样的兜底。
thinking: { type: "disabled" }时跳过兜底,不做任何字段注入;返回给客户端的方向则由cleanStreamDelta负责,在不需要 reasoning 时把reasoning_content(含空串)从流中清理掉。注:上游为 OpenAI 兼容端点,网关不校验 Anthropic 原生 thinking 的
signature。若将来直连 Anthropic 官方端点,空串兜底会失效(官方要求signature原样回传),届时应改为丢弃无签名的 thinking 块。
查询免费模型:
curl https://oc2api-edgeone.edgeone.dev/v1/models发起 Chat Completions 请求:
curl https://oc2api-edgeone.edgeone.dev/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{
"role": "user",
"content": "Reply with exactly OK"
}
],
"stream": false,
"max_tokens": 128
}'启用 SSE 时只需设置 "stream": true。
| 客户端路径 | OpenCode Zen 上游路径 |
|---|---|
/v1/models |
/zen/v1/models |
/v1/responses |
/zen/v1/responses |
/v1/chat/completions |
/zen/v1/chat/completions |
/v1/messages |
/zen/v1/messages |
/zen/v1/* |
/zen/v1/*(原样透传) |
查询参数、端到端请求头和上游状态码会保留。逐跳头、Host、Content-Length 和客户端鉴权头会被移除,由运行时重新生成必要字段。
除上述四条会做协议转换的路由外,网关注册了 /zen/v1/* 路由,把请求原样转发到上游 OpenCode Zen 的同一路径:请求体、查询参数与响应(含状态码、响应头、SSE 流)都不做改写——不过滤免费模型、不追加 -free 后缀、不进行协议转换,也没有 reasoning_content 兜底。客户端需按上游原生协议调用(模型 ID 需自行使用 -free 后缀)。鉴权头处理与其它路由一致:客户端传入的 Authorization / x-api-key 被移除,统一注入 Bearer public。
注:上游在推理层对 Bearer public 强制模型门槛——付费模型(如 claude-opus-5、gpt-5.6-sol)会返回 401 AuthError,只有免费模型可被调用。因此即使透传原样转发 model,也无法借 public 令牌消耗付费额度(模型列表可见 ≠ 可调用)。
需要 Node.js 22 或更高版本:
npm ci
npm test启动 EdgeOne Makers 本地服务:
npm exec edgeone makers devEdgeOne CLI 默认监听 http://localhost:8088。本地调试环境不能通过 fetch 访问 EdgeOne 节点缓存或源站,因此真实上游连通性需要部署后验证。
登录并绑定 EdgeOne Makers 项目后运行:
npm exec -- edgeone makers deploy -a overseas -e production新增或变更 edge-functions/ 下的路由文件后,部署前需刷新平台级路由文件:npx edgeone makers generate-routes(注意:该命令在 routes.json 已存在时会跳过重新生成,需先删除 .edgeone/routes.json 再执行)。否则新路径(如 /zen/v1/*)虽然进了边端函数包,却不会触发,请求会落到默认静态页。
项目锁定使用 edgeone@1.6.19,仓库不包含账号 Token、.env 或本地 .edgeone 项目绑定。
- Edge Function 客户端请求 body 上限为 1 MB。
- 上游连接、读取和写入超时均设置为 300 秒。
- 每个请求只发起一次上游
fetch;网络异常返回通用502 Bad Gateway。 - 模型列表响应和三种推理请求体需要在函数中读取,受 1 MB body 限制。
/v1/chat/completions的响应流式透传;/v1/messages与/v1/responses的响应(含 SSE 流)会被解析并重写为对应协议。 - 除成功的模型列表响应外,上游 4xx、5xx、重定向、响应头和响应体不会被业务逻辑改写。
该服务没有代理层限流或访问控制。公开部署前应根据流量和滥用风险增加相应保护。
edge-functions/v1/[[default]].js EdgeOne 路由与代理实现
edge-functions/zen/v1/[[default]].js /zen/v1/* 原样透传路由(委托给主实现)
test/v1-proxy.test.js Node.js 单元测试