flexgate 0.7.0__tar.gz → 0.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flexgate-0.7.0 → flexgate-0.9.0}/CLAUDE.md +4 -3
- {flexgate-0.7.0 → flexgate-0.9.0}/PKG-INFO +50 -7
- {flexgate-0.7.0 → flexgate-0.9.0}/README.md +49 -6
- {flexgate-0.7.0 → flexgate-0.9.0}/config.yaml.template +12 -0
- flexgate-0.9.0/docs/api.md +66 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/cli.md +6 -1
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/conf.py +3 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/configuration.md +13 -1
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/development.md +5 -2
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/index.md +8 -2
- flexgate-0.9.0/docs/usage.md +77 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/__init__.py +1 -1
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/cli.py +23 -6
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/config.py +54 -8
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/usage.py +229 -18
- flexgate-0.7.0/docs/usage.md +0 -43
- {flexgate-0.7.0 → flexgate-0.9.0}/.github/workflows/docs.yml +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/.github/workflows/release.yml +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/.gitignore +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/Makefile +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/_static/.gitkeep +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/quickstart.md +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/docs/requirements.txt +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/__main__.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/doctor.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/fallback.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/healthcheck.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/images.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/main.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/migrate.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/proxy.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/router.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/server.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/service.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/settings.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/sync.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/ui.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/flexgate/update.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/pyproject.toml +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/test.png +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/test_multimodal.py +0 -0
- {flexgate-0.7.0 → flexgate-0.9.0}/test_multimodal_gateway.py +0 -0
|
@@ -22,6 +22,7 @@ flexgate service install # install + enable + start systemd u
|
|
|
22
22
|
flexgate service {install|start|stop|restart|reload|status|uninstall}
|
|
23
23
|
flexgate run # foreground/debug only
|
|
24
24
|
flexgate status # providers, fallback chains, per-key usage, active routes
|
|
25
|
+
flexgate usage [--force] # per-key usage/quota only; --force rechecks cached failures
|
|
25
26
|
flexgate log # service journal (-f follow, -r route lines only)
|
|
26
27
|
|
|
27
28
|
# Config
|
|
@@ -91,7 +92,7 @@ OpenAI-style client → POST /v1/images/generations
|
|
|
91
92
|
| `config.py` | Pydantic-like dataclasses (`GatewayConfig`, `ProviderConfig`, `RouteConfig`, `ScheduleEntry`), YAML load/save, `TIER_PATTERNS` regex map, `is_placeholder_key` |
|
|
92
93
|
| `router.py` | `resolve(config, model)` — schedule-first then default routes, first regex match wins; model aliases normalized before matching |
|
|
93
94
|
| `proxy.py` | `handle_request()` — httpx async proxy, per-key fallback retry loop, SSE streaming + JSON pass-through |
|
|
94
|
-
| `usage.py` | `flexgate status` usage queries — per-platform adapters (MiniMax coding_plan API, Kimi Code usages API, z.ai quota API, LiteLLM `/key/info`) plus a minimal chat probe fallback |
|
|
95
|
+
| `usage.py` | `flexgate status` usage queries — per-platform adapters (MiniMax coding_plan API, Kimi Code usages API, z.ai quota API, zhipu team quota API, LiteLLM `/key/info`) plus a minimal chat probe fallback |
|
|
95
96
|
| `server.py` | Starlette app creation, `POST /v1/messages` + `POST /v1/images/{generations,edits}` endpoints, `SIGUSR1` lifespan reload |
|
|
96
97
|
| `images.py` | OpenAI Images API → MiniMax `/v1/image_generation` translation (`image-01`, size→width/height clamped to 512–2048 mult of 8, `data.image_base64[]`→`data[].b64_json`); edits endpoint returns 501; unknown image model names get 501 `model_not_supported` |
|
|
97
98
|
| `fallback.py` | Catch-all route: merged Anthropic/OpenAI-shaped JSON errors for every unserved path — 404 `route_not_found` (lists valid routes), 405 `method_not_allowed`, 501 `endpoint_not_supported` per recognized API family with an actionable reason |
|
|
@@ -110,8 +111,8 @@ OpenAI-style client → POST /v1/images/generations
|
|
|
110
111
|
- **Model alias normalization** (`router.py`): before matching, bare aliases (`sonnet`/`opus`/`haiku`/`default`, case-insensitive, optional `[plan]` suffix) map to `claude-<tier>` prefixes (`default` → sonnet, Claude Code's default tier), and legacy numbered names (`claude-3-7-sonnet-latest`) reduce to their tier prefix; everything else passes through unchanged, so custom patterns and the catch-all behave exactly as before.
|
|
111
112
|
- **Model resolution & `available_models` fallback**: A route may omit `model`; `router.resolve()` then falls back to the provider's first `available_models` entry, so `model_override` handed to the proxy is always a concrete name. `config._parse_routes` rejects routes that omit `model` on a provider with no `available_models` — so adding a provider without models requires an explicit `model` on every route using it.
|
|
112
113
|
- **Proxy rewrite contract** (`proxy.py`): the upstream request gets the provider's `x-api-key` plus a fixed header set, and the JSON `model` field is rewritten only when the route set an override. Streaming responses are forwarded as raw bytes (`aiter_bytes`), never parsed.
|
|
113
|
-
- **Key fallback** (`proxy.py`): a provider's `api_keys` list holds one or more keys for the same upstream (entries are key strings or `{key, note}` mappings; `note` is a free-form label shown by `flexgate status` and in fallback logs). Multiple accounts on one upstream — e.g. several MiniMax subscriptions — belong in ONE provider, not separate ones. Each *route* has an active-key pointer (`active_key` in YAML, 1-based; `RouteConfig.key_index` 0-based, default first key): requests on that route start from the pointed key, and on a retryable failure (HTTP 401/402/403/429/500/502/503/529, connect error, or timeout) the next key is tried and the pointer advances with it (in memory only, wrapping around — it is not written back to the file); every key is tried at most once and a full circle of failures returns the last error. The pointer is set interactively via `flexgate config edit` → "api keys" (pick a route, with live per-key usage) or by editing the route's `active_key` directly. `resolve()` (`router.py`) returns the matched `RouteConfig` so the proxy can read/advance its pointer. Streaming requests can only fall back before the upstream returns 200. `_regular_proxy`/`_stream_proxy` return `(response, retryable)`; `handle_request` owns the loop and returns the last error when all keys fail. The legacy `api_key` + `fallback_keys` schema is still parsed (`config._parse_api_keys`); migration v3 → v4 rewrites it to `api_keys`. `ProviderConfig.api_key` remains as a first-key property (getter/setter) for the settings import code.
|
|
114
|
-
- **Usage inspection** (`usage.py`): `flexgate status` maps `base_url` to a platform adapter (`_ADAPTERS`): MiniMax → `{origin}/v1/api/openplatform/coding_plan/remains` (only the "general" text-model quota entry is used; its counts are usually 0/0, so usage is read from the `*_remaining_percent` fields), Kimi Code → `{base}/v1/usages` (undocumented, same endpoint as the CLI's `/usage`; reports weekly quota, 5-hour window and parallel limit), z.ai
|
|
114
|
+
- **Key fallback** (`proxy.py`): a provider's `api_keys` list holds one or more keys for the same upstream (entries are key strings or `{key, note}` mappings — plus optional `organization`/`project` on zhipu team keys, used only by the usage check; `note` is a free-form label shown by `flexgate status` and in fallback logs). Multiple accounts on one upstream — e.g. several MiniMax subscriptions — belong in ONE provider, not separate ones. Each *route* has an active-key pointer (`active_key` in YAML, 1-based; `RouteConfig.key_index` 0-based, default first key): requests on that route start from the pointed key, and on a retryable failure (HTTP 401/402/403/429/500/502/503/529, connect error, or timeout) the next key is tried and the pointer advances with it (in memory only, wrapping around — it is not written back to the file); every key is tried at most once and a full circle of failures returns the last error. The pointer is set interactively via `flexgate config edit` → "api keys" (pick a route, with live per-key usage) or by editing the route's `active_key` directly. `resolve()` (`router.py`) returns the matched `RouteConfig` so the proxy can read/advance its pointer. Streaming requests can only fall back before the upstream returns 200. `_regular_proxy`/`_stream_proxy` return `(response, retryable)`; `handle_request` owns the loop and returns the last error when all keys fail. The legacy `api_key` + `fallback_keys` schema is still parsed (`config._parse_api_keys`); migration v3 → v4 rewrites it to `api_keys`. `ProviderConfig.api_key` remains as a first-key property (getter/setter) for the settings import code.
|
|
115
|
+
- **Usage inspection** (`usage.py`): `flexgate status` maps `base_url` to a platform adapter (`_ADAPTERS`): MiniMax → `{origin}/v1/api/openplatform/coding_plan/remains` (only the "general" text-model quota entry is used; its counts are usually 0/0, so usage is read from the `*_remaining_percent` fields), Kimi Code → `{base}/v1/usages` (undocumented, same endpoint as the CLI's `/usage`; reports weekly quota, 5-hour window and parallel limit), z.ai → `{origin}/api/monitor/usage/quota/limit` (undocumented but used by z.ai's own plugin; personal coding plans only), bigmodel.cn → the same endpoint with `?type=2` plus `bigmodel-organization`/`bigmodel-project` headers read from the key entry's `organization`/`project` fields (team plans; also fetches the team subscription detail for plan name/expiry — a key entry without both fields gets no adapter at all and goes straight to the probe, with a hint line), USTC/LiteLLM → `{origin}/key/info`. Hosts in `_PROBE_ONLY_MARKERS` (e.g. xiaomimimo.com — no key-based usage API) and unknown platforms get the minimal chat probe: `POST /v1/messages` with input `"hi"`, `max_tokens=128`. A failed adapter call also degrades to the probe. Any key whose usage query errored — a hard failure (adapter AND probe), or an adapter error merely recovered by the probe — is recorded in `~/.flexgate/usage-cache.json` (sha256 fingerprint, never key material; entry keeps the `ok` flag and output lines) and skipped by later `status`/`usage` runs, shown as `cached (… ago)` / `cached failure (… ago)` with a hint; `flexgate usage --force` rechecks them and a clean success clears the entry. Placeholder keys are never cached.
|
|
115
116
|
- **Multimodal degradation**: `MULTIMODAL_MODELS` (currently `{"MiniMax-M3", "glm-4.6v"}`) is the allowlist. Requests carrying image blocks aimed at any other model have images stripped and a `[flexgate]` text note injected into both the outgoing request and the returned response, so non-multimodal backends don't 4xx.
|
|
116
117
|
- **Schedule-based overrides**: Optional time windows (e.g. 22:00-06:00) override default routes. Overnight wrap is supported.
|
|
117
118
|
- **Service-first lifecycle**: `flexgate.service` is the sole persistent runtime. systemd owns restart, boot startup, logs, and process state.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flexgate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Flexible local API gateway for Claude Code — route models to different providers
|
|
5
5
|
Project-URL: Homepage, https://github.com/Agony5757/flexible-gateway
|
|
6
6
|
Project-URL: Repository, https://github.com/Agony5757/flexible-gateway
|
|
@@ -89,6 +89,7 @@ systemd **用户服务**是 Linux 上唯一推荐的持久化运行方式,负
|
|
|
89
89
|
```bash
|
|
90
90
|
flexgate service install # 安装、启用并立即启动
|
|
91
91
|
flexgate service install --no-start # 仅安装并启用,不立即启动
|
|
92
|
+
flexgate service install --no-claude-settings # 跳过修改 ~/.claude/settings.json 的交互询问
|
|
92
93
|
flexgate service start # 启动;自动修复旧格式或失效的 unit
|
|
93
94
|
flexgate service stop # 停止
|
|
94
95
|
flexgate service restart # 重启
|
|
@@ -113,7 +114,7 @@ flexgate service uninstall # 停止、禁用并删除 unit
|
|
|
113
114
|
```bash
|
|
114
115
|
flexgate --version # 打印版本号(service status / 裸 flexgate 也会显示)
|
|
115
116
|
flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings、上游连通性
|
|
116
|
-
flexgate doctor --offline #
|
|
117
|
+
flexgate doctor --offline # 跳过全部网络检查(PyPI 新版检查 + 上游探测)
|
|
117
118
|
flexgate update # 一键升级:pip/pipx/uv 升级包 + 迁移配置 schema + 热重载服务
|
|
118
119
|
flexgate update --check # 只报告将要做什么,不改动
|
|
119
120
|
flexgate update --config-only # 只迁移配置,不升级包
|
|
@@ -170,6 +171,7 @@ flexgate status --no-usage # 跳过用量查询,只看配置
|
|
|
170
171
|
flexgate status --usage-timeout 30
|
|
171
172
|
flexgate usage # 只看每个 key 的用量/额度(不打印配置和路由)
|
|
172
173
|
flexgate usage --usage-timeout 30
|
|
174
|
+
flexgate usage --force # 重查上次失败的 key(默认跳过,读缓存)
|
|
173
175
|
```
|
|
174
176
|
|
|
175
177
|
`flexgate status` 展示当前配置中的所有 provider、每个 provider 的 key 及
|
|
@@ -190,6 +192,24 @@ fallback 链、当前生效的路由,并逐一查询**每个 key** 的用量/
|
|
|
190
192
|
如果某平台的专用接口调用失败,flexgate 会自动退化为 minimal probe 再试一次。
|
|
191
193
|
用量查询接口多为平台内部接口,可能随时变动;查询结果仅供参考。
|
|
192
194
|
|
|
195
|
+
**查询失败缓存**:用量查询中报错的 key(彻底失败,或专用接口报错但 probe
|
|
196
|
+
证明 key 仍可用,例如智谱的按量付费 key)会记入
|
|
197
|
+
`~/.flexgate/usage-cache.json`(只存 key 指纹,不存明文),此后 `status` /
|
|
198
|
+
`usage` 默认跳过这些 key 并显示缓存错误与提示(`cached failure`);
|
|
199
|
+
`flexgate usage --force` 强制重查并更新缓存,干净成功后自动恢复实时查询。
|
|
200
|
+
|
|
201
|
+
### HTTP API(图像生成与结构化错误)
|
|
202
|
+
|
|
203
|
+
除 `POST /v1/messages` 外,网关还提供 OpenAI 兼容的图像生成端点
|
|
204
|
+
`POST /v1/images/generations`:自动发现配置中的 MiniMax provider,把请求
|
|
205
|
+
翻译为 MiniMax `image-01` 文生图(模型名提示如 `gpt-image`/`dall-e` 均可,
|
|
206
|
+
`size` 钳制到 512–2048 的 8 倍数,响应为 `data[].b64_json`)。
|
|
207
|
+
`/v1/images/edits` 固定返回 501(上游仅支持文生图)。
|
|
208
|
+
|
|
209
|
+
所有未支持的路径(如 `/v1/chat/completions`、`/v1/embeddings`、`count_tokens`)
|
|
210
|
+
返回 Anthropic/OpenAI 双兼容的结构化 JSON 错误(404/405/501),而不是裸
|
|
211
|
+
404。详见[HTTP API 文档](https://agony5757.github.io/flexible-gateway/api.html)。
|
|
212
|
+
|
|
193
213
|
### 前台调试
|
|
194
214
|
|
|
195
215
|
`run` 是独立的顶层调试命令,不属于持久化服务模式:
|
|
@@ -244,16 +264,19 @@ flexgate config set haiku MiniMax-M3
|
|
|
244
264
|
|
|
245
265
|
```text
|
|
246
266
|
Flexgate config — ~/.flexgate/config.yaml
|
|
247
|
-
↑/↓ move · Enter edit
|
|
267
|
+
↑/↓ move · Enter edit · s save · q quit
|
|
248
268
|
|
|
249
269
|
▶ opus ustc / deepseek-v4-pro
|
|
250
270
|
sonnet ustc / deepseek-v4-pro
|
|
251
271
|
haiku ustc / deepseek-v4-pro
|
|
272
|
+
fallback ustc / deepseek-v4-pro
|
|
273
|
+
api keys select the active key per route
|
|
252
274
|
|
|
253
275
|
○ no unsaved changes
|
|
254
276
|
```
|
|
255
277
|
|
|
256
|
-
- 方向键选中某个 tier(opus/sonnet/haiku
|
|
278
|
+
- 方向键选中某个 tier(opus/sonnet/haiku)或 `fallback`(兜底路由 `.*`,未命中任何 tier 的请求走它),回车进入:先从候选 **provider** 列表选择,再从该 provider 的候选 **model** 列表选择。
|
|
279
|
+
- 选中 `api keys` 回车进入:先选一条**路由**,再选它的 **active key**;key 列表会实时查询每个 key 的用量/有效性(与 `flexgate status` 相同),并标注当前 active 的 key。
|
|
257
280
|
- model 列表包含:`available_models` 中的各个模型、「使用 provider 默认(首个可用模型,不写死 model)」、以及「自定义模型…」(手动输入)。
|
|
258
281
|
- 按 `s` 保存(并向运行中的网关发送 SIGUSR1 热重载,**无需重启即生效**),按 `q` 退出(有未保存改动时会询问 "Config changed — activate now?":选 Yes 立即保存并热重载生效,选 No 放弃改动);子菜单中按 `Esc`/`←` 返回上一级。
|
|
259
282
|
- 需要交互式终端(TTY);非交互场景请改用 `flexgate config set`。
|
|
@@ -286,6 +309,7 @@ API_TIMEOUT_MS、三个 `ANTHROPIC_DEFAULT_*_MODEL`),settings.json 中的
|
|
|
286
309
|
| `~/.flexgate/config.yaml` | 主配置文件 |
|
|
287
310
|
| `~/.flexgate/service-state.json` | 最近一次成功启动所应用的 config 路径与 endpoint |
|
|
288
311
|
| `~/.flexgate/update-check.json` | PyPI 新版本检查的缓存(24h 有效期) |
|
|
312
|
+
| `~/.flexgate/usage-cache.json` | 用量查询失败缓存(key 指纹 + 错误文本;`usage --force` 重查后更新) |
|
|
289
313
|
| `~/.config/systemd/user/flexgate.service` | 唯一的持久化服务 unit |
|
|
290
314
|
| systemd journal | 服务日志(`flexgate log`,即 `journalctl --user -u flexgate`) |
|
|
291
315
|
|
|
@@ -313,6 +337,13 @@ providers:
|
|
|
313
337
|
- key: "your-minimax-api-key-2"
|
|
314
338
|
note: "备用账号"
|
|
315
339
|
- "your-minimax-api-key-3" # 纯字符串写法(无备注)
|
|
340
|
+
zhipu-team:
|
|
341
|
+
base_url: "https://open.bigmodel.cn/api/anthropic"
|
|
342
|
+
api_keys:
|
|
343
|
+
- key: "your-zhipu-team-api-key"
|
|
344
|
+
note: "队友名"
|
|
345
|
+
organization: "org-XXXXXXXX" # 智谱团队版 key:组织/项目 ID
|
|
346
|
+
project: "proj_XXXXXXXX" # (flexgate usage 查团队套餐额度用)
|
|
316
347
|
|
|
317
348
|
claude_settings:
|
|
318
349
|
default_opus_model: "claude-opus-4-7"
|
|
@@ -337,6 +368,7 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
337
368
|
- pattern: "^claude-sonnet"
|
|
338
369
|
provider: minimax
|
|
339
370
|
model: "MiniMax-M3"
|
|
371
|
+
active_key: 2 # 可选:该路由从 minimax 的第 2 个 key 开始用(1 起始,默认 1)
|
|
340
372
|
- pattern: "^claude-haiku"
|
|
341
373
|
provider: minimax
|
|
342
374
|
model: "MiniMax-M3"
|
|
@@ -351,12 +383,13 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
351
383
|
|------|------|
|
|
352
384
|
| `server.host/port` | 网关监听地址 |
|
|
353
385
|
| `providers.<name>.base_url` | Provider 的 API 地址 |
|
|
354
|
-
| `providers.<name>.api_keys` | API key 列表(一个或多个,互为 fallback);每项为 key 字符串或 `{key, note}
|
|
386
|
+
| `providers.<name>.api_keys` | API key 列表(一个或多个,互为 fallback);每项为 key 字符串或 `{key, note}`(`note` 是备注)。智谱团队版 key 还可加 `organization`/`project`(团队组织/项目 ID),供 `flexgate usage` 查询团队套餐额度 |
|
|
355
387
|
| `providers.<name>.available_models` | 该 provider 的可用模型列表,首个条目作为路由省略 `model` 时的回退模型 |
|
|
356
388
|
| `claude_settings.*` | 写入 settings.json 的模型和超时配置 |
|
|
357
|
-
| `routes[].pattern` | 正则匹配请求中的 model
|
|
389
|
+
| `routes[].pattern` | 正则匹配请求中的 model 字段(匹配前归一化裸别名 `sonnet`/`opus`/`haiku`/`default` 与旧编号名) |
|
|
358
390
|
| `routes[].provider` | 路由到的 provider 名称 |
|
|
359
391
|
| `routes[].model` | 可选,替换发给 provider 的模型名 |
|
|
392
|
+
| `routes[].active_key` | 可选,1 起始的 provider api_keys 序号,该路由的请求从哪个 key 开始(默认 1,即第一个 key) |
|
|
360
393
|
| `schedule[].name` | 定时规则名称 |
|
|
361
394
|
| `schedule[].start/end` | 时间窗口(HH:MM 格式,支持跨夜如 22:00-06:00) |
|
|
362
395
|
| `schedule[].routes` | 该时间窗口内生效的路由(格式同 `routes`) |
|
|
@@ -368,7 +401,13 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
368
401
|
`{key, note}` 加一个存在配置里的备注(`flexgate status` 和 fallback 日志
|
|
369
402
|
都会显示 note,方便分辨是哪个账号的 key):
|
|
370
403
|
|
|
371
|
-
-
|
|
404
|
+
- 每条路由有一个「当前 key」指针(路由上的 `active_key`,默认指向
|
|
405
|
+
provider 的第一个 key):该路由的请求从指针指向的 key 开始;key 失败
|
|
406
|
+
时自动换用下一个 key(循环一圈),指针也随之自动前进——后续请求直接
|
|
407
|
+
从能用的 key 开始。**所有 key 轮换一圈都失败时,请求返回最后一次的
|
|
408
|
+
错误**。指针的运行时前进只存在于网关进程内存中,不写回配置文件;
|
|
409
|
+
可通过 `flexgate config edit` → "api keys" 交互切换。
|
|
410
|
+
- 请求先走 active key;失败时按列表顺序自动重试后续 key,直到某个 key
|
|
372
411
|
成功或返回不可重试的错误。
|
|
373
412
|
- 触发切换的条件:HTTP **401 / 402 / 403 / 429 / 500 / 502 / 503 / 529**
|
|
374
413
|
(key 失效、余额/额度耗尽、限流、平台过载)以及连接错误、超时。
|
|
@@ -378,6 +417,10 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
378
417
|
- 每次切换都会在服务日志中留下记录(key 只显示前后各 4 位)。
|
|
379
418
|
- 用 `flexgate status` 可以查看每个 provider 的 fallback 链和每个 key 的
|
|
380
419
|
实时用量。
|
|
420
|
+
- 智谱 GLM Coding Plan **团队版** key 在条目上配 `organization`/`project`
|
|
421
|
+
(团队组织/项目 ID)后,`flexgate status`/`usage` 会用团队版接口查询
|
|
422
|
+
套餐名、有效期和 5 小时/每周积分窗口;未配置这两个字段的 key 只做
|
|
423
|
+
连通性探测。
|
|
381
424
|
- 旧版 `api_key` + `fallback_keys` 写法仍然兼容,`flexgate update` 会
|
|
382
425
|
自动迁移为 `api_keys` 列表(config_version 3 → 4)。
|
|
383
426
|
|
|
@@ -72,6 +72,7 @@ systemd **用户服务**是 Linux 上唯一推荐的持久化运行方式,负
|
|
|
72
72
|
```bash
|
|
73
73
|
flexgate service install # 安装、启用并立即启动
|
|
74
74
|
flexgate service install --no-start # 仅安装并启用,不立即启动
|
|
75
|
+
flexgate service install --no-claude-settings # 跳过修改 ~/.claude/settings.json 的交互询问
|
|
75
76
|
flexgate service start # 启动;自动修复旧格式或失效的 unit
|
|
76
77
|
flexgate service stop # 停止
|
|
77
78
|
flexgate service restart # 重启
|
|
@@ -96,7 +97,7 @@ flexgate service uninstall # 停止、禁用并删除 unit
|
|
|
96
97
|
```bash
|
|
97
98
|
flexgate --version # 打印版本号(service status / 裸 flexgate 也会显示)
|
|
98
99
|
flexgate doctor # 只读体检:Python、PyPI 新版、配置 schema、端口、systemd、Claude settings、上游连通性
|
|
99
|
-
flexgate doctor --offline #
|
|
100
|
+
flexgate doctor --offline # 跳过全部网络检查(PyPI 新版检查 + 上游探测)
|
|
100
101
|
flexgate update # 一键升级:pip/pipx/uv 升级包 + 迁移配置 schema + 热重载服务
|
|
101
102
|
flexgate update --check # 只报告将要做什么,不改动
|
|
102
103
|
flexgate update --config-only # 只迁移配置,不升级包
|
|
@@ -153,6 +154,7 @@ flexgate status --no-usage # 跳过用量查询,只看配置
|
|
|
153
154
|
flexgate status --usage-timeout 30
|
|
154
155
|
flexgate usage # 只看每个 key 的用量/额度(不打印配置和路由)
|
|
155
156
|
flexgate usage --usage-timeout 30
|
|
157
|
+
flexgate usage --force # 重查上次失败的 key(默认跳过,读缓存)
|
|
156
158
|
```
|
|
157
159
|
|
|
158
160
|
`flexgate status` 展示当前配置中的所有 provider、每个 provider 的 key 及
|
|
@@ -173,6 +175,24 @@ fallback 链、当前生效的路由,并逐一查询**每个 key** 的用量/
|
|
|
173
175
|
如果某平台的专用接口调用失败,flexgate 会自动退化为 minimal probe 再试一次。
|
|
174
176
|
用量查询接口多为平台内部接口,可能随时变动;查询结果仅供参考。
|
|
175
177
|
|
|
178
|
+
**查询失败缓存**:用量查询中报错的 key(彻底失败,或专用接口报错但 probe
|
|
179
|
+
证明 key 仍可用,例如智谱的按量付费 key)会记入
|
|
180
|
+
`~/.flexgate/usage-cache.json`(只存 key 指纹,不存明文),此后 `status` /
|
|
181
|
+
`usage` 默认跳过这些 key 并显示缓存错误与提示(`cached failure`);
|
|
182
|
+
`flexgate usage --force` 强制重查并更新缓存,干净成功后自动恢复实时查询。
|
|
183
|
+
|
|
184
|
+
### HTTP API(图像生成与结构化错误)
|
|
185
|
+
|
|
186
|
+
除 `POST /v1/messages` 外,网关还提供 OpenAI 兼容的图像生成端点
|
|
187
|
+
`POST /v1/images/generations`:自动发现配置中的 MiniMax provider,把请求
|
|
188
|
+
翻译为 MiniMax `image-01` 文生图(模型名提示如 `gpt-image`/`dall-e` 均可,
|
|
189
|
+
`size` 钳制到 512–2048 的 8 倍数,响应为 `data[].b64_json`)。
|
|
190
|
+
`/v1/images/edits` 固定返回 501(上游仅支持文生图)。
|
|
191
|
+
|
|
192
|
+
所有未支持的路径(如 `/v1/chat/completions`、`/v1/embeddings`、`count_tokens`)
|
|
193
|
+
返回 Anthropic/OpenAI 双兼容的结构化 JSON 错误(404/405/501),而不是裸
|
|
194
|
+
404。详见[HTTP API 文档](https://agony5757.github.io/flexible-gateway/api.html)。
|
|
195
|
+
|
|
176
196
|
### 前台调试
|
|
177
197
|
|
|
178
198
|
`run` 是独立的顶层调试命令,不属于持久化服务模式:
|
|
@@ -227,16 +247,19 @@ flexgate config set haiku MiniMax-M3
|
|
|
227
247
|
|
|
228
248
|
```text
|
|
229
249
|
Flexgate config — ~/.flexgate/config.yaml
|
|
230
|
-
↑/↓ move · Enter edit
|
|
250
|
+
↑/↓ move · Enter edit · s save · q quit
|
|
231
251
|
|
|
232
252
|
▶ opus ustc / deepseek-v4-pro
|
|
233
253
|
sonnet ustc / deepseek-v4-pro
|
|
234
254
|
haiku ustc / deepseek-v4-pro
|
|
255
|
+
fallback ustc / deepseek-v4-pro
|
|
256
|
+
api keys select the active key per route
|
|
235
257
|
|
|
236
258
|
○ no unsaved changes
|
|
237
259
|
```
|
|
238
260
|
|
|
239
|
-
- 方向键选中某个 tier(opus/sonnet/haiku
|
|
261
|
+
- 方向键选中某个 tier(opus/sonnet/haiku)或 `fallback`(兜底路由 `.*`,未命中任何 tier 的请求走它),回车进入:先从候选 **provider** 列表选择,再从该 provider 的候选 **model** 列表选择。
|
|
262
|
+
- 选中 `api keys` 回车进入:先选一条**路由**,再选它的 **active key**;key 列表会实时查询每个 key 的用量/有效性(与 `flexgate status` 相同),并标注当前 active 的 key。
|
|
240
263
|
- model 列表包含:`available_models` 中的各个模型、「使用 provider 默认(首个可用模型,不写死 model)」、以及「自定义模型…」(手动输入)。
|
|
241
264
|
- 按 `s` 保存(并向运行中的网关发送 SIGUSR1 热重载,**无需重启即生效**),按 `q` 退出(有未保存改动时会询问 "Config changed — activate now?":选 Yes 立即保存并热重载生效,选 No 放弃改动);子菜单中按 `Esc`/`←` 返回上一级。
|
|
242
265
|
- 需要交互式终端(TTY);非交互场景请改用 `flexgate config set`。
|
|
@@ -269,6 +292,7 @@ API_TIMEOUT_MS、三个 `ANTHROPIC_DEFAULT_*_MODEL`),settings.json 中的
|
|
|
269
292
|
| `~/.flexgate/config.yaml` | 主配置文件 |
|
|
270
293
|
| `~/.flexgate/service-state.json` | 最近一次成功启动所应用的 config 路径与 endpoint |
|
|
271
294
|
| `~/.flexgate/update-check.json` | PyPI 新版本检查的缓存(24h 有效期) |
|
|
295
|
+
| `~/.flexgate/usage-cache.json` | 用量查询失败缓存(key 指纹 + 错误文本;`usage --force` 重查后更新) |
|
|
272
296
|
| `~/.config/systemd/user/flexgate.service` | 唯一的持久化服务 unit |
|
|
273
297
|
| systemd journal | 服务日志(`flexgate log`,即 `journalctl --user -u flexgate`) |
|
|
274
298
|
|
|
@@ -296,6 +320,13 @@ providers:
|
|
|
296
320
|
- key: "your-minimax-api-key-2"
|
|
297
321
|
note: "备用账号"
|
|
298
322
|
- "your-minimax-api-key-3" # 纯字符串写法(无备注)
|
|
323
|
+
zhipu-team:
|
|
324
|
+
base_url: "https://open.bigmodel.cn/api/anthropic"
|
|
325
|
+
api_keys:
|
|
326
|
+
- key: "your-zhipu-team-api-key"
|
|
327
|
+
note: "队友名"
|
|
328
|
+
organization: "org-XXXXXXXX" # 智谱团队版 key:组织/项目 ID
|
|
329
|
+
project: "proj_XXXXXXXX" # (flexgate usage 查团队套餐额度用)
|
|
299
330
|
|
|
300
331
|
claude_settings:
|
|
301
332
|
default_opus_model: "claude-opus-4-7"
|
|
@@ -320,6 +351,7 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
320
351
|
- pattern: "^claude-sonnet"
|
|
321
352
|
provider: minimax
|
|
322
353
|
model: "MiniMax-M3"
|
|
354
|
+
active_key: 2 # 可选:该路由从 minimax 的第 2 个 key 开始用(1 起始,默认 1)
|
|
323
355
|
- pattern: "^claude-haiku"
|
|
324
356
|
provider: minimax
|
|
325
357
|
model: "MiniMax-M3"
|
|
@@ -334,12 +366,13 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
334
366
|
|------|------|
|
|
335
367
|
| `server.host/port` | 网关监听地址 |
|
|
336
368
|
| `providers.<name>.base_url` | Provider 的 API 地址 |
|
|
337
|
-
| `providers.<name>.api_keys` | API key 列表(一个或多个,互为 fallback);每项为 key 字符串或 `{key, note}
|
|
369
|
+
| `providers.<name>.api_keys` | API key 列表(一个或多个,互为 fallback);每项为 key 字符串或 `{key, note}`(`note` 是备注)。智谱团队版 key 还可加 `organization`/`project`(团队组织/项目 ID),供 `flexgate usage` 查询团队套餐额度 |
|
|
338
370
|
| `providers.<name>.available_models` | 该 provider 的可用模型列表,首个条目作为路由省略 `model` 时的回退模型 |
|
|
339
371
|
| `claude_settings.*` | 写入 settings.json 的模型和超时配置 |
|
|
340
|
-
| `routes[].pattern` | 正则匹配请求中的 model
|
|
372
|
+
| `routes[].pattern` | 正则匹配请求中的 model 字段(匹配前归一化裸别名 `sonnet`/`opus`/`haiku`/`default` 与旧编号名) |
|
|
341
373
|
| `routes[].provider` | 路由到的 provider 名称 |
|
|
342
374
|
| `routes[].model` | 可选,替换发给 provider 的模型名 |
|
|
375
|
+
| `routes[].active_key` | 可选,1 起始的 provider api_keys 序号,该路由的请求从哪个 key 开始(默认 1,即第一个 key) |
|
|
343
376
|
| `schedule[].name` | 定时规则名称 |
|
|
344
377
|
| `schedule[].start/end` | 时间窗口(HH:MM 格式,支持跨夜如 22:00-06:00) |
|
|
345
378
|
| `schedule[].routes` | 该时间窗口内生效的路由(格式同 `routes`) |
|
|
@@ -351,7 +384,13 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
351
384
|
`{key, note}` 加一个存在配置里的备注(`flexgate status` 和 fallback 日志
|
|
352
385
|
都会显示 note,方便分辨是哪个账号的 key):
|
|
353
386
|
|
|
354
|
-
-
|
|
387
|
+
- 每条路由有一个「当前 key」指针(路由上的 `active_key`,默认指向
|
|
388
|
+
provider 的第一个 key):该路由的请求从指针指向的 key 开始;key 失败
|
|
389
|
+
时自动换用下一个 key(循环一圈),指针也随之自动前进——后续请求直接
|
|
390
|
+
从能用的 key 开始。**所有 key 轮换一圈都失败时,请求返回最后一次的
|
|
391
|
+
错误**。指针的运行时前进只存在于网关进程内存中,不写回配置文件;
|
|
392
|
+
可通过 `flexgate config edit` → "api keys" 交互切换。
|
|
393
|
+
- 请求先走 active key;失败时按列表顺序自动重试后续 key,直到某个 key
|
|
355
394
|
成功或返回不可重试的错误。
|
|
356
395
|
- 触发切换的条件:HTTP **401 / 402 / 403 / 429 / 500 / 502 / 503 / 529**
|
|
357
396
|
(key 失效、余额/额度耗尽、限流、平台过载)以及连接错误、超时。
|
|
@@ -361,6 +400,10 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
361
400
|
- 每次切换都会在服务日志中留下记录(key 只显示前后各 4 位)。
|
|
362
401
|
- 用 `flexgate status` 可以查看每个 provider 的 fallback 链和每个 key 的
|
|
363
402
|
实时用量。
|
|
403
|
+
- 智谱 GLM Coding Plan **团队版** key 在条目上配 `organization`/`project`
|
|
404
|
+
(团队组织/项目 ID)后,`flexgate status`/`usage` 会用团队版接口查询
|
|
405
|
+
套餐名、有效期和 5 小时/每周积分窗口;未配置这两个字段的 key 只做
|
|
406
|
+
连通性探测。
|
|
364
407
|
- 旧版 `api_key` + `fallback_keys` 写法仍然兼容,`flexgate update` 会
|
|
365
408
|
自动迁移为 `api_keys` 列表(config_version 3 → 4)。
|
|
366
409
|
|
|
@@ -8,6 +8,9 @@ server:
|
|
|
8
8
|
# 日志都会显示)。某个 key 遇到 401/402/403/429/5xx/529 或连接错误(如额度
|
|
9
9
|
# 用尽、平台过载)时,按顺序自动切换到下一个 key 重试。同一上游的多个账号
|
|
10
10
|
# 应这样配置,而不是拆成多个 provider。
|
|
11
|
+
# 智谱 GLM Coding Plan 团队版 key 还需在 key 条目上配置 organization 和
|
|
12
|
+
# project(团队组织/项目 ID,从团队用量页的浏览器请求头里一次性获取);
|
|
13
|
+
# flexgate usage 依赖这两个字段查询团队套餐额度,未配置则只做连通性探测。
|
|
11
14
|
providers:
|
|
12
15
|
minimax:
|
|
13
16
|
base_url: "https://api.minimaxi.com/anthropic"
|
|
@@ -26,6 +29,15 @@ providers:
|
|
|
26
29
|
available_models:
|
|
27
30
|
- "glm-5.3" # 路由省略 model 时的回退模型
|
|
28
31
|
- "glm-4.6v"
|
|
32
|
+
zhipu-team:
|
|
33
|
+
base_url: "https://open.bigmodel.cn/api/anthropic"
|
|
34
|
+
api_keys:
|
|
35
|
+
- key: "your-zhipu-team-api-key"
|
|
36
|
+
note: "队友名"
|
|
37
|
+
organization: "org-XXXXXXXX" # 智谱团队版:组织 ID
|
|
38
|
+
project: "proj_XXXXXXXX" # 智谱团队版:项目 ID
|
|
39
|
+
available_models:
|
|
40
|
+
- "glm-5.3"
|
|
29
41
|
xiaomi:
|
|
30
42
|
base_url: "https://token-plan-cn.xiaomimimo.com/anthropic"
|
|
31
43
|
api_keys:
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# HTTP API
|
|
2
|
+
|
|
3
|
+
Flexgate 在本地监听(默认 `127.0.0.1:8765`)提供以下端点:
|
|
4
|
+
|
|
5
|
+
| 端点 | 说明 |
|
|
6
|
+
|------|------|
|
|
7
|
+
| `POST /v1/messages` | Anthropic Messages API 代理(核心端点) |
|
|
8
|
+
| `POST /v1/images/generations` | OpenAI 兼容图像生成(转 MiniMax `image-01`) |
|
|
9
|
+
| `POST /v1/images/edits` | 固定返回 501(上游仅支持文生图) |
|
|
10
|
+
| 其他路径 | 结构化 JSON 错误(404 / 405 / 501,见下文) |
|
|
11
|
+
|
|
12
|
+
## POST /v1/messages
|
|
13
|
+
|
|
14
|
+
标准的 Anthropic Messages 格式代理。请求体中的 `model` 字段用于路由:
|
|
15
|
+
|
|
16
|
+
- **模型别名归一化**:匹配路由前,裸别名(`sonnet` / `opus` / `haiku` /
|
|
17
|
+
`default`,大小写不敏感,可带 `[plan]` 后缀)映射为对应的
|
|
18
|
+
`claude-<tier>` 前缀(`default` → sonnet);旧编号名
|
|
19
|
+
(如 `claude-3-7-sonnet-latest`)归约为 tier 前缀;其余名称原样匹配。
|
|
20
|
+
- 命中路由后,仅当路由显式配置了 `model` 时才改写上游请求的 model 字段;
|
|
21
|
+
认证头替换为该 provider 当前 active key 的 `x-api-key`。
|
|
22
|
+
- 流式(SSE)响应按原始字节透传,不做解析;非流式 JSON 原样转发。
|
|
23
|
+
- key 级 fallback:可重试错误按 `api_keys` 顺序切换(详见
|
|
24
|
+
[配置文件](configuration.md#key-fallback))。
|
|
25
|
+
- **多模态降级**:请求携带图片块且目标模型不在多模态允许列表
|
|
26
|
+
(`MULTIMODAL_MODELS`,当前为 `MiniMax-M3`、`glm-4.6v`)中时,图片会被
|
|
27
|
+
剥离,并在请求与响应中注入 `[flexgate]` 文本说明,避免非多模态上游报 4xx。
|
|
28
|
+
|
|
29
|
+
## POST /v1/images/generations
|
|
30
|
+
|
|
31
|
+
OpenAI Images API 兼容端点,让 OpenAI 风格的客户端无需任何额外配置即可
|
|
32
|
+
通过网关生成图片:
|
|
33
|
+
|
|
34
|
+
- **上游自动发现**:使用配置中 `base_url` 指向 MiniMax
|
|
35
|
+
(`api.minimaxi.com` / `api.minimax.io`)的 provider 及其 key,无需单独
|
|
36
|
+
配置图像 provider。
|
|
37
|
+
- **模型名映射**:请求中的 `model` 含已知图像模型提示(`gpt-image`、
|
|
38
|
+
`dall-e`、`image-01`、`seedream`、`flux`、`sdxl`、`stable-diffusion`、
|
|
39
|
+
`minimax` 等)即接受并映射为 MiniMax 的 `image-01`;无法识别的模型名
|
|
40
|
+
返回 501 `model_not_supported`。
|
|
41
|
+
- **尺寸**:`size: "WxH"` 映射为 width/height,各边钳制到 512–2048 并取
|
|
42
|
+
8 的倍数;无法解析的 size 忽略(用上游默认值)。
|
|
43
|
+
- **prompt** 超过 1500 字符会被截断。
|
|
44
|
+
- **响应**:MiniMax 返回的 `data.image_base64[]`(JPEG)原样转发为 OpenAI
|
|
45
|
+
风格的 `data[].b64_json`,不引入转码依赖。
|
|
46
|
+
|
|
47
|
+
## POST /v1/images/edits
|
|
48
|
+
|
|
49
|
+
固定返回 501:MiniMax `image-01` 仅支持文生图,没有通用的图像编辑 /
|
|
50
|
+
inpainting 能力。
|
|
51
|
+
|
|
52
|
+
## 未支持端点的结构化错误
|
|
53
|
+
|
|
54
|
+
所有未匹配的请求都不会得到裸 404,而是返回 Anthropic / OpenAI 双兼容
|
|
55
|
+
的 JSON 错误体,客户端可以据此判断"端口错了"还是"网关不支持该能力":
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{"type": "error", "error": {"type": "...", "message": "...", "code": "..."}}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| 状态码 | code | 触发条件 |
|
|
62
|
+
|--------|------|----------|
|
|
63
|
+
| 404 | `route_not_found` | 完全未知的路径;message 中列出全部有效路由 |
|
|
64
|
+
| 405 | `method_not_allowed` | 路径有效但 HTTP 方法不对 |
|
|
65
|
+
| 501 | `endpoint_not_supported` | 识别出的 API 家族但网关不服务(`/v1/chat/completions`、`/v1/responses`、`/v1/messages/count_tokens`、`/v1/embeddings` 等),message 给出可操作的建议 |
|
|
66
|
+
| 501 | `capability_not_supported` / `model_not_supported` | 有效路由上不支持的操作或模型名(由所属模块返回) |
|
|
@@ -19,6 +19,7 @@ systemd **用户服务**是 Linux 上唯一推荐的持久化运行方式,负
|
|
|
19
19
|
```bash
|
|
20
20
|
flexgate service install # 安装、启用并立即启动
|
|
21
21
|
flexgate service install --no-start # 仅安装并启用,不立即启动
|
|
22
|
+
flexgate service install --no-claude-settings # 跳过修改 ~/.claude/settings.json 的交互询问
|
|
22
23
|
flexgate service start # 启动;自动修复旧格式或失效的 unit
|
|
23
24
|
flexgate service stop # 停止
|
|
24
25
|
flexgate service restart # 重启
|
|
@@ -55,9 +56,13 @@ flexgate status --no-usage # 跳过用量查询,只看配置
|
|
|
55
56
|
flexgate status --usage-timeout 30
|
|
56
57
|
flexgate usage # 只看每个 key 的用量/额度(不打印配置和路由)
|
|
57
58
|
flexgate usage --usage-timeout 30
|
|
59
|
+
flexgate usage --force # 重查上次失败的 key(默认跳过,读缓存)
|
|
58
60
|
```
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
查询失败的 key 会被缓存并在此后的 `status` / `usage` 中默认跳过
|
|
63
|
+
(显示为 `cached failure` 并附带提示),`--force` 强制重新查询;
|
|
64
|
+
详见[用量查询](usage.md)。各平台的用量查询适配器同样见
|
|
65
|
+
[用量查询](usage.md)。
|
|
61
66
|
|
|
62
67
|
## 查看日志(log)
|
|
63
68
|
|
|
@@ -29,6 +29,9 @@ myst_enable_extensions = [
|
|
|
29
29
|
"linkify",
|
|
30
30
|
]
|
|
31
31
|
|
|
32
|
+
# Allow cross-document links to implicit heading anchors (e.g. configuration.md#key-fallback)
|
|
33
|
+
myst_heading_anchors = 3
|
|
34
|
+
|
|
32
35
|
source_suffix = {".md": "markdown"}
|
|
33
36
|
templates_path = ["_templates"]
|
|
34
37
|
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
| `~/.flexgate/config.yaml` | 主配置文件 |
|
|
8
8
|
| `~/.flexgate/service-state.json` | 最近一次成功启动所应用的 config 路径与 endpoint |
|
|
9
9
|
| `~/.flexgate/update-check.json` | PyPI 新版本检查的缓存(24h 有效期) |
|
|
10
|
+
| `~/.flexgate/usage-cache.json` | 用量查询失败缓存(key 指纹 + 错误文本;`usage --force` 重查后更新,见[用量查询](usage.md)) |
|
|
10
11
|
| `~/.config/systemd/user/flexgate.service` | 唯一的持久化服务 unit |
|
|
11
12
|
| systemd journal | 服务日志(`flexgate log`,即 `journalctl --user -u flexgate`) |
|
|
12
13
|
|
|
@@ -36,6 +37,13 @@ providers:
|
|
|
36
37
|
- key: "your-minimax-api-key-2"
|
|
37
38
|
note: "备用账号"
|
|
38
39
|
- "your-minimax-api-key-3" # 纯字符串写法(无备注)
|
|
40
|
+
zhipu-team:
|
|
41
|
+
base_url: "https://open.bigmodel.cn/api/anthropic"
|
|
42
|
+
api_keys:
|
|
43
|
+
- key: "your-zhipu-team-api-key"
|
|
44
|
+
note: "队友名"
|
|
45
|
+
organization: "org-XXXXXXXX" # 智谱团队版 key:组织/项目 ID
|
|
46
|
+
project: "proj_XXXXXXXX" # (flexgate usage 查团队套餐额度用)
|
|
39
47
|
|
|
40
48
|
claude_settings:
|
|
41
49
|
default_opus_model: "claude-opus-4-7"
|
|
@@ -75,7 +83,7 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
75
83
|
|------|------|
|
|
76
84
|
| `server.host/port` | 网关监听地址 |
|
|
77
85
|
| `providers.<name>.base_url` | Provider 的 API 地址 |
|
|
78
|
-
| `providers.<name>.api_keys` | API key 列表(一个或多个,互为 fallback);每项为 key 字符串或 `{key, note}
|
|
86
|
+
| `providers.<name>.api_keys` | API key 列表(一个或多个,互为 fallback);每项为 key 字符串或 `{key, note}`(`note` 是备注)。智谱团队版 key 还可加 `organization`/`project`(团队组织/项目 ID),供 `flexgate usage` 查询团队套餐额度 |
|
|
79
87
|
| `providers.<name>.available_models` | 该 provider 的可用模型列表,首个条目作为路由省略 `model` 时的回退模型 |
|
|
80
88
|
| `claude_settings.*` | 写入 settings.json 的模型和超时配置 |
|
|
81
89
|
| `routes[].pattern` | 正则匹配请求中的 model 字段 |
|
|
@@ -108,6 +116,10 @@ routes: # 从上到下匹配,首个命中生效
|
|
|
108
116
|
当前使用的 key 和每个 key 的实时用量;在 `flexgate config edit` 交互
|
|
109
117
|
界面的「api keys」入口可以按路由查看各 key 的实时用量/有效性并切换
|
|
110
118
|
active key。
|
|
119
|
+
- 智谱 GLM Coding Plan **团队版** key 在条目上配 `organization`/`project`
|
|
120
|
+
(团队组织/项目 ID)后,`flexgate status`/`usage` 会用团队版接口查询
|
|
121
|
+
套餐名、有效期和 5 小时/每周积分窗口;未配置这两个字段的 key 只做
|
|
122
|
+
连通性探测(团队 key 不适用个人版查询接口)。
|
|
111
123
|
- 旧版 `api_key` + `fallback_keys` 写法仍然兼容,`flexgate update` 会
|
|
112
124
|
自动迁移为 `api_keys` 列表(config_version 3 → 4);路由上的
|
|
113
125
|
`active_key` 字段在 config_version 5 引入,旧配置的每条路由默认指向
|
|
@@ -9,8 +9,11 @@
|
|
|
9
9
|
| `flexgate/config.py` | dataclass 配置模型(`GatewayConfig`、`ProviderConfig`、`RouteConfig` 等),YAML 加载/保存,`is_placeholder_key` |
|
|
10
10
|
| `flexgate/router.py` | `resolve(config, model)` — 先定时路由后默认路由,首个正则命中生效;匹配前归一化模型别名(`sonnet`/`claude-3-7-sonnet-latest` → `^claude-<tier>`) |
|
|
11
11
|
| `flexgate/proxy.py` | `handle_request()` — httpx 异步代理,per-key fallback 重试,SSE 流式 + JSON 透传;记录每个请求由哪把 key 服务 |
|
|
12
|
-
| `flexgate/usage.py` | `flexgate status` / `flexgate usage` 的用量查询 — 各平台适配器 + minimal chat probe 兜底 |
|
|
13
|
-
| `flexgate/server.py` | Starlette 应用,`POST /v1/messages` 端点,SIGUSR1 热重载 |
|
|
12
|
+
| `flexgate/usage.py` | `flexgate status` / `flexgate usage` 的用量查询 — 各平台适配器 + minimal chat probe 兜底 + 查询失败缓存(`usage --force` 强制重查) |
|
|
13
|
+
| `flexgate/server.py` | Starlette 应用,`POST /v1/messages` + `POST /v1/images/{generations,edits}` 端点,SIGUSR1 热重载 |
|
|
14
|
+
| `flexgate/images.py` | OpenAI Images API → MiniMax `/v1/image_generation` 翻译(模型名映射、size 钳制、`b64_json` 透传;edits 返回 501) |
|
|
15
|
+
| `flexgate/fallback.py` | 兜底路由:所有未服务路径返回 Anthropic/OpenAI 双兼容的结构化 JSON 错误(404 `route_not_found` / 405 / 501 `endpoint_not_supported`) |
|
|
16
|
+
| `flexgate/main.py` | 启动引导:加载配置 → 创建 app → 跑 uvicorn |
|
|
14
17
|
| `flexgate/service.py` | systemd 用户服务的安装/启停/重载/状态(持久化运行的唯一入口);journal 日志查看 |
|
|
15
18
|
| `flexgate/healthcheck.py` | 上游连通性探测(`POST /v1/messages`,`max_tokens=1`),由 `doctor` 调用(`flexgate check` 为弃用别名) |
|
|
16
19
|
| `flexgate/settings.py` | config.yaml ↔ `~/.claude/settings.json` 双向桥接(apply 非破坏性:只改托管 env 键) |
|
|
@@ -23,12 +23,17 @@ Claude Code → localhost:8765 → opus → z.ai (glm-5.1)
|
|
|
23
23
|
|
|
24
24
|
## 特性一览
|
|
25
25
|
|
|
26
|
-
- **按 model 路由**:正则匹配请求中的 model
|
|
26
|
+
- **按 model 路由**:正则匹配请求中的 model 字段,首个命中生效,支持兜底路由;
|
|
27
|
+
裸别名(`sonnet`/`opus`/`haiku`)与旧编号名自动归一化
|
|
27
28
|
- **定时路由**:按时间窗口自动切换路由(支持跨夜,如 22:00-06:00)
|
|
28
29
|
- **多 key fallback**:同一上游配置多个 key,遇到 401/402/403/429/5xx/529
|
|
29
30
|
或连接错误时自动切换到下一个 key
|
|
31
|
+
- **多模态降级**:非多模态模型的请求自动剥离图片块并注入说明,避免上游 4xx
|
|
32
|
+
- **OpenAI 兼容图像生成**:`POST /v1/images/generations` 自动转 MiniMax
|
|
33
|
+
`image-01`,详见 [HTTP API](api.md)
|
|
30
34
|
- **用量查询**:`flexgate status` / `flexgate usage` 按平台适配器查询每个
|
|
31
|
-
key 的实时额度(MiniMax、Kimi Code、z.ai、LiteLLM
|
|
35
|
+
key 的实时额度(MiniMax、Kimi Code、z.ai、LiteLLM 等);查询失败的 key
|
|
36
|
+
自动缓存跳过,`usage --force` 强制重查
|
|
32
37
|
- **Claude Code settings 管理**:import / apply 双向同步
|
|
33
38
|
- **配置同步**:`flexgate sync` 通过 confsync 服务器加密同步配置
|
|
34
39
|
- **自愈升级**:`flexgate doctor` 体检、`flexgate update` 一键升级并迁移配置
|
|
@@ -40,6 +45,7 @@ Claude Code → localhost:8765 → opus → z.ai (glm-5.1)
|
|
|
40
45
|
|
|
41
46
|
quickstart
|
|
42
47
|
configuration
|
|
48
|
+
api
|
|
43
49
|
cli
|
|
44
50
|
usage
|
|
45
51
|
development
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# 用量查询
|
|
2
|
+
|
|
3
|
+
`flexgate status` 和 `flexgate usage` 会逐一查询**每个 key** 的用量/额度。
|
|
4
|
+
各平台的查询方式差异很大(有的平台根本没有可用的接口),flexgate 按
|
|
5
|
+
`base_url` 自动选择适配器:
|
|
6
|
+
|
|
7
|
+
| 平台 | 查询方式 | 说明 |
|
|
8
|
+
|------|----------|------|
|
|
9
|
+
| MiniMax(api.minimaxi.com / api.minimax.io) | `GET /v1/api/openplatform/coding_plan/remains`(Bearer 认证,复用 provider key) | 官方 token plan 接口,返回 5 小时窗口和周窗口的**剩余**次数(注意响应里 `*_usage_count` 字段实际是剩余量) |
|
|
10
|
+
| Kimi Code(api.kimi.com) | `GET {base}/v1/usages`(Bearer 认证,复用 provider key) | 未公开文档、与 Kimi Code CLI `/usage` 相同的接口,返回周配额、5 小时滚动窗口剩余量和并发上限 |
|
|
11
|
+
| z.ai 个人版(api.z.ai) | `GET /api/monitor/usage/quota/limit`(Authorization 直接带 key) | 未公开文档、但 z.ai 官方 coding 插件在用的接口,返回各窗口已用百分比与重置时间。**仅对 GLM Coding Plan 个人订阅有效**:按量付费 key 会返回"当前用户不存在coding plan"并退化为 probe |
|
|
12
|
+
| 智谱团队版(open.bigmodel.cn) | `GET /api/monitor/usage/quota/limit?type=2`,带 `bigmodel-organization`/`bigmodel-project` 头(取自 key 条目的 `organization`/`project` 字段) | 同一 monitor 接口的团队版变体,返回 5 小时/每周窗口的积分用量(绝对值 + 百分比 + 重置时间);另查 `querySubscribeDetail` 显示套餐名与有效期。**key 条目未配 `organization`/`project` 时不查询**,退化为 probe(团队 key 不适用个人版接口) |
|
|
13
|
+
| USTC(api.llm.ustc.edu.cn,LiteLLM) | `GET /key/info`(Bearer 认证) | LiteLLM proxy 自带的 key 信息接口,返回 spend / max_budget / 限速等 |
|
|
14
|
+
| 小米 MiMo(token-plan-cn.xiaomimimo.com) | **无 key 可用的官方接口**(控制台内部接口需要浏览器 cookie,不采用) | 退化为 minimal probe |
|
|
15
|
+
| 其他/未知平台 | minimal chat probe | 发一条输入 `"hi"`、`max_tokens=128` 的最小 `/v1/messages` 请求,验证 key 是否还能正常服务(会消耗极少量额度) |
|
|
16
|
+
|
|
17
|
+
如果某平台的专用接口调用失败,flexgate 会自动退化为 minimal probe 再试
|
|
18
|
+
一次。
|
|
19
|
+
|
|
20
|
+
:::{caution}
|
|
21
|
+
用量查询接口多为平台内部接口,可能随时变动;查询结果仅供参考。
|
|
22
|
+
:::
|
|
23
|
+
|
|
24
|
+
## 查询失败缓存与 `--force`
|
|
25
|
+
|
|
26
|
+
用量查询中**报错的 key**(彻底失败,或专用接口报错但 probe 证明 key 仍
|
|
27
|
+
可用)会记录到 `~/.flexgate/usage-cache.json`(只存 key 的 sha256 指纹和
|
|
28
|
+
结果文本,不存 key 明文),此后 `flexgate status` / `flexgate usage`
|
|
29
|
+
默认**跳过**这些 key——不再发起任何网络请求,直接显示缓存的错误和一行
|
|
30
|
+
提示:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
Usage (timeout 15s per key)
|
|
34
|
+
2 key(s) skipped — last check failed (recheck with: flexgate usage --force)
|
|
35
|
+
zai
|
|
36
|
+
✓ key #1 (9f2c***abCD) cached (15s ago)
|
|
37
|
+
z.ai quota API (unofficial) failed (platform error: 当前用户不存在coding plan); probe: key can serve glm-5.3
|
|
38
|
+
recheck with: flexgate usage --force
|
|
39
|
+
ustc
|
|
40
|
+
✗ key #1 (sk-G***jJYg) cached failure (8s ago)
|
|
41
|
+
LiteLLM /key/info failed (ConnectError: ); probe: ConnectError:
|
|
42
|
+
recheck with: flexgate usage --force
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- 跳过的 key 按**上次结果**显示状态:key 仍可用的显示暗色 ✓ +
|
|
46
|
+
`cached (… ago)`,彻底失败的显示暗色 ✗ + `cached failure (… ago)`。
|
|
47
|
+
- `flexgate usage --force` 忽略缓存、重新查询所有 key 并更新缓存;
|
|
48
|
+
重查干净成功(无任何报错)的 key 会自动清除缓存条目,恢复默认实时查询。
|
|
49
|
+
- 占位符 key(未填写的默认值)不会进入缓存。
|
|
50
|
+
|
|
51
|
+
## 输出示例
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Usage (timeout 15s per key):
|
|
55
|
+
minimax:
|
|
56
|
+
✓ key #1 (sk-c***abcd) [main] MiniMax coding_plan API
|
|
57
|
+
MiniMax-M3: 5h window remaining 450/450 (reset 08-24 00:00); weekly remaining 900/900 (reset 08-24 00:00)
|
|
58
|
+
kimi:
|
|
59
|
+
✓ key #1 (sk-k***66N6) [ywj] Kimi Code usages API (unofficial)
|
|
60
|
+
plan: advanced
|
|
61
|
+
weekly remaining 63/100 (reset 08-28 22:17)
|
|
62
|
+
5h window remaining 74/100 (reset 08-23 14:17)
|
|
63
|
+
parallel limit: 30
|
|
64
|
+
zhipu-team:
|
|
65
|
+
✓ key #2 (ddb6***oZoj) [zhangsiyi] zhipu team quota API (unofficial)
|
|
66
|
+
plan: 团队套餐高级版 (until 2026-10-14, auto-renew off)
|
|
67
|
+
5h window: used 264/35000 credits (1%), reset 09-25 14:00
|
|
68
|
+
weekly window: used 93043/155000 credits (60%), reset 09-28 16:17
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 新增平台适配器
|
|
72
|
+
|
|
73
|
+
适配器登记在 `flexgate/usage.py` 的 `_ADAPTERS` 列表中:每条是
|
|
74
|
+
`(url 子串, 适配器协程, 方法标签)`,首个命中生效。bigmodel.cn 的团队版
|
|
75
|
+
适配器额外要求 key 条目上配置 `organization`/`project`,否则视为无适配
|
|
76
|
+
接口。已知没有 key 可用接口的平台放入 `_PROBE_ONLY_MARKERS`,直接走
|
|
77
|
+
probe,避免浪费一次失败的 HTTP 请求。
|