推理网关
HeteroFlow 是本站的异构算力与大模型调度产品。推理网关。推理网关 推理网关(Gateway)是 HeteroFlow 所有推理流量的统一入口:对外提供与 OpenAI API 逐字节兼容的四条数据面端点,对内把请求按模型路由、灰度权重、会话粘性与负载均衡算法分发到健康的推理副本,并在同一条链路上完成身份鉴权、租户隔离、key 级限流与…
推理网关
推理网关(Gateway)是 HeteroFlow 所有推理流量的统一入口:对外提供与 OpenAI API 逐字节兼容的四条数据面端点,对内把请求按模型路由、灰度权重、会话粘性与负载均衡算法分发到健康的推理副本,并在同一条链路上完成身份鉴权、租户隔离、key 级限流与额度熔断、幂等去重、Token 用量核算和后端健康治理。任何 OpenAI SDK 的应用只需把 Base URL 换成 http://<server>:3333/v1、Key 换成平台颁发的密钥即可完成迁移,网关之下的多副本分发、故障转移、协议转译(Anthropic Messages 上游)与用量采集对调用方完全透明。
网关与推理服务(TaskGroup + Endpoint + ModelRoute)的关系:服务负责把引擎容器跑起来,网关负责让流量正确、公平、可计量地到达这些容器。本篇覆盖网关体系的全部分支能力;服务本身的创建、伸缩与生命周期见《推理服务》篇。
功能总览
| 能力 | 一句话说明 | 状态 |
|---|---|---|
| OpenAI 兼容统一入口 | chat/completions、completions、embeddings、models 四端点,只改 URL 与 Key 即迁移 | 真机验证(450 并发压测) |
| 负载均衡四算法 | round_robin(默认)/ random / least_connections / engine_aware 引擎指标感知 | 已实现(engine_aware 实验性) |
| 会话粘性 | 五级会话 key 级联命中同副本复用 KV Cache,过载自动降级重选 | 真机验证(5~40 并发梯度校准) |
| 灰度路由 | 多路由按 priority 分组、weight 加权随机、无健康后端逐档降级 | 已实现 |
| 模型路由与智能路由 | ModelRoute 自动注册 + model=auto 按策略替调用方挑模型、按序降级 | 已实现 |
| 温度过滤 | GPU 温度超阈值的后端自动摘除出候选集 | 已实现 |
| 后端健康探测与摘除 | 10 秒轮探测、连续失败摘除 + ENDPOINT_UNHEALTHY 告警、防抖加回 | 已实现 |
| 故障恢复 | 代理失败换健康后端重试、RecoveryHint 交调度器恢复、单副本兜底 | 已实现 |
| key 级治理 | 每把成员 Key 独立 QPS / 并发上限 / 日月额度,超限 429 | 已实现 |
| 幂等键 | Idempotency-Key 去重重试,防重复调用与重复扣费 | 已实现 |
| Anthropic 协议适配 | upstream_protocol=anthropic 端点,请求/响应/流式三处双向转译 | 已实现 |
| Token 用量采集与核算 | 流式/非流式 usage 旁路解析,按租户/成员落库聚合 | 真机验证 |
| 高并发承载 | 转发层超时与审计中间件修复后 450 并发成功率 99.8% | 真机验证 |
分支能力详解
OpenAI 兼容统一入口
POST /v1/chat/completions # Chat 补全(负载均衡 + 粘性 + 用量核算全链路)
POST /v1/completions # 文本补全
POST /v1/embeddings # 文本向量(与 chat 复用同一鉴权与选路逻辑)
GET /v1/models # 可用模型列表(按调用方租户过滤)
ANY /api/v1/proxy/{endpoint}/… # 通用推理代理(透传任意路径到指定端点)- 两种认证、一套代码:
sk-端点专属 Key(创建端点时一次性生成,代表端点本身,适合分享给非平台成员的外部调用方)与sk-tenant-成员租户 Key / 登录态 JWT(代表具体成员,调用记录可归属到人)二选一;中间件判定身份后构造行为一致的"虚拟端点",路由、负载均衡、用量核算对两条路径完全复用同一实现。 - 多租户约束:候选路由始终收敛到调用方所在租户(
callerScopedRoutes),default 租户的普通成员与 default 端点专属 Key 同样只认 default 自己的路由;仅平台运营者代调可跨租户,且同名模型只要存在 default 路由就只保留 default(platformRoutesWin),租户注册同名路由截不走平台流量。 - Key 缓存与撤销:API Key 校验走 sha256 哈希比对 + 30 秒缓存,另有端点表版本戳轮询,其它实例上的 Key 轮换/撤销数秒内生效。
- 冷请求 lazy-wake:路由存在但后端休眠时,网关先唤醒该服务再有界等待就绪(时长取
min(60s, max(start_period_seconds, 1s)),未配健康检查用 30 秒兜底);等到即正常服务,没等到返回 503 +Retry-After: 30+code: service_waking。卡被训练借走返回wake_queued_gpu_borrowed,节点离线返回wake_failed_node_offline(均Retry-After: 60,服务端会推进,客户端等着重试即可)。
四种负载均衡算法
端点字段 algorithm 四选一,决定同一服务多个副本间如何选主:
| 算法 | 机制 | 适用 |
|---|---|---|
round_robin(默认) | 依次轮询分配 | 通用、无状态副本 |
random | 随机选一个 | 简单打散 |
least_connections | 选当前活跃连接数最少的副本 | 请求耗时差异大时 |
engine_aware(实验性) | 按引擎实时指标评分选最空闲副本 | vLLM 多副本、追求吞吐 |
engine_aware 引擎实时指标感知(2026-09-11,Phase 1 仅 vLLM,opt-in):
GPU 利用率对 LLM 推理是弱信号——continuous batching 下利用率常驻 99% 但引擎仍能吃进更多并发,真正的瓶颈信号是引擎自己暴露的排队深度与 KV Cache 占用率。engine_aware 据此选主:
- 指标抓取:独立 worker 每 5 秒一轮,对全部 running 且引擎为 vLLM 的后端并发抓取
/metrics(最大并发 10、单次超时 2 秒);结果纯内存态,多实例部署下每个网关实例独立抓取、独立选主。 - 陈旧度上限:距上次成功抓取超过 15 秒(抓取周期 3 倍)按"无数据"处理,不用陈旧值选主。
- 评分公式:
score = 排队深度(num_requests_waiting) × 100 + KV Cache 占用率(%) × 1,取分数最低(最空闲)的健康副本。权重 100:1 意味着"排队深度低者胜"是主判据,KV 占用率只在排队深度完全相同时作 tie-break。 - 三级平局判定:综合分打平时先比实时活跃连接数(网关原子维护、无抓取延迟),仍打平才落回"先者胜"。修复前真实故障:抓取指标 5 秒一刷,同一窗口内的并发突发看到同一份快照,两个空闲副本同分时永远选第一个——真机 2 副本组 12 个并发请求全部堆到 rank0。
- 退化语义:候选池中无任何后端有新鲜指标时整体退化为
least_connections(不是盲选第一个);部分有数据时,无数据后端按"有数据后端的平均分"填充,不惩罚也不优待,避免刚启动还没被抓到的健康副本被饿死。 - 边界:engine_aware 只优化组内副本选择,多 ModelRoute 之间的灰度/优先级选路(见下)不受影响。
会话粘性(Session Affinity)
与负载均衡算法正交的一层 opt-in 能力(端点字段 session_affinity,默认关闭):同一会话的连续请求尽量落到同一副本,复用其上已有的前缀 KV Cache,多轮对话响应更快。仅对 /v1/chat/completions 生效(/v1/completions、/v1/embeddings 不做粘性;经 /api/v1/proxy/{endpoint}/v1/chat/completions 调用同样生效)。
- 五级会话 key 级联,从①到⑤依次查表,前一级命中即不再后查:
1. 请求头 X-Session-Id(客户端显式声明,最稳)
2. 请求体 prompt_cache_key
3. 请求体 user
4. 内容指纹 L2 = hash(system + 首条 user + 首条 assistant)
5. 内容指纹 L1 = hash(system + 首条 user)
什么都不带的普通多轮对话靠④⑤自动识别;想要最稳的粘性,客户端每轮带同一个 X-Session-Id 即可。
- 作用域防跨租户:所有 key(含客户端自报的
X-Session-Id)都带(TaskGroupID, TenantID)作用域前缀,不能跨服务、跨租户生效;key 值经 sha256 不透明化后存储,长度封顶。 - 双重边际过载判断:命中粘性不等于无条件复用——粘性副本负载
L_sticky与池内最空闲副本L_min同时满足L_sticky − L_min ≥ 4(绝对边际 ABS)且L_sticky ≥ 1.5 × L_min(相对边际 REL)才判定过载并按 algorithm 重选。两个条件缺一不可:池里有完全空闲副本时靠 ABS 挡住"多一个请求就迁移",整体都忙时靠 REL 挡住"40 对 30 这种大差距小倍数的无意义迁移"。负载信号与端点算法一致(engine_aware 比排队深度,其余比活跃连接数)。 - 存储与上限:单进程内存态,滑动 TTL 30 分钟(命中即刷新)+ 10 万条硬上限,逐出最旧/已过期条目。
- 诊断与观测:响应头
X-Session-Id回传本轮会话 token(下轮放进请求头即收敛到①级);X-Session-Affinity诊断头取值hit:l2/miss/overload:header/stale:l1,区分"没生效"与"生效了但因过载/副本下线降级"。Prometheus 计数器heteroflow_gateway_session_affinity_total{outcome, level}供线上校准 ABS/REL。 - 真机校准数据(2026-09-12,5~40 并发梯度):0.5B 模型 overload 占比 4.2%~15.2%(随并发先涨后降,属"判定后维持同副本、分母线性增长"的正常表现);7B 模型同档 17.5%~17.7%(单请求 p95 更长、排队更易堆积)。结论:当前负载规模下 ABS=4 / REL=1.5 符合预期方向,暂无需上调。v2.6.51 上线。
灰度路由
同一模型名注册多条 ModelRoute 时,网关按确定性规则分流:
1. 按 priority 升序分组(0 最高),只在最高优先级组内选;
2. 组内按 weight 加权随机(80/20 即金丝雀比例);
3. 选中路由无健康后端时降级到下一优先级组;
4. weight=0 的路由不参与主动分流,仅作降级备选。
示例:模型 llama-3 挂三条路由——A(priority=0, weight=80, 生产)、B(priority=0, weight=20, canary)、C(priority=1, weight=100, 降级备选)。正常流量 80%→A、20%→B;A 与 B 全不健康时 100%→C。
模型路由与智能路由(model=auto)
ModelRoute 基础:创建推理服务时自动注册一条路由(model_name 优先取请求体的对外模型名、未传回退服务名;engine 从镜像推断;priority=0、weight=100、active、租户继承任务组)。训练组不注册路由(避免污染推理选路);去重复用命中时按 (tenant_id, model_name) 判定补建缺失路由。也可经 POST / PUT / DELETE /api/v1/model-routes 手动管理(非平台运营者 priority 不得为负、模型名不得与 default 租户已有路由同名、只能指向自己创建的任务组)。
智能路由 model=auto(2026-09-30,opt-in,默认关闭):请求体 model 填 auto,由网关在调用方租户内按策略挑模型承接,主选异常按序降级。三层配置优先级:密钥级覆盖(PUT /api/v1/tenant/api-keys/{id}/routing-policy,仅 sk-tenant- Key)> 全局默认(PUT /api/v1/system/inference-config 的 auto_routing_enabled / auto_routing_strategy)> 关闭。三种策略:
| 策略 | 排序分 |
|---|---|
quality(缺省) | 模型 quality_weight |
speed | speed_weight − 近期延迟惩罚(近 30 分钟平均耗时每 50ms 扣 1 分、最多扣 50 分;无延迟数据不扣分,新模型不被"未知"垫底) |
cost | cost_weight——静态权重占位,平台未内置真实价格数据 |
- 候选与用途过滤:候选 = 租户内 active、有健康后端、未被
routing_enabled=false排除的模型,再按用途(模型策略purpose字段:chat/completion/embedding/未标注)过滤——embeddings 请求永远不会经 auto 选到标了 chat 的模型;已标注匹配的优先,未标注只作回退(响应头X-Routing-Purpose-Fallback: unlabeled),全不匹配返回 503no_auto_candidates_for_purpose,绝不静默选错类型。之后按任务组去重,单次最多尝试前 3 个候选。 - 三级降级链:同后端原地重试(仅连接层瞬时错误)→ 同候选内其它健康副本 → 跨候选降级(
model改写成真实模型名后端才认识),用量归属跟随实际承接组。响应已开始下发后立即停止一切重试;后端自身 4xx 原样透传不降级。 - 观测:响应头
X-Routed-Model标明实际承接模型;开启 auto 的调用方GET /v1/models列表首位多一项{"id": "auto", "owned_by": "heteroflow-router"};Prometheus 计数器heteroflow_gateway_auto_routing_total{outcome, strategy};错误码no_auto_candidates(503) /no_auto_candidates_for_purpose(503) /auto_routing_all_failed(502)。 - 模型级策略(三权重、routing_enabled、purpose)经
/api/v1/models/routing-policies管理(读nodes:read、写system:write;含/的 HF 风格模型名必须走?name=传参)。
温度过滤
Scheduler 配置 gpu_temperature_threshold(如 85℃)后,网关在收集健康后端时检查节点上报的 GPU 温度,温度超标节点上的后端不参与路由,防止持续向过热卡分发推理流量。
后端健康探测与摘除
网关内置周期健康探测 worker(多实例部署下仅主实例运行,随选主生命周期启停):
| 参数 | 默认值 | 说明 |
|---|---|---|
| 探测间隔 | 10 秒 | 对全部 active 端点的 running 后端并发探测(最大并发 10) |
| 单次超时 | 3 秒 | 可被端点 health_check.timeout_seconds 覆盖 |
| 探测路径 | /health | 可被 health_check.path 覆盖;失败自动回退探测 /v1/models |
| 摘除阈值 | 连续 3 次失败 | health_check.unhealthy_threshold 可配 |
| 加回防抖 | 连续 2 次通过 | 摘除后须连续两次探测通过才回到候选集 |
- 摘除闭环(2026-10-01 T4):连续失败达阈值 → 立即从路由候选摘除(对手动路由、model=auto、/api/v1/proxy 全入口一致)、失效健康缓存、写审计日志、产生
ENDPOINT_UNHEALTHY(ERROR)告警(按(类型, task_id)去重,规则缺失视为开启)。加回时清零计数、失效缓存、告警自动消解为 RECOVERED;数据面真实请求成功清摘除态时走同一条恢复事件路径。 - 启动宽限期:端点配置
health_check.start_period_seconds后,容器启动后该窗口内的探测失败不计入计数(背景:vLLM 冷启动加载大模型可达 50 秒,探针窗口把副本判死过)。 - 重启/换主对账:摘除状态在内存,进程重启归零;被摘除后端已恢复的,下一次探测通过时把遗留告警对账消解、失败计数归零,告警不会永远 ACTIVE。
- 单副本兜底:单次代理失败短期封禁该后端 15 秒、连续 3 次失败熔断 30 秒;若排除被封禁/熔断后端后候选池为空,回退用被排除的后端兜底(
falling back to them anyway to avoid total outage)——单副本部署不会因一次瞬时失败完全断服。
故障恢复
代理失败时记录错误计数并自动换其它健康后端重试一次;反复失败的组设置 RecoveryHint 标记,交由 Scheduler 恢复循环接手(重建/换节点)。删除端点时同步清空关联 TaskGroup 的 Endpoint 反向引用,避免恢复循环对着已删端点空转死锁。转发层(v2.6.84)另修复三处:超时/断连后等转发 goroutine 退出再返回(消除对复用连接的迟到写入竞争)、上游 1xx 信息响应一律丢弃(不再冲掉网关已设的头)、上游 Access-Control-* 头一律剔除(网关是 CORS 唯一权威)。
key 级治理:限流 / 并发上限 / 日月额度熔断
给每把 sk-tenant- 成员 Key 单独配置四项限额(POST/PUT /api/v1/tenant/api-keys),超限返回 429:
| 字段 | 值域 | 语义 |
|---|---|---|
qps_limit | 0-100000 | 每秒请求数(1 秒滑动窗口) |
concurrency_limit | 0-10000 | 同时在途请求数 |
daily_call_limit | 0-1e9 | 日调用次数 |
monthly_call_limit | 0-1e12 | 月调用次数 |
- 检查顺序 QPS → 并发 → 额度;全部为 0(存量 Key 默认)= 不限制,中间件整段跳过。仅对四条推理数据面路由生效,管理面接口不计入。
- 超限响应带明确错误码(
QPS_EXCEEDED/CONCURRENCY_EXCEEDED/DAILY_LIMIT_EXCEEDED/MONTHLY_QUOTA_EXCEEDED)、Retry-After、X-RateLimit-*,额度类另带X-Quota-Reset(结算时区HETEROFLOW_BILLING_TZ的下一个日界/月界)。 - 多实例口径:额度计数走数据库原子 UPSERT(多实例精确;数据库故障时 fail-open 放行并记 WARN,不打挂推理主路径);QPS/并发为进程内存态,多实例下全局阈值约 N × limit。
quota_metric=tokens/monthly_token_quota目前为占位枚举,Token 计量强制执行本期不做;额度按调用次数计。
幂等键(Idempotency-Key)
网络超时后调用方不知道请求是否已被处理,盲目重试可能重复调用模型、重复扣费。推理数据面四条路由支持请求头 Idempotency-Key(1-128 字节):
| 情形 | 返回 | 说明 |
|---|---|---|
| 同键不同请求体 | 422 IDEMPOTENCY_KEY_BODY_MISMATCH | 键被复用到新请求,必须换新键 |
| 原请求处理中 | 409 IDEMPOTENCY_REQUEST_IN_PROGRESS | 稍后同键同体重试 |
| 原请求已成功 | 200 重放缓存响应(X-Idempotent-Replay: true) | 不再调上游、不再扣额度、不再落账;流式只返回"已成功且只核算一次"的说明性 JSON,不重放内容 |
| 原请求已失败 | 重新处理 | 失败含非 2xx、panic、以及"2xx 但响应不完整"(字节数与 Content-Length 不符)——不完整响应绝不当作成功缓存 |
请求体指纹 = SHA-256(方法 + 路径 + 原始请求体),重试必须逐字节相同。记录保留 10 分钟(环境变量 HETEROFLOW_IDEMPOTENCY_TTL_MINUTES 可配 1-1440);上限 10 万条记录 + 成功响应快照总预算 256MB(超预算的新成功记录不留快照但仍不重复核算)。重放/409/422 不消耗 key 的日/月额度,重试风暴不烧额度。记录为单进程内存态,多实例部署同一重试打到不同实例不命中。
Anthropic Messages 协议适配
端点字段 upstream_protocol(openai 缺省 / anthropic)声明后端服务的 API 协议。网关对外始终是 OpenAI 兼容接口;声明 anthropic 的端点,网关在转发链路内做三处双向转译:请求 ChatCompletions → Messages、非流式响应 Message → chat.completion(usage 映射后计量零改动)、流式 SSE 事件 → chat.completion.chunk + [DONE]。因转译发生在反向代理内层,5xx 拦截、重试、故障转移、智能路由降级、幂等、计量语义与 OpenAI 路径完全一致。
- 只映射
/v1/chat/completions;其它路径打到 anthropic 上游返回 400unsupported_endpoint_for_upstream_protocol。 - 映射不了的参数一律 400,不静默丢弃:
temperature超出 [0,1] 直接 400(不钳制不缩放)、n≠1、logprobs、response_format等;max_tokens缺省用 4096;stop→stop_sequences;user→metadata.user_id。 - 安全红线:不要把 anthropic 协议端点指向第三方托管上游——上游请求头
x-api-key取自调用方的平台 key,指向第三方等于把平台密钥发给对方。该协议当前只适用于自部署、能说 Anthropic Messages 协议的后端;端点级上游凭据管理尚未提供。 POST /api/v1/endpoints/{id}/test按端点声明的协议对一个健康副本发一次max_tokens=1的最小真实请求(60 秒超时),HTTP 恒 200、结论看ok字段。
Token 用量采集与核算
- 流式:网关自动注入
stream_options.include_usage(客户端已设则尊重),引擎在流的最后一个 chunk 返回 usage,网关在转发循环中旁路解析,不增加延迟;非流式直接解析 JSON 响应体usage。 - 落库:
recordInferenceUsage异步 fire-and-forget(不阻塞热路径)——tenant_usage_events写单次明细(prompt/completion tokens、耗时、状态),tenant_usage_daily同步 UPSERT 按日聚合(核算依据)。 - 失败也记账:按真实结果写
status(模型缺失 400 / 未找到 404 / 无后端 503 / 后端全失败 502 均记 error),tokens 为 0 也记一次请求;retry 不重复核算。 - 按成员拆分:走成员 Key / JWT 的调用记录
user_id+api_key_id,GET /api/v1/tenant/usage?user_id=X查个人用量(非 admin 强制查自己)、?group_by=user一次返回全员。端点专属 Key 无成员身份,只计入租户总量(预期行为)。 - 归属口径:租户归属优先取本次选中路由的租户(跨租户复用下"B 调 A 的模型"记到调用方 B),选路前失败的请求按 task_group → endpoint → 调用方上下文回退。
高并发承载
网关转发层曾有两处高并发缺陷:全局 10 秒 WriteTimeout 对长流式响应偏紧,且审计中间件缺 Unwrap() 导致连接控制穿透失败——vLLM 450 并发压测成功率仅 40.7%。修复后同场景成功率 99.8%(剩余 0.2%~2.4% 为后端自身连接抖动,非网关层问题)。这是"OpenAI 兼容入口可当生产入口用"的真机背书。
页面功能介绍(/inference → 端点管理区)
推理页右侧服务详情的"网关端点"区块是端点的可视化管理入口:
| 界面元素 | 行为 | 触发 API |
|---|---|---|
| "+ 创建端点"按钮 | 仅服务 running 且尚无端点时显示;弹出创建弹窗 | — |
| 创建弹窗(端点名称 / 服务端口 / 上游协议下拉 / 会话粘性勾选) | 名称默认 {服务名}-endpoint,端口 1-65535,协议带场景提示文案 | POST /api/v1/gateway/endpoints |
| "请立即保存 API Key"弹层 | 创建成功后一次性展示明文 Key,含复制按钮与"我已保存"关闭;明文此后不再可见 | —(创建响应携带) |
| 端点卡片信息行 | 展示端点名、端口、算法中文名(轮询/随机/最少连接)、活跃状态、N/M 健康、K 个副本已被探测摘除 | 列表自动轮询 |
| 会话粘性开关(Toggle) | 切换即时生效、不重启容器;成功用响应值回写,失败保持原状并提示 | PUT /api/v1/gateway/endpoints/{id}(只带 session_affinity 一个键) |
| 上游协议下拉 | openai / anthropic 切换,成功后旧连通性结论作废 | PUT /api/v1/gateway/endpoints/{id}(只带 upstream_protocol) |
| "连通性测试"按钮 | 按当前协议对一个健康副本发 max_tokens=1 最小真实请求,就地展示成功(协议/请求/模型/耗时)或失败原因与修复提示 | POST /api/v1/gateway/endpoints/{id}/test |
| API Key 行 | 不做显示/复制——明文仅创建时返回一次,遗失只能轮换 | PUT …/{id} 带 api_key(轮换)/ revoke_api_key(撤销) |
| Base URL 行 | 展示 http://<server>:3333/v1 并一键复制 | — |
| 副本状态区 | 每副本状态徽标;running 但被探针摘除的副本另挂红色"探测摘除"徽标(容器活着与还接不接流量是两件事) | 副本列表自动轮询 |
后端逻辑概念表
| 概念 | 一句话解释 |
|---|---|
| 五级 key 级联 | 粘性会话识别按 X-Session-Id → prompt_cache_key → user → 内容指纹 L2 → L1 依次查表,前一级命中即止 |
| 作用域前缀 | 粘性存储键带 (任务组, 租户) 前缀,客户端自报的会话 ID 不能跨服务、跨租户生效 |
| 双重边际过载 | 粘性副本须同时满足绝对差 ≥4 且倍数 ≥1.5 才判过载迁移,避免无意义抖动 |
| 陈旧度上限 | engine_aware 指标距上次成功抓取超 15 秒即视为无数据,不用旧快照选主 |
| 三级平局判定 | engine_aware 综合分打平 → 比实时活跃连接数 → 仍平才先者胜 |
| 降级链 | 灰度路由无健康后端逐档下调 priority;model=auto 同后端重试 → 组内换副本 → 跨候选换模型 |
| 懒唤醒(lazy-wake) | 请求打到休眠服务时网关先唤醒再有界等待,等不到返回 503 + Retry-After |
| proxyBan / 熔断 | 单次代理失败封禁 15 秒、连续 3 次熔断 30 秒;候选池清空时回退用被排除后端兜底 |
| 加回防抖 | 被摘除后端须连续 2 次探测通过才回候选集,抖动后端不会反复进出 |
| RecoveryHint | 网关标记反复失败任务组的恢复线索,调度器定期接手重建 |
| 虚拟端点 | 成员 Key / JWT 调用时构造的等价端点对象,使两条认证路径复用同一套路由与用量核算代码 |
| platformRoutesWin | 平台运营者代调同名模型时 default 路由胜出,租户同名路由截不走平台流量 |
| purpose 回退 | model=auto 无已标注且匹配用途的候选时才用未标注模型,响应头带 fallback 标记 |
| 幂等窗口 | 同键请求 10 分钟内去重;成功响应缓存重放,流式只确认"已成功且只核算一次" |
| usage 旁路解析 | 网关在转发循环中解析 SSE 末尾或 JSON 的 usage 字段,不增加响应延迟 |
API 参考
基础调用(带会话粘性):
curl http://43.133.65.61:3333/v1/chat/completions \
-H "Authorization: Bearer sk-tenant-xxxxxxxx" \
-H "Content-Type: application/json" \
-H "X-Session-Id: conv-abc-123" \
-d '{"model": "qwen-7b", "messages": [{"role": "user", "content": "你好"}]}'
# 响应头:X-Session-Id: <本轮会话 token,下轮带回即收敛到①级粘性>
# X-Session-Affinity: hit:header | miss | overload:header | stale:l1智能路由:
curl http://43.133.65.61:3333/v1/chat/completions \
-H "Authorization: Bearer sk-tenant-xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"model": "auto", "messages": [...]}'
# 响应头:X-Routed-Model: qwen-7b(实际承接模型)幂等键:
curl http://43.133.65.61:3333/v1/chat/completions \
-H "Authorization: Bearer sk-tenant-xxxxxxxx" \
-H "Idempotency-Key: order-20261005-0001" \
-H "Content-Type: application/json" \
-d '{"model": "qwen-7b", "messages": [...]}'
# 网络超时后原样重发(同键同体):
# 处理中 → 409 IDEMPOTENCY_REQUEST_IN_PROGRESS
# 已成功 → 200 + X-Idempotent-Replay: true(缓存重放,不再核算用量)
# 换了请求体 → 422 IDEMPOTENCY_KEY_BODY_MISMATCH超限响应(429):
{"error": {"message": "API key daily call limit exceeded", "type": "rate_limit_error",
"code": "DAILY_LIMIT_EXCEEDED", "limit": 1000, "current": 1000,
"remaining": 0, "scope": "per_api_key",
"reset_at": "2026-10-06T00:00:00+08:00"}}已知边界
1. engine_aware 为实验性:评分权重 100:1 与退化语义是分析拍板的初始值,未经真机数据校准;Phase 1 仅 vLLM,其它引擎配置后自动降级 least_connections。
2. 粘性映射表、幂等记录均为网关单进程内存态:当前单实例部署无影响;横向扩多实例后同一会话/重试可能打到不同实例而不命中,届时需外部共享存储。
3. key 级 QPS/并发限流为进程内存态,多实例下全局实际阈值约为 N × limit(与租户级限流同一局限);额度计数器数据库故障时 fail-open 放行(记 WARN),优先保可用性。
4. 智能路由 cost 策略与 quota_metric=tokens 均为占位实现,无真实价格/Token 强制执行。
5. anthropic 协议端点不可指向第三方托管上游(x-api-key 会外泄平台密钥),端点级上游凭据管理未提供。
6. 冷启动后网关健康缓存存在最长约 80 秒的滞后窗口:容器 /health 已 200 但网关探测周期未确认前,经网关调用可能偶发 503 no_backends_available——对此敏感的应用侧应做几次退避重试(开放问题,无证据表明已修复)。
7. 会话粘性仅对 /v1/chat/completions 生效;/v1/completions、/v1/embeddings 不做粘性(按代码 isSessionAffinityPath 判定)。
8. 端点专属 sk- Key 无成员身份,调用量只能计入租户总量、无法按人拆分;需要按人算账必须用成员 sk-tenant- Key。
<!-- 状态标注说明:本文能力状态口径与平台能力树 A9 域一致——"真机验证"指真实 GPU 节点端到端运行并确认(450 并发网关压测、5~40 并发粘性梯度校准);"已实现"指代码合入且有测试覆盖、未做专项真机端到端;"实验性"指机制上线但关键参数(engine_aware 权重)未经真机校准。粘性生效路径、engine_aware 评分公式、限流/幂等实现位置均经源码核对(gateway_session_affinity.go / gateway_balancer.go / api_key_limits.go / gateway_idempotency.go)。功能细节依据《推理服务架构与功能详解》第 6-7 章、《API 参考》网关相关章节与《多租户管理》第七章。 -->