From 96587f1ad0a3f22e407af024990e8f22121e2ccc Mon Sep 17 00:00:00 2001 From: hex2077 Date: Sat, 20 Dec 2025 17:43:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(provider-pool-manager):=20=E7=94=A8LRU?= =?UTF-8?q?=E7=AD=96=E7=95=A5=E6=9B=BF=E6=8D=A2=E8=BD=AE=E8=AF=A2=E7=AE=97?= =?UTF-8?q?=E6=B3=95=E4=BB=A5=E5=9D=87=E8=A1=A1=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进提供商选择逻辑,从简单的取模轮询改为基于最后使用时间和使用次数的LRU策略,确保在动态变化的可用列表情况下也能平均分配到各个账号 --- src/provider-pool-manager.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/provider-pool-manager.js b/src/provider-pool-manager.js index 119ca42..6a5bc98 100644 --- a/src/provider-pool-manager.js +++ b/src/provider-pool-manager.js @@ -144,17 +144,16 @@ export class ProviderPoolManager { return null; } - // 为每个提供商类型和模型组合维护独立的轮询索引 - // 使用组合键:providerType 或 providerType:model - const indexKey = requestedModel ? `${providerType}:${requestedModel}` : providerType; - const currentIndex = this.roundRobinIndex[indexKey] || 0; - - // 使用取模确保索引始终在有效范围内,即使列表长度变化 - const providerIndex = currentIndex % availableAndHealthyProviders.length; - const selected = availableAndHealthyProviders[providerIndex]; - - // 更新下次轮询的索引 - this.roundRobinIndex[indexKey] = (currentIndex + 1) % availableAndHealthyProviders.length; + // 改进:使用“最久未被使用”策略(LRU)代替取模轮询 + // 这样即使可用列表长度动态变化,也能确保每个账号被平均轮到 + const selected = availableAndHealthyProviders.sort((a, b) => { + const timeA = a.config.lastUsed ? new Date(a.config.lastUsed).getTime() : 0; + const timeB = b.config.lastUsed ? new Date(b.config.lastUsed).getTime() : 0; + // 优先选择从未用过的,或者最久没用的 + if (timeA !== timeB) return timeA - timeB; + // 如果时间相同,使用使用次数辅助判断 + return (a.config.usageCount || 0) - (b.config.usageCount || 0); + })[0]; // 更新使用信息(除非明确跳过) if (!options.skipUsageCount) {