Skip to content

智能模型路由(Router 服务)

版本:v0.13.2+ · 状态:阶段一(容灾与信号底座)+ 阶段二(任务感知与模型池)已落地

Router 是 VeyraOS 的智能模型路由服务,承担模型调用的「路由大脑」与「信号闭环」角色。它把 LiteLLM 从「模型转发器」升级为可观测、可容灾、可审计、按任务自动选模型的智能路由平台。

架构定位

Router 与其专属的 LiteLLM 实例组成独立部署栈(独立 namespace veyra-router),与主系统零耦合:不引用主系统的 Deployment/Service/Secret,不使用主系统的 LiteLLM 实例与数据库。成熟后主系统再以服务方式集成。

调用方(per-key,OpenAI 兼容)


  LiteLLM(:4000,L1 供应适配层 + 数据面;本栈专属 wrapper 实例)
        │  GenericAPILogger 批量上报调用事件(脱敏,不带对话内容)

  Router 服务(:8005,L4 路由大脑 + L2 信号闭环)


  PostgreSQL(栈内两个独立 database:router / router_litellm)
  • 数据面自包含:调用方直连本栈 LiteLLM /v1/chat/completions;模型注册、key 签发、计费归因全部在本栈 LiteLLM 实例内完成(Admin API + master key)。
  • 控制面独立:Router 不查询 manager 或其他服务,只依赖本栈 LiteLLM(其 L1 适配层)与自身 PG 库。
  • 归属反解自包含:签发方在创建 LiteLLM key 时把 {instance_id, group_id} 写入 key metadata;Router 周期同步 LiteLLM /key/listapi_key_registry 表,事件摄入时按 user_api_key_hash(= key 的 sha256,与 key list 的 token 一致)精确反解归属。

阶段一能力清单

能力说明
自动容灾LiteLLM Router 失败重试 + 连续失败冷却(num_retries=2allowed_fails=3cooldown=60s),上游 429/5xx 自动重试并隔离故障通道;降级链(fallbacks)为可配置项,默认关闭
健康画像每 (模型组, 通道) 5min 滚动窗口聚合:错误率(分母 = 成功 + 上游失败,model_health.window_health_base 随快照持久化供跨通道归并)/ 首字延迟 p50 / p99 / 流式生成速度 p50(tokens/s,e2e 耗时受输出长度主导不可比,故不采用)/ 三态(正常·恢复中·不可用),model_health 表快照;供应商账户级聚合(账户整体状态 + 每个上游模型一条通道记录——同通道跨模型组归并;账户级只汇聚调用/错误等计数类指标,首字延迟/生成速度等性能指标只在模型层面统计,零流量账户显式暴露;停用/删除通道即退出健康监控(快照行随生命周期同步清理,已删部署不留幽灵数据))与近 7 天历史。控制台统一以 TTFT / TPOT 术语展示(TPOT = 1000/生成速度,ms/token)
决策日志每次 LLM 调用一行 routing_decisions永久保留——账务凭证属性;按月 RANGE 分区 + DEFAULT 兜底分区,worker 滚动预建未来分区,启动迁移把存量平面表幂等转换为分区表,PK 为 (created_at, id) 含分区键;老分区可 detach 归档),含错误四问分类(配置/客户端/上游/限流)、首字延迟与流式生成速度落库(ttft_ms/tps,历史统计口径统一为 TTFT)、fallback 链标记、成本与 token 用量;控制台按决策链路呈现——模型池调用 = 分类决策 + 动态权重两段、直连模型调用 = 仅动态权重一段(按 routed_model 有无自然区分),链路末段通道附着供应商账户名与上游模型
审计存证决策日志日级链式 sha256 锚(routing_decision_anchors 长青表),支持重放校验与篡改/断链检测
权重再平衡普通模型组多上游按 健康×延迟×成本 动态调权(热写回 LiteLLM,默认关闭,UA_ROUTING_WEIGHT_ENABLED=true 开启);权重为供应商模型级语义——同一供应商模型的多协议通道共享组目标(同值写回各成员部署),组间竞争、组内不按协议竞争(协议偏好是路由阶段的事);每次调整落档 routing_weight_events(30 天 TTL,含调整前后权重、目标权重与错误率/首字延迟/成本三因子依据),控制台决策日志页可查
Wrapper 钩子engines/litellm/veyra_hooks.py:路由决策响应头回传(x-veyra-routing-*/x-veyra-cls-*)、per-key 质量阈值注入、RPO 风险定价信号、G2 健康画像软转移、空回复保险、供应商模型优先路由(权重选组 → 协议偏好选通道 → veyra:dep:* 标签钉住,见关键设计约束)——全部默认 shadow 观察模式,环境变量翻牌,任何异常一律放行(绝不影响请求路径);流式 usage 回传走 LiteLLM 原生 general_settings.always_include_stream_usage(生成速度指标与输出 token 计费的分子来源,litellm.yaml 已开启)

阶段二能力清单

能力说明
任务语义分类器engines/litellm/veyra_classifier.py:BGE 嵌入原型(19 任务类型 × SIMPLE/MEDIUM/COMPLEX/REASONING 四档)+ 难度信号修正(长度/代码块/轮次深度/工具密度升档,高风险关键词地板 COMPLEX);ONNX INT8 进程内推理,prompt 不出网关;UA_CLASSIFIER_MODE=off/shadow/active 三态
智能模型组(模型池)POST /api/router/model-groups 创建即渲染为 LiteLLM 池部署(热生效):smart 智能路由(成员画像自动推导难度阶梯)/ tiered 按难度选择 / cost_first 成本优先 / quality_first 质量优先(后两者走 bandit 从真实反馈学习);支持关键词分档规则与成本↔质量偏好权重
分类粘性会话短续轮(「继续」等)继承首轮分类结果,同会话语义连贯
级联观测(N5 shadow)低置信偏低档分类记录「假设级联复核」(不调二次模型,零成本收集触发率数据)
飞轮聚合面板数据GET /api/router/routing-flywheel/summary:决策量/环比、分类覆盖率、shadow 分歧率、日×档位趋势、任务类型分布、按 LiteLLM 实时定价估算的节省额
训练语料采样POST /api/router/internal/prompt-samples(默认关,采样率页面可配——控制台「分类器与训练 → 采样配置」,runtime_config 覆写优先 env),分类器校准/重训语料,30 天 TTL

关键设计约束

  • 错误四问:401/403/404 → 配置错误(不计健康,人工修正);400/422 → 客户端错误(不计健康);429 且命中我方限流签名(ProxyRateLimitError 类名或「Max budget / Rate Limit Handler」等 limiter 特征串)→ 限流(throttle,平台主动拒绝——key 速率/并发/月度预算超限,不计通道健康);其余 429/5xx/408/超时 → 上游错误(计入健康,触发冷却/fallback);无状态码且类名缺失时按消息签名兜底(鉴权拒绝归 config)。无模型标识且未带 key 的认证拒绝(公网扫描器探测)不入明细表,计 INGEST_STATS.scanner_dropped
  • 供应商模型优先路由:wrapper 按入站协议(/v1/messages → anthropic、/v1/responses → responses、其余 → chat)与通道标签做两级选择——先按权重(静态权重/动态再平衡,均为供应商模型级:同组多协议通道共享同值)在「有健康通道」的供应商组间加权随机,再在选中组内按协议偏好选通道(同入站协议优先 → 预置顺序 chat → anthropic → responses 回落,缺同协议通道时由 LiteLLM 翻译);选定通道用 veyra:dep:* 唯一标签 + 请求级标签过滤精确钉住(router 级不开,客户端 tags 行为不变)。健康口径 = 不在 LiteLLM 冷却名单(429/401/408/404/5xx 原生冷却)且进程内失败计数未达阈值——LiteLLM 刻意不对 APIConnectionError 冷却(防自身网络抖动误杀),但端点宕机最常见的形态恰是连接失败,wrapper 读 Router 每次失败回调维护的滚动分钟窗计数(TTL 60s 自动恢复,阈值 = allowed_fails)补上这个盲区;多副本时冷却名单经 Redis 跨副本共享,失败计数各副本独立收敛。故障转移:钉住通道失败后,下一请求重选时该组若无健康成员即自然跨组降级;组内全部部署缺标签(未回填/池别名/带前缀直通名)不插手,交 LiteLLM 原行为。
  • 软偏好硬兜底:Router 与钩子的全部智能都只降优先级、绝不阻断请求;Router 服务自身不可用时 LiteLLM 照常转发(事件上报 fire-and-forget)。
  • 多副本拆分(api / worker)router-api ×2(UA_WORKER_ENABLED=false + UA_MIGRATE_ON_STARTUP=false,无状态 HTTP,console session 为 HMAC 无状态 token 任意副本可服务)+ router-worker ×1(全部后台循环 + 启动迁移单点执行)。事件摄入无状态化(2026-09-17 起):摄入只写库不维护进程状态——健康窗口从摄入进程内存改为读 routing_decisions 近 5min 明细聚合(尾部连败/百分位语义不变,worker 重启不再清零窗口),is_fallback 改 DB 预取 + 批内累积(跨副本一致);LiteLLM 事件上报因此改指 router api 双副本 Service,worker 重启/滚动更新不再产生丢事件窗口。幂等:routing_decisions.event_id 部分唯一索引((event_id, created_at),分区表约束须含分区键)+ ON CONFLICT DO NOTHING,重复 flush/重试静默去重不双计;摄入丢弃计数(received/accepted/deduped/malformed/constraint_dropped/oversized_body)经 GET /internal/ingest-stats 暴露。数据面 litellm 多副本(×2):冷却名单/限流计数/spend 经 Redis(DualCache 两级)跨副本共享;分类器 embedder 每副本镜像内置,无共享态。
  • 事件端点防伪造:未配置 UA_LITELLM_CALLBACK_TOKEN/api/router/internal/events 拒绝一切写入。
  • 数据回流分流(阶段 1,2026-09 起):摄入落库成功后决策指标行(无明文)转发 Kafka inference-events,prompt 采样脱敏后转发 inference-samples(不脱敏不出 VPC);发送失败落 pod 本地 WAL 60s 重放,不阻塞摄入主路径;worker 自消费攒批写 OSS 语料冷层(lake/<topic>/dt=/hour=/part-*.jsonl.gz,offset 上传成功才 commit)。Kafka 为栈内自建 KRaft 单节点(deploy/router-prod/kafka.yaml,托管起步价不划算的决策记录见数据回流文档选型表)。阶段 2 起第二路消费者ch_writer,group=router-ch-writer)攒批写栈内自建 ClickHouse 单节点,供 console「实时监控」页分钟级查询;worker 每 60s 评估告警规则(通道不可用/上游错误率突增/费用速率异常)落 alert_events 并推飞书群机器人。UA_KAFKA_ENABLED=false(默认)时全链路 no-op。详见 数据回流管道
  • 事件体量上限:事件体含完整 messages/response,单事件可达数十 KB~MB。/api/router/internal/events/prompt-samples 流式读取并在超过 UA_LITELLM_CALLBACK_MAX_BODY_BYTES(默认 2MB)时整包丢弃(仍回 2xx accepted: 0,LiteLLM 无重试),防止大对象驻留抬升内存高水位。

部署

独立部署栈 deploy/router/(独立 namespace veyra-router),主系统部署流程(deploy/ci/deploy.sh)不包含本栈。详细步骤与验证脚本见 deploy/router/README.md

  • 镜像:veyraos/routerservices/router/Dockerfile)、veyraos/litellm(wrapper,engines/litellm/Dockerfile)与 veyraos/console-router(运营控制台,apps/console-router/Dockerfile),构建 make docker-router / make docker-litellm / make docker-console-router
  • 数据库:栈内两个独立库 router / router_litellm;测试环境由 worker / litellm 的 initContainer 幂等创建,生产 RDS 无超管权限需 DBA 预建(PG 实例由栈自己的 Secret 指定,库级隔离);schema 迁移(create_all + 增量列补齐,幂等)仅在 router-worker 单点执行(UA_MIGRATE_ON_STARTUP),api 副本跳过避免并发 DDL 竞争。
  • 共享缓存:litellm 多副本的冷却/限流/花费一致性依赖 Redis(router-secretredis-host/port/password);测试环境用 redis-standin.yaml 替身,生产指向阿里云 Redis。
  • 配置项(env 前缀 UA_):UA_DATABASE_URLUA_LITELLM_BASE_URLUA_LITELLM_MASTER_KEYUA_LITELLM_CALLBACK_TOKENUA_LITELLM_CALLBACK_MAX_BODY_BYTES(默认 2MB)、UA_ROUTING_WEIGHT_ENABLED(默认 false)、UA_CONSOLE_ADMIN_PASSWORD / UA_CONSOLE_SECRET_KEY(运营控制台)、UA_PUBLIC_API_BASE_URL(控制台「快速接入」页展示的对外接入地址,服务根地址不含 /v1,仅展示用途)等,完整见 services/router/app/settings.py
  • 对外入口:控制台挂 router.<域名>(或 NodePort 31116);数据面(OpenAI 兼容)挂 routerapi.<域名>,ingress 暴露 /v1 路径前缀到 litellm:4000(Anthropic 协议经 /anthropic 前缀 + StripPrefix 中间件映射到同一数据面)与 /api/pricing 到 router:8005(公开价格表,New API 兼容,无鉴权只读),管理面端点不对公网开放(见 deploy/router/ingress.yaml)。

运营控制台(Console)

独立前端 apps/console-router(Vue 3 + Element Plus),与主系统管理台零耦合,随栈部署(NodePort 31116,域名入口 router.<域名>deploy/router/ingress.yaml)。面向调用方的文档中心 apps/docs-router(VitePress)打进同一镜像、挂在同域 /docs/ 下(仿主站 admin nginx 先例),含快速开始、用户指南、接入工具与平台(15 个主流工具/平台逐一单页详述)与 API 参考;控制台「快速接入」页的工具接入入口同源跳转对应文档页。

  • 认证与账号(P1-b → SSO → P2 org 语义切换):调用方登录走 VeyraOS 账号统一登录(OIDC 授权码流 + PKCE,console 作 RP,IdP 为 account 服务,UA_CONSOLE_SSO_ENABLED 等六项配置齐备后生效(含 operator 判定查 staff 绑定用的 UA_OAUTH_ACCOUNT_INTERNAL_TOKEN),见 deploy/router/router.yaml 注释与 #391 设计文档);未登录访问控制台页面由服务端 302 直跳授权页——nginx auth_request 复用 /auth/me 探测会话,401 反代 GET /api/router/console/auth/sso/entry,由 router 后端生成 PKCE/state(verifier 暂存短时 HttpOnly cookie,回调兑换复核 state 用后即焚),浏览器不再加载 SPA 即开始登录(消除登录页闪烁;/oauth/callback/login 与静态资源豁免探测,/login?local=1 应急通道保留)。本地账号体系(console_orgs / console_users 表)已随 P2 退役(#480 拍板:不迁存量;表留存 DB 不再读写),env admin 保留为应急运营通道。id_token 的 display_name claim 由 account 侧回退链兜底(账号名 → 手机号 → email,空值不再裸露用户 id)。会话为 HMAC 签名 cookie,载荷含角色与 org 归属(org 主数据归 account organizations——org_id = account 组织 UUID,instance_id 归因链语义不变,String(64) 容纳无 schema 改动)。
  • org 绑定与切换(P2):caller 登录时经 account /internal/users/{id}/organizations 绑默认 org——与账号中心工作区切换器同语义(最近活跃企业优先,无企业回退个人 workspace),查询失败降级无 org(不阻断登录,/my 面提示未关联组织)。多 org 用户在控制台头部切换(GET /auth/my-orgs 列表 + POST /auth/switch-org 校验归属后重签本地会话,不动 IdP——#391 挂起的 switch-org 拍板项落地)。存量未迁移 org(本地体系退役前签发的 key)照常归因调用,运营面对不到组织名显示裸 id。
  • 双角色:operator(运营方,全量菜单)/ caller(调用方,仅 /api/router/console/my/* 自助面)。角色来源:SSO 登录签发会话时经 account /internal/platform-staff/{user_id} 点查 platform_staff 绑定——active 且含 router:operator scope → operator,无绑定或查询失败降级 caller(不阻断登录,#391 §4.5 #5);env admin 登录签发 operator。运营端点走 require_operator 守卫(caller 一律 403);调用方数据强制按 instance_id == org_id 隔离(归属在事件摄入时从 key 注册表拷贝)。「路由偏好」页(operator,原「组织管理」)列表 = account 组织投影(/internal/organizations + 进程内 60s 缓存)+ 本栈 key 归属计数;组织级路由偏好 / 预算按 org 管控(org 选择器数据源同上);用户主数据归 account(注册/邀请/成员管理在账号中心,本面不建号)。
  • 凭证隔离:console 面与内部查询面(X-Internal-Token)互不相通;console 前端 nginx 只反代 console 面。
  • 运营面:概览、模型与供应商(三层结构——router_supplier_accounts 供应商账户(供应商类型 + 名称 + 账户级 API 地址/协议端点 + 账户级密钥。新建时可选国内/海外预置供应商(只收录 LiteLLM 原生支持的厂商——名称自动带出,官方默认端点界面只读展示、地址不可填也不落库,通道直连官方端点、deployment 不注入地址;无原生 provider 的厂商如智谱不进预置表)或自定义端点(自建/中转端点及无原生 provider 的厂商一律走此接法——需填写名称,并按协议配置 Anthropic / Chat Completions / Responses 三种上游地址中的至少一个)。供应商类型记录于 provider 列,建供应商模型时前缀按所选类型原生解析;存量未标类型的账户沿用「名称即 LiteLLM 供应商标识」旧规则——名称校验为标识符(字母/数字开头,仅字母/数字/. _ -),裸模型名自动补 {名称}/ 前缀,已带 / 原样保留;存量账户名命中预置类型时启动自动补齐类型(幂等迁移,不回填地址);旧版 zhipu 预置的存量行带地址的自动平移为自定义端点(地址归位 Chat 端点字段,前缀与端点行为不变);旧版 custom_openai / custom_anthropic 两类自定义账户合一为 custom(地址分别归位 Chat / Anthropic 端点字段)。可按账户代调供应商 GET /models 拉取模型列表供参考选择,api_base 缺省按「账户显式地址 → 预置官方端点 → 账户名对应官方端点」回落(自定义端点账户取 Chat / Anthropic 端点地址);价格/上下文在选定供应商模型后按 LiteLLM 内置价格库自动带出参考值(构建期打包进 router 镜像,运行时离线读;未收录的模型——如智谱直连接口新型号——保持手填)。密钥 Fernet 加密落库——services/secrets.py,HKDF-SHA256 派生自 console_secret_key,仅在建/改供应商模型、轮换传播与拉取模型列表时于服务端解密使用,轮换自动同步该账户全部在线 deployment,任何 API 响应/审计/日志只出 has_api_key 布尔、绝不出明文或密文)→ router_suppliers 供应商模型(LiteLLM deployment 存档,1:N;api_key 缺省继承所属账户密钥;protocol 列标识通道协议 chat/anthropic/responses——预置账户按上游前缀推导单协议通道;自定义端点账户按已配置协议各注册一条通道(上游模型按协议取 LiteLLM 原生前缀 openai/anthropic,裸模型名即可不补账户前缀;同地址的 Chat 与 Responses 端点去重合一避免权重翻倍;控制台把同账户同模型的多协议通道合并展示为一行,连通性测试逐协议各探测一次),各通道打 veyra:proto/sup/dep:* 三类标签(dep 标签携带 deployment id 前 8 位唯一后缀——同账户+同上游+同协议可注册多条物理通道,无后缀时钉住集合大于一、容量剔除等 per-dep 语义失效;id 由 router 服务注册时铸造传入,存量旧格式标签启动 reconcile 收敛重写),调用时 wrapper 做供应商模型优先的两级选择(按权重选供应商组 → 组内协议偏好选通道,同入站协议优先、缺时回落翻译——仅配 Chat 端点的账户经桥接同样支持 Responses 入站;详见「关键设计约束」);存量通道启动时自动补齐标签,幂等;账户端点变更时名下在线通道自动按协议对齐(增协议补建通道、删协议摘除通道、改地址热更新 deployment,chat 桥接标记随端点组合重算,幂等可重试))→ router_models 对外模型(调用方 model 字段取值);新增供应商模型强制模型已注册、可选关联账户(api_base 缺省取账户默认地址);一模型多供应商自动负载容灾;通道可选容量(每分钟请求/tokens,按上游配额录入,写穿 litellm_params rpm/tpm 存储,wrapper 自维护固定窗计数剔除——tag 钉住会绕过 LiteLLM 原生 per-deployment 容量过滤(实测钉住通道 30/30 照单全收),故选组前由 wrapper 读固定窗计数(自然分钟;写入经 llm_router.cache INCR 原子回源 Redis 跨副本共享,饱和判定直读 Redis——DualCache 批量读为进程内存优先 + 节流回源,多 worker/多副本下每进程计数稀释会致剔除失效,实测串行流量 12/12 全落饱和通道)剔除饱和通道,选中通道再做 rpm 原子占位(INCR 即判、超限 DECR 回滚并排除重选——并发突发下也不超放,预读只是省 Redis 往返的粗滤);成功事件按实际 tokens 补记 tpm(窗口内滞后,语义同 key 级 limiter);超容通道路由自动避让、调用方无感;同账户同模型的多协议兄弟通道同值扇出防协议穿透;容量随停用/启用生命周期存档恢复);供应商三态生命周期——停用(配置存档,密钥不入档,litellm_params 原生参数经 extra_params 全量保真)/ 启用(按存档重建 deployment,密钥取账户密钥或重填)/ 删除(彻底);在线通道可一键连通性测试(数据面对该通道发起真实轻量调用,返回可用性与耗时,不写库不留审计);LiteLLM 侧绕过控制台产生的未注册模型/未关联账户模型在页面显性暴露并可收纳/关联;池部署归模型组页管理)、模型组 CRUD、动态权重(runtime_config 热生效)、供应商健康(账户主从视图:左列供应商列表 + 右侧供应商概览/近 7 天趋势/通道明细(每个上游模型一条记录,近 7 天趋势通栏展示、次要指标内联),未关联供应商的通道单独归组展示(池入口部署属路由层内部组件,不归入该组;池级失败仍可在决策日志查询);健康历史接口 GET /api/router/console/model-health(账户树)与 /history(分段统计,首字延迟口径))、路由调试(实时决策头)、决策日志(单列表决策链路:模型池调用呈现「分类决策 → 动态权重选路 → 调用结果」、直连调用呈现「动态权重选路 → 调用结果」,详情抽屉含同链兜底重试时间线;链路末段通道带供应商账户与上游模型归属;权重调整记录与审计锚链为独立页签,权重记录按模型/模型组筛选,锚链支持重放校验)、操作记录(console_audit_logs,同事务留痕;按操作人/动作/时间/关键字筛选)、路由偏好(account 组织投影 + 组织级偏好管控,原「组织管理」页,已并入智能路由菜单组)。
  • 调用方自助(P1-b):快速接入首页(三步动线向导——创建 API Key → 配置接入(三协议接入地址:Anthropic Messages / OpenAI Chat Completions / OpenAI Responses,地址按 UA_PUBLIC_API_BASE_URL 服务根地址派生;每协议提供 curl / Python / Node.js 通用示例(按所选模型实时插值),工具与平台接入指南在文档中心 /docs/)→ 发起调用;下接可用模型目录(GET /my/models:智能路由池 + 直调模型,售价口径价格与上下文)与今日用量/7 天趋势)、调用记录(本 org 过滤,响应字段白名单——单条费用为售价口径 charge_cny;落地通道/延迟/救援/健康转移/RPO 等内部实现细节不出调用方面)、API Keys 自助(签发写 LiteLLM metadata 归属、注册表即时可见、明文仅展示一次、删除不可恢复)、偏好设置(调用方仅数据采样开关;路由策略面参数——成本带/延迟敏感/排除通道——由运营侧在「路由偏好」页按组织管控,org_preferences 表 + 写穿 key metadata 的 veyra_pref,两侧写穿互不覆盖)。
  • 偏好生效(P2-a,wrapper veyra_pref 模块):pre-call 从 key metadata 读取偏好参与决策,全部软偏好硬兜底——cost_band 调分类档(cost_first 低置信降档 / quality_first 模糊升档,adaptive 池注入质量下限)、excluded_providers 替换干预目标组(同档成员 → 相邻档就近,全排除维持原决策并记 blocked 信号)、latency_sensitive 收紧健康软转移阈值、prompt_sample_opt_out 跳过采样上报。落库的 veyra_cls_tier 保持分类器原始输出(偏好调整单独记录,shadow 分歧率口径不被污染)。
  • 分类器与训练(P2-a):wrapper 按采样率直报 prompt 采样(独立显式通道,fire-and-forget;流式/非流式调用均覆盖——LiteLLM proxy 流式响应不触发 post-call success 钩子,采样入口在 success 钩子与流式 iterator 钩子两侧分挂互不重复;采样率页面可配——「分类器与训练 → 采样配置」tab 写 runtime_config.prompt_sample_rate,wrapper 经 GET /api/router/internal/sample-config stale-while-revalidate 热拉取 60s 收敛,env UA_PROMPT_SAMPLE_RATE 仅作冷启动/兜底)→ 控制台「分类器与训练」页人工标注(采纳预测/改标,19 类 × 4 档)→ 训练集 JSONL 导出 → 离线训练 → 产物注册(manifest sha256 + feature_version 锚)→ 灰度状态机(registered → staging → active → retired,active 全局唯一并写 runtime_config 生效锚点;wrapper 侧热加载在后续迭代,当前翻转走 artifacts/ 打入镜像重新构建,加载期校验失败自动回退 v1 原型)。
  • 评测 Benchmark(P2-b):评测集管理(手编 JSON / 引用已标注样本生成开放题集,题目带类型 × 难度档标签)→ 导出 → 离线跑批(services/router/scripts/run_benchmark.py,stdlib-only;确定性判分 exact/contains/regex,开放题由评判模型打 1-5 分)→ 结果 JSON 导入(同评测集下跑批名唯一,重复导入幂等拒绝)→ 结果矩阵(总准确率 × 分档准确率 × 延迟 × 成本)→ 阶梯晋级建议(分档准确率过线 0.7 且题数达标推导胜任档,对比 tiered 组 member.tier / smart 组 locked_tier 给升/降档结论,一键跳模型组;跑批控制台内触发在 P3 API 化)。
  • 计费与毛利(P3):全栈人民币 ¥ 口径——rated events:事件摄入时逐单计价routing_decisions.charge_cny 售价快照按调用当时生效规则落库——改价对下一单立即生效,规则快照 10s 进程缓存;失败/限流单不计价);usage_daily 日账本长青表(rollup = rated 快照直加 + 存量未计价行分段冻结兜底——冻结边界前的未计价费用冻在 charge_frozen_cny,隔夜改价完全不追溯;删后插幂等,小时级重滚昨日+今日;明细永久保留后 rollup 是纯聚合层,查询免扫明细);售价规则 pricing_rules(显式售价 ¥/1M tokens 优先,缺省成本加成——全局默认 0.3 可 runtime_config 热调);毛利 = 售价收入 − 通道成本,运营面按模型组/按组织出矩阵 + 环比概览;调用方费用一律售价口径(/my/overview/my/billing),通道买价与加成率不外泄;调用记录与账单支持按 key 过滤/拆分(api_key_hash 摄入时随事件落库,别名读侧解析注册表——已删 key 兜底「已删除」;ix_routing_decisions_org_key_time 复合索引承载过滤与聚合)。单 key 限额(总额 / 日 / 周 / 月四类窗口,总额与周期互斥、周期可叠加)——配置写 key metadata veyra_budget(签发/编辑经 /key/generate/key/update 透传),wrapper pre_call 直读 Redis 判定 + router 摄入侧按事件售价快照记账(rated events——计数与账单同源同数,售价口径与调用方所见一致;此前 wrapper 按通道成本记账存在口径偏差):veyra:budget:{kind}:{key_hash}:{窗口},自然边界 +08:00;pre_call 任一窗口达限抛 429(ProxyRateLimitError 含 Budget has been exceeded 签名与 retry-after,决策行归 throttle),失败/丢弃事件不占额(计数跟随账单落库);pre-call 检查 + 摄入后记账不原子 + flush 秒级滞后:在途调用可能超放一次响应 + 一个 flush 周期量级,语义与 LiteLLM 原生 budget 一致;总量清空 = 控制台调端点 DEL 总额计数(周期窗口到点自动重置);keys 列表用量展示 = router 服务直连同一 Redis 批量 MGET(app/services/budget_usage.py,窗口算法与 wrapper 双侧锚定)。选择 wrapper 自维护而非 LiteLLM 原生 max_budget 的原因:原生只支持单窗口 budget_duration,无法表达「日/周/月可叠加」与「总额手动复位」。价格库自动带出按 fx_usd_cny 汇率(runtime_config 热调,缺省 7.2)把 LiteLLM 内置 USD 价换算为 ¥。
  • 价格运营(pricing ops):价格体系的全生命周期管理。售价快照usage_daily.charge_cny 在 rollup 时按当时生效规则落价——改价不追溯重算历史账单——分段冻结口径:usage_daily.charge_frozen_cny/charge_frozen_until 把上次冻结边界之前的费用冻结(rollup 只按当前规则计算尾段并推进边界,带 10min 滞后吸收在途事件;改价分辨率 = rollup 周期小时级,昨日补滚冻结线钳到日末即隔夜改价完全不追溯;存量 NULL 行由一次性回填循环按当前规则收敛,NULL 回退现算保本),月口径收入 = 快照和 + 未快照行现算。成本漂移检测:rollup 按日 × 通道比对实际入账成本与存档单价期望成本,偏差 >5% 且样本 ≥1 万 tokens 落 cost_drift_alerts(上游 usage 畸形/价格写穿失效的系统级发现通道),台账接口暴露近两日告警、台账页顶部 banner 展示。成本价展示精度可按供应商账户配置price_display_decimals/price_display_rounding,仅展示层,计费始终全精度——对账场景可与供应商账单末位对齐,如截断 vs 四舍五入)。结构化变更留痕price_change_logs 按字段一行(成本价挂通道、售价挂出口名),create/update 通道与售价规则全部写点同事务挂钩(enable 恢复不记——重注入存档价非变更);变更历史页可查(审计流水回答「谁操作过」,本表回答「价格从多少变成多少」;读侧把同次操作的协议兄弟扇出行归并为一行——秒级时间 × 字段 × 旧新值 × 归一裸名标签同键合并,写侧仍 per-channel 留痕供台账「最近变更」取数)。台账总览GET /console/pricing/ledger):出口(模型组 + 直调模型,同名组优先)× 通道成本 × 售价规则 × 毛利率矩阵——成本两级聚合(协议兄弟通道先按(账户, 模型, 裸上游名)归并为一行再聚合——多协议兄弟同价同权,不按协议重复计数;成员模型内按 weight 加权、跨模型简单平均,weight 跨模型不可比;offline 剔除、无价通道计总数不进聚合),毛利率徽章为 1:1 token 混合的单元口径(阈值 pricing_margin_alert_threshold 默认 0.1,显式价才有意义),建议价 = 聚合成本 ×(1 + 有效加成)一键应用写显式规则(与 put_pricing 共享 _upsert_rule,校验/留痕一致)。上游价格同步:worker _price_sync_loop(默认 6h,UA_PRICE_SYNC_ENABLED 可关)两路来源只认上游真实报价——OpenRouter 风格 /models pricing(USD/token 字符串 ×1e6×fx)→ New API 风格 {站点根}/api/pricing(api_base 的 /v1 后缀剥到站点根;ratio×2=USD/1M,按次跳过)自动检测,不做目录兜底(上游查不到价就是查不到);漂移(相对 0.1%/绝对 ¥0.0001)进 price_sync_items 待办(同价 touch/异价更新保首个 old/部分唯一索引防并发),人工确认才生效——采纳走 update_provider 同路径写穿(LiteLLM model_info + 存档行 + 协议兄弟扇出)+ 留痕 source=sync 回指 + 毛利跌破阈值告警名单。公开价格表 GET /api/pricing(New API 兼容,无鉴权只读,字段集按上游 main 分支源码校准):售价 ¥ 按 fx 折 USD(ratio×2=USD/1M),只列显式定价(固定单价)出口——固定比例(加成计价)出口没有固定单价承诺,不进价格表(不给参考价,避免误导);计价模式标签只在运营面出现,调用方页面/API 不暴露 metered/计价方式字样;数据面 ingress 把 routerapi.<域名>/api/pricing 路由到 router:8005(traefik 最长前缀优先于 /v1 → litellm),不改开源 LiteLLM 一行代码。
  • 路线图:语义缓存、分类器 v2(LightGBM 本服务语料训练)、级联实装(响应后重决策)。

查询接口(阶段一:X-Internal-Token 鉴权,集群内访问)

端点说明
GET /api/router/model-health供应商健康列表(内存实时窗口覆盖 DB 快照)
GET /api/router/model-health/history供应商健康时间条(6h 分段 × 7 天;首字延迟 p50 口径 + 上游错误分子/健康分母计数,仅含有流量的分段)
GET /api/router/routing-decisions决策明细分页查询(支持实例/模型组/档位/状态过滤)
GET /api/router/routing-decisions/export决策明细 cursor 导出(训练集构建用)
GET /api/router/routing-decisions/anchors日锚存证列表
POST /api/router/routing-decisions/anchors/{day}/verify重放校验某日锚
GET /api/router/routing-flywheel/summary飞轮聚合(覆盖率/分歧率/趋势/类型分布/节省估算)
GET/POST/PUT/DELETE /api/router/model-groups智能模型组(池)管理,保存即渲染热生效
POST /api/router/model-groups/preview-ladder难度阶梯预览(不落库)
POST /api/router/model-groups/{id}/apply手动重新渲染(LiteLLM 侧漂移后恢复对齐)

本地排障示例:kubectl port-forward -n veyra-router svc/router 8005:8005 后携带 X-Internal-Token 访问。

路线图

  • 阶段一:容灾止血(重试/冷却、健康画像、决策日志、审计锚)
  • 阶段二:任务感知路由(语义分类器 + 智能模型组 + 粘性会话)与飞轮聚合 ✅(分类器当前 shadow 灰度中,观察分歧率达标后翻 active)
  • 阶段三(部分):对外服务能力 ✅(external key 自助签发 P1-b;配额与预算、成本账本与毛利引擎 P3);剩余:语义缓存、分类器 v2(LightGBM,用本服务沉淀的语料训练)、级联实装(响应后重决策)。

基于内网部署的企业级 AI 智能体平台