Skip to content

Repository files navigation

routeOpen

最小化的 OpenAI 兼容中转站。网关跑在 Cloudflare Workers 上,模型后端既可以是任意 OpenAI 兼容服务,也可以是通过 Cloudflare Tunnel 接回来的本机 Cursor SDK 容器。

OpenAI 客户端
  │  Authorization: Bearer sk-ro-...
  ▼
Worker (hashneuron.space 控制台 + api.hashneuron.space API)
  │                                    鉴权 / 限流 / 配额 / 渠道选择 / 用量记账
  │   ├── D1                           令牌、渠道、请求日志
  │   └── Durable Object               每令牌的 RPM 计数
  │
  ├──► 渠道 A:https://api.openai.com/v1        直连 OpenAI 或任何兼容端点
  └──► 渠道 B:https://bridge.hashneuron.space/v1
              │  Cloudflare Tunnel
              ▼
         本机 Docker 容器(Node + @cursor/sdk)──► Cursor API

两条链路对客户端完全一致:都是 /v1/chat/completions。对 Worker 来说本机 bridge 也只是一个普通渠道,网关侧没有任何特殊分支。

控制台

https://hashneuron.space/ 是一个仿 platform.openai.com 的控制台,由 Worker 的静态资源 托管,和 API 同源,所以前端直接用相对路径调 /v1/admin,没有跨域问题。

登录

控制台支持 GitHub 和 Google 授权登录,另外保留 ADMIN_TOKEN 作为脚本通道和救急入口。

会话是 HMAC-SHA256 签名的 cookie(ro_session={userId}.{exp}.{sig},HttpOnly / Secure / SameSite=Lax,30 天),服务端不存 session 记录,只在校验时回查用户是否仍被放行。签名 密钥取 SESSION_SECRET,没配就退回 ADMIN_TOKEN——也就是说换掉 ADMIN_TOKEN 会让所有 会话立刻失效。

授权登录即注册,不需要审批,和常规的第三方登录一致。

账号和登录方式是分开的:users 是账号,identities 记录绑了哪些 provider。登录时按已验证 邮箱认人,所以同一个人用 GitHub 还是 Google 进来都落在同一个账号上,看到的是同一批密钥和 用量。只有 provider 明确标记为已验证的邮箱才参与关联,否则别人拿你的邮箱注册一个第三方账号 就能顶掉你的账号。拿不到邮箱的情况下会各自独立成账号。

安全性靠数据隔离而不是准入门槛:

  • 第一个登录的人是 owner,能看全量数据,并且独占 Channels、Users、Settings 三个页面。 所以部署完应该尽快自己登一次把 owner 占住。
  • 其余用户是普通成员,只看得到自己签发的密钥和自己产生的用量,上游渠道对他们完全不可见 ——就像 OpenAI 不会把自己的算力供应商暴露给用户一样。
  • owner 可以在 Users 页面停用或删除某个账号。

普通成员默认使用 Free 套餐,限制按账号聚合,创建多把 API Key 不能绕过:

  • 5 RPM
  • 每日 200,000 tokens(UTC 零点重置)
  • 最多 2 把 API Key
  • 同时 1 个请求

owner 不受这些限制,并可在 Users 页把成员改为自定义额度。单把 Key 自身的 RPM、总配额和 模型白名单仍然保留;请求必须同时满足 Key 限制和用户限制。

配置登录方式(Settings 页面,owner 可见):

  • GitHub — 点「一键创建 GitHub App」,跳到 GitHub 确认后凭据自动写回;也可以自己建 OAuth App 再把 Client ID / Secret 填进来。回调地址 https://<域名>/auth/github/callback
  • Google — 在 Google Cloud Console 建 OAuth 2.0 客户端(类型选 Web application), 授权重定向 URI 填 https://<域名>/auth/google/callback,然后把 Client ID / Secret 填进来。

凭据也可以走 Worker secret,优先级高于数据库里的配置,配了之后控制台不允许再改:

npx wrangler secret put SESSION_SECRET
npx wrangler secret put GITHUB_CLIENT_ID
npx wrangler secret put GITHUB_CLIENT_SECRET
npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET

/admin/* 同时认会话 cookie 和 ADMIN_TOKEN。cookie 是 SameSite=Lax,写操作再校验一次 同源;/v1/* 才开放 CORS,/admin/auth 保持同源。

页面

  • Chat — 模型下拉按 Composer / Claude / GPT / Gemini / Grok 分组,列出所有渠道 声明的模型;支持流式、思考过程折叠、system prompt、temperature、max_tokens、 reasoning_effort,回复下方显示本次真实 token 消耗。
  • API keys — 签发、停用、删除自己的令牌,明文只在创建后弹窗里出现一次。
  • Usage — 请求数 / 错误数 / token 用量 / 平均延迟,按模型统计与最近请求明细。
  • Channels(owner)— 增删改上游、连通性测试,以及一键同步上游模型列表。
  • Users(owner)— 停用 / 提权 / 删除控制台用户。
  • Settings(owner)— 配置 GitHub 与 Google 登录。

Chat 页面不会拿管理口令去调模型,而是自动签发一把名为 console 的普通客户端令牌, 走的是和外部客户端完全相同的 /v1 链路,因此限流、配额、日志都照常生效。

能力

对外(OpenAI 兼容)

端点 说明
GET /health 探活
GET /v1/models 汇总所有启用渠道的模型
POST /v1/chat/completions 支持 stream: true(SSE)与非流式
POST /v1/completions 透传
POST /v1/embeddings 透传
POST /v1/responses 透传

中转站自身

  • 自签发令牌 sk-ro-...,数据库只存 SHA-256,上游密钥不下发给客户端
  • 每令牌的 RPM 限流、token 配额、模型白名单、有效期、启停
  • 每用户聚合的 Free 套餐限流、每日 token 配额、Key 数与并发限制
  • 多渠道:优先级 + 权重随机,失败自动转移(最多 3 次),4xx 不重试直接回传
  • 模型别名映射,例如把 gpt-4o-mini 指到某渠道的实际模型
  • 用量记账:优先用上游真实 usage,拿不到时估算并在日志标记 estimated
  • 请求日志与统计,定时任务按保留天数清理

未做(有意的边界):多租户计费、Web 管理后台、n>1 / logprobs 这类 Cursor 侧对不上的参数。

走 Cursor bridge 时注意:SDK 是 agent 运行时而不是裸模型接口,每次请求都会带上它自己的 系统提示,一句"你好"实测也要 11k 左右的 prompt tokens。配额按这个量级估算。

一、部署网关(Cloudflare)

npm install
npx wrangler login

# 建库,把返回的 database_id 填进 wrangler.jsonc
npx wrangler d1 create routeopen
npx wrangler d1 migrations apply routeopen --remote

npx wrangler secret put ADMIN_TOKEN     # 管理 API 口令
npx wrangler deploy

自定义域名在 wrangler.jsoncroutes 里,默认 api.hashneuron.space

二、部署本机 bridge(Cursor SDK)

  1. 在 Cloudflare Zero Trust → Networks → Tunnels 新建隧道,拿到 TUNNEL_TOKEN, public hostname 配成 bridge.hashneuron.spacehttp://localhost:8080。 走 API 建隧道的话面板不会替你建 DNS,要自己补一条 CNAME bridge → <tunnel-id>.cfargotunnel.com(proxied), 对应的 API token 需要 Zone → DNS → Edit 权限。
  2. 准备环境变量:
cd bridge
cp .env.example .env
# 填 CURSOR_API_KEY、TUNNEL_TOKEN,并生成 BRIDGE_TOKEN:
openssl rand -hex 32
  1. 一条命令拉起全部(dockerd → bridge 容器 → cloudflared 隧道):
./local-up.sh          # 可重复执行,已在跑的组件会跳过
./local-down.sh        # 停 bridge 与隧道,保留 dockerd
./local-down.sh --all  # 连 dockerd 一起停

这台机器没有 systemd,所以脚本用 nohup 拉起进程并把 PID 记在 logs/*.pid, 容器本身靠 compose 的 restart: unless-stopped 保活。停止按 PID 文件进行, 不用 pkill -f:模式匹配会误伤命令行里恰好含有该字符串的其他进程。

日志在 bridge/logs/dockerd.logcloudflared.log,容器日志用 docker logs routeopen-bridge

CURSOR_API_KEY 只存在本机,不进 Cloudflare。隧道是公网可达的,所以 bridge 强制 校验 BRIDGE_TOKEN,缺少就拒绝启动。

bridge 默认允许 Cursor run 最长执行 90 秒。客户端断开或超时后会调用 SDK 的 run.cancel() 并释放并发槽,避免已超时的请求继续占住队列。Worker 等待 bridge 首个响应头的时间为 100 秒,略长于 run 超时,以便把明确错误返回给客户端。

受限网络下的注意事项

这套东西跑在一台出网受限的机器上,几个结论值得记下:

  • Cursor SDK 模型请求直连。Node 容器不注入 HTTP_PROXY / HTTPS_PROXY; SSH SOCKS 长连接会让本地运行时的 Agent.create() 卡住,而且代理出口也不能解除 Cursor 账号级的 GPT / Claude 区域限制。
  • 镜像构建不联网。容器内构建阶段不经过 SSH 隧道,镜像里跑 apt-getnpm install 会直连外网挂住。所以 Dockerfile 只做拷贝,依赖先在宿主机 npm install。 ripgrep 和沙箱助手由 @cursor/sdk-linux-x64 提供,不需要 apt。
  • 拉基础镜像要让 daemon 走代理。BuildKit 会绕过 daemon 的 proxies 配置自行做 DNS 解析,所以先 docker pull node:24-slim(daemon 自己的拉取器认代理), 再用 DOCKER_BUILDKIT=0 docker build 复用本地镜像。 bridge/docker-daemon.local.json 是一份不含国内镜像源、带 SOCKS 代理的 daemon 配置。
  • cloudflared 跑在宿主机,因为拉 cloudflare/cloudflared 镜像同样会失败, 而系统里已经装了这个二进制。
  • 本机可能有 TLS 拦截。直连 https://api.hashneuron.space 会拿到企业代理签发的 证书而报 unable to get local issuer certificate;用 curl -x socks5h://127.0.0.1:10808 验证才准。这只影响本机验证,不影响线上服务。

三、接线

GW=https://api.hashneuron.space
ADMIN="Authorization: Bearer $ADMIN_TOKEN"

# 把本机 bridge 注册成渠道,api_key 就是 BRIDGE_TOKEN
curl -X POST $GW/admin/channels -H "$ADMIN" -H 'content-type: application/json' -d '{
  "name": "cursor-local",
  "base_url": "https://bridge.hashneuron.space/v1",
  "api_key": "<BRIDGE_TOKEN>",
  "models": "composer-2.5",
  "priority": 10
}'

# 别手写模型清单,直接从 bridge 同步。bridge 可用 ENABLED_MODELS 过滤
# Cursor 返回但当前账号无法调用的目录项。
curl -X POST $GW/admin/channels/<channel-id>/sync-models -H "$ADMIN"

# 需要直连 OpenAI 时再加一个渠道
curl -X POST $GW/admin/channels -H "$ADMIN" -H 'content-type: application/json' -d '{
  "name": "openai",
  "base_url": "https://api.openai.com/v1",
  "api_key": "sk-...",
  "models": "gpt-4o,gpt-4o-mini"
}'

# 签发客户端令牌,明文只在这次响应里出现
curl -X POST $GW/admin/tokens -H "$ADMIN" -H 'content-type: application/json' \
  -d '{"name":"my-laptop","rpm":60,"quota_tokens":0}'

客户端照常用:

curl $GW/v1/chat/completions \
  -H "Authorization: Bearer sk-ro-..." \
  -H 'content-type: application/json' \
  -d '{"model":"composer-2.5","stream":true,"messages":[{"role":"user","content":"你好"}]}'

管理 API

需要 Authorization: Bearer $ADMIN_TOKEN,或者一个已放行用户的会话 cookie。

方法与路径 说明
GET /admin/me 当前调用者身份与是否 owner
GET /admin/users 列出控制台用户(owner)
PATCH/DELETE /admin/users/:id 停用 / 提权 / 删除(owner)
GET /admin/settings/oauth 登录方式配置状态,密钥不回传(owner)
PUT/DELETE /admin/settings/oauth/:provider 写入 / 清除 OAuth 凭据(owner)
GET/POST /admin/tokens 列出 / 签发令牌,成员只看得到自己的
PATCH/DELETE /admin/tokens/:id 改配额限流状态 / 删除,成员只能动自己的
GET/POST /admin/channels 列出 / 新增渠道(owner)
PATCH/DELETE /admin/channels/:id 修改 / 删除渠道(owner)
POST /admin/channels/:id/test 探测渠道可达性(owner)
POST /admin/channels/:id/sync-models 拉取上游模型列表写回渠道(owner)
GET /admin/logs?limit=&token_id= 请求日志,成员只看得到自己的
GET /admin/stats?hours=24 汇总与按模型统计,成员只统计自己的

配置项

Worker(wrangler.jsoncvars 与 secret)

名称 说明
ADMIN_TOKEN secret,管理 API 口令,同时是会话签名的兜底密钥
SESSION_SECRET secret,会话 cookie 的 HMAC 密钥
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET 可选,配了就不能在控制台里改
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET 同上
DEFAULT_MODEL 客户端未指定模型时的默认值
UPSTREAM_TIMEOUT_MS 等待上游响应头的上限,默认 30000,不限制流式正文时长
LOG_RETENTION_DAYS 日志保留天数,定时任务按此清理
OPENAI_API_KEY / OPENAI_BASE_URL 可选,数据库没配渠道时的兜底上游

bridge 见 bridge/.env.example

本地开发

npx wrangler d1 migrations apply routeopen --local
node scripts/mock-upstream.mjs      # 假上游,不消耗真实额度
npx wrangler dev --port 8890

把渠道 base_url 指向 http://127.0.0.1:8788/v1 即可端到端验证转发、流式和记账。

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages