V2 独立版愿景

推理网关

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
speedspeed_weight − 近期延迟惩罚(近 30 分钟平均耗时每 50ms 扣 1 分、最多扣 50 分;无延迟数据不扣分,新模型不被"未知"垫底)
costcost_weight——静态权重占位,平台未内置真实价格数据
  • 候选与用途过滤:候选 = 租户内 active、有健康后端、未被 routing_enabled=false 排除的模型,再按用途(模型策略 purpose 字段:chat/completion/embedding/未标注)过滤——embeddings 请求永远不会经 auto 选到标了 chat 的模型;已标注匹配的优先,未标注只作回退(响应头 X-Routing-Purpose-Fallback: unlabeled),全不匹配返回 503 no_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_limit0-100000每秒请求数(1 秒滑动窗口)
concurrency_limit0-10000同时在途请求数
daily_call_limit0-1e9日调用次数
monthly_call_limit0-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 上游返回 400 unsupported_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 参考》网关相关章节与《多租户管理》第七章。 -->