
腾讯 CodeBuddy 账号池管理控制台 + OpenAI 兼容反代网关。扫码纳管账号、自动签到、多密钥分发、IP 管控、调用日志与用量统计。UI 对标 linux-do/cdk。
腾讯 CodeBuddy 账号池管理控制台 + OpenAI 兼容反代网关。扫码纳管账号、自动签到、多密钥分发、IP 管控、调用日志与用量统计。UI 对标 linux-do/cdk。
workbuddy2api 是一个把腾讯 CodeBuddy 账号池包装成 OpenAI 兼容接口的反代服务(Go 编写)。它的能力很完整,但只有命令行:加账号要跑脚本、看状态要 curl /status、发密钥没有界面。
本项目补上这一块 —— 一个可以公网运营的 Web 控制台:
| 你原本要做的 | 现在在面板上 |
|---|---|
服务器上跑 login.sh 扫码加号 |
点「添加账号」扫码,自动签到并纳管 |
curl /status 看哪个号挂了 |
仪表盘实时展示健康度、冷却、有效期 |
手动改 config.json 调签到/并发 |
中文可视化设置,开关 + 数字框 |
| 所有下游共用一个全局 Key | 多密钥分发,各自独立配额、IP 与模型白名单 |
| 无法知道谁用了多少 | 每次调用的模型、Token、延迟、来源 IP 全量留痕 |
| 无任何 IP 防护 | 入站白/黑名单 + 每密钥 IP 上限与白名单 |
与 workbuddy2api 的关系:本项目是为它做可视化的配套项目 —— 让能力强大的 上游网关变得看得见、管得动。面板不侵入上游:没有修改它一行代码,账号轮询、 并发与熔断仍由它负责。两者配合的方式很自然:
欢迎参与共建:上游的改进建议提到 workbuddy2api,面板相关的问题与想法 提到本仓库。
深色模式(点击展开)
Token 有效期按剩余时间分档着色(已过期 / 即将过期 / 偏紧 / 健康)
扫码添加账号(点击展开)
签到结果、上游原始日志、自动任务与积分收益集中一页(30 秒自动刷新)
限定版本(国内版 / 国际版)、独立配额、IP 限制、模型白名单,明文仅创建时展示一次
按时间 / 密钥 / 状态 / 模型 / IP 筛选,含首字延迟、总耗时与 Token 计量
「首字」= 从发起上游请求到收到第一个含正文的 delta,反映上游响应快慢;
「总耗时」含模型生成全程,回答越长越大,用于看单次请求的整体开销。
非流式请求没有中间过程,首字显示 —。
按天、按模型、按密钥多维统计 Token 消耗
账号可用模型一览:显示名、上下文、最大输出、推理档位与系列分组
数据直连腾讯模型接口,因此有显示名和推理档位(上游 /v1/models 会丢掉这两项)。
顶部统计卡与列表全部由真实数据计算;来源取不到时回退上游简表并如实标注,不编造字段。
不建密钥直接试调模型;真实模型选择、思考强度与实时积分消耗
请求经管理端登录态转发到上游(与下游同一账号池),仅管理员可用—— 试调会真实扣积分。右下角显示本次会话累计消耗,每条回答下标注该次扣费与 token 数。
全局白/黑名单、CIDR 规则、访问审计与拦截记录
上游配置可视化,中文说明 + 开关 / 数字框
…单进程单端口:前端由 next build 静态导出,交由 FastAPI 托管,/api 与 /v1 同源,无需 CORS。
技术栈
| 层 | 选型 |
|---|---|
| 前端 | Next.js 15(App Router)· React 19 · TypeScript · shadcn/ui · Tailwind CSS v4 · motion · recharts · sonner |
| 后端 | Python 3.11+ · FastAPI · uvicorn · httpx · SQLite(标准库,无重依赖) |
| 部署 | systemd 常驻 + 1Panel 反向代理 + Let's Encrypt HTTPS |
# 0) 可选:本机没有真实的 workbuddy2api 时,起一个模拟上游
# 自带模型列表与示例账号,便于查看完整界面
python dev/mock_upstream.py # 监听 127.0.0.1:7863
# 1) 后端(终端 A)
python -m pip install -r server/requirements.txt
WB_ADMIN_PASSWORD=admin123 \
WB_DATA_DIR=./data \
WB_AUTH_DIR=/opt/workbuddy2api/auths \
WB2API_BASE=http://127.0.0.1:7863 \
python -m uvicorn server.main:app --reload --port 7864
# 2) 前端(终端 B)—— next dev 会把 /api、/v1 反代到 :7864
cd web
npm install
npm run dev # http://localhost:3000首次启动会自动生成 users.json 与随机签名密钥。若未设置 WB_ADMIN_PASSWORD,会在日志中打印一次随机管理员密码。
代理注意事项 若本机装有代理软件(Clash / V2Ray 等),尤其是 TUN 模式,访问
127.0.0.1:7863可能被代理劫持,表现为接口长时间无响应。 本项目对内部请求默认trust_env=False(不读取系统代理);确需走代理时设置WB_HTTP_PROXY。 TUN 模式下请在代理软件中把127.0.0.1加入直连 / 绕过列表。
# 配置读写的回归测试:时刻数组 / 时长字符串 / 部分提交不覆盖同段其他键
python -m unittest discover -s server/tests -t . -v测试用临时目录模拟上游
config.json,不触碰真实配置,可安全反复运行。 这一组测试专门守住两个曾经写坏配置的坑:把整点数组当成数字间隔、 把时长字符串当成秒数。
前提:workbuddy2api 已在本机运行,并有可用的启停脚本与文件日志。
git clone https://github.com/ithtelab/workbuddy-manager.git
cd workbuddy-manager
Copy-Item .env.example .env在 .env 中至少设置以下项目(Windows 路径建议使用 /):
WB_MANAGER_HOST=127.0.0.1
WB_SECURE_COOKIE=false
WB2API_MODE=native
WB_UPSTREAM_DIR=C:/path/to/workbuddy2api
WB_AUTH_DIR=C:/path/to/workbuddy2api/auths
WB_UPSTREAM_CONFIG=C:/path/to/workbuddy2api/config.json
WB2API_START_SCRIPT=C:/path/to/workbuddy2api/start-workbuddy2api.cmd
WB2API_STOP_SCRIPT=C:/path/to/workbuddy2api/stop-workbuddy2api.cmd
WB2API_LOG_FILE=C:/path/to/workbuddy2api/data/server.err.log安装依赖、构建前端并后台启动:
py -3.11 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r server\requirements.txt
Set-Location web
npm ci
npm run build:export
Set-Location ..
powershell -ExecutionPolicy Bypass -File .\service-tools.ps1 start用 service-tools.ps1 status|restart|stop 管理后台进程。Windows 原生模式支持
保存配置后重启上游及读取上游日志;网页一键更新依赖 Linux/Docker,当前会明确拒绝,
请手动更新代码后重启服务。
启停脚本优先用上游自带的:上游
workbuddy2api2026-09-18 起自带start/stop/status-workbuddy2api.cmd(PID 文件 + 进程路径校验,不会误杀同名进程), 直接把WB2API_START_SCRIPT/WB2API_STOP_SCRIPT指过去即可。若你的上游目录里 没有这三个文件(旧版上游),deploy/windows-native/下有一对可直接改用的模板。
两个约定必须满足(上游脚本已满足):启动脚本要立即返回(前台运行会让 「重启」等到超时才报失败),日志要写到
WB2API_LOG_FILE(否则「任务记录」读不到 自动任务日志)。细节见deploy/windows-native/README.md。
仓库自带 Dockerfile 与 docker-compose.yml,适合已经用 Docker 跑上游的用户:
git clone https://github.com/ithtelab/workbuddy-manager.git
cd workbuddy-manager
# 按需改 compose 里的 WB2API_BASE 与卷路径(默认假设上游在 ../workbuddy2api)
docker compose up -d --build
docker compose logs workbuddy-manager | grep -A2 密码 # 首启随机密码也可以直接用构建好的镜像(每次发版会推到 GHCR):
docker pull ghcr.io/ithtelab/workbuddy-manager:latest镜像同时提供
linux/amd64与linux/arm64(Apple Silicon、ARM 云主机可直接拉取, 无需 QEMU 模拟)。docker pull会按你的机器架构自动选择对应的那一份。
容器版与宿主版的能力是一致的 —— compose 里默认挂载了三样东西让它们对齐:
| 挂载 | 作用 |
|---|---|
| 上游仓库目录 | 读上游 compose 做端口收敛;git pull 更新上游;读写 config.json 与 auths/(扫码添加账号会写 auths,所以不能只读) |
./data |
数据库、日志、更新状态。必须持久化 |
/var/run/docker.sock |
让容器内的管理端能重启/重建上游容器 —— 即「更新上游」「保存设置后自动重载」「读上游日志」 |
关于 docker.sock 的取舍:挂它等于把宿主 root 权限交给本容器。但这不是新增的风险等级——宿主部署时本服务本来就是 root 运行(systemd 单元无
User=、安装脚本要求 root),而 root 进程本来就能docker run -v /:/host拿到宿主文件系统,两者权限等价。 若你的要求是最小权限,把那一行注释掉即可:依赖 docker 的功能会自动降级为「请到宿主机操作」,界面如实提示,不会静默失败。
还有两处与宿主部署的差异(界面都会提示):
restart 策略用新代码拉起」,所以 compose 里必须保留 restart: unless-stopped。127.0.0.1:管理端持有全部账号凭据,应当藏在反向代理之后。确需直接访问请自行改 compose,并确保 HTTPS。与宿主机安装一样,一键更新强制验签发布包。镜像本身不参与这套签名 (那是另一条信任链,依赖 GHCR 的 digest 与 GitHub 账号安全)。
本项目依赖上游 workbuddy2api
(账号池与 OpenAI 兼容接口),单独 clone 本仓库无法运行。
为此提供了一键脚本,会在干净机器上自动装好两者:
# 推荐:用 Release 包(内含已构建的前端,无需 Node.js)
wget https://github.com/ithtelab/workbuddy-manager/releases/latest/download/workbuddy-manager-.tar.gz
tar xzf workbuddy-manager-*.tar.gz && cd workbuddy-manager-*
sudo bash deploy/install.sh脚本自动完成:
api_key、修正目录属主、
构建并启动容器、等待就绪全程无需手工编辑配置。 若已自备上游,加 --skip-upstream 即可跳过,
脚本不会改动已有配置与账号。
通过
git clone部署时,需先在web/执行npm ci && npm run build:export(构建产物不入库),或改用 Release 包。
首次启动的管理员密码:
journalctl -u workbuddy-web | grep -A3 '初始管理员'公网访问请务必配置 HTTPS 反向代理(否则会话 Cookie 与密码可被窃听)。
1Panel 用户:网站 → 创建反向代理 → 目标 http://127.0.0.1:7864 →
申请 Let's Encrypt 证书 → 开启强制 HTTPS。
完整部署说明(含 Nginx 配置、加固建议、常见问题)见
deploy/README.md。
环境变量一览
| 变量 | 默认 | 说明 |
|---|---|---|
WB_MANAGER_PORT |
7864 |
监听端口 |
WB2API_BASE |
http://127.0.0.1:7863 |
workbuddy2api 地址 |
WB2API_KEY |
读 config.json | 上游 API Key |
WB2API_MODE |
docker |
上游运行方式:docker 或 native |
WB2API_CONTAINER |
workbuddy2api |
重载用的容器名 |
WB_AUTH_DIR |
/opt/workbuddy2api/auths |
账号授权目录 |
WB_UPSTREAM_CONFIG |
/opt/workbuddy2api/config.json |
上游配置文件 |
WB2API_START_SCRIPT |
上游目录下的 .cmd |
native 模式启动脚本 |
WB2API_STOP_SCRIPT |
上游目录下的 .cmd |
native 模式停止脚本 |
WB2API_LOG_FILE |
data/server.err.log |
native 模式上游日志 |
WB_DATA_DIR |
./data |
本服务数据目录 |
WB_STATIC_DIR |
./web/out |
静态导出目录 |
WB_ADMIN_PASSWORD |
随机生成 | 首次启动的 admin 密码 |
WB_SECURE_COOKIE |
auto |
会话 Cookie 的 Secure 标志:auto 依 X-Forwarded-Proto 判定、也可写死 true/false |
WB_SESSION_DAYS |
1 |
会话总时长上限(天),到点必须重新登录 |
WB_SESSION_IDLE_HOURS |
12 |
会话空闲上限(小时):多久没操作就失效(滑动续期窗口) |
WB_HTTP_PROXY |
空 | 出口代理,留空 = 全部直连 |
完整清单见 .env.example。
登录后进入「账号」页,点右上角 添加账号 → 用微信 / QQ 扫码 → 授权成功后自动签到、落盘并重载上游容器。
进入「密钥」页点 新建密钥,按需设置:
限定版本 —— 国内版密钥只能调国内版模型,国际版密钥只能调 global: 开头的
国际版模型,跨版本调用会被拒绝(/v1/models 也只返回对应版本的模型)。
默认跟随当前所在版本;选「不限制」则两版都能调
有效期 —— 留空或 0 表示永不过期
最大 IP 数 —— 限制同一密钥可使用的来源 IP 数量
IP 白名单 —— 更严格,仅允许指定 IP / CIDR 调用
模型白名单 —— 在所选版本之内再限制到具体模型
Token 配额 —— Token 用尽后自动拒绝(按 prompt + completion 累计)
积分配额 —— 按真实扣费累计的额度,用尽后同样拒绝(429)。
为什么除了 Token 还要有积分:同样 1M Token,便宜模型与贵模型的扣费能差
几十倍,拿 Token 数当预算估不出实际花了多少。数据来自上游每次响应末帧
usage.credit(真实扣费,不是估算),与「用量统计」页看到的是同一份。
两个额度各自独立,任一超限即拒绝,都留 0 = 不限。上游没返回该字段的调用 不计入(而不是按 0 记):那代表「不知道扣了多少」,按 0 记等于把它当免费, 数字会假装准确。代价是老版本上游(2026-09-13 之前)下这个额度不会增长, 界面上用量一直是 0 —— 那种情况下请用 Token 配额。
密钥明文只在创建时展示一次,请立即保存。
完全兼容 OpenAI 协议,Base URL 指向本服务的 /v1:
curl https://wb.example.com/v1/chat/completions \
-H "Authorization: Bearer wbk_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.2",
"messages": [{"role": "user", "content": "你好"}],
"stream": true
}'Python 示例:
from openai import OpenAI
client = OpenAI(
base_url="https://wb.example.com/v1",
api_key="wbk_xxxxxxxx",
)
resp = client.chat.completions.create(
model="glm-5.2",
messages=[{"role": "user", "content": "你好"}],
stream=True,
)
for chunk in resp:
print(chunk.choices[0].delta.content or "", end="")流式请求会自动注入
stream_options.include_usage=true,以便精确统计 Token 消耗。
OpenAI Responses API(Codex / DeepSeek Harness 等)
本服务同时提供 Responses 协议(/v1/responses,SDK 的 baseURL 不含 /v1
时也支持 /responses)。请求体用 input 而非 messages,instructions 承载
system 文本:
from openai import OpenAI
client = OpenAI(base_url="https://wb.example.com/v1", api_key="wbk_xxxxxxxx")
resp = client.responses.create(
model="glm-5.2",
instructions="你是一个简洁的助手",
input="你好",
stream=True,
)
for event in resp:
if event.type == "response.output_text.delta":
print(event.delta, end="")工具调用同样支持:客户端发扁平形状的 tools({type:"function", name, parameters}),
返回的是 function_call 输出项与 response.function_call_arguments.delta 事件。
只发
openai-responses协议的客户端(如 DeepSeek Harness 的自定义提供方) 把「API 协议」选成openai-responses即可;它谈的协议与openai-completions不是同一个,需要单独建一个提供方。
Anthropic Messages API(Claude Code / Cursor / Cline 等)
只认 Anthropic 协议的客户端可直接把 Base URL 指向本服务——ANTHROPIC_BASE_URL
配到根路径即可(协议层面 /v1/messages 与官方一致):
export ANTHROPIC_BASE_URL=https://wb.example.com
export ANTHROPIC_AUTH_TOKEN=wbk_xxxxxxxx # 也接受 x-api-key 头
export ANTHROPIC_MODEL=glm-5.2模型名与 OpenAI 侧同一套(含 global: 前缀的版本规则与密钥版本隔离),
/v1/messages/count_tokens 亦可用。
可用模型
以「设置 → 可用模型」实时拉取结果为准,常见如下(上下文均为 131072):
glm-5.2 · glm-5.1 · glm-5v-turbo · kimi-k2.7 · minimax-m3 · hy3 · hy3-preview
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
POST |
/v1/chat/completions |
网关密钥 | OpenAI 兼容对话(流式 / 非流式) |
POST |
/v2/chat/completions |
网关密钥 | 同上(v2 路径) |
POST |
/v1/responses /responses |
网关密钥 | OpenAI Responses API 兼容(流式 / 非流式) |
POST |
/v1/messages |
网关密钥 | Anthropic Messages API 兼容(Claude Code 等) |
POST |
/v1/messages/count_tokens |
网关密钥 | 按字符数粗估输入 token |
GET |
/v1/models |
网关密钥 | 模型列表 |
GET |
/healthz |
无 | 存活探测(含上游连通性) |
GET |
/api/me |
会话 | 当前登录用户 |
POST |
/api/login /api/logout |
无 | 登录 / 登出 |
GET |
/api/accounts |
会话 | 账号列表 |
POST |
/api/auth/start /api/auth/poll |
管理员 | 扫码授权流程 |
POST |
/api/accounts/{file}/checkin /test /refresh |
管理员 | 签到 / 测活 / 刷新 |
DELETE |
/api/accounts/{file} |
管理员 | 删除账号 |
GET/POST/PATCH/DELETE |
/api/keys[/{id}] |
会话 / 管理员 | 密钥管理 |
GET |
/api/logs /api/stats/* |
会话 | 日志与用量 |
GET/POST/DELETE |
/api/security/* |
会话 / |