Go

workbuddy-gateway

用Go语言写的腾讯 CodeBuddy 账号池纯Cli管理控制台 + OpenAI 兼容反代网关

C

CangShui

Dernière activité 24 sept. 2026
CangShui/workbuddy-gateway

187

étoiles

30

forks

1

issues ouvertes

Ce README est souvent en anglais.

WorkBuddy Local Gateway

image

基于腾讯 CodeBuddy 协议开发的纯 Go、零 CGO 依赖、跨平台单二进制本地 AI 代理网关。默认无 Web UI,全部通过命令行(CLI)完成登录、凭据续期与服务控制;可选开启网页管理台(-webui,见下文)。

v1.14.0:新增配置热生效、全局账号与模型网页开关、凭据 JSON 编辑、端口设置及日志保留/清理。旧配置缺省日志保留天数时不自动删除;端口修改仍需重启。请先升级二进制,再添加新增配置字段。

v1.14.1:网页凭据页已移除,新增只读定时任务时间页;执行记录来自现有后端日志,无新增调度模块。高频任务日志按分钟汇总,状态变化即时记录。

同时支持两个上游站点(同一套 /v2/plugin/* 协议,凭据按站点隔离,账号池可混挂轮询):

站点 上游 登录方式 登录命令
国内站 copilot.tencent.com / www.codebuddy.cn 微信 / 企业微信扫码 login
国际站 www.workbuddy.ai 浏览器内登录(邮箱 / 验证码 / SSO) login -intl

目录


核心特性

  • 国内 / 国际双站反代:两个站点走同一套协议,凭据通过 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 API 监听端口;显式传入时覆盖 config.json 的 gateway.apiPort
-auth <path> 自动发现 凭据文件路径,支持逗号分隔多个
-auth-dir <dir> 空 凭据目录,自动加载目录内所有 workbuddy*.json
-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 命令
-webui false 启用独立网页控制台(默认 http://127.0.0.1:8316/ui/);管理 Key 与模型 API 鉴权由 config.json 配置

配置网页控制台与模型 API 鉴权

工作目录 config.json 的 gateway 段控制监听端口、网页控制台管理 Key 和模型 API 鉴权,全部为明文配置(config.json 已被 Git 忽略,请自行限制文件权限):

{
  "gateway": {
    "apiPort": 8317,
    "webPort": 8316,
    "adminKey": "",
    "apiKeyEnabled": false,
    "apiKey": ""
  }
}
配置 默认 说明
apiPort 8317 模型 API 监听端口,省略或 0 使用默认值;也可用 -port 临时覆盖
webPort 8316 网页控制台监听端口,省略或 0 使用默认值;仅在显式 -webui 时监听
adminKey "" 网页控制台管理 Key,有两种设置方式:① 页面一键生成——为空时在服务器本机(或 SSH 本地端口转发)打开网页,生成 32 字符随机 Key 写入本文件,并在弹窗中仅展示一次;② 手动编辑本文件——直接把本字段改成任意随机字符串(建议 32 位),保存后约 1 秒热生效。设置完成后可从其他设备用该 Key 登录
apiKeyEnabled false 模型 API 是否校验 Key。关闭时不带 Key 或任意 Key 均可调用模型;开启时必须匹配 apiKey
apiKey "" 模型 API Key。开启校验时必须非空;关闭时保留原值,重新开启即可继续使用

网页控制台也可在「访问设置」页切换 apiKeyEnabled 并设置 apiKey,保存后立即生效并写回本文件;端口修改需要重启。管理 Key 与模型 API Key 相互独立:关闭模型 API 鉴权不会关闭管理鉴权,模型 API Key 也不能登录网页控制台。为避免他人抢先生成,页面一键生成管理 Key 只允许本机访问;手动编辑 config.json 设置 gateway.adminKey 不受此限制,效果与一键生成完全相同。

升级顺序(重要):新版本能读取不含 gateway 段的旧配置,但旧版本二进制遇到含 gateway 段的新配置会启动失败(json: unknown field "gateway")。请先替换二进制、再添加 gateway 配置。

JSON 调试日志

工作目录中的 config.json 控制结构化调试日志,默认关闭。修改后约 1 秒热生效,无需重启:

{
  "debug": {
    "enabled": true
  }
}

开启后,网关把单行 JSON 写入 logs/debug-YYYY-MM-DD.jsonl;普通运行日志仍写入原来的 logs/gateway-YYYY-MM-DD.log,两者互不替代。可复制 config.example.json 作为起点。

日志保留与清理

{
  "logs": {
    "retentionDays": 7
  }
}
  • retentionDays 范围为 0~36500:0 或省略表示保留全部,兼容旧配置;7 表示按服务器本地日期保留今天及此前 6 天。设为正数后会自动删除过期日志,删除不可撤销。
  • 配置热加载后应用新规则;启动/规则变化时扫描,此后每小时自动扫描。网页「日志」页可以保存保留天数,也可以立即按已保存规则清理。
  • 只删除 logs/ 内日期合法的 gateway-*.log、debug-*.jsonl、deployment-*.jsonl、frontend-*.log;不跟随符号链接,不删除目录、凭据、配置、报告或其他文件,不删除正在写入的日志。
  • 普通日志和调试日志在跨午夜后的下一次写入切换到新日期文件。尚未切换的旧日志保持保护,关闭后在后续扫描清理。
  • 请先替换新二进制,再添加 logs 段;旧二进制可能因未知配置字段拒绝启动。

配置系统提示词

工作目录 config.json 的 systemPrompt 段有两个独立选项(修改后约 1 秒热生效):

{
  "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 时,发往上游的是 <客户端原 system>\n\n请用中文回答。。配置值仅支持 JSON 字符串;空串或全空白视为未配置。不会写出或替换客户端的 user、assistant、tool 消息,也不改变账号选择。普通日志和 JSON 调试日志只记录规则分支、位置与字符数,不记录提示词正文。

实验功能风险自负: force 后置于 system 末尾(紧贴用户消息),因此比客户端自带指令更"新近",冲突时通常更有影响力——这正是人设类、风格类指令希望达到的效果,但也可能与客户端的 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 但实际不可用」的凭据覆盖掉还能用的旧凭据 同上

校验接口自身不可用时按通过处理,不会因为校验抖动而拒绝有效的新凭据。校验失败不计入「判定失效」的计数,因此不会把还能用的账号停掉。

判定失效、准备删除凭据之前:

  1. 先停止调度并写入失效标记;
  2. 再用只读接口确认该凭据确实取不到账号数据,才删除文件;
  3. 凭据仍能取到数据 → 保留文件;
  4. 无法判定(网络故障、上游 5xx)→ 保守保留文件。

凭据文件被保留时,失效标记在重启后依然生效,账号不会被重新调度。如果你重新 login 或手动续期了该凭据,凭据文件会比标记更新,网关会自动清除过期标记并恢复该账号。

模型黑白名单

config.json 的 models 段可按模型名启用黑白名单(大小写与首尾空白不敏感):

{
  "models": {
    "blocklist": ["deepseek-v4-pro"]
  }
}
字段 说明
blocklist 黑名单,命中即禁用
allowlist 白名单,非空时只放行列表内模型,其余一律禁用

规则:

  • 模型黑名单与白名单选择一种。非空 allowlist 和非空 blocklist 同时存在会校验失败,避免配置歧义;旧示例同时包含两个空数组、或其中一个为空时仍可读取。
  • 两个列表都为空或省略时不做任何限制(默认行为不变)。
  • 被禁用的模型会从 /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 文件黑白名单:保留键 all 控制所有模型的全局账号调度,其余键控制对应模型。未配置 all 或全局列表为空时与旧版本相同。全局规则和模型专属规则都通过才允许调度,模型专属白名单不能绕过全局停用。与上面的 models.allowlist / models.blocklist(控制模型是否可调用)互不替代:

{
  "models": {
    "blocklist": [],
    "accounts": {
      "all": {
        "allowlist": [],
        "blocklist": ["paused-account.json"]
      },
      "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。
  • all.blocklist 中的账号不再参与任何模型的请求调度、失败换号和模型生成探测。账号仍显示在管理台,凭据、额度账本和历史统计保留;后台凭据保活/额度查询不属于模型生成,保持原有行为。
  • 全局账号白名单非空时,账号池开关反映白名单规则。首次网页账号操作会删除 all.allowlist(包括空数组或 null),将当前账号池的全局启停状态转换为 all.blocklist,再应用本次操作;其他当前账号状态和模型专属规则保留,之后新增账号默认开启(黑名单语义)。
  • 只接受凭据文件名(如 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 约 1 秒热生效;示例中的文件名均为占位值。没有配置 models.accounts 时原行为不变。

config.json 热生效与旧版本升级

serve 独立每 1 秒按文件内容检测配置变化,不受 -reload-interval 0(只关闭凭据扫描)影响。网页开关先写入配置文件、再立即应用;外部编辑器修改则在下一次扫描应用。

配置 生效方式
模型名单、models.accounts(含 all) 热生效,控制后续调度
gateway.adminKey / apiKeyEnabled / apiKey 热生效;管理 Key 改变后需使用新 Key 登录
systemPrompt / debug.enabled 热生效
upstream 超时、网络重试次数 后续上游请求使用新值;已有流式响应保持原空闲超时
gateway.apiPort / webPort 写入配置但重启后变更监听;页面仍显示实际监听端口
  • 配置先整体解析、校验,再应用。运行时遇到半写 JSON、空文件、文件短暂缺失、错误类型或非法账号路径时,保留上一份有效配置,错误原因写入 logs/gateway-YYYY-MM-DD.log。修正并保存后自动重试;不会把配置读取失败误当作“全部开启”。
  • 要恢复默认规则,请保存有效的 {} 或将对应列表设为 [],而不是删除运行中的配置文件。
  • 上一版本省略 all、accounts、models 或 gateway 的配置仍可读取;accounts: {}、accounts: null、all: {} 和空名单均表示无全局限制。默认示例包含空的 models.accounts.all.allowlist/blocklist。
  • 如旧配置同时填写了两种非空模型名单,请在升级前选择并保留一种;新版本不再接受相互冲突的模型黑白名单。运行中错误配置会保留上次生效状态,启动时则给出明确错误。
  • 旧配置中只有白名单生效时,管理页开关反映白名单;首次网页模型操作会删除 models.allowlist,将当前已知模型的启停状态转换为 models.blocklist。其他已知模型状态不变,之后新增的模型默认开启(黑名单语义)。模型账号规则保持独立。
  • 新版本中的 all 是保留键;不要把它当作真实模型 ID。先升级二进制,再添加 all;旧二进制不识别全局语义,会把它当作名为 all 的模型专属规则。

每条 JSON 调试日志都包含时间、级别、稳定事件名、trace_id、request_id、服务/实例/版本、路由、方法、模型、账号、流式标记和累计耗时,并记录客户端地址、代理头、协议、TLS、Content-Type、Content-Length、deadline 等请求元数据。客户端传入的 X-Trace-ID 会优先复用并透传到上游。

请求体只记录以下安全摘要,不记录正文:

  • declared_body_bytes、actual_body_bytes、body_read_ms
  • body_sha256_prefix(SHA-256 前 12 位)
  • json_valid、json_decode_ms
  • body_limit_bytes、body_limit_exceeded(当前未设置请求体限制,因此分别为 0、false)
  • read_error_type、脱敏截断后的 read_error

调试日志不会记录 Authorization、Cookie、API Key、Access Token、Refresh Token 或完整请求体。只记录是否提供 Authorization,以及凭据的不可逆短哈希 api_key_fingerprint。


serve

启动本地网关,默认命令。

# 默认监听 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

# 上游走代理 + 详细日志(客户端鉴权在 config.json 的 gateway 段配置)
workbuddy-gateway serve -proxy http://127.0.0.1:7890 -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 /ui/ 网页控制台静态页面(独立端口,仅 -webui 启用时存在)
GET /admin/api/* 网页控制台数据接口(独立端口,仅 -webui 启用时存在,需管理 Key)
GET / 简单文本说明

从 v1.13.15 起,Responses function_call_output.output 支持文本和图片内容块数组: 文本原样保留在 tool 结果中,input_image 图片提升为全部配对工具结果之后的 user 多模态消息,图片 URL 和数据不变。图片不再被序列化成 Base64 文本混入 上下文,避免截图会话异常消耗大量 token,最终触发 11133 model_param_invalid。 并行工具调用的结果仍连续排列,不会因插入图片而破坏配对。普通字符串和 JSON 工具结果保持原行为;网关不截断操作手册或会话历史。11133 本身是上游通用参数 错误码,不仅限于图片或上下文长度问题;排障仍需结合模型、TraceID 与日志。

从 v1.13.17 起,网关在客户端未声明输出预算(max_tokens 与 max_completion_tokens 都不带有效值)时,按模型目录声明的输出上限补一个 max_tokens。上游按「输入 token + 输出预算」判断是否超出模型窗口,而请求不带该字段时上游会为输出默认预留 384000: 标称 1048576 窗口的 deepseek-v4.1-flash 实际只剩约 664576 可用输入,长会话会在远未 到窗口上限时被 11133 model_param_invalid 拒绝,表现为「聊着聊着就 400」。实测 678912 输入不带预算返回 400/11133,带 max_tokens=128000 返回 200。客户端显式 传入的值一律不覆盖;目录未收录的模型保持原行为,网关不做猜测。注意可用输入与输出上限 共用同一窗口(可用输入 = 窗口 − 声明的输出预算),需要更长输入时应让客户端声明更小的 输出预算,而不是更大。

后台任务(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 错误事件,避免下游把残缺输出当成完整结果。


login

登录并保存凭据。国内站输出终端 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",与国内站凭据可混挂在同一账号池。
  • 重新登录会覆盖原凭据并自动清除该账号的失效标记,无需重启服务(热加载会生效)。

status

查看账号池状态,包含站点、冷却、额度与 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)

refresh

立即刷新所有账号的 Access Token(正常情况下由后台每 5 分钟自动检查,无需手动执行)。

workbuddy-gateway refresh
  • 成功 / 失败 / 跳过(授权失效)会分别统计。
  • 刷新失败若属于授权类错误,会禁用该账号并删除凭据文件。

monitor

前台实时监控,周期刷新展示「账号表格 + 模型统计附表 + 最近日志」,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        | 2          | 0          |
| 2    | workbuddy2.json| user-b     | 国际站 | 付费耗尽   | 2027-09-05 01:57:00 | 1100     | 1100     | 0      | Pro试用    | 2          | 0          |
+------+----------------+------------+--------+------------+---------------------+----------+----------+--------+------------+------------+------------+

状态取值:可用、冷却、付费耗尽、已过期、失效。

“免费模型”列按账号所属站点,统计下方模型统计附表中对应倍率为 0.00x 的模型数量,不再统计该账号自己的实测免费记录。该数量仅用于展示,不代表该账号一定可调用这些模型;实测账本、probe、账号调度和计费判断仍保持原有逻辑。

套餐取值: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 的请求不估算

webui(网页控制台)

默认关闭。显式 -webui 后在 gateway.webPort(默认 8316)提供独立网页控制台,用于在浏览器管理账号池开关、模型列表开关,查看日志、config.json 与凭据文件(令牌脱敏),并在「访问设置」页切换模型 API Key 校验。它与模型 API 端口分离,未启用时两个端口都不监听。

# 只有显式 -webui 才开启网页控制台;模型 API 仍监听 8317
workbuddy-gateway serve -webui

# 方式一:本机或 SSH 本地端口转发打开页面,一键生成管理 Key
ssh -L 8316:127.0.0.1:8316 root@服务器
# 浏览器打开
# http://127.0.0.1:8316/ui/

# 方式二:不打开页面,直接在服务器上手动设置管理 Key(建议 32 位随机字符串)
python3 - <<'PY'
import json, secrets, pathlib
p = pathlib.Path("/opt/workbuddy-gateway/config.json")
cfg = json.loads(p.read_text())
cfg.setdefault("gateway", {})["adminKey"] = secrets.token_hex(16)  # 32 字符
p.write_text(json.dumps(cfg, ensure_ascii=False, indent=2) + "\n")
print("已写入 gateway.adminKey,运行中的新版本约 1 秒热生效")
PY
systemctl restart workbuddy-gateway
项 说明
入口 GET /ui/(独立管理端口,静态外壳不含任何数据)
数据接口 GET /admin/api/status、/admin/api/models、/admin/api/logs、/admin/api/config、/admin/api/tasks,一律需要 Authorization: Bearer <adminKey>
写入接口 POST /admin/api/setup(仅本机首次生成管理 Key)、POST /admin/api/settings(模型 API 鉴权与端口)、POST /admin/api/account-toggle / model-toggle(账号/模型开关)、POST /admin/api/credential-edit(凭据 JSON)、POST /admin/api/log-settings / log-cleanup(保留设置与过期清理)
页面 总览(含国内站 / 国际站数量与已停用账号)、账号池(全局调度开关)、模型列表(启停开关,含停用模型)、日志(保留天数与清理)、配置(只读 · Key 已隐藏,systemPrompt 正文直接展示)、定时任务(只读日志视图)、访问设置(鉴权与端口编辑)。网页不再提供凭据列表或编辑器
数据来源 复用 serve 的状态快照、完整模型目录、logs/ 日志与本地配置/凭据文件;开关受控写入配置并应用原有调度过滤
定时任务 周期、启用状态、最近执行、完成时间、执行结果、下次预计执行与日志说明;仅展示、不触发任务或修改调度

只读定时任务与访问设置

  • 「定时任务」通过只读 GET /admin/api/tasks 从现有 logs/gateway-*.log 中的 [定时任务] JSON 记录聚合 11 项后台任务,包含启动续期补跑。没有新增任务调度模块、任务状态文件或持久化登记表;关闭 debug 仍会记录任务事件。

  • 每条任务事件包含任务 ID、轮次 TraceID、进程 PID、开始/完成时间、执行结果和已知下次计划。只聚合当前进程启动后的记录,旧进程、损坏行不充当当前成功记录;没有记录时显示“无执行记录”。日志扫描预算为 16 MiB,达到预算会明确提示。

  • 配置检查、凭据扫描、状态快照这三项高频任务,每 60 秒记录最近一次执行,实际变化/状态变化即时记录。任务页每 15 秒读取日志;周期性下次时间可按日志中的定时锚点推算,并标记“推算”,事件触发可能提前。一次性任务完成后不再安排下一次;过期且无法推算的计划等待新日志,不伪造执行结果。

  • 网页凭据页和编辑器已移除,不再自动读取或展示完整凭据。原 /admin/api/credentials 与 /admin/api/credential-edit 后端接口暂保留兼容,仍受独立管理鉴权、同源、文件范围和版本冲突保护,网页不再调用。

  • 「访问设置」可编辑 gateway.apiPort / gateway.webPort,保存调用原来的 POST /admin/api/settings。配置端口与实际监听端口分别显示,修改后需重启网关,不会直接中断当前页面或流式请求;显式 -port 仍优先于配置。

  • 「日志」页通过 GET/POST /admin/api/log-settings 读写 logs.retentionDays,通过 POST /admin/api/log-cleanup(空 JSON 对象)清理过期日志,返回删除数量、回收字节、正在写入跳过数量与失败数量。

  • 所有新接口均需要独立管理 Key,并复用同源校验和 TraceID 落盘审计;模型 API Key 不能编辑凭据、修改端口或清理日志。

  • 未启用 -webui 时,管理端口不监听,/ui 与 /admin/api/* 也不注册路由。

  • 管理 Key 的两种设置方式(二选一即可):

    1. 页面一键生成:adminKey 为空时,在服务器本机、或用 SSH 本地端口转发(ssh -L 8316:127.0.0.1:8316 用户@服务器)后访问 http://127.0.0.1:8316/ui/,点击生成 32 字符随机 Key;Key 写入 config.json 并仅在弹窗中展示一次。远程(非本机)访问不能触发一键生成,避免他人抢先生成;但远程仍可用已设置好的 Key 登录。
    2. 手动编辑配置文件:直接在服务器上编辑 config.json,把 gateway.adminKey 设为你自己的随机字符串(建议 32 位),保存后约 1 秒生效。此方式不需要本机访问,也不需要页面操作;登录时填写该字符串即可。
  • /admin/api/logs 只允许读取 logs/ 下命名受限的普通、调试、部署和前端审计日志,拒绝任意路径与目录穿越;返回日志先做秘密值脱敏,且单次读取有约 1 MiB 的扫描预算,超长单行会被省略。

  • 前端为原生 HTML/CSS/JS,通过 go:embed 嵌入二进制,无额外构建步骤与运行时依赖;管理 Key 只保存在当前标签页的 sessionStorage,验证成功后才保存。

  • 状态快照缺失或损坏时接口返回 503,页面保留上次数据并提示,不会把读取失败显示成零账号。


probe

免费 / 收费属性按「账号(含站点)+ 模型」学习,只有该账号真正请求过该模型才会写入账本。默认调度优先使用有余额账号,余额耗尽的账号几乎不会被选中,也就学不到属性。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 校验时同样需要携带 gateway.apiKey。


reset

清空除登录凭据以外的全部本地数据,并重新拉取模型与倍率。

workbuddy-gateway reset

清理范围:

  • workbuddy-status.json(账号与模型状态快照)
  • wb-models-cache.json(模型目录、倍率、价格探测结论)
  • *.disabled / *.json.disabled(授权失效标记)
  • logs/(运行日志)

保留:workbuddy*.json 登录凭据。

清理后会立即重新拉取模型目录与倍率。账号账本同时存在于 serve 进程内存中,若服务正在运行,请重启使其同步归零:

systemctl restart workbuddy-gateway

version / help

workbuddy-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=你的模型APIKey   # config.json 未开启 apiKeyEnabled 时随意填
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

各平台部署

Windows

  1. 从 Releases 下载 workbuddy-gateway-windows-amd64.exe。

  2. 在 PowerShell / CMD 中进入文件所在目录:

    .\workbuddy-gateway-windows-amd64.exe login
    .\workbuddy-gateway-windows-amd64.exe serve -port 8317
  3. 开机自启:Win+R → shell:startup,把 exe 快捷方式放入启动文件夹,并在快捷方式“目标”后追加 serve。

Linux

# 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

systemd 服务(推荐)

创建 /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,并在 config.json 中开启模型 API Key 校验:

{"gateway":{"apiKeyEnabled":true,"apiKey":"sk-changeme"}}
ExecStart=/opt/workbuddy-gateway/workbuddy-gateway serve -addr 0.0.0.0

macOS

  1. 下载 workbuddy-gateway-darwin-arm64(Apple Silicon)或 workbuddy-gateway-darwin-amd64(Intel)。

  2. 移除隔离属性:

    chmod +x workbuddy-gateway-darwin-arm64
    xattr -d com.apple.quarantine workbuddy-gateway-darwin-arm64 2>/dev/null || true
  3. 登录与启动:

    ./workbuddy-gateway-darwin-arm64 login
    ./workbuddy-gateway-darwin-arm64 serve
  4. 开机自启(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,并在 config.json 中开启模型 API Key 校验(gateway.apiKeyEnabled),或置于反向代理之后。
  • config.json 中的 gateway.adminKey 与 gateway.apiKey 按要求明文保存,请限制该文件权限;网页配置页只显示脱敏后的内容。
  • /admin/probe 仅接受回环来源调用。
  • 不再需要某账号授权时,删除对应凭据文件并在 CodeBuddy 控制台撤销授权。

从源码构建

需要 go.mod 声明的 Go 1.26.5 或更新工具链:

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 .

PowerShell 一键构建:

.\build.ps1                         # 检查并构建全部 9 个目标
.\build.ps1 -Only windows           # Windows x86、x64、ARM64
.\build.ps1 -Only linux             # Linux x86、x64、ARMv7、ARM64
.\build.ps1 -Only linux -Architecture arm -ArmVersion 6
系统 架构 产物
Windows x86 32 位 / 386(需要 SSE2) workbuddy-gateway-windows-386.exe
Windows x86-64 / amd64 workbuddy-gateway-windows-amd64.exe
Windows ARM64 workbuddy-gateway-windows-arm64.exe
Linux x86 32 位 / 386(需要 SSE2) workbuddy-gateway-linux-386
Linux x86-64 / amd64 workbuddy-gateway-linux-amd64
Linux ARM 32 位(默认 ARMv7) workbuddy-gateway-linux-armv7
Linux ARM64 workbuddy-gateway-linux-arm64
macOS x86-64 / amd64 workbuddy-gateway-darwin-amd64
macOS ARM64 workbuddy-gateway-darwin-arm64
  • Windows ARM32 不受当前 Go 工具链支持,不能用 ARM64 文件替代。Linux ARM32 可用 -ArmVersion 5/6/7 选择,文件名与最低 ARM 版本一致。
  • 默认先运行 go vet、go test;不受调用者遗留的 GOOS / GOARCH 影响。各目标使用 CGO_ENABLED=0,x64 基线为 GOAMD64=v1、ARM64 基线为 GOARM64=v8.0。成功或失败后恢复原构建环境和工作目录。
  • 默认输出到 dist/,同时生成 SHA256SUMS、build-manifest.json 与空密钥的 config.example.json;校验和覆盖二进制、清单与示例配置。
  • -OutputDir 必须是项目内的独立子目录;-Clean 仅清理已知构建文件,不递归删除目录、配置凭据或其他文件。构建日志写入 logs/build-YYYY-MM-DD.jsonl。

免责声明

本项目仅用于个人学习与技术研究。腾讯 CodeBuddy(含国内站与国际站 workbuddy.ai)的接口协议与风控策略可能随时变化;请遵守腾讯服务条款,自行承担使用风险。本仓库不包含任何官方未公开的密钥或凭据。

Projets similaires

把腾讯WorkBuddy账号变成 OpenAI 兼容 API 的多账号网关,同时自动完成任务中心全部任务,附 Web 管理面板(账号池可视化 / 积分任务 / 配置热更新)。基于 Sliverkiss/workbuddy2api 的增强分支

Goadmin-panelcodebuddygateway
Llinguo2625469
1,4 k étoiles381

WorkBuddy 国际国内多账号反代网关,支持 Codex / Claude Code / DSH与标准 OpenAI 客户端。

Pythonapi-gatewayclaude-codecodebuddy
Aardeyouxipianyi
460 étoiles112

腾讯 CodeBuddy 账号池管理控制台,内置 OpenAI 兼容反代网关:扫码批量纳管账号、定时签到与保活、密钥分组分发、IP 与模型白名单、调用日志与用量统计;支持带签名校验的一键更新。

Pythonaccount-managerapi-gatewaycodebuddy
Iithtelab
656 étoiles161