From ad40956f33dca5f5a33a6c8bbc982ef5afb5dcfe Mon Sep 17 00:00:00 2001 From: hmo Date: Sat, 1 Aug 2026 14:39:32 +0800 Subject: [PATCH] docs: ocg_router spec file (human help + AI spec) --- gateway/scripts/specs/ocg_router.json | 95 +++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 gateway/scripts/specs/ocg_router.json diff --git a/gateway/scripts/specs/ocg_router.json b/gateway/scripts/specs/ocg_router.json new file mode 100644 index 0000000..b84bf11 --- /dev/null +++ b/gateway/scripts/specs/ocg_router.json @@ -0,0 +1,95 @@ +{ + "module": "ocg_router", + "version": "1.0", + "purpose": "OCG 路由代理。OpenAI 兼容代理(:19878),背后池化 6 个 OpenCode Go API key,按剩余 quota 智能路由,402/429/5xx 自动故障切换。替代写死的 key3 配置,让所有 OMO 子 agent 自动使用最空闲的 key。", + "ui_location": "I Tab (Infrastructure) → OCG 路由代理 section (API 用量下方)", + + "human_help": { + "title": "OCG 路由代理", + "description": [ + "把 6 个 OpenCode Go key 池化成一个 OpenAI 兼容的 API 端点(:19878)。", + "每次请求自动选剩余 quota 最多的 key,用完后自动切下一个。", + "402(余额不足)、429(限流)、5xx(服务器错误) 自动标记故障 key 并切换,5 分钟后恢复。", + "取代原来写死 key3 的配置——key3 订阅已取消,不改的话所有子 agent 都会 Insufficient balance。", + "Dashboard 可以看到当前路由到哪个 key、各 key 用量、命中次数。" + ], + "usage": [ + "1. 确保 systemd 服务 ocg-router 在运行 (systemctl status ocg-router)", + "2. OMO 配置指向 http://192.168.1.246:19878/v1(已在 oh-my-openagent.jsonc 和 config.json 配置好)", + "3. 本区块自动每 10 秒刷新,显示当前路由 key 和池状态", + "4. 如果代理挂了,Dashboard 会显示「代理未运行」并给出错误信息" + ], + "troubleshooting": [ + "代理未运行 → ssh 246 systemctl restart ocg-router", + "所有 key 故障 → 检查 246 到 opencode.ai 网络是否通 (curl https://opencode.ai/zen/go/v1/models)", + "某个 key 一直在冷却中 → 等 5 分钟冷却期过去,或重启代理清冷却 (systemctl restart ocg-router)", + "当前路由 key 为空 → 代理刚启动还没收到请求,先发一个请求就会显示" + ] + }, + + "ai_spec": { + "apis": [ + {"method": "GET", "path": "http://192.168.1.246:19878/health", "returns": "{ok, time}", "proxied_to": "ocg_router.py status"}, + {"method": "GET", "path": "http://192.168.1.246:19878/v1/models", "returns": "OpenAI 兼容模型列表", "proxied_to": "ocg_router.py → opencode.ai"}, + {"method": "POST", "path": "http://192.168.1.246:19878/v1/chat/completions", "returns": "OpenAI 兼容响应 (含 stream)", "proxied_to": "ocg_router.py → opencode.ai"}, + {"method": "GET", "path": "http://192.168.1.246:19878/api/status", "returns": "代理状态 {current_key, pool, hits}", "proxied_to": "ocg_router.py internal"}, + {"method": "GET", "path": "/api/proxy/status", "returns": "代理状态(通过 dashboard 代理)", "proxied_to": "dashboard.py → 19878"} + ], + "dependencies": [ + "ocg_router.py — 代理核心,systemd 常驻 (:19878)", + "usage_stats.json — 每 2 分钟刷新,提供各 key 用量数据", + "accounts.json — 提供 key 列表和 API key", + "dashboard.py — /api/proxy/status 代理端点", + "dashboard.html — OCG 路由代理 section (id=proxy-router-section)", + "oh-my-openagent.jsonc — OMO 配置,所有 agent/category 指向 ocg-router", + "~/.config/opencode/config.json — ocg-router provider 定义" + ], + "architecture": { + "flow": "OMO(Windows) → ocg-router(:19878, 246) → 按 usage_stats.json 选最空闲 key → opencode.ai/zen/go/v1", + "key_selection": "健康度 score = rolling%*0.6 + weekly%*0.3 + monthly%*0.1。score 最低的 key 被选中。订阅取消/采集错误的 key score=999,故障冷却期内 score=888", + "failover": "402/429/5xx → 标记 key 故障 5 分钟 → 自动重试下一个 key", + "providers": ["ocg-key1 (staymo7777@gmail.com)", "ocg-key2 (hua65111@gmail.com)", "ocg-key3 (staymo@163.com — 订阅已取消, 不可用)", "ocg-key4 (staywithmo@163.com)", "ocg-key5 (damnedmoon@163.com)", "ocg-key6 (ycdennismo@163.com)"], + "port": "19878" + }, + "constraints": [ + "代理必须跑在 246 上 — usage_stats.json 在 246 本地", + "firewall: ufw allow 19878/tcp from 192.168.1.0/24", + "pid lock: proc_guard('ocg_router') — 防止重复启动", + "冷却期 300 秒 — key 被标记故障后 5 分钟自动恢复", + "用量刷新间隔 120 秒", + "User-Agent 必须用 Mozilla/5.0 — 否则 Cloudflare 1010 拦截" + ], + "must_not": [ + "不要把代理跑在 206 上 — 206 是阿里云,到 opencode.ai 的网络被 Cloudflare 按数据中心 IP 拦截", + "不要绕过代理直接配 ocg-key3 — key3 订阅已取消,会 Insufficient balance", + "不要改 baseURL 从 http 到 https — 内网走 HTTP 性能更好", + "不要在 Windows 本机直接拉 usage_stats.json — 数据在 246 上,代理跑 246 避免网络依赖" + ], + "related_modules": [ + {"module": "usage_monitor", "relation": "提供 usage_stats.json 用量数据,代理依赖它做 key 选择"}, + {"module": "dashboard", "relation": "/api/proxy/status 端点代理到路由器;前端 OCG 路由代理 section 展示状态"} + ], + "tests": [ + {"id": "ROUTER01", "name": "GET /health returns ok", "endpoint": "GET http://192.168.1.246:19878/health"}, + {"id": "ROUTER02", "name": "GET /v1/models returns model list", "endpoint": "GET http://192.168.1.246:19878/v1/models"}, + {"id": "ROUTER03", "name": "POST /v1/chat/completions non-stream", "endpoint": "POST http://192.168.1.246:19878/v1/chat/completions"}, + {"id": "ROUTER04", "name": "GET /api/status returns pool health", "endpoint": "GET http://192.168.1.246:19878/api/status"}, + {"id": "ROUTER05", "name": "Dashboard /api/proxy/status proxies correctly", "endpoint": "GET http://192.168.1.246:5803/api/proxy/status"} + ], + "known_issues": [ + "Cloudflare 1010: opencode.ai API 需要真实 User-Agent(Mozilla/5.0),代理已内置", + "阿里云到 opencode.ai: 数据中心 IP 可能被 Cloudflare WAF 拦截,所以代理必须跑在 246(家庭宽带 IP)", + "key3 订阅已取消: key3 在池中但 score=999(不可用),自动跳过" + ], + "related_files": [ + "gateway/scripts/ocg_router.py — 代理核心", + "gateway/scripts/dashboard.py — /api/proxy/status", + "gateway/scripts/templates/dashboard.html — proxy-router-section", + "gateway/scripts/specs/ocg_router.json — 本 spec 文件", + "gateway/temp/usage_stats.json — 用量数据源", + "gateway/scripts/usage_monitor/accounts.json — key 配置", + "~/.config/opencode/oh-my-openagent.jsonc — OMO 配置", + "/etc/systemd/system/ocg-router.service — systemd 服务定义" + ] + } +}