diff --git a/README.md b/README.md index 1150c9e..4942c50 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ ### 极致轻量 - **单二进制**:编译后约 10MB,零运行时依赖(仅依赖系统 libc),部署即用 -- **极低内存占用**:空闲状态仅 ~15MB RSS,满载并发 100+ 请求时峰值 < 100MB +- **极低内存占用**:空闲 ~10MB RSS,带 29MB 历史审计日志启动仅 ~19MB,满载并发 100+ 请求时峰值 < 100MB +- **日志按需加载**:审计日志不常驻内存——默认只加载首屏,下滚自动分页,CSV 导出流式写出(O(1) 内存),离页即释放 - **零运行时依赖**:纯 Go + LuaJIT 静态链接,无需安装 Python/Node/Java 等运行时 - **启动极快**:冷启动 < 200ms,热重载配置 < 10ms @@ -24,6 +25,7 @@ - **多密钥多租户**:支持无限密钥,每个密钥独立角色、模型范围、Token 配额、重置周期 - **AUTO 智能调度**:基于优先级档位的分级调度,同优先级源自动轮询负载均衡,故障自动毫秒级故障转移 +- **自愈冷却**:冷却上限 5 分钟,过半后放行 1 个探测请求,上游/额度恢复即刻回归轮询,无需等满冷却窗口 - **Token 配额管理**:精确到模型级别的 Token 配额控制,支持小时/周/月/自定义小时周期自动重置 - **同优先级源负载均衡**:同一优先级档位的多个源,请求自动 Round-Robin 均匀分发,故障毫秒级故障转移 - **Source-Model 前缀路由**:支持 `source-model`/`source:model`/`source/model` 精确指定上游源 @@ -37,7 +39,7 @@ ### 灵活的协议适配 -- **LuaJIT VM**:每个适配器独立 VM + worker 池,安全并发,Lua 脚本热加载无需重启 +- **LuaJIT VM**:每个适配器独立 VM + **弹性 worker 池**(按需扩缩容,空闲时自动回收),安全并发,Lua 脚本热加载无需重启 - **Lua 适配器协议**:`transform_request` / `transform_response` / `transform_stream_chunk` 双向转换 - **动态请求头钩子**:`build_headers(meta)` 支持 HMAC 签名、动态 Header 注入 - **多模态透传**:`image_url` 等多模态内容在多源间无损透传,Anthropic/Gemini/Ollama 自动转换 @@ -60,6 +62,12 @@ Groq、Mistral、Ollama、KimiCode…)通过 **Lua 适配器** 做协议转换 - **生图**:`POST /v1/images/generations`,`kind: image` 的模型独立路由。 - **多模态**:`content` 数组(`image_url` 等)在多源间无损透传,Anthropic/Gemini/Ollama 自动转换。 - **LuaJIT VM**:基于 golua 绑定的 LuaJIT,每个适配器独立 VM + worker 池,安全并发。 + 池是 **弹性** 的:`Σ max_concurrent` 只是上限而非预分配,状态按需创建、空闲时自动回收, + 因此空载网关几乎不持有 Lua 状态(启动 0 个)。 + - 扩容步长由适配器最大并发决定:`clamp(ceil(max/8), 1, 8)`,且仅在**真实并发争用** + (所有现有状态均已占用)时批量预热,顺序流量始终只用 1 个状态。 + - 缩容步长由当前连接数决定:`clamp(ceil(冗余/(1+占用)), 1, 冗余)`——无连接时一轮收到 + 常驻下限,忙时每轮只释放 1 个,保护热路径。WebUI「适配器」页展示实时池指标。 - **disable_thinking**:请求 `disable_thinking:true`(或上游对应字段)动态开关推理。 - **Lua 适配协议**:每个源挂一个 `.lua` 适配器,完成 `transform_request` / `transform_response` / `transform_stream_chunk` 双向转换,协议差异全在 Lua 层。 @@ -203,6 +211,33 @@ AUTO 调度**只**由优先级页保存的规则决定,源配置里的 `models - 同 tier 内按「偏好分」排序,失败槽位冷却后自动跳过;冷却 / 配额耗尽 / hard 错误会顺延到下一 tier,全部失败时返回 503 并附上每档失败摘要。 +### 冷却与半冷却探测(自愈调度) + +槽位失败后进入指数退避冷却(5s → 10s → 20s …,上限 **5 分钟**)。冷却不是全时段 +硬闸: + +- **前半段完全静默**:刚失败的槽位不接任何流量,避免对故障上游持续施压。 +- **后半段放行 1 个探测**:窗口过半后,同一 `(源, 模型)` 最多允许 **一个** 请求作为 + 探测通过。探测槽数 = `clamp(max_concurrent / 10, 1, 2)`——`max_concurrent: 10` + 的源恰好放行 1 个探测请求。 +- **探测排在最后**:同 tier 内探测候选永远排在健康候选之后,只有没有正常槽可用时 + 才承接真实流量,因此探测不会抢走可用容量。 +- **探测即真实请求**:成功则立即清零失败计数与冷却,槽位当场回到正常轮询—— + 上游恢复/额度恢复后不必等满整个冷却窗口。失败则重开一个新窗口,下次探测顺延到 + 新窗口的中点,不会连续重试。 + +分类冷却策略: + +| 情况 | 冷却 | 说明 | +|---|---|---| +| 传输错误 / 5xx | 5s→10s→20s…,上限 5min | 指数退避 | +| 401 / 403 凭据错误 | 10min | 换 key 后由下一次探测自动接回 | +| 429 限流 | 30s 固定 | 「太快」不等于「坏了」,不进指数阶梯 | +| 配额耗尽(`insufficient_quota` / `余额不足` 等) | 对齐配额窗口,上限 30min | **不进指数阶梯、不涨失败计数**,额度恢复即可用 | + +WebUI「优先级」页的槽位健康标签会区分 `冷却` / `待探测` / `探测中`,悬停可看窗口 +起点、探测放行时刻与完全恢复时刻。 + ### 源(Source)与适配器(Adapter)的关系 - **源** 是到某个上游的连接描述:`name`、`base_url`、`api_key`、模型列表与优先级。 @@ -220,7 +255,7 @@ AUTO 调度**只**由优先级页保存的规则决定,源配置里的 `models 2. `config.Load` 读取 `config.yaml`,`config.NewStore(runtime_file)` 读 WebUI 改动的 运行时源,二者按名称合并成完整源列表。 3. `rebuildRegistry` 为每个源创建 `provider.Provider`(持有目标适配器),并按源的 - 并发上限配置适配器 worker 池大小。 + 并发上限配置适配器 worker 池**上限**(不预分配,见下)。 4. 请求进来时 `Registry` 按 `model` 路由到 Provider,Provider 调适配器 `transform_request` → HTTP 发送 → `transform_response` / `transform_stream_chunk`。 diff --git a/cmd/gui/package-lock.json b/cmd/gui/package-lock.json index f2e1275..096af7d 100644 --- a/cmd/gui/package-lock.json +++ b/cmd/gui/package-lock.json @@ -1,12 +1,12 @@ { "name": "modelrouter-gui", - "version": "1.2.0", + "version": "1.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "modelrouter-gui", - "version": "1.2.0", + "version": "1.4.0", "license": "Proprietary", "devDependencies": { "electron": "^33.0.0", diff --git a/cmd/gui/package.json b/cmd/gui/package.json index b90729b..bc7eecc 100644 --- a/cmd/gui/package.json +++ b/cmd/gui/package.json @@ -1,6 +1,6 @@ { "name": "modelrouter-gui", - "version": "1.2.0", + "version": "1.4.0", "description": "ModelRouter Desktop — embedded ModelRouter core with tray", "author": "ModelRouter", "main": "main.js", @@ -22,7 +22,7 @@ "build": { "appId": "com.modelrouter.gui", "productName": "ModelRouter", -"linux": { + "linux": { "target": [ "deb", "rpm", @@ -32,9 +32,9 @@ "icon": "build/icon.png", "maintainer": "ModelRouter", "synopsis": "ModelRouter Desktop", -"desktop": { + "desktop": { "entry": { - "StartupWMClass": "modelrouter-gui" + "StartupWMClass": "modelrouter-gui" } }, "extraResources": [