2.6 KiB
Account Scheduling Flow(SelectAccountWithLoadAwareness)
本文档对应后端主调度入口 SelectAccountWithLoadAwareness,用于说明 Anthropic 网关的账号选择流程、亲和策略与关键过滤规则。
代码入口与引用
- 调度主入口:
backend/internal/service/gateway_service.go中的SelectAccountWithLoadAwareness - 亲和详情 API:
backend/internal/handler/admin/account_affinity_handler.go中的GetAffinityDetails - Admin 路由:
backend/internal/server/routes/admin.go(/api/v1/admin/accounts/:id/affinity-details)
流程概览(修正版)
-
解析输入参数
sessionHash、stickyAccountID、affinityClientID(metadata.user_id 提取)、affinityUserID(sub2api user id)。 -
Claude Code 限制与分组降级
先执行checkClaudeCodeRestriction,必要时替换groupID。 -
Legacy / Load-aware 分支
若concurrencyService == nil || !LoadBatchEnabled走传统路径;否则走负载感知路径。 -
Layer 1(模型路由优先)
- 路由候选过滤(排除、平台、模型、配额、窗口费用、RPM)
- 路由范围内 sticky 优先
- 路由内按(优先级 > 负载 > 亲和数 > LRU)尝试获取槽位
-
Layer 1.3(pinned_users 预处理)
仅做UpdateAffinity预热,不直接做调度决策。 -
Layer 1.4(客户端亲和调度)
按亲和记录尝试命中;allow_switch=false且无一票放行时尝试等待计划,否则返回ErrAffinityNoSwitch。 -
Layer 1.5(粘性会话)
仅在!affinityHit && routingAccountIDs==0时生效;先过shouldClearStickySession。 -
Layer 2(负载感知选择)
分层过滤:优先级 -> 亲和区(单维客户端) -> 最低负载 -> 最少亲和客户端 -> LRU。 -
Layer 3(兜底排队)
按FallbackSelectionMode(last_used或random)排序后返回等待计划。
注意:此层不是“按最低负载”。
关键业务规则(2026-03)
无客户端 ID 时过滤亲和 Anthropic 账号
当 metadata.user_id 无法提取 client_id(即 affinityClientID == "")时:
- 会直接过滤 Anthropic 平台且开启客户端亲和 的账号(覆盖 OAuth / SetupToken / API Key / Bedrock 等类型)
- 该规则只看平台与亲和开关,不再限定账号类型
设计目标:避免无客户端标识的请求误用客户端亲和账号。
亲和详情 API 契约
GET /api/v1/admin/accounts/:id/affinity-details 返回结构(后端已对齐前端):
users[]:包含user_id、user_email、client_count、is_pinned、clients[]total_userstotal_clientspinned_users