refactor: 自适应 RPM 从边界记忆改为多次观察确认 + 置信度衰减

将自适应 RPM 限制算法从"单次 429 即设限"重构为基于置信度的学习机制:

- 收到 429 时仅记录观察(本地 RPM + 上游 header 限制值),不立即设限
- 有 header 的观察需 2 次一致确认,无 header 需 3 次一致确认
- confidence 随时间自然衰减,确保限制永远不会固化
- confidence 低于阈值时停止本地 RPM 限制,429 直接透传客户端
- 统一 get_effective_limit 入口,消除多处重复的限制获取逻辑
- Admin API 增加置信度、观察数量等诊断字段
This commit is contained in:
fawney19
2026-02-10 14:58:15 +08:00
parent fc1ad44346
commit 4276e7835c
6 changed files with 388 additions and 282 deletions

View File

@@ -57,6 +57,12 @@ class AdaptiveStatsResponse(BaseModel):
last_429_type: str | None
adjustment_count: int
recent_adjustments: list[dict]
# 置信度相关
learning_confidence: float | None = Field(None, description="学习置信度 (0.0-1.0)")
enforcement_active: bool | None = Field(None, description="是否正在执行本地 RPM 限制")
observation_count: int = Field(0, description="429 观察记录数")
header_observation_count: int = Field(0, description="带 header 的观察记录数")
latest_upstream_limit: int | None = Field(None, description="最近一次上游 header 限制值")
class KeyListItem(BaseModel):
@@ -219,6 +225,7 @@ class ListAdaptiveKeysAdapter(AdminApiAdapter):
query = query.filter(ProviderAPIKey.provider_id == self.provider_id)
keys = query.all()
adaptive_manager = get_adaptive_rpm_manager()
return [
KeyListItem(
id=key.id,
@@ -227,11 +234,7 @@ class ListAdaptiveKeysAdapter(AdminApiAdapter):
api_formats=key.api_formats or [],
is_adaptive=key.rpm_limit is None,
rpm_limit=key.rpm_limit,
effective_limit=(
key.learned_rpm_limit # 自适应模式:使用学习值,未学习时为 None不限制
if key.rpm_limit is None
else key.rpm_limit
),
effective_limit=adaptive_manager.get_effective_limit(key),
learned_rpm_limit=key.learned_rpm_limit,
concurrent_429_count=key.concurrent_429_count or 0,
rpm_429_count=key.rpm_429_count or 0,
@@ -275,16 +278,13 @@ class ToggleAdaptiveModeAdapter(AdminApiAdapter):
context.db.refresh(key)
is_adaptive = key.rpm_limit is None
adaptive_manager = get_adaptive_rpm_manager()
return {
"message": message,
"key_id": key.id,
"is_adaptive": is_adaptive,
"rpm_limit": key.rpm_limit,
"effective_limit": (
key.learned_rpm_limit # 自适应模式:使用学习值,未学习时为 None不限制
if is_adaptive
else key.rpm_limit
),
"effective_limit": adaptive_manager.get_effective_limit(key),
}
@@ -312,6 +312,11 @@ class GetAdaptiveStatsAdapter(AdminApiAdapter):
last_429_type=stats["last_429_type"],
adjustment_count=stats["adjustment_count"],
recent_adjustments=stats["recent_adjustments"],
learning_confidence=stats.get("learning_confidence"),
enforcement_active=stats.get("enforcement_active"),
observation_count=stats.get("observation_count", 0),
header_observation_count=stats.get("header_observation_count", 0),
latest_upstream_limit=stats.get("latest_upstream_limit"),
)