mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
feat: 自适应 RPM 未学习时不限制,改为碰壁学习策略
- 移除自适应模式的默认初始限制(RPMDefaults.INITIAL_LIMIT) - 未学习到边界前不限制 RPM,让系统自由运行直到遇到 429 - 前端自适应 Key 显示学习到的值或"探测中"状态 - 批量余额查询改为并行执行,提升性能
This commit is contained in:
@@ -156,8 +156,8 @@ export interface EndpointAPIKey {
|
||||
updated_at: string
|
||||
// 自适应 RPM 字段
|
||||
is_adaptive?: boolean // 是否为自适应模式(rpm_limit=NULL)
|
||||
effective_limit?: number // 当前有效 RPM 限制(自适应使用学习值,固定使用配置值)
|
||||
learned_rpm_limit?: number // 学习到的 RPM 限制
|
||||
effective_limit?: number | null // 当前有效 RPM 限制(自适应使用学习值,固定使用配置值,未学习时为 null)
|
||||
learned_rpm_limit?: number | null // 学习到的 RPM 限制
|
||||
// 滑动窗口利用率采样
|
||||
utilization_samples?: Array<{ ts: number; util: number }> // 利用率采样窗口
|
||||
last_probe_increase_at?: string // 上次探测性扩容时间
|
||||
|
||||
@@ -323,7 +323,11 @@
|
||||
<!-- RPM 限制信息(第二位) -->
|
||||
<template v-if="key.rpm_limit || key.is_adaptive">
|
||||
<span class="text-muted-foreground/40">|</span>
|
||||
<span>{{ key.is_adaptive ? '自适应' : key.rpm_limit }} RPM</span>
|
||||
<span v-if="key.is_adaptive">
|
||||
{{ key.learned_rpm_limit != null ? `${key.learned_rpm_limit}` : '探测中' }} RPM
|
||||
<span class="text-muted-foreground/60">(自适应)</span>
|
||||
</span>
|
||||
<span v-else>{{ key.rpm_limit }} RPM</span>
|
||||
</template>
|
||||
<span class="text-muted-foreground/40">|</span>
|
||||
<!-- API 格式:展开显示每个格式、倍率、熔断状态 -->
|
||||
|
||||
@@ -18,7 +18,6 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from src.api.base.admin_adapter import AdminApiAdapter
|
||||
from src.api.base.pipeline import ApiRequestPipeline
|
||||
from src.config.constants import RPMDefaults
|
||||
from src.core.exceptions import InvalidRequestException, translate_pydantic_error
|
||||
from src.database import get_db
|
||||
from src.models.database import ProviderAPIKey
|
||||
@@ -226,7 +225,7 @@ class ListAdaptiveKeysAdapter(AdminApiAdapter):
|
||||
is_adaptive=key.rpm_limit is None,
|
||||
rpm_limit=key.rpm_limit,
|
||||
effective_limit=(
|
||||
(key.learned_rpm_limit if key.learned_rpm_limit is not None else RPMDefaults.INITIAL_LIMIT)
|
||||
key.learned_rpm_limit # 自适应模式:使用学习值,未学习时为 None(不限制)
|
||||
if key.rpm_limit is None
|
||||
else key.rpm_limit
|
||||
),
|
||||
@@ -279,7 +278,7 @@ class ToggleAdaptiveModeAdapter(AdminApiAdapter):
|
||||
"is_adaptive": is_adaptive,
|
||||
"rpm_limit": key.rpm_limit,
|
||||
"effective_limit": (
|
||||
(key.learned_rpm_limit if key.learned_rpm_limit is not None else RPMDefaults.INITIAL_LIMIT)
|
||||
key.learned_rpm_limit # 自适应模式:使用学习值,未学习时为 None(不限制)
|
||||
if is_adaptive
|
||||
else key.rpm_limit
|
||||
),
|
||||
|
||||
@@ -13,7 +13,6 @@ from sqlalchemy.orm import Session
|
||||
from src.api.base.admin_adapter import AdminApiAdapter
|
||||
from src.api.base.models_service import invalidate_models_list_cache
|
||||
from src.api.base.pipeline import ApiRequestPipeline
|
||||
from src.config.constants import RPMDefaults
|
||||
from src.core.crypto import crypto_service
|
||||
from src.core.exceptions import InvalidRequestException, NotFoundException
|
||||
from src.core.key_capabilities import get_capability
|
||||
@@ -539,11 +538,7 @@ def _build_key_response(
|
||||
"avg_response_time_ms": round(avg_response_time_ms, 2),
|
||||
"is_adaptive": is_adaptive,
|
||||
"effective_limit": (
|
||||
(
|
||||
key.learned_rpm_limit
|
||||
if key.learned_rpm_limit is not None
|
||||
else RPMDefaults.INITIAL_LIMIT
|
||||
)
|
||||
key.learned_rpm_limit # 自适应模式:使用学习值,未学习时为 None(不限制)
|
||||
if is_adaptive
|
||||
else key.rpm_limit
|
||||
),
|
||||
|
||||
8
src/services/cache/aware_scheduler.py
vendored
8
src/services/cache/aware_scheduler.py
vendored
@@ -315,7 +315,7 @@ class CacheAwareScheduler:
|
||||
获取有效的 RPM 限制
|
||||
|
||||
新逻辑:
|
||||
- rpm_limit=NULL: 启用自适应,使用 learned_rpm_limit(如无学习记录则使用默认初始值)
|
||||
- rpm_limit=NULL: 启用自适应,使用 learned_rpm_limit(如无学习记录则不限制,等待碰壁学习)
|
||||
- rpm_limit=数字: 固定限制,直接使用该值
|
||||
|
||||
Args:
|
||||
@@ -330,10 +330,8 @@ class CacheAwareScheduler:
|
||||
if learned is not None:
|
||||
return int(learned)
|
||||
|
||||
# 未学习到值时,使用默认初始限制,避免无限制打爆上游
|
||||
from src.config.constants import RPMDefaults
|
||||
|
||||
return int(RPMDefaults.INITIAL_LIMIT)
|
||||
# 未学习到值时,不限制,让其碰壁后再学习真实边界
|
||||
return None
|
||||
else:
|
||||
# 固定限制模式
|
||||
return int(key.rpm_limit)
|
||||
|
||||
@@ -599,7 +599,7 @@ class ProviderOpsService:
|
||||
self, provider_ids: Optional[List[str]] = None
|
||||
) -> Dict[str, ActionResult]:
|
||||
"""
|
||||
批量查询余额
|
||||
批量查询余额(优先返回缓存,后台异步刷新)
|
||||
|
||||
Args:
|
||||
provider_ids: Provider ID 列表,None 表示查询所有已配置的
|
||||
@@ -616,9 +616,24 @@ class ProviderOpsService:
|
||||
if p.config and p.config.get("provider_ops")
|
||||
]
|
||||
|
||||
# 并行查询,使用缓存优先策略
|
||||
tasks = [
|
||||
self.query_balance_with_cache(provider_id, trigger_refresh=True)
|
||||
for provider_id in provider_ids
|
||||
]
|
||||
results_list = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
results = {}
|
||||
for provider_id in provider_ids:
|
||||
results[provider_id] = await self.query_balance(provider_id)
|
||||
for provider_id, result in zip(provider_ids, results_list):
|
||||
if isinstance(result, Exception):
|
||||
logger.warning(f"查询余额失败: provider_id={provider_id}, error={result}")
|
||||
results[provider_id] = ActionResult(
|
||||
status=ActionStatus.UNKNOWN_ERROR,
|
||||
action_type=ProviderActionType.QUERY_BALANCE,
|
||||
message=str(result),
|
||||
)
|
||||
else:
|
||||
results[provider_id] = result
|
||||
|
||||
return results
|
||||
|
||||
|
||||
@@ -211,7 +211,11 @@ class AdaptiveRPMManager:
|
||||
if not is_adaptive:
|
||||
return None
|
||||
|
||||
current_limit = int(key.learned_rpm_limit or self.DEFAULT_INITIAL_LIMIT)
|
||||
# 未碰壁学习前,不主动设置限制,让系统自由运行直到遇到 429
|
||||
if key.learned_rpm_limit is None:
|
||||
return None
|
||||
|
||||
current_limit = int(key.learned_rpm_limit)
|
||||
|
||||
# 获取已知边界(上次触发 429 时的 RPM)
|
||||
known_boundary = key.last_rpm_peak
|
||||
|
||||
@@ -102,10 +102,8 @@ class RequestExecutor:
|
||||
|
||||
# 获取有效的 RPM 限制(自适应或固定)
|
||||
if key.rpm_limit is None:
|
||||
# 自适应模式:优先使用学习值,否则使用默认初始限制,避免无限制打爆上游
|
||||
from src.config.constants import RPMDefaults
|
||||
|
||||
effective_key_limit = int(key.learned_rpm_limit or RPMDefaults.INITIAL_LIMIT)
|
||||
# 自适应模式:使用学习值,未学习时为 None(不限制,等待碰壁学习)
|
||||
effective_key_limit = int(key.learned_rpm_limit) if key.learned_rpm_limit is not None else None
|
||||
else:
|
||||
effective_key_limit = int(key.rpm_limit)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user