基于腾讯 CodeBuddy 协议开发的纯 Go、零 CGO 依赖、跨平台单二进制本地 AI 代理网关。无 Web UI,全部通过命令行(CLI)完成登录、凭据续期与服务控制。
同时支持两个上游站点(同一套 /v2/plugin/* 协议,凭据按站点隔离,账号池可混挂轮询):
| 站点 | 上游 | 登录方式 | 登录命令 |
|---|---|---|---|
| 国内站 | copilot.tencent.com / www.codebuddy.cn |
微信 / 企业微信扫码 | login |
| 国际站 | www.workbuddy.ai |
浏览器内登录(邮箱 / 验证码 / SSO) | login -intl |
- 核心特性
- 命令总览
- serve
- login
- status
- refresh
- monitor
- probe
- reset
- version / help
- 多账号池
- 模型列表与倍率
- 客户端接入
- 各平台部署
- 安全提示
- 从源码构建
- 国内 / 国际双站反代:两个站点走同一套协议,凭据通过
edition字段区分,刷新与对话自动路由到各自上游。 - 模型完全透传:客户端传什么
model就原样中继到上游,无白名单限制。/v1/models仅用于客户端自动补全,不影响实际转发。 - 模型列表双来源合并:实时接口 + npm 静态目录,按 ID 去重、接口优先;失败用本地缓存,两边都失败且无缓存时该站点本轮不展示模型(不影响调用)。
- 模型倍率与价格探测:促销生效时展示
credits× factor;促销过期或接口无有效倍率时由余额未耗尽的同站点账号实测(启动即探测、重置后立即探测、每模型 12 小时一轮)。 - 多账号池 + 轮询负载均衡:
-auth逗号分隔或-auth-dir目录,请求按 round-robin 分发;国内站与国际站账号可混挂。 - 模型级隔离:
6004只冷却触发它的账号 + 模型,14018只阻断该账号的当前收费模型,不再因为一个模型拖垮整个账号。 - 免费站点优先:同一模型若「一个站点免费、另一个站点收费」,优先使用免费站点账号直至其受限;两个站点都收费(仅倍率不同)时不做倾斜,正常轮询。
- 免费/收费学习:按「账号 + 模型」从响应
usage.credit学习;credit=0且样本足够(total_tokens ≥ 100)才判定免费,避免小样本误判。 - 国内站每日自动签到:服务启动、凭据热加载时立即补签,之后每天
UTC+8 09:00自动签到;国际站跳过。 - 凭据热加载(免重启):默认每 5 秒扫描凭据来源,新增 / 更新 / 删除凭据免重启生效。
- 授权失效自动禁用:401/403 /
invalid token/ 登录过期时禁止调度、删除凭据文件并写入失效标记,重新login后自动恢复。 - 后台自动续期:每 5 分钟检查 Token,距过期不足 15 分钟自动刷新并写回凭据文件;另可按
-keepalive-hours在固定时刻主动刷新全部账号(默认每天 22:00),避免长期空闲账号静默失效。 - 流式分片规范化:把上游每个分片携带的
finish_reason:""归一化为null,避免 Anthropic 翻译层误判stop_reason导致工具不执行。 - 工具调用序列自愈:出站前按
tool_call_id修复并行调用中夹入 message 的历史结构,合并 Responses API 拆散的并行调用,并删除无配对调用、孤儿或重复结果,避免国际站返回11148 tool_call_sequence_broken。 - OpenAI 兼容协议:
/v1/chat/completions(SSE 流式 + 非流式聚合)、/v1/responses(Responses API)、/v1/models、/health。 - Anthropic 协议原生入口:
/v1/messages(SSE 流式 + 非流式聚合)与/v1/messages/count_tokens,Claude Code 等 Anthropic 客户端免外部翻译层直连,鉴权兼容x-api-key头。
workbuddy-gateway [command] [options]
命令:
serve 启动本地网关(默认命令,不带子命令时等同 serve)
login 登录并获取 / 更新凭据
status 查看账号池状态
refresh 手动刷新所有账号访问令牌
monitor 前台实时监控:账号表格 + 模型统计附表 + 最近日志
probe 主动探测账号对指定模型的免费 / 收费属性(需 serve 运行中)
reset 清空除登录凭据外的全部本地数据,并重新拉取模型与倍率
version 查看版本信息
help 查看帮助
全局选项(对所有命令可用):
| 选项 | 默认 | 说明 |
|---|---|---|
-addr <ip> |
127.0.0.1 |
网关监听地址 |
-port <port> |
8317 |
网关监听端口 |
-auth <path> |
自动发现 | 凭据文件路径,支持逗号分隔多个 |
-auth-dir <dir> |
空 | 凭据目录,自动加载目录内所有 workbuddy*.json |
-api-key <key> |
空 | 设置后调用网关必须携带 Authorization: Bearer <key> |
-proxy <url> |
空 | 上游请求代理,如 http://127.0.0.1:7890、socks5://... |
-verbose |
false |
输出详细调试日志 |
-intl |
false |
仅 login 生效:登录国际站 |
-reload-interval <sec> |
5 |
凭据热加载扫描间隔,0 关闭 |
-models-refresh <min> |
60 |
模型目录刷新间隔,0 关闭 |
-disable-price-probes |
false |
禁止后台自动价格探测,避免自动发起模型生成请求;不影响客户端请求及显式 probe 命令 |
工作目录中的 config.json 控制结构化调试日志,默认关闭。修改后需要重启网关进程:
{
"debug": {
"enabled": true
}
}开启后,网关把单行 JSON 写入 logs/debug-YYYY-MM-DD.jsonl;普通运行日志仍写入原来的 logs/gateway-YYYY-MM-DD.log,两者互不替代。可复制 config.example.json 作为起点。
工作目录 config.json 的 systemPrompt 段有两个独立选项(修改后需重启 serve):
{
"systemPrompt": {
"fallback": "",
"force": ""
}
}| 配置 | 空值的默认行为 | 非空时的行为 |
|---|---|---|
fallback |
继续使用 You are a helpful assistant. |
仅在客户端没有任何 system 时,替换网关注入的保底提示词;已有 system 不变 |
force |
不启用;请求提示词完全按原规则处理 | 实验功能:在 Chat、Responses、Anthropic Messages 三个入口的首条 system 内容之前加上配置文本;原 system 内容仍保留 |
例如 {"systemPrompt":{"fallback":"你是一个助手。","force":"请用中文回答。"}}:客户端没有 system 时,发往上游的是 请用中文回答。\n\n你是一个助手。;客户端自带 system 时,发往上游的是 请用中文回答。\n\n<客户端原 system>。配置值仅支持 JSON 字符串;空串或全空白视为未配置。不会写出或替换客户端的 user、assistant、tool 消息,也不改变账号选择。普通日志和 JSON 调试日志只记录规则分支与字符数,不记录提示词正文。
实验功能风险自负:
force可能与客户端的 system 指令冲突、改变模型行为、增加 token 消耗,或触发上游内容/参数校验。需要回退时将force改回""并重启;建议先在测试会话验证,切勿在配置中写入密码、密钥或个人隐私。config.json已被 Git 忽略,不要将真实配置提交到仓库。
/v1/messages/count_tokens 仅对客户端提供的内容做本地近似估算,不调用上游,也不计入网关随后注入的 fallback / force 文本;最终消耗以模型返回的 usage 为准。
从 v1.13.9 起,账号套餐不再仅凭 ProTrialStatus=1 判定为“Pro试用”。每轮额度刷新会额外调用官网的只读通用资源接口,根据有效状态、权益起止时间及当前订阅信息确认套餐:
- 查询不限定
PackageCodes,支持分页;官网新增套餐编码不会被固定名单漏掉。 - 名称按站点区分:国内站四档规范显示为 体验版 / 标准版 / 高级版 / 旗舰版;国际站保留 免费 / pro / Pro试用。国内标准版不会误标为国际站 pro。
- 新套餐优先显示接口返回的
PackageName,历史套餐也不会强行归入四档。新编码没有名称时显示“未识别订阅”,不猜成 Free 或 Pro。 - 赠送积分包、加量包不当成订阅;额度用尽但权益未到期的套餐仍保留套餐身份。
- 已过期、退款、尚未生效的权益不当成当前套餐。试用标记仍为
1,但已无有效试用且只有 Free 权益时,显示“免费”。 - 查询失败或遇到无法解释的字段/子产品时,已有核验结果标
*(待刷新),无核验结果显示“待确认”。额度查询成功时仍正常更新额度,不因套餐识别失败丢弃额度。 - 快照增加
planCheckedAt、planStale字段。旧版本未核验的套餐标签不会作为可信结果沿用;新版本启动后会重新校验。
兼容边界:同一产品和资源字段结构下新增套餐通常可直接展示官方名称;若官网改变产品编码、接口、状态枚举或权益规则,仍可能需要更新程序。这不是对未来任意接口变更的保证。此过程只查询会员/额度信息,不领取试用、不购买/续费,也不请求模型。
登录凭据分两种令牌:访问令牌用于请求模型和查询额度;刷新令牌用于换取新的访问令牌。刷新令牌本身也有有效期,一旦它到期或被上游判定失效,就必须重新 login,程序无法绕过。
从 v1.13.11 起,网关同时使用两条触发路径续期:
| 触发方式 | 时机 | 说明 |
|---|---|---|
| 临近过期续期 | 后台每 5 分钟检查,访问令牌剩余不足 15 分钟时刷新 | 保证请求不会用到过期令牌 |
| 主动定时续期 | -keepalive-hours 指定的本地时刻(默认 22,即每天 22:00) |
不等访问令牌临近过期就刷新全部账号,避免长期空闲账号静默失效 |
# 默认每天 22:00 主动续期
workbuddy-gateway serve
# 每天 10:00 和 22:00 各一次
workbuddy-gateway serve -keepalive-hours 10,22
# 关闭主动续期,只保留临近过期时的按需刷新
workbuddy-gateway serve -keepalive-hours ""实现要点:
- 只调刷新接口,不请求模型、不消耗额度、不产生对话记录。
- 串行 + 节流:账号之间间隔 1 秒逐个刷新,避免批量并发刷新形成机器特征。
- 启动补跑:距上次成功续期超过 20 小时的账号,在服务启动 90 秒后补做一轮,避免重启错过时刻。
- 失败不轻易删号:单次失败只累计计数并保留原凭据;连续失败 3 次才判定登录态失效并停止调度。上游明确返回会话失效(如
12153/invalid_grant)时首次即告警,但仍保留凭据等待阈值。 - 记录续期元数据:刷新成功后把
refreshExpiresAt、lastRefreshTime写回凭据文件,status与monitor会显示刷新令牌到期时间,并在剩余不足 7 天或已过期时给出重新登录提醒。 - 不掩盖问题:刷新成功但访问令牌期限没有顺延时会单独告警,提示该账号可能已接近上游的登录态上限。
注意刷新令牌是独占的。 每次续期上游通常会下发新的刷新令牌并让旧的失效。如果同一个账号的凭据还被其他工具(脚本、其他网关、桌面客户端)同时使用,双方会互相把对方的刷新令牌作废。请确保一个账号只由一处负责续期。
-keepalive-hours留空即可关闭本功能。
凭据文件是登录态的唯一副本,删掉就只能重新登录。因此「覆盖」和「删除」这两个不可逆动作之前都会先做只读校验。
续期成功、准备覆盖旧凭据之前:
| 检查 | 目的 | 不通过时 |
|---|---|---|
新旧凭据账号标识一致(访问令牌 sub) |
防止上游串号或响应错配,把凭据写到别的账号上 | 拒绝覆盖,保留旧凭据并告警 |
新旧凭据站点一致(iss realm) |
防止国内站/国际站凭据互相覆盖 | 同上 |
| 新访问令牌能取到账号数据 | 防止「接口返回 200 但实际不可用」的凭据覆盖掉还能用的旧凭据 | 同上 |
校验接口自身不可用时按通过处理,不会因为校验抖动而拒绝有效的新凭据。校验失败不计入「判定失效」的计数,因此不会把还能用的账号停掉。
判定失效、准备删除凭据之前:
- 先停止调度并写入失效标记;
- 再用只读接口确认该凭据确实取不到账号数据,才删除文件;
- 凭据仍能取到数据 → 保留文件;
- 无法判定(网络故障、上游 5xx)→ 保守保留文件。
凭据文件被保留时,失效标记在重启后依然生效,账号不会被重新调度。如果你重新 login 或手动续期了该凭据,凭据文件会比标记更新,网关会自动清除过期标记并恢复该账号。
config.json 的 models 段可按模型名启用黑白名单(大小写与首尾空白不敏感):
{
"models": {
"blocklist": ["deepseek-v4-pro"],
"allowlist": []
}
}| 字段 | 说明 |
|---|---|
blocklist |
黑名单,命中即禁用 |
allowlist |
白名单,非空时只放行列表内模型,其余一律禁用 |
规则:
- 黑名单优先:命中黑名单直接禁用,即使同时出现在白名单里。
- 两个列表都为空或省略时不做任何限制(默认行为不变)。
- 被禁用的模型会从
/v1/models、/health的model_count和monitor的模型统计附表中直接隐藏。 - 请求被禁用模型时返回
403与中文提示,不会消耗任何上游账号额度:
{
"error": {
"message": "模型 deepseek-v4-pro 已被网关禁用(命中黑名单),请联系管理员调整 config.json",
"type": "model_disabled",
"code": 403
}
}serve 启动横幅会打印当前名单状态,例如 模型黑白名单: 已启用 (黑名单 1 个 / 白名单 0 个...)。
models.accounts 是模型专属的凭据 JSON 文件黑白名单,不是全局账号名单;未配置的模型仍可使用原有账号池。与上面的 models.allowlist / models.blocklist(控制模型是否可调用)互不替代:
{
"models": {
"blocklist": [],
"allowlist": [],
"accounts": {
"deepseek-v4.1-flash": {
"allowlist": ["intl-a.json", "intl-b.json"],
"blocklist": ["intl-b.json"]
},
"hy3": {
"blocklist": ["old-account.json"]
}
}
}
}- 同一模型内黑名单优先;账号白名单为空表示不限制,黑名单为空表示不排除。上述示例中
deepseek-v4.1-flash最终只允许intl-a.json,hy3仅排除old-account.json。 - 只接受凭据文件名(如
intl-a.json),不接受路径或通配符;同名凭据位于多个目录时会拒绝匹配,避免误用。模型名忽略大小写,文件名必须与实际凭据文件一致。 - 请求调度与失败换号都不会绕过账号名单;后台价格探测与本机
/admin/probe也会跳过不允许的账号。若没有匹配的账号,请求返回403 model_account_disabled中文提示,且不会调用上游。 - 实时运行日志
logs/gateway-YYYY-MM-DD.log在有账号被排除时记录汇总一行(模型、候选账号数、排除明细);开启调试时logs/debug-YYYY-MM-DD.jsonl记录每个账号的model_account_policy_checked。monitor模型统计表的“可用账号”列已按名单过滤,只统计符合规则的账号。 config.json在服务启动时读取,修改后需重启网关;示例中的文件名均为占位值。没有配置models.accounts时原行为不变。
每条 JSON 调试日志都包含时间、级别、稳定事件名、trace_id、request_id、服务/实例/版本、路由、方法、模型、账号、流式标记和累计耗时,并记录客户端地址、代理头、协议、TLS、Content-Type、Content-Length、deadline 等请求元数据。客户端传入的 X-Trace-ID 会优先复用并透传到上游。
请求体只记录以下安全摘要,不记录正文:
declared_body_bytes、actual_body_bytes、body_read_msbody_sha256_prefix(SHA-256 前 12 位)json_valid、json_decode_msbody_limit_bytes、body_limit_exceeded(当前未设置请求体限制,因此分别为0、false)read_error_type、脱敏截断后的read_error
调试日志不会记录 Authorization、Cookie、API Key、Access Token、Refresh Token 或完整请求体。只记录是否提供 Authorization,以及凭据的不可逆短哈希 api_key_fingerprint。
启动本地网关,默认命令。
# 默认监听 127.0.0.1:8317,自动加载当前目录下所有 workbuddy*.json
workbuddy-gateway serve
# 自定义端口与监听地址
workbuddy-gateway serve -port 9000 -addr 0.0.0.0
# 显式指定多个凭据文件(逗号分隔,轮询)
workbuddy-gateway serve -auth workbuddy.json,workbuddy2.json
# 目录模式:加载目录内所有 workbuddy*.json
workbuddy-gateway serve -auth-dir ./auths
# 上游走代理 + 开启客户端鉴权 + 详细日志
workbuddy-gateway serve -proxy http://127.0.0.1:7890 -api-key sk-xxx -verbose
# 关闭凭据热加载
workbuddy-gateway serve -reload-interval 0
# 关闭模型目录自动刷新
workbuddy-gateway serve -models-refresh 0启动后提供的端点:
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /v1/chat/completions、/chat/completions |
Chat Completions,支持 SSE 流式与非流式 |
| POST | /v1/responses、/responses |
OpenAI Responses API |
| POST | /v1/messages |
Anthropic Messages API(Claude Code 直连,内部转 Chat 走同一条上游管线) |
| POST | /v1/messages/count_tokens |
Anthropic 令牌计数(本地估算,CJK 1 token/字、ASCII 4 字符/token) |
| GET | /v1/models、/models |
模型列表,响应头 X-Model-Source 标注来源 |
| GET | /health、/ping |
健康检查,返回 version、model_count、model_source |
| POST | /admin/probe |
供 probe 命令调用,仅接受回环来源 |
| GET | / |
简单文本说明 |
后台任务(serve 启动后自动运行):
| 任务 | 周期 | 说明 |
|---|---|---|
| Token 续期检查 | 5 分钟 | 距过期不足 15 分钟自动刷新 |
| 额度扫描 | 5 分钟 | 每凭据 10 秒超时,超时保留旧值;剩余=0 标记付费耗尽 |
| 模型目录刷新 | 60 分钟 | 实时接口 + npm 目录,合并去重后写缓存 |
| 模型价格探测 | 30 分钟检查 / 每模型 12 小时一轮 | 单轮最多 5 个,仅探测需要确认的模型 |
| 每日签到 | 每天 UTC+8 09:00 |
仅国内站 |
| 状态快照 | 3 秒 | 写 workbuddy-status.json 供 monitor 读取 |
| 凭据热加载 | 5 秒 | 扫描凭据新增 / 更新 / 删除 |
上游超时策略
网关不再对上游请求设置「整条流的总超时」,避免长时间但持续有输出的流被中途掐断(会丢失 usage、返回残缺内容,并被上游代理判为故障触发 503):
| 阶段 | 策略 |
|---|---|
| 连接与响应头 | ResponseHeaderTimeout 默认 300 秒。上游对 3MB+ 大请求排队+预处理可能接近 1 分钟(实测 2.3MB 请求曾需 50.8s 才回响应头),因此默认放宽到 5 分钟兜底 |
| 流式响应体 | 空闲读超时默认 120 秒:持续有数据就永不超时,只有 120 秒无任何新数据才判定卡死并中断 |
| 控制类短请求 | 令牌刷新 / 额度查询 / 模型目录等 60 秒超时 |
| 服务端写响应 | 不设总时长上限(原 300 秒),长流不会被服务端截断 |
两个上游超时可在工作目录 config.json 的 upstream 段覆盖(单位秒,省略或非正数则用默认值):
{
"upstream": {
"headerTimeoutSeconds": 300,
"idleTimeoutSeconds": 120,
"transientRetries": 2
}
}瞬时网络错误重试
网关与上游 CDN 边缘节点之间的单条 TCP 连接可能被对端重置(connection reset by peer)、被关闭(use of closed network connection),或命中已被回收的 keep-alive 连接。这类错误属于瞬时故障,与请求体大小无关(实测 >5MB 请求 95% 成功,而 0.5MB 请求也会偶发失败)。
只有请求头尚未写出时,才能确认上游不可能处理本次 POST,网关才对瞬时连接错误重试。Do 返回 EOF、RST 或超时但请求头已写出时,上游可能已经收到并处理请求;即使尚未收到响应头,也不会自动重放,以免重复生成。
| 项 | 默认 | 说明 |
|---|---|---|
| 重试次数 | 2 | upstream.transientRetries 可覆盖;显式设为 0 可禁用 |
| 重试间隔 | 300ms | 给上游边缘节点留出恢复时间 |
| 重试范围 | 请求头未写出时的瞬时错误 | 包括建连阶段 EOF、RST、broken pipe、connection refused 等 |
| 不重试 | — | 请求头已写出的 EOF/RST/超时(执行结果不确定)、客户端取消、上游 HTTP 错误响应 |
| 连接处理 | 新连接 | 重试时设置 Connection: close 并 CloseIdleConnections(),避免复用坏连接 |
重试会在日志中留下明确记录:
[网络重试] traceId=... requestId=389 账号=example.json 第 1/2 次重试,上一尝试请求头未写出,已重建连接
启动横幅会打印生效值,便于确认。流被中断时不会伪造 [DONE](chat)或 response.completed(Responses),而是下发明确的 upstream_stream_interrupted / response.failed 错误事件,避免下游把残缺输出当成完整结果。
登录并保存凭据。国内站输出终端 ASCII 二维码;国际站在浏览器内完成。
# 国内站(微信 / 企业微信扫码)
workbuddy-gateway login
# 保存到指定文件(多账号推荐)
workbuddy-gateway login -auth workbuddy2.json
# 国际站(浏览器内完成,邮箱 / 验证码 / SSO)
workbuddy-gateway login -intl
workbuddy-gateway login -intl -auth workbuddy-intl.json说明:
- 默认保存到
workbuddy.json;-auth可指定其他路径。 - 国际站凭据写入
edition: "intl",与国内站凭据可混挂在同一账号池。 - 重新登录会覆盖原凭据并自动清除该账号的失效标记,无需重启服务(热加载会生效)。
查看账号池状态,包含站点、冷却、额度与 Token 过期时间。
workbuddy-gateway status输出示例:
================== WorkBuddy 账号池状态 ==================
账号总数: 2
--- 账号 #1 ---
凭据文件: workbuddy.json
站点: 国内站 (copilot.tencent.com)
用户昵称: user-a
用户 UID: uid-xxx
企业 ID: (个人账号)
认证域名: www.codebuddy.cn
冷却状态: 可用
Token 状态: 有效
过期时间: 2026-09-22 12:32:07 (剩余 119h30m0s)
立即刷新所有账号的 Access Token(正常情况下由后台每 5 分钟自动检查,无需手动执行)。
workbuddy-gateway refresh- 成功 / 失败 / 跳过(授权失效)会分别统计。
- 刷新失败若属于授权类错误,会禁用该账号并删除凭据文件。
前台实时监控,周期刷新展示「账号表格 + 模型统计附表 + 最近日志」,Ctrl+C 退出。
# 必须在 serve 的工作目录执行(读取 workbuddy-status.json)
cd /opt/workbuddy-gateway
workbuddy-gateway monitor
# 附加展示 systemd 服务最近日志(Linux)
workbuddy-gateway monitor -journal workbuddy-gateway
# 附加展示指定日志文件
workbuddy-gateway monitor -logfile /var/log/workbuddy-gateway.log
# 调整刷新间隔与日志行数
workbuddy-gateway monitor -interval 2 -lines 20| 选项 | 默认 | 说明 |
|---|---|---|
-interval <sec> |
3 |
状态刷新间隔 |
-journal <svc> |
空 | 同时展示 journalctl -u <svc> 最近日志 |
-logfile <path> |
空 | 同时展示指定日志文件末尾内容 |
-lines <n> |
15 |
每次展示的日志行数 |
账号表格
账号池: 共 2 个 | 可用 1 | 冷却 0 | 付费耗尽 1 | 过期 0 | 失效 0
+------+----------------+------------+--------+------------+---------------------+----------+----------+--------+------------+------------+------------+
| 序号 | 凭据文件 | 账号 | 站点 | 状态 | Token 有效期 | 总额度 | 已用 | 剩余 | 套餐 | 免费模型 | 模型冷却 |
+------+----------------+------------+--------+------------+---------------------+----------+----------+--------+------------+------------+------------+
| 1 | workbuddy.json | user-a | 国内站 | 可用 | 2026-09-22 12:32:07 | 2300 | 1200 | 1100 | pro | 1 | 0 |
| 2 | workbuddy2.json| user-b | 国际站 | 付费耗尽 | 2027-09-05 01:57:00 | 1100 | 1100 | 0 | Pro试用 | 0 | 0 |
+------+----------------+------------+--------+------------+---------------------+----------+----------+--------+------------+------------+------------+
状态取值:可用、冷却、付费耗尽、已过期、失效。
套餐取值:Pro试用(上游 ProTrialStatus=1)、pro(上游 IsPaidUser=true)、免费(其余,含识别不出)。
模型统计附表
模型统计 (来源 live-api@2026-09-17 14:57):
+----------------------------+------------------+------------------+----------+----------+---------------+-----------------+------------+
| 模型 | 国内倍率 | 国际倍率 | 可用账号 | 请求 | 平均首字(5h) | 平均总耗时(5h) | 总Token(M) |
+----------------------------+------------------+------------------+----------+----------+---------------+-----------------+------------+
| hy3 | 0.00x | 0.00x | 8 | 3 | 1.9s | 2.3s | 0.12M |
| deepseek-v4.1-flash | 0.03x | 0.00x | 5 | 12 | 820ms | 3.4s | 1.75M |
| hy4-preview | 0.00x | 收费(倍率未知) | 8 | 4 | 1.3s | 4.1s | 0.00M |
+----------------------------+------------------+------------------+----------+----------+---------------+-----------------+------------+
| 列 | 含义 |
|---|---|
| 模型 | 模型 ID |
| 国内倍率 | 国内站生效倍率(credits × 促销 factor);免费显示 0.00x,促销过期或接口无有效倍率时显示 -,实测确认收费显示 收费(倍率未知) |
| 国际倍率 | 国际站同上 |
| 可用账号 | 当前可调度该模型的账号数(已计入账号冷却、模型冷却、模型额度阻断) |
| 请求 | 客户端请求次数 |
| 平均首字(5h) | 最近 5 小时滚动窗口内的平均首字响应时间(TTFT),按小时分桶、自动淘汰过期样本 |
| 平均总耗时(5h) | 最近 5 小时滚动窗口内的平均总耗时 |
| 总Token(M) | 进程启动后累计的上游 usage token,单位百万;优先 usage.total_tokens,没有则用 prompt_tokens + completion_tokens;上游未返回 usage 的请求不估算 |
免费 / 收费属性按「账号(含站点)+ 模型」学习,只有该账号真正请求过该模型才会写入账本。默认调度优先使用有余额账号,余额耗尽的账号几乎不会被选中,也就学不到属性。probe 用于主动补课。
注意:额度耗尽的账号会被上游整体拒绝(
14018 Credits exhausted),此时连免费模型也会失败。要验证某模型是否免费,请使用额度未耗尽的账号。
# 探测全部账号,每个账号取模型目录前 5 个模型
workbuddy-gateway probe
# 只探测指定账号
workbuddy-gateway probe -auth workbuddy4.json
# 指定模型
workbuddy-gateway probe -auth workbuddy4.json -models hy3,deepseek-v4.1-flash
# 指定数量上限(默认 5,上限 50)
workbuddy-gateway probe -auth workbuddy4.json -limit 8| 选项 | 默认 | 说明 |
|---|---|---|
-auth <path> |
全部账号 | 只探测指定凭据(文件名或路径均可) |
-models <m1,m2> |
目录前几个 | 指定要探测的模型 |
-limit <n> |
5 |
未指定 -models 时探测的模型数量,上限 50 |
输出示例:
正在请求 http://127.0.0.1:8317/admin/probe(账号=workbuddy4.json,模型=hy3)...
账号 站点 模型 结果 credit tokens 说明
workbuddy4.json intl hy3 paid 0.42 820 usage.credit=0.42,收费
汇总: paid=1
结果状态:
| 状态 | 含义 |
|---|---|
free |
usage.credit=0 且 total_tokens ≥ 100,已学习为免费 |
paid |
usage.credit > 0,已学习为收费 |
unknown |
未返回 credit,或 credit=0 但样本过小 |
quota |
14018 额度耗尽,记为该账号该模型收费并阻断该模型 |
rate_limited |
6004 模型级限流,只冷却该模型 |
auth_failed |
授权失效(probe 不会自动禁用账号) |
skipped |
账号失效或无凭据 |
error |
网络 / 协议错误 |
原理:
probe作为客户端调用运行中服务的/admin/probe。账本保存在serve进程内存中,独立进程直接写状态文件会被服务快照覆盖,因此探测必须由运行中的服务执行。该接口仅接受回环来源;服务启用-api-key时同样需要鉴权。
清空除登录凭据以外的全部本地数据,并重新拉取模型与倍率。
workbuddy-gateway reset清理范围:
workbuddy-status.json(账号与模型状态快照)wb-models-cache.json(模型目录、倍率、价格探测结论)*.disabled/*.json.disabled(授权失效标记)logs/(运行日志)
保留:workbuddy*.json 登录凭据。
清理后会立即重新拉取模型目录与倍率。账号账本同时存在于 serve 进程内存中,若服务正在运行,请重启使其同步归零:
systemctl restart workbuddy-gatewayworkbuddy-gateway version # 输出 WorkBuddy Local Gateway vX.Y.Z
workbuddy-gateway help # 输出完整帮助
workbuddy-gateway -v # 同 version
workbuddy-gateway -h # 同 help三种配置方式:
# 方式一(推荐):自动发现
# 把多个凭据文件放进工作目录,无需任何参数
workbuddy-gateway serve
# 方式二:-auth 逗号分隔
workbuddy-gateway serve -auth workbuddy.json,workbuddy2.json
# 方式三:-auth-dir 目录
workbuddy-gateway serve -auth-dir ./auths行为说明:
- 轮询:请求按 round-robin 在可用账号间分发。
- 429 冷却:
6004只冷却触发模型;无法归因到模型的 429 才进入账号级冷却,冷却到期自动恢复。 - 授权失效:401/403 类错误禁用账号并删除凭据文件,同时写
*.disabled标记;重新login后自动恢复。 - 额度耗尽:
剩余=0标记「付费耗尽」,仍可服务已确认免费的模型。 - 热加载:默认每 5 秒扫描,新增 / 更新 / 删除凭据免重启。
- 串行化:同一账号请求严格排队,避免并发双发触发风控;不同账号可并行。
列表来源:实时接口 GET {Base}/v2/enterprises/personal/models 与 npm 包静态目录,按模型 ID 去重、接口优先。
两路都成功 → 合并去重
一路成功 → 使用成功那路
两路都失败 → 使用本地缓存 wb-models-cache.json
失败且无缓存→ 该站点本轮不展示模型(不影响模型调用)
免费站点优先:若某模型出现「一个站点免费、另一个站点收费」,调度优先使用免费站点的账号,直到该站点账号全部不可用(冷却 / 耗尽 / 失效)才回退到另一站点;若两个站点都免费或都收费(只是倍率不同),则不设优先,保持正常轮询。
倍率:
1. 促销生效中:生效倍率 = credits × factor(factor=0 → 0.00x)
2. 促销已过期:接口 credits 不可信(上游常把促销价固化进 credits),
探测出结果前显示 -,随后由实测决定
3. 模型不在接口目录中:同样交由实测决定
4. 无促销且 credits 有值:直接展示该倍率
价格探测:由「余额未耗尽」的同站点账号发一次最小请求实测。
探测免费 → 展示 0.00x,并每 12 小时复测确认
探测收费 → 展示 收费(倍率未知),直到接口重新给出未过期的 0.00x
14018 / 无 usage.credit / 样本过小 → 不覆盖,保持未知
探测调度:
| 时机 | 说明 |
|---|---|
| 服务启动 | 启动后约 20 秒执行首轮 |
| 首次 / 重置后 | 单轮最多 30 个,快速补齐结论 |
| 收敛后 | 单轮最多 5 个,每模型 12 小时最多一次 |
| 待探测未清空 | 用 2 分钟短间隔追赶,清空后回到 30 分钟 |
| 目录刷新成功 | 立即触发一轮 |
| 凭据变化 | 立即触发一轮(含「原本没有某站点账号、后来加入」的情况) |
仅探测被实际请求过、或接口明确需要确认的模型,避免无谓消耗额度。
/v1/models 响应头 X-Model-Source 与 /health 的 model_source 会标注目录来源。
网关启动后服务地址为 http://127.0.0.1:8317/v1。
curl:
curl -N -s http://127.0.0.1:8317/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"hy4-preview","messages":[{"role":"user","content":"你好"}],"stream":true}'Python OpenAI SDK:
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8317/v1", api_key="none")
resp = client.chat.completions.create(
model="hy4-preview",
messages=[{"role": "user", "content": "写一个快速排序"}],
)
print(resp.choices[0].message.content)Claude Code(Anthropic 协议直连,免外部翻译层):
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
export ANTHROPIC_API_KEY=你的网关-api-key # 网关未启用 -api-key 时随意填
claude网关在
/v1/messages入口完成 Anthropic → Chat 双向转译:思维链回译为thinking内容块、tool_calls回译为tool_use、finish_reason映射stop_reason(tool_calls→tool_use、length→max_tokens),并复用账号池轮询、工具序列自愈与 WAF 脱敏管线。 模型名直接填网关/v1/models列表中的 ID。
DSH(~/.dsh/settings.yaml):
llm-pi-ai:
providers:
workbuddy-local:
baseURL: http://127.0.0.1:8317/v1
apiKeyEnv: LOCAL_API_KEY # 任意字符串即可
api: openai-completions
models:
- id: hy4-preview
contextWindow: 1000000
maxTokens: 128000-
从 Releases 下载
workbuddy-gateway-windows-amd64.exe。 -
在 PowerShell / CMD 中进入文件所在目录:
.\workbuddy-gateway-windows-amd64.exe login .\workbuddy-gateway-windows-amd64.exe serve -port 8317
-
开机自启:
Win+R→shell:startup,把 exe 快捷方式放入启动文件夹,并在快捷方式“目标”后追加serve。
# x86_64
wget https://github.com/CangShui/workbuddy-gateway/releases/latest/download/workbuddy-gateway-linux-amd64
sudo install -m 755 workbuddy-gateway-linux-amd64 /usr/local/bin/workbuddy-gateway
# ARM64
wget https://github.com/CangShui/workbuddy-gateway/releases/latest/download/workbuddy-gateway-linux-arm64
sudo install -m 755 workbuddy-gateway-linux-arm64 /usr/local/bin/workbuddy-gateway
workbuddy-gateway login
workbuddy-gateway serve -addr 127.0.0.1 -port 8317创建 /etc/systemd/system/workbuddy-gateway.service:
[Unit]
Description=WorkBuddy Local Gateway (CodeBuddy OpenAI-compatible proxy)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/workbuddy-gateway
ExecStart=/opt/workbuddy-gateway/workbuddy-gateway serve -addr 0.0.0.0 -port 8317
Restart=on-failure
RestartSec=5
User=root
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=false
[Install]
WantedBy=multi-user.target部署与启动:
sudo mkdir -p /opt/workbuddy-gateway
sudo cp workbuddy-gateway /opt/workbuddy-gateway/
sudo /opt/workbuddy-gateway/workbuddy-gateway login
sudo systemctl daemon-reload
sudo systemctl enable --now workbuddy-gateway
sudo systemctl status workbuddy-gateway
sudo journalctl -u workbuddy-gateway -f
WorkingDirectory决定自动发现的凭据目录。把多个凭据文件放进该目录即可组成账号池,新增 / 更新 / 删除会自动热加载。
常用运维:
sudo systemctl restart workbuddy-gateway
sudo systemctl stop workbuddy-gateway
sudo systemctl disable workbuddy-gateway对外开放时(例如局域网其他设备)把 -addr 改为 0.0.0.0,并务必设置 -api-key:
ExecStart=/opt/workbuddy-gateway/workbuddy-gateway serve -addr 0.0.0.0 -port 8317 -api-key sk-changeme-
下载
workbuddy-gateway-darwin-arm64(Apple Silicon)或workbuddy-gateway-darwin-amd64(Intel)。 -
移除隔离属性:
chmod +x workbuddy-gateway-darwin-arm64 xattr -d com.apple.quarantine workbuddy-gateway-darwin-arm64 2>/dev/null || true
-
登录与启动:
./workbuddy-gateway-darwin-arm64 login ./workbuddy-gateway-darwin-arm64 serve
-
开机自启(launchd):创建
~/Library/LaunchAgents/com.workbuddy.gateway.plist:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key><string>com.workbuddy.gateway</string> <key>ProgramArguments</key> <array> <string>/path/to/workbuddy-gateway-darwin-arm64</string> <string>serve</string> <string>-port</string><string>8317</string> </array> <key>RunAtLoad</key><true/> <key>KeepAlive</key><true/> <key>WorkingDirectory</key><string>/path/to/workbuddy-gateway-dir</string> </dict> </plist>
launchctl load ~/Library/LaunchAgents/com.workbuddy.gateway.plist
workbuddy*.json包含真实访问凭据(Access Token / Refresh Token),严禁提交到 Git 或公开分享;本仓库.gitignore已排除。- 网关默认只监听
127.0.0.1。需要局域网 / 公网访问时改用-addr 0.0.0.0并配合-api-key,或置于反向代理之后。 /admin/probe仅接受回环来源调用。- 不再需要某账号授权时,删除对应凭据文件并在 CodeBuddy 控制台撤销授权。
需要 Go 1.20+:
git clone https://github.com/CangShui/workbuddy-gateway.git
cd workbuddy-gateway
go vet ./...
go test ./...
# 当前平台
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o workbuddy-gateway .
# 交叉编译示例
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o dist/workbuddy-gateway-linux-amd64 .
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o dist/workbuddy-gateway-windows-amd64.exe .本项目仅用于个人学习与技术研究。腾讯 CodeBuddy(含国内站与国际站 workbuddy.ai)的接口协议与风控策略可能随时变化;请遵守腾讯服务条款,自行承担使用风险。本仓库不包含任何官方未公开的密钥或凭据。