Files

330 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# tools-pve 统一模型代理
## ZenMux 订阅退役(2026-11-02)
本节覆盖下文历史的订阅优先策略。`zenmux_subscription_enabled: false`,Compose 不再
传入订阅 Key;即使旧环境中仍有该变量,renderer 也忽略它。
- Claude、DeepSeek、GLM、Kimi、MiMo:OpenRouter 优先,ZenMux BYOK/PAYG 最后备用。
- `auto/...`、无前缀兼容名使用上述顺序;旧 `zenmux/...` 为避免客户端中断保留,
现在也遵循主备,不代表仍使用 ZenMux 订阅。新配置推荐用 `auto/...`。
- `zenmux-payg/...` 显式指定 BYOK,仍可直调;不能给显式 provider 路由虚构优先级。
- Gemini 旧 ZenMux 兼容名优先使用已有 Google 路由,BYOK 最后。
- OpenAI 官方 API、Codex OAuth、xAI OAuth、Google 路由顺序不变。
- 没有其他同模型后端的路由,只能用保留的 BYOK,不做跨型号伪回退。
- BYOK 按量付费,不再受已取消订阅配额保护;跨 provider 缓存不共享。
OpenRouter Claude 合成直连探针在两台生产主机均返回条款限制类 403,
不是订阅退役是否生效的判断依据,也不能宣称首选上游已通过。
## OpenAI 官方 API 与订阅回退(2026-10-29)
官方 API key 由用户生成,经过明确授权,仅加入本 tools-pve 项目的 Arcane 私有
`OPENAI_API_KEY`。不写入 Git、不复制到 HK、不替换客户端 virtual key 或 OAuth。
官方上游固定为 `https://api.openai.com/v1`,不能因 LiteLLM provider 同为 openai
就误归入 ZenMux。未配置 key 时不生成这些路由和 fallback。
| 首选订阅路由 | 官方 API 备用路由 | 当前实际模型 |
| --- | --- | --- |
| `codex/gpt-luna-latest` | `openai/gpt-luna-latest` | `gpt-6-luna` |
| `codex/gpt-sol-latest` | `openai/gpt-sol-latest` | `gpt-6.1-sol` |
| `codex/gpt-astra-latest` | `openai/gpt-astra-latest` | `gpt-6-astra` |
| `codex/gpt-6-sol` | `openai/gpt-6-sol` | `gpt-6-sol` |
| `codex/gpt-5.5` | `openai/gpt-5.5` | `gpt-5.5` |
原不带provider的GPT兼容别名也保留同型号fallback。renderer从chatgpt表生成
对应的API别名,因此既有latest维护更新后,两侧不会各自残留不同型号。
`openai/...`显式路由只走官方API,不回到订阅,不改变Grok/Claude/Google/开放模型的主备。
订阅429、认证或暂时故障可以回退;不自动跨型号降级,失败冷却仍为60秒。
跨后端不共享prompt cache,也不承诺中途流断线或previous_response_id跨后端续接。
需要保留完整上下文以便调用方重试,不自动重放已经执行的工具。
API专有补充:`openai/gpt-terra-latest`(目前6.1 Terra);
`openai/gpt-transcribe`、`openai/gpt-4o-transcribe`、
`openai/gpt-4o-mini-transcribe`、`openai/gpt-4o-transcribe-diarize`;
`openai/text-embedding-3-small`、`openai/text-embedding-3-large`;
`openai/gpt-4o-mini-tts`;`openai/gpt-image-2.5-flare`、
`openai/gpt-image-2.5-sunburst`。图像路线可配置不代表做过昂贵出图验收,
各接口按实际测试结果记录。没有修改现有ASR热词、Hindsight embedding或客户端默认模型。
Terra与其他API专有模型暂按models.yaml显式维护,不擅自扩张既有Hermes自动维护授权。
现有lan-agents应用key增补这些API路线;Hindsight等受限key只增补其原先已允许的
GPT路线对应备用模型,不开放图像、语音等无关能力。Claude专用key不变。
赠金需绑定到此key所属API组织,并在该订阅账期末到期,不结转。赠金额度先消耗,
余额不足后若有已购额度可继续消费;没有任何额度则返回429 credit_balance_exhausted。
代理不能凭普通project key保证“只花赠金”,不替用户开启充值。这里提供的是
标准API请求的主备,不把官方赠金解释为可给Codex CLI的API-key模式增加额度。
依据:[OpenAI赠金说明](https://developers.openai.com/api/docs/guides/chatgpt-api-credits)、
[LiteLLM回退](https://docs.litellm.ai/docs/proxy/reliability)。
本轮验收:18项配置测试通过;官方Luna/Sol/Terra的Responses、Luna Chat、
Codex Luna Responses完整SSE通过(正常请求fallbacks=0);embedding small、
TTS与合成语音的gpt-transcribe/mini-transcribe通过。图像未实际生成,
diarize与embedding large只配置且模型目录可见,不能据此声称完成任务验收。
`verify_openai_fallback.py`在独立容器exec进程中对Chat与Responses各注入
429/401/503,六例均收到真实官方API的短回复;不是人为耗尽订阅,也不修改
生产worker的函数或真实OAuth token。复测命令(会有少量API用量):
```bash
ssh tools@192.168.50.49 'sudo -n docker exec -i tools-litellm python -' < verify_openai_fallback.py
```
Arcane Sync及Up终态success;PostgreSQL启动时间仍是
`2026-10-12T05:46:12.472887407Z`,数据库及OAuth卷未重建。
## 部署状态
2026-10-09:已通过 Arcane 上线,LiteLLM 1.104.2 与 PostgreSQL 均 healthy。
UI HTTP 200;应用 virtual key 的 OpenRouter MiMo 请求返回 OK。
ZenMux Sonnet 5.5 原生 Messages 正常;重复请求证实写入与读取
21,502 prompt-cache tokens。Codex/xAI 已独立授权,SDK 原生请求验证
Luna、Sol 6.1 和 Grok 4.7 返回 OK。用户更新后的 PAYG key 原生 Claude 请求 HTTP 200。
Google AI Studio key 模型目录 HTTP 200,使用上游提供的三个 latest 别名。
17 条路线已加载;原客户端 key 权限已更新,Luna/Sol 的 gateway Responses SSE、
Luna 非流式 Chat Completions、Grok/Gemini 三条 Chat 路线和 PAYG Messages 均实测 OK。
本项目对其他模型的自动 latest 维护尚未实现。
- Environment:`ff859844-8393-4f87-8caf-054df735a65d`。
- Project:`06052b47-f640-4e23-968d-bfc25a8a6e7a`,名称 `tools-litellm`。
- Git Sync:`49148e73-65ca-43a6-a859-efc9cc750b93`;Auto Sync 关闭。
- 宿主机项目目录:`/var/lib/docker/volumes/arcane-agent_agent-data/_data/projects/litellm`。
- 管理凭据:.145 的 `/home/claw/codex-workspace/server-management/.secrets/tools-litellm.env`。
- 普通客户端配置:同目录 `tools-litellm-client.env`;两者均为 0600,不提交 Git。
## 架构与入口
部署在 `192.168.50.49`,LiteLLM 与独立 PostgreSQL 17。
- OpenAI 兼容客户端:`http://192.168.50.49:4000/v1`。
- Anthropic SDK:`http://192.168.50.49:4000`,请求 `/v1/messages`。
- 管理界面:`http://192.168.50.49:4000/ui`。
- PostgreSQL 不发布主机端口。
- named volume:`tools-litellm-database`、`tools-litellm-oauth`。
只使用单个代理 worker,降低 OAuth refresh token 竞争的风险。
所有配置从 Git 生成,不允许 UI 中的模型配置成为另一份权威。
未提供 key 或未完成 OAuth 登录的路线不会进入运行配置。
OAuth 判定检查 auth.json 中 access_token,不仅检查文件存在性:
Codex 设备授权期间会先写入冷却占位文件,这不代表已经授权。
## Provider 与缓存
ZenMux Claude 使用 Anthropic Messages 上游:
`https://zenmux.ai/api/anthropic`。
LiteLLM 的 `anthropic/anthropic/claude-sonnet-5.5` 第一个前缀是
LiteLLM provider,第二个前缀是 ZenMux 的模型 ID,不是笔误。
订阅路线为 `claude-sonnet-latest`、`claude-opus-latest`、
`claude-haiku-latest`;PAYG 路线在同名末尾加 `-payg`。
不自动由订阅切换到 PAYG,也不设置跨模型 fallback。
Claude 客户端优先使用原生 `/v1/messages`,保留 `cache_control`、
稳定的 tools/system 前缀以及原样回传的 thinking/signature。
不能保证每次 cache hit;首次创建、最小缓存长度、TTL 和上游路由都会影响结果。
上线验收需重复发送足够长且完全相同的前缀,检查
`cache_creation_input_tokens` 和 `cache_read_input_tokens`,不能只看 HTTP 200。
不把 LiteLLM 的响应缓存当作 Anthropic prompt cache。
实测 ZenMux Sonnet 5.5 会拒绝强制 `tool_choice.type=tool/any`,
错误由上游返回;使用支持的 `auto` 模式,不在代理中静默改写调用者的要求。
开放模型已改为 ZenMux 订阅优先、OpenRouter 回退;`models.yaml` 来自实际 provider 目录。
除 Google 自带 latest 映射由其上游维护外,其他 `latest` 都是本项目手动维护的稳定别名。
Google AI Studio 使用独立 key 与模型表,已实际查询模型目录,
不把 Google OAuth/ADC 当成 AI Studio API key。
Google 三条模型为 gemini-flash-latest、gemini-flash-lite-latest、gemini-pro-latest。
用户新 provider key 的权威位置是 Arcane tools-litellm Project `.env`;
不要用 .145 首次生成的 tools-litellm.env 整体覆盖它,那份文件可能还含旧 provider 值。
该本机文件主要用于 master key 管理与数据库凭据恢复;提供商配置必须先从 Arcane 实查。
## 开源模型主备路由(2026-10-12)
| 客户端稳定别名 | 两侧具体模型 |
| --- | --- |
| `deepseek-flash-latest` | `deepseek/deepseek-v4.1-flash` |
| `deepseek-pro-latest` | `deepseek/deepseek-v4-pro` |
| `glm-latest` | `z-ai/glm-5.3-prime` |
| `kimi-latest` | `moonshotai/kimi-k3` |
| `mimo-flash-latest` | `xiaomi/mimo-v2.6-flash` |
这些原有别名先调用 ZenMux `/api/v1`,失败后由 Router 转向同名末尾加
`-openrouter` 的备用组;不是随机分流,不切到 PAYG,也不改变 Claude/OAuth。
DeepSeek Pro 原 OpenRouter 日期版 `v4-pro-0813` 改为双方共有的 `v4-pro`,
两侧返回模型 ID 已核验一致,但不能仅据 ID 保证供应商权重实现完全相同。
只配置现有五组,不把整个供应商目录自动开放。
缺 ZenMux key 时原别名仍直接走 OpenRouter;缺 OpenRouter key 时不生成悬空
fallback。普通 virtual key 需同时允许主组与备用组,现有 lan-agents key
通过 `/key/update` 增补五个备用别名,无需更换 key。
部署所用 SDK 的回环 mock 已验证 402、403、429、500 自动回退。
显式部署级异常策略让 429/500 在第一次失败后冷却 60 秒;402/403 仍会在
下一请求尝试主组,不宣称已按订阅窗口熔断。Router 默认最多一次重试,
不是耗尽后无限等待。两家共享订阅额度的跨模型熔断尚未实现。
请求开始前的失败已覆盖;流式输出中途断开不承诺无缝拼接或恰好一次执行工具。
ZenMux 恢复后重新优先使用它。OpenRouter 会产生其账户费用;缓存不跨
供应商共享。上游工具/推理参数兼容性仍按调用者实际用法验收,不能只凭
短文本成功宣称所有 Agent 工作流均兼容。
参考:[LiteLLM Fallbacks](https://docs.litellm.ai/docs/proxy/reliability)。
## Hermes 两个 profile 的集中接入
Hermes 使用三种协议入口:Claude 经 Anthropic Messages,Gemini/Grok/开源模型
经 Chat Completions,Codex 订阅经 Responses。不要为了单一 URL 把所有模型强行
桥接成同一种协议;`/v1/responses` 和 `/v1/messages` 均由同一代理提供。
补充路线 `gemini-flash-zenmux` 保留 Hermes 原 ZenMux Gemini 3.8 Flash 数据去向,
不自动换到 Google ADC。`gpt-work-sol`、`gpt-review-5.5`、`gpt-astra-latest` 分别
保留原 gpt-6-sol、gpt-5.5、gpt-6-astra;三者均在独立 Codex OAuth 实时目录中。
它们是兼容现有分工,不以过期型号或“最新总更好”为由静默更换。
`glm-flash-latest` 补齐原选择器中的 GLM 5.3 Flash,并使用同一 ZenMux/OpenRouter 主备模式。
用户同日确认的最终策略:default 用 `grok-latest`,work 用 `gpt-sol-latest`;
辅助全部用 `gpt-luna-latest`(一般 low、任务拆解 medium),审阅及后台审阅用
`gpt-sol-latest` high。当前分别映射 Grok 4.7、GPT-6 Luna、GPT-6.1 Sol。
原 Haiku/Flash/GPT-5.5 分工为迁移阶段,不再作为 Hermes 的当前策略。
旧兼容路线留给历史客户端,Hermes GPT 选择器只列 Luna/Sol/Astra latest。
MoA 仅按需启动,参考模型为 Sonnet 5.5/Grok/Luna,Astra 聚合。
work 的旧 Sonnet 5 参考槽统一到已有 Sonnet 5.5 路线。旧直连 provider 只保留
回滚兼容,新默认与任务槽不再引用;已打开 session 的 provider/model 覆盖不自动改写。
## 密钥
真实 `.env` 权限 `0600`,不提交 Git;模板见 `.env.example`。
ZenMux subscription/PAYG 的 key 需要明确确认用途,不能按外观推断。
数据库密码使用无特殊 URL 字符的随机值,避免 `DATABASE_URL` 编码问题。
`LITELLM_MASTER_KEY` 以 `sk-` 开头,salt 独立随机生成。
UI 使用数据库管理员 `kai@litellm.local`(只是登录标识,不发送邮件),
设置 `disable_env_credential_login: true`,禁用 UI_PASSWORD 以及 master key 的网页登录。
用户已修改首次临时密码,临时文件已删除。数据库保存密码哈希,
用户的新密码不写入环境变量,也不由 Agent 保存。
master key 仍能管理 API,用于恢复权限,不再充当网页登录密码。
不能直接用这份配置初始化空库后期待默认 admin 登录:必须预先通过
`/user/new` 建立管理员,再 `/user/update` 设置临时密码,随后启用限制。
日常客户端应使用管理界面创建的应用专属 virtual key,不共享 master key。
不要开启输出请求全文的 debug 日志。
## 独立 OAuth 登录
不复制 Codex CLI、Grok CLI 或 Hermes 的 refresh token。
在目标主机项目目录执行:
```bash
bash oauth-login.sh codex
```
打开终端显示的设备验证网址并输入验证码。
xAI 需要本机浏览器回调。先在浏览器所在电脑保持 SSH 隧道:
```bash
ssh -N -L 56121:127.0.0.1:56121 tools@192.168.50.49
```
然后在 tools-pve 的另一个终端运行:
```bash
bash oauth-login.sh xai
```
打开输出的授权 URL;若 56121 被占用,先关闭占用者再重试,
不要把临时改用的端口当作已有隧道可达。
登录 helper 使用 host network 仅供本地 OAuth 回调,生产代理仍使用独立 bridge。
确认账号实际支持的模型 ID 后,在 `models.yaml` 的 `chatgpt`/`xai` 表添加别名。
OAuth 映射为 gpt-luna-latest -> gpt-6-luna、gpt-sol-latest -> gpt-6.1-sol、
grok-latest -> grok-4.7,独立账号目录与 SDK 请求均已验证。
Codex 路线由 `chatgpt/` 访问,优先 `/v1/responses`;
原生 Responses 使用消息列表形式的 input 和 stream=true,按 SSE 读取到 response.completed。
常规 OpenAI SDK 客户端也可用 /v1/chat/completions,Luna 非流式桥接已实测 OK。
实测直接给字符串 input 会被 Codex backend 拒绝;不要把已授权误写成协议完全兼容。
xAI 路线使用 `xai/` 与 `use_xai_oauth: true`,不能设置 XAI API key 覆盖它。
新增 token 后需重启代理,运行时 refresh 会写回同一个持久卷。
## 部署及验收
正常走 Arcane Git Sync;Manager 已恢复,本项目已通过控制面部署。
如用户明确同意临时直接部署,将本目录放到 tools-pve,准备 `.env` 后执行:
```bash
docker compose config --quiet
docker compose up -d
docker compose ps
```
恢复 Arcane 后应纳管这套已有卷和项目,避免生成第二套数据库。
上线必须验证健康、带 virtual key 的模型列表、实际请求、stream 和工具调用;
OAuth 与 Claude cache hit 分别验收,未通过不能写成可用。
回滚只停止新增项目或回退配置/image pin,不删除 named volume。
定期 `pg_dump` 并保留独立备份,数据库卷不是备份。
参考:[LiteLLM ChatGPT OAuth](https://docs.litellm.ai/docs/providers/chatgpt)、
[xAI OAuth 官方源码](https://github.com/BerriAI/litellm/blob/main/litellm/llms/xai/oauth.py)、
[ZenMux prompt cache](https://zenmux.ai/docs/guide/advanced/prompt-cache.html)。
## Google Agent Platform 与检索模型
2026-10-09 用户确认 Pro 赠金已绑定结算账号后,接入项目
`gen-lang-client-0312436655`,区域 `global`。复用此前已授权的用户 ADC,
保存在既有 `tools-litellm-oauth` 卷的 `/tokens/google/adc.json`(0600),
不进 Git;容器通过 `GOOGLE_APPLICATION_CREDENTIALS` 读取并刷新凭据。
Arcane Project `.env` 设置 `VERTEXAI_ENABLED=true`、`VERTEXAI_PROJECT`、
`VERTEXAI_LOCATION`。默认关闭该路线,避免仅有项目名就自动发起付费调用。
| 对外路由 | 实际模型 | 验收 |
| --- | --- | --- |
| `gemini-flash-vertex` | `gemini-3.8-flash` | 原生及普通客户端 Chat 均成功 |
| `gemini-flash-lite-vertex` | `gemini-3.5-flash-lite` | 原生及普通客户端 Chat 均成功 |
| `gemini-pro-vertex` | `gemini-3.1-pro-preview` | 原生及普通客户端 Chat 均成功 |
| `gemini-embedding-2-studio` | AI Studio `gemini-embedding-2` | `/v1/embeddings` 两条输入返回两条 1024 维向量,index 正确 |
前三条不冒充 Google 厂商自动 latest 别名;保持与 AI Studio 既有路由分开。
Google 官方说明 AI Pro 月赠金可用于 Agent Platform,但本次没有从账单
实证某次请求扣的是赠金;兑换状态由用户确认。赠金耗尽后可能继续产生付费,
当前没有基于 Google 实时赠金余额的硬停机制,不设置自动跨 provider fallback。
AI Studio 当前账号目录含 `gemini-embedding-001`、`gemini-embedding-2-preview`、
`gemini-embedding-2`,没有独立 rerank 模型。优先用已经 GA 的 Embedding 2。
原生 Agent Platform `gemini-embedding-2:embedContent` 已实测返回 1024 维。
但 LiteLLM 1.104.2 的 `vertex_ai/gemini-embedding-2` 两条输入只返回一条向量,
故没有开放该代理路由供批量检索使用;不要把 API HTTP 200 当成批量验收。
Google rerank 是 Discovery Engine 的独立 Ranking API,不属于 AI Studio
embedding 接口。候选 `semantic-ranker-default@latest`、`semantic-ranker-fast@latest`;
005 为较新模型版本,官方页面 latest 指向说明与表格存在矛盾,不能仅凭别名
断言实际模型版本。当前项目两条路线均返回 403:Discovery Engine API 未启用。
尚未启用或纳入 LiteLLM,可到 Google Console 启用 `discoveryengine.googleapis.com`
后复测中文排序、权限、价格及延迟。当前 LiteLLM 已包含原生 Vertex rerank 适配。
Hindsight 0.10.1 当前生产仍用 unRaid TEI 的 `BAAI/bge-m3` embedding 和
`Alibaba-NLP/gte-multilingual-reranker-base` rerank,Cohere/rrf 是 fallback。
该版本原生 Google embedding provider 会把 Vertex Embedding 2 拆成逐条请求,
并验证输入与输出数量一致,因此后续可优先原生 Google ADC 路线,而非有问题
的 LiteLLM Vertex embedding 路线。不要直接改生产 provider:即使都选 1024 维,
BGE 与 Gemini 的向量空间不同,必须重嵌入并重建索引。rerank 切换不要求重建向量。
embedding 模型禁止使用自动追踪 latest 的别名,否则升级会混用旧向量。
参考:[Google Pro 赠金](https://developers.google.com/program/plans-and-pricing)、
[Gemini embedding](https://ai.google.dev/gemini-api/docs/embeddings)、
[Google Ranking API](https://docs.cloud.google.com/generative-ai-app-builder/docs/ranking)、
[Hindsight 配置](https://hindsight.vectorize.io/developer/configuration)。
# 个人语音输入热词路由(2026-10-25)
独立别名 `gemini-transcribe-personal` 使用 `gemini/gemini-3.5-transcribe`,经 Google AI Studio 凭据转发。客户端调用现有 `/v1/audio/transcriptions`,无需自行传词表。该别名附带 `personal_vocabulary: true`;启动适配器仅对明确标记的 Gemini 转写请求注入原生 `generation_config.transcription_config.custom_vocabulary` 和 `mode: smart`,普通路由不变。SMART 与 HK 保持相同的功能意图,但 AI Studio 使用小写字符串 `smart`,不是 Vertex 的大写 `SMART` 和 camelCase 字段。
当前个人词表仅包含 10 个人名、10 个公司名。按用户要求,从 Obsidian People/Companies 已确认卡片取规范名,以正式工作笔记的独立文档频次和 Hindsight 实体 mention_count 交叉排序;不加入产品、项目、文档标题、职务说明或错误别名。旧的 SQLite 100 词自动抽取已被替代,因为它把文档式长名称作为热词,出现了过度引导。
导出与私有频次审计使用 server-management 的 `scripts/export-entity-dictation-vocabulary.py`;具体名单与卡片证据不提交本配置仓库。私有文件仍为 tools-pve `/opt/litellm/personal-vocabulary.json`(0600)。每次请求读取文件;若通过原子替换文件更新,单文件 bind mount 需重启 LiteLLM 重新挂载。没有自动扩词任务,后续按实际误识别逐条复测。
语音输入使用 `response_format=json`,与 HK 的 Spokenly 设置一致;当前 text 请求虽 HTTP 200 仍返回 JSON 包装,不选用。不支持词级时间戳、字幕及说话人分离。Google 目前不允许 SMART/原生热词与说话人分离或词级时间戳组合。不要把这条路由用于需要 diarization 的会议流程。
LiteLLM 1.104.2 原生适配未映射热词/SMART,因此 `personal_transcription.py` 使用受路由开关约束的启动适配。升级 LiteLLM 后必须重跑 `scripts/test-personal-transcription-wire.py`,确认私有开关不泄漏上游、普通请求不变、Google 请求体中存在原生词表和 `mode: smart`。不要将 mock 验证等同于识别质量提升。
首次上线通过两次合成词 HTTP mock 验证,以及一秒合成静音的真实 Google HTTP 200 测试;未使用私人录音,未改会议配置。LAN 客户端 key 已单独增加本别名权限,其他受限 key 需按需授权。
同日启用 SMART 后,再次通过 mock 确认 native mode/词库和普通请求隔离;既有客户端 key 的静音及 Google 公开语音样本 JSON 转写均返回 200。只重启 tools-litellm,会议 worker/web 与 Postgres 启动时间未变。中文效果仍需真实使用评估。