# 📦 @goodandready/dsh-key-rotation

适用于 DeepSeek Harness 的企业级无感 API 密钥轮换、预判限流与跨提供商故障转移引擎

npm version license DSH Plugin Node version

GoodAndReady Showcase

🇬🇧 English🇷🇺 Русский🇨🇳 中文说明

如果您喜欢这个插件,请在 GitHub 上为它点亮 Star — 这能让我知道插件对您有用,并鼓励我继续开发和维护它。

🐛 如果您发现 Bug 或希望增加功能,请使用任意语言在 GitHub 上提交 Issue — 我会评估您的建议,并在后续版本中实现有价值的改进。
--- ## ⚡ 概述与核心痛点 ### 🚀 v0.8.10 版本新特性(流并发加固与状态自动修剪) - **杜绝并发计数泄漏**:在 `try ... finally` 中强制释放流并发占用,防止在正常完成或客户端中断时密钥被永久锁定。 - **探测抗网络抖动重试**:在 `probeModels` 中遇到套接字网络临时错误时自动重试一次,避免密钥被误判损坏。 - **内存与过期状态自动清理**:在定期清理周期中自动清除已删除密钥的内部映射记录。 ### 🚀 v0.8.9 版本新特性(智能路由与界面升级) - **前瞻性限流防护 (Proactive Rate-Limit Guard)**:根据 `x-ratelimit-remaining-*` 和 `Retry-After` 响应头在触发 429 错误前自动预冷密钥。 - **自愈恢复 (Self-Healing / Auto-Unbreak)**:通过免费的 `/models` 接口进行定期后台探测,自动恢复处于 `broken` 状态的密钥,无需消耗聊天代币。 - **延迟感知路由 (Latency-Aware Routing)**:可选路由策略:`round-robin`(轮询)、`least-loaded`(并发负载最低)与 `lowest-latency`(p95 延迟最低)。 - **`dsh-clinebot` 风格界面升级**:支持带进度提示的批量“测试所有密钥”(Test All Keys)、实时事件流折叠抽屉(Live Event Stream)及配额重置倒计时徽标。 - **原生中英文双语支持**:内置英文(`en`)与中文(`zh`)用户界面词典。 ### 🛠️ v0.8.0 版本新特性(稳定性) - **🔌 熔断器**:连续失败后快速失败(`CIRCUIT_OPEN`),半开探测自动恢复。 - **🕒 单调时钟**:冷却/熔断使用进程单调时间,NTP 校时不会颠倒剩余时间。 - **📮 非阻塞 Webhook**:有界队列 + backoff,轮换不等待 HTTP。 - **🧱 原子写文件**:损坏 JSON 不会覆盖既有状态。 - **🧹 克隆路由 GC**:清理孤儿自动路由。 - **🧭 错误分类**:408/425/429/5xx、套接字与 gRPC 的 switch/surface/soft。 - **📡 Status**:提供商 `circuit` + `meta`。 - **🧪 Smoke**:429 → 切换密钥 → 成功。 ### 🛠️ v0.7.33 版本新特性 (稳定性与问题修复) - **🔍 修复密钥探测 BaseURL 解析**:`resolveBaseUrl` 现已支持从密钥 ref 反查归属提供商池,恢复在线模型连通性探测。 - **🛡️ 防御级联无限递归**:在跨提供商故障转移中增加递归深度防护,彻底杜绝循环级联导致的堆栈溢出。 - **🕒 纠正 PST 太平洋时间配额重置**:修复 UTC-8 时区偏移符号,确保日配额在太平洋时间午夜准时重置。 - **🧹 定时器生命周期自动回收**:将金丝雀探测与自愈定时器纳入 Cordis 效应生命周期,消除热重载遗留孤儿定时器。 - **⚡ 负载均衡超时锁自动释放**:`pickLeastLoaded` 算法现已检测过期连接锁,确保最小连接调度不发生偏移。 - **🌐 完整中文界面本地化**:为 React 设置面板补充全部 `zh` 语言包,实现标准的三语(英/俄/中)无缝对齐。 ### 🚀 v0.7.31 版本新特性 - **⚡ O(1) 令牌桶累加器**:将速率限制计算升级为 O(1) 时间复杂度与零内存分配,并支持响应头自适应同步。 - **🛡️ 软/硬故障分级退避**:区分临时网络抖动(502/503/超时获得 10 秒平缓冷却)与硬性配额超限(指数退避倍增)。 - **⏳ 惩罚衰减(Penalty Decay)**:持续稳定运行的密钥每小时自动平减一次失败惩罚系数。 - **🎲 冷却抖动(Jitter)**:为解锁时间添加 ±12.5% 随机离散度,彻底消除上游惊群效应。 - **🎯 定向金丝雀探测**:支持针对具体目标模型进行轻量级单 Token 连通性探测。 - **📊 TTFT 百分位数(p50 / p95 / p99)**:在高精健康度指标中计算首字延迟百分位数。 - **🔔 Webhook 警报聚合摘要**:在 5 秒窗口内将突发告警合并为单一结构化事件摘要,支持 Telegram/Discord/Slack。 - **🧹 30 天用量压缩**:自动清理超过 30 天的历史统计数据,保障长期运行内存上限。 - **✨ 乐观 UI 与快速筛选标签**:一键重置即时生效,密钥列表新增 `全部`、`就绪`、`冷却中`、`故障` 状态筛选胶囊。 在高吞吐量自主智能体运行、多子智能体并行执行与多轮工具调用场景下,API 极易触发上游服务商的速率限制(HTTP 429 Too Many Requests、RPM/TPM 耗尽、每日配额限制或网络抖动)。在原生的 DeepSeek Harness 中,单个密钥耗尽会导致整个智能体执行链路崩溃,破坏会话的 Replay 状态并要求人工干预。 **`dsh-key-rotation`** 基于 Cordis 微内核架构构建,提供了无缝透明的 **API 密钥池轮换、客户端预判限流(Token Bucket)与跨提供商故障转移(Failover Cascade)** 解决方案。 与修改模型提供商 ID 的传统网关代理不同,`dsh-key-rotation` 通过运行时拦截 `ctx.credentials.resolve` 与 `llm/stream` 钩子工作: * **保持提供商身份一致**:仅切换底层解析的 API 密钥,维持 `pi-ai` 多轮会话与工具状态 100% 一致。 * **令牌桶预判限流**:在发起网络请求前预先跳过已饱和的密钥,彻底消除重试网络延迟。 * **最小连接数并发控制**:动态均衡各密钥的 In-Flight 并发流,防止并发突发拥塞。 * **金丝雀自愈与级联**:通过轻量 Sandbox 探测探活冷却密钥,密钥全耗尽时自动级联到备用提供商。 --- ## 🏗️ 架构与请求生命周期 ```mermaid graph LR subgraph ClientLayer ["客户端与智能体层"] UserMsg["用户 / 智能体消息"] --> Adapter["pi-ai 模型适配器"] end subgraph RotationEngine ["dsh-key-rotation 核心引擎"] Adapter --> StreamHook["llm/stream 拦截器"] StreamHook --> BucketCheck{"Token Bucket\nRPM / TPM 校验"} BucketCheck -->|未超限| ConcurrencyCheck{"并发跟踪器\n最小连接数"} BucketCheck -->|已超限| NextKey1["选取下一可用密钥"] ConcurrencyCheck -->|有空闲槽位| KeyResolver["ctx.credentials.resolve"] ConcurrencyCheck -->|槽位已满| NextKey1 KeyResolver --> ActiveKey["活跃密钥 (执行中)"] ActiveKey -.->|HTTP 429 / Quota / 错误| Failover["即时故障转移"] Failover --> BackoffCalc["指数退避与隔离"] Failover --> NextKey2["重试下一密钥 (零 Token 丢失)"] Failover -.->|所有密钥均在冷却中| CascadeEngine["跨提供商级联"] BackoffCalc --> QuotaWindow["日历重置 / 午夜对齐窗口"] BackoffCalc --> CanaryProbe["金丝雀探针 (Sandbox Ping)"] CanaryProbe -->|探活成功| PoolReady["恢复至就绪池"] end subgraph UpstreamLayer ["上游服务商端点"] ActiveKey --> UpstreamAPI["主要提供商 API"] CascadeEngine --> FallbackAPI["备用提供商 API"] end style ClientLayer fill:#1e1e2e,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4 style RotationEngine fill:#181825,stroke:#cba6f7,stroke-width:2px,color:#cdd6f4 style UpstreamLayer fill:#11111b,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4 ``` --- ## ✨ 核心功能详解 ### 🔄 1. 透明轮换与即时故障转移 * **维持提供商标识一致**:轮换仅替换底层解析的凭证引用,不改变 Provider ID,彻底避免 `INVALID_REPLAY_STATE` 异常。 * **零 Token 丢失重试**:在首个内容块发出前发生错误时,无感重试并切换至池中下一个健康密钥。 * **全状态码支持**:支持 `QUOTA`、`RATE_LIMIT`、`SERVER`、`TIMEOUT`、`TRANSPORT`、`EMPTY_RESPONSE`、`UNKNOWN_MODEL`、`AUTH` 等。 * **正则消息模式分类**:内置 `SWITCHABLE_MESSAGE_PATTERN` 正则引擎,自动识别 SDK 抛出的非结构化配额与限流异常。 * **非流式安全防护**:通过 `agent/request-error` 生命周期钩子保护 Embeddings 及 Batch 调用。 ### ⏱️ 2. 预判限流与并发控制 * **Token Bucket 令牌桶 (`lib/bucket.js`)**:滑动窗口跟踪每分钟请求数 (`rpmLimit`) 与 Token 数 (`tpmLimit`),预先拦截超限密钥。 * **最小连接负载均衡 (`lib/concurrency.js`)**:实时追踪每把密钥的活跃流数量 (`inFlight`),执行 `maxConcurrency` 限制。 * **死锁自动释放**:针对网络异常中断连接,超时 5 分钟自动清理占用计数。 ### 🛡️ 3. 自动愈合与跨提供商级联 * **跨提供商故障转移级联 (`lib/cascade.js`)**:主提供商密钥全部冷却时,自动级联路由到备用提供商池。 * **沙箱密钥探测 (`lib/sandbox.js`)**:按需对密钥执行 `/models` 探测后再回到轮换;空闲冷却由 self-heal sweep 解除。 * **配额日历重置对齐 (`lib/quota-window.js`)**:支持 `midnight_utc`、`midnight_pst` 与 `rolling_24h` 配额刷新窗口。 * **自适应指数退避 (`lib/pool.js`)**:连续失败使冷却时间呈指数递增(基准 → ×2 → ×4 → 上限 ×8)。 ### 📊 4. 统计分析与多平台交互式 Webhook * **交互式 Webhook (`lib/webhook.js`)**:向 **Telegram**、**Discord**、**Slack** 推送带交互按钮的富文本警报,可在移动聊天中一键重置冷却或暂停提供商。 * **使用量与成本报表 (`lib/usage-report.js`)**:按日统计各密钥请求数与预估成本,支持一键导出 CSV/JSON (`GET /dsh-key-rotation/usage-report`)。 * **延迟 SLO 监控 (`lib/histogram.js`)**:记录首字延迟(TTFT)与健康度评分 (`0..100`)。 --- ## 🖥️ Web GUI 控制台 (**设置 → 密钥轮换**) | 功能 | 说明 | |---|---| | **顶部状态栏微件** | DSH 顶栏实时健康徽章:🟢 正常 \| 🟡 存在冷却 \| 🔴 密钥池耗尽,点击弹出快速操作面板。 | | **一键健康矩阵** | 运行全量密钥与模型并行沙箱测试,直观展示 HTTP 状态码与 TTFT 首字延迟。 | | **一键凭证录入** | 点击添加自动生成规范名称(`_API_KEY`, `_2`, `_3`),悬停显示尾号。 | | **实时状态徽章** | 实时显示:`使用中`、`就绪`、`冷却中`(带倒计时)以及 `凭证未找到`。 | | **拖拽与顺序调整** | 使用 按钮调整轮换优先级。 | | **密钥泄漏探测器** | 实时校验输入格式(`sk-...` 等),防止误贴私钥或无关 Token。 | | **批量 `.env` 导入** | 支持文件导入解析并自动填充至对应提供商池。 | | **5 秒撤销栏** | 误删密钥或提供商时提供 5 秒快速撤销操作。 | --- ## 🔒 安全性与凭证存储 * **配置零明文**:插件配置仅保存环境变量引用名(如 `MY_PROVIDER_API_KEY`)。 * **宿主安全存储**:真实密钥持久化保存在 `$DSH_HOME/.credentials.yaml`。 * **前台 5 字符脱敏**:前端仅展示密钥后 5 位字符进行视觉区分。 * **环回安全隔离**:管理接口严格限制来自本地同源请求 (`isTrustedBridgeRequest`)。 --- ## 📦 安装指南 ```bash # 通过 DSH 插件管理器安装 (Web Profile): dsh plugin --profile web add @goodandready/dsh-key-rotation # 或直接从 GitHub 安装: dsh plugin --profile web add github:GooDAnDReaDY/dsh-key-rotation ``` > [!IMPORTANT] > 安装后请重启 DSH Web 服务并刷新浏览器页面: > ```bash > systemctl --user restart dsh-web > ``` --- ## ⚙️ 配置示例 (`settings.yaml`) ```yaml dsh-key-rotation: switchCodes: - QUOTA - RATE_LIMIT - SERVER - TIMEOUT - TRANSPORT - EMPTY_RESPONSE - UNKNOWN_MODEL - AUTH cooldownMs: 60000 circuitBreakerEnabled: true circuitBreakerThreshold: 5 circuitBreakerOpenMs: 30000 circuitBreakerHalfOpenProbes: 1 concurrencyLimit: 5 quotaResetWindow: type: midnight_utc hour: 0 cascade: - provider: backup-provider-id model: your-backup-model-id webhookUrl: "https://api.telegram.org/bot/sendMessage?chat_id=" providers: - provider: your-primary-provider rpmLimit: 60 tpmLimit: 100000 keys: - PRIMARY_API_KEY - PRIMARY_API_KEY_2 - PRIMARY_API_KEY_BACKUP - provider: secondary-provider keys: - SECONDARY_API_KEY - SECONDARY_API_KEY_2 ``` --- ## 📄 开源许可 MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY) ### v0.7.39 - **自动恢复与 lastUsedAt 修复**:修复了 `healIdleCooldowns` 中对密钥调用时间戳的读取逻辑,直接从 `lastUsedAt` 映射读取。在 `credentials.resolve` 中补充记录每次密钥调用的时间戳,使状态面板的最近使用时间生效并正确支持空闲密钥恢复。 - **运行期快照缓存优化**:消除了定时维护清理、`/status` 路由及密钥池耗尽处理中重复调用 `buildRuntime()` 的开销。 - **CI 测试稳定性提升**:对维护定时器与通知防抖定时器执行 `unref`,确保 Node.js 事件循环在测试完成后干净退出,彻底解决 CI 运行器假死问题。 ### v0.7.38 - **热路径流处理优化**:在 `rotate()` 结束块处理中消除 4 次多余的 `buildRuntime()` 重复调用,直接复用请求作用域内的 `runtime0` 快照。 - **零额外字符串分配的限流头解析**:重构 `extractRateLimit()`,采用单次遍历结合键长度检查,彻底消除对每个响应头执行 `.toLowerCase()` / `.toUpperCase()` 的内存碎片分配。 - **日期 ISO 字符串记忆化**:在统计 `costDays` 与 `usageDays` 时将 `todayIso` 计算收敛为单次,杜绝重复创建 `Date` 实例。 - **状态统计零数组分配**:在 `/dsh-key-rotation/status` 中将 `totalUsage` 的计算由 `[...values()].reduce()` 改为直接迭代累加,避免频繁轮询引发的垃圾回收波动。 - **孤立通知记录自动清理**:在配置移除提供商模型池时,自动清理关联的通知限频缓存。 ### v0.7.37 - **通过 AsyncLocalStorage 隔离请求上下文**:使用 Node.js 的 `node:async_hooks` 将解析后的密钥 (`pickedRef`)、启动时间和重试严格限定在单个请求上下文内,彻底消除并发请求间的竞态条件与误罚。 - **流异常自动故障转移**:修复流在首个 token 返回前抛出传输异常(如 HTTP 429)直接终止的问题。若未发送内容块,现在会自动触发 `isSwitchableError` 并顺畅切换到备用密钥。 - **避免在 rotate() 中直接修改共享状态**:遍历候选列表改用纯净的局部切片,不再直接覆盖修改 `pool.weightedRefs`。 - **测试成功后自动解除隔离**:在设置界面通过沙箱成功验证密钥有效性后,自动清除 `failedUntil` 和 `brokenUntil` 惩罚标记。 - **定期内存压缩清理**:将 `compactUsage(pool, 30, now)` 接入 30 秒后台巡检定时器,杜绝超长运行环境下的内存增长。 - **并发环境下的精确延迟统计**:为每个请求独立计时,避免全局变量被并发请求覆盖导致 p50/p95 延迟失真。 ### v0.7.36 - **架构精简与稳定性加固**:移除 6 个过度设计的模块(`shadow`、`incident`、`agent-budget`、`region`、`canary`、`maintenance`)与废弃端点。 - **buildRuntime 高性能记忆化**:消除每个流式 token/chunk 上的深拷贝与模式重解析开销。 - **原子轮询指针推进**:并发请求在选定候选密钥时立即推进指针,消除并发工具调用中的竞争条件。 - **增强的可切换错误检测**:直接解析 HTTP 状态码(`429`, `401`, `403`, `5xx`)与 gRPC 状态码(`RESOURCE_EXHAUSTED`, `UNAVAILABLE`)。 - **用户友好的耗尽提示**:密钥池耗尽时返回带恢复倒计时的清晰通知。 - **智能轮询(Smart Polling)**:标签页不活动时暂停客户端后台轮询。 ### v0.7.35 - **生命周期清理**: 将 `credentials.resolve` 猴子补丁和 `ctx.on` 事件监听器 (`llm/stream`, `agent/request-error`) 封装在 `ctx.effect` 作用域内,确保卸载时自动注销并恢复原始方法 (#238, #239)。 - **配置密钥角色**: 在 `Config` Schema 中为 `incidentGitHubToken` 和 `webhookActionToken` 增加 `.role('secret')`,避免明文泄露并在 UI 中掩码显示 (#237)。 - **设置架构与状态**: 在设置卡片中增加原生 `settingsScope` 绑定支持,保留 HTTP 桥接安全回退机制 (#235)。 - **原生设计系统 (Changed in v0.8.3)**: 与 `dsh-clinebot` 基准对齐:模块化分区卡片、实时密钥池指标块、胶囊状态徽章与全局主题语义 token (#281)。 - **本地化与文案 (Changed in v0.8.2)**: 插件仅注册英文源字符串 `en`;俄文/中文由 DSH 核心 locale 与 translation 插件通过 `props.t` 提供。活动语言回退:snapshot → 首个 `navigator.languages` → `en`。已移除 `settings.section` 回退与内置 `ru`/`zh` 表 (#236, #275, #277)。 - **死代码清理**: 移除 header-chip 迁移后残留的废弃 `mountDashboard` 函数 (#240)。 ### 熔断器参数(v0.8.0) | 参数 | 类型 | 默认 | 说明 | |---|---|---|---| | `circuitBreakerEnabled` | boolean | `true` | 启用熔断 | | `circuitBreakerThreshold` | number | `5` | 连续失败阈值 | | `circuitBreakerOpenMs` | number | `30000` | 打开时长 ms | | `circuitBreakerHalfOpenProbes` | number | `1` | 半开探测次数 |