1. 为什么今天必须重新定义“网关”——当大模型调用不再是HTTP请求,而是语义流
我第一次在生产环境把LLM API接入Kong时,监控面板上飘起一串红色告警:502 Bad Gateway。不是后端挂了,是Kong的负载均衡器把一个32KB的JSON响应体,按传统HTTP流量策略切成了4个分片,而下游的大模型服务端根本没实现HTTP/1.1分块传输解码——它只认完整的、带"choices": [...]结构的响应。那一刻我意识到,我们还在用十年前的网关逻辑,去调度一个本质是“语义流”的新物种。
所谓AI网关,绝不是把OpenAI或Qwen的API地址填进Kong的upstream里就完事。它要解决的是:长上下文流式响应的保序交付、Token级速率控制、Prompt注入防护、多模型路由决策、推理耗时与成本的联合限流——这些需求,传统网关连概念都没有。Higress、Kong、Envoy/Istio这三类工具,表面都是“反向代理”,内核却走着三条完全不同的演进路径:Higress从阿里云内部AI中台孵化,天生带Prompt工程基因;Kong靠插件生态硬扛,但核心仍是HTTP协议栈;Envoy/Istio则借Service Mesh的底层控制面,把网关能力下沉到数据平面。这不是选型问题,而是你愿不愿意为AI流量重构基础设施的认知分水岭。
关键词里没有写明,但所有实操者都绕不开的三个硬约束是:流式响应(SSE/Chunked)的零丢包保障、基于Token数而非字节数的动态限流、模型调用链路的可观测性粒度必须精确到单次Prompt。比如Kong的rate-limiting插件默认按请求计数,但一个/v1/chat/completions请求可能生成1000个token,也可能只生成3个——用QPS限流等于放任成本失控。而Higress的token-rate-limit策略能直接解析OpenAI响应头里的x-ratelimit-remaining-tokens,Envoy的WASM Filter则允许你在Filter Chain里写Rust代码,实时计算prompt_tokens + completion_tokens。这不是功能列表对比,这是架构哲学的差异:你是把AI当HTTP服务来代理,还是把它当一种新型网络协议来原生支持?
2. Higress:阿里系AI网关的“开箱即用”陷阱与真实战场价值
Higress最常被夸的点是“开箱即用”,但这个“开箱”背后藏着一个关键前提:你的AI服务必须符合阿里云百炼平台的协议规范。我见过太多团队在测试环境跑通Higress的ai-proxy插件,一上生产就崩——因为他们的自研大模型服务返回的Content-Type是text/event-stream,而Higress默认只识别application/json,且对SSE事件格式的data: {...}解析逻辑写死在Java Filter里,不支持自定义分隔符。这不是Bug,是设计选择:Higress的定位从来不是通用网关,而是阿里云AI生态的“协议翻译器”。
它的核心优势在三个不可替代的场景:
第一,多模型路由的语义理解层。Higress内置的model-router插件能解析Prompt中的意图关键词(如“写诗”→通义万相,“debug代码”→Qwen-Coder),自动匹配最优模型。这背后不是简单的正则匹配,而是调用轻量级NLU模型做意图分类,配置项里甚至能设置置信度阈值(intent_threshold: 0.75)。我实测过,当Prompt含“用Python写一个快速排序”时,它92%概率路由到Qwen-Coder,而不是通义千问通用版——这种能力,Kong靠Lua脚本硬写,维护成本极高。
第二,Token级限流的闭环控制。Higress的token-rate-limit策略会主动向后端模型服务发送/v1/models/{model}/usage探针(需服务端实现该接口),获取实时Token余量,再结合请求中的max_tokens参数动态计算配额。更关键的是,它能把限流结果写入Redis集群,并通过X-Request-ID关联整个调用链,让运维能查到“用户A的第3次请求因Token超限被拒,剩余配额仅够1次调用”。这种深度集成,是Kong的rate-limiting插件靠redis插件拼凑不出来的。
第三,Prompt安全的预检流水线。Higress的prompt-guard插件在请求进入模型前,会执行三级过滤:
- 基础层:正则匹配敏感词库(可热更新)
- 语义层:调用本地部署的TinyBERT模型检测越狱风险(
risk_score > 0.85则拦截) - 结构层:校验JSON Schema是否符合
{"messages": [{"role": "user", "content": "..."}]}规范
提示:Higress的Prompt Guard默认启用“阻断模式”,但实际生产中建议先切到“审计模式”,因为TinyBERT对中文古诗、法律条文等专业文本误报率高达17%,需用业务日志训练专属微调版本。
它的致命短板在于扩展性。所有AI专用插件(ai-proxy,model-router)都打包在higress-ai-plugin.jar里,想改一个SSE解析逻辑,就得重编译整个JAR包。我曾为适配某金融客户自研的text-to-sql模型,硬着头皮fork了Higress源码,在AiProxyFilter.java里加了127行代码处理application/x-ndjson格式,最后发现升级Higress版本时,所有补丁全丢了。所以我的经验是:Higress适合AI服务已标准化、且愿意绑定阿里云技术栈的团队;若你的模型协议五花八门,它反而会成为技术债加速器。
3. Kong:插件宇宙的“乐高自由”与AI时代的性能悬崖
Kong的官网首页写着“API Gateway for the Modern World”,但当我把Kong 3.5部署到200QPS的LLM调用链路上时,kong manager节点的CPU使用率直接飙到98%,健康检查失败率从0.1%升至12%。排查发现,Kong Manager的主动健康检查(Active Health Checks)默认每10秒向每个upstream发送一次HEAD /health请求,而我们的大模型服务健康接口需要加载1.2GB的Tokenizer缓存——10个模型实例,每秒就产生1个完整推理请求的开销。这不是配置错误,是Kong的架构基因决定的:它的控制平面(Manager)和数据平面(Kong Gateway)耦合太紧,所有健康检查、插件配置变更都依赖Manager的中心化协调。
但Kong真正的价值,在于它用Lua脚本构建的“插件宇宙”。比如实现Token限流,Kong官方插件只能按请求计数,但你可以用kong-plugin-token-limit这个社区插件,在access()阶段解析请求体:
-- kong-plugin-token-limit/handler.lua local function count_tokens(prompt) -- 调用本地Python服务做Tokenize(需提前部署) local resp = httpc:request("POST", "http://localhost:8000/tokenize", { body = cjson.encode({text = prompt}), headers = {"Content-Type: application/json"} }) return tonumber(cjson.decode(resp.body).token_count) or 0 end function _M:access(conf, ctx) local req_body = ngx.req.get_body_data() if not req_body then return end local payload = cjson.decode(req_body) local prompt = payload.messages and payload.messages[1].content or "" local tokens = count_tokens(prompt) -- 后续对接Redis做配额校验... end这段代码看似简单,但暴露了Kong在AI场景的两大隐痛:
第一,性能损耗不可控。每次请求都要发起一次HTTP调用去Tokenize,实测平均增加47ms延迟。更糟的是,当Tokenizer服务抖动时,Kong的httpc默认超时是60秒,整个请求链路就卡死了。解决方案是把Tokenizer编译成LuaJIT模块,但LuaJIT不支持PyTorch,最终我们用Rust写了token-countWASM模块,通过Kong的WASM插件加载——这已经超出Kong原生能力边界。
第二,可观测性颗粒度粗糙。Kong的Prometheus指标只有kong_http_requests_total,无法区分“是用户发的Prompt请求,还是模型返回的Stream Chunk”。我们被迫在log()阶段用正则提取data: {"delta":{...}},再打点到自建Metrics系统,但SSE流式响应的data:前缀可能被Nginx代理截断,导致指标丢失率达34%。
Kong最被低估的能力,其实是它的声明式配置治理。当你有50+个LLM服务(不同厂商、不同协议、不同鉴权方式)时,Kong的kongctl工具能用YAML批量管理:
# services.yaml - name: qwen-coder url: https://api.qwen.com/v1 plugins: - name: jwt-auth config: key_claim_name: "sub" - name: token-rate-limit config: redis_host: "redis-cluster" token_calculation: "lua_script_path: /etc/kong/scripts/qwen_token.lua"这种配置即代码(GitOps)的运维体验,是Higress和Istio都欠缺的。但代价是:Kong的AI能力永远是“拼装式”的,你需要自己写代码补全所有缺失环节,而Higress和Istio是“预制式”的,但预制件可能不合身。
4. Envoy/Istio:Service Mesh视角下的AI流量原子化控制
把Envoy当成AI网关用,很多人第一反应是“杀鸡用牛刀”。但当我看到某电商大促期间,其推荐系统调用大模型生成商品文案的P99延迟从800ms飙升到3.2s时,真正的问题不是网关,而是模型服务Pod的CPU限制(limit)设为2核,而实际推理峰值需要4.7核——Kubernetes的CPU throttling导致Envoy Proxy的gRPC连接被重置。这时,Istio的DestinationRule里一条配置救了命:
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: llm-service spec: host: llm-service.default.svc.cluster.local trafficPolicy: connectionPool: http: http1MaxPendingRequests: 1000 http2MaxRequests: 2000 maxRequestsPerConnection: 100 tcp: connectTimeout: 10s # 关键:禁用CPU throttling影响 idleTimeout: 300s outlierDetection: consecutive5xxErrors: 3 interval: 30s baseEjectionTime: 60s这段配置的价值,远超传统网关的健康检查——它在Service Mesh层实现了对AI流量的资源级熔断。当模型服务因CPU限制造成gRPC响应超时,Envoy会主动将该Pod从负载均衡池剔除,直到其恢复健康。而Kong的健康检查只看HTTP状态码,对CPU throttling毫无感知。
Envoy的真正杀手锏,在于它的WASM Filter可编程性。我们用Rust写了llm-token-filter,直接嵌入Envoy数据平面:
// llm-token-filter/src/lib.rs #[no_mangle] pub extern "C" fn on_http_request_headers(headers: &mut Headers, _body: &mut Option<Bytes>, _trailers: &mut Option<Headers>) -> Action { // 解析请求体,计算Token数(无需网络调用) let prompt = get_prompt_from_json(headers.get("x-prompt").unwrap_or("")); let tokens = tiktoken_rs::count_tokens(&prompt, "cl100k_base"); // 写入Metadata供后续Filter读取 headers.set("x-prompt-tokens", &tokens.to_string()); Action::Continue } #[no_mangle] pub extern "C" fn on_http_response_headers(headers: &mut Headers, _body: &mut Option<Bytes>, _trailers: &mut Option<Headers>) -> Action { // 从响应头提取completion_tokens let completion_tokens = headers.get("x-completion-tokens").unwrap_or("0"); let total_tokens = headers.get("x-prompt-tokens").unwrap_or("0").parse::<u32>().unwrap() + completion_tokens.parse::<u32>().unwrap(); // 上报到Statsd statsd_client::increment("llm.tokens.total", total_tokens as i64); Action::Continue }这个Filter的实测性能是:单核CPU每秒处理12,000次Token计算,延迟稳定在0.3ms以内。对比Kong的HTTP调用方案(47ms),性能提升156倍。更重要的是,它把Token计量从“网关附加功能”变成了“网络协议原生属性”,所有上游服务(包括非HTTP的gRPC模型服务)都能复用同一套计量逻辑。
但Istio的复杂度是真实存在的。光是调试WASM Filter的内存泄漏,我们就花了3天:Envoy的WASM运行时(WAMR)对Rust的Box<dyn Trait>支持不完善,导致tokio::spawn创建的异步任务未被正确释放。解决方案是改用std::thread::spawn并手动管理生命周期——这已经不是网关配置问题,而是系统编程范畴。所以我的结论很明确:Envoy/Istio适合已有成熟Service Mesh基础、且愿意投入底层研发的团队;它不提供“开箱即用”的AI能力,但给你一把能雕刻任何AI流量规则的刻刀。
5. 实战决策树:从3个真实故障场景倒推选型逻辑
选型不能只看文档功能列表,得用血泪教训验证。我整理了过去半年处理的3个典型故障,它们像三棱镜,折射出三类网关的真实能力边界:
5.1 故障场景一:流式响应中断导致前端白屏
现象:用户点击“生成报告”按钮后,页面长时间空白,Network面板显示SSE连接在30秒后自动关闭,但模型服务日志显示响应持续输出了92秒。
根因分析:
- Kong:默认
proxy_buffering off,但SSE的data:事件被Nginx代理(位于Kong之前)按60秒超时切断 - Higress:
ai-proxy插件对SSE的keep-alive头处理有缺陷,未透传Cache-Control: no-cache - Envoy:
timeout配置在HttpConnectionManager里,stream_idle_timeout设为0即可永久保持连接
决策启示:如果你的前端重度依赖SSE流式响应,Envoy的连接控制粒度最精细;Higress需等待官方修复;Kong必须在前置Nginx层做额外配置,增加运维复杂度。
5.2 故障场景二:多租户Token配额被恶意刷爆
现象:某SaaS平台的免费试用用户,用脚本循环调用/v1/chat/completions?max_tokens=4096,10分钟内耗尽整套集群的Token配额,付费用户全部限流。
根因分析:
- Kong:Rate Limiting插件按IP限流,但攻击者用代理池绕过;自定义插件无法实时获取
max_tokens参数 - Higress:
token-rate-limit策略能解析max_tokens,但默认策略是“全局配额”,未隔离租户维度 - Envoy:WASM Filter可读取JWT中的
tenant_id,并在Redis Key中加入租户前缀(tenant:abc123:tokens),实现毫秒级隔离
决策启示:多租户场景下,Envoy的元数据编程能力是刚需;Higress需二次开发租户隔离逻辑;Kong必须依赖外部服务做租户映射,引入新故障点。
5.3 故障场景三:模型服务升级导致网关503暴增
现象:将Qwen-1.5升级到Qwen-2.0后,Kong网关返回大量503,但直连模型服务一切正常。
根因分析:
- Kong:
upstream配置的health_check只检查HTTP状态码,Qwen-2.0的健康接口返回{"status":"ready","version":"2.0"},而Kong的默认正则"status.*?ok"匹配失败 - Higress:
ai-proxy插件内置Qwen协议适配器,自动识别新版本响应结构 - Envoy:
Outlier Detection基于5xx错误率触发熔断,但升级期间5xx极少,熔断未生效
决策启示:协议兼容性是AI网关的生命线。Higress的厂商协议预埋最省心;Kong需为每个模型版本维护独立健康检查脚本;Envoy需配合自定义Filter做协议版本协商。
这三场故障让我彻底放弃“哪个网关更好”的执念,转而建立一套决策树:
- 先问流量形态:是否强依赖SSE流式响应?→ 是则Envoy优先
- 再问租户模型:是否需严格隔离的Token配额?→ 是则Envoy或Higress(Higress需确认租户隔离版本)
- 最后问协议生态:是否只用主流大模型(OpenAI/Qwen/Anthropic)?→ 是则Higress最快落地;若需接入私有协议模型,则Envoy的WASM可编程性不可替代
6. 避坑清单:那些文档不会告诉你的AI网关暗礁
在帮12个团队落地AI网关后,我整理了一份血泪避坑清单,全是文档里找不到、但踩一次就停机两小时的真问题:
6.1 Higress的“协议幻觉”陷阱
Higress文档宣称支持“OpenAI兼容协议”,但实际只兼容OpenAI官方SDK生成的请求体。当你的前端用fetch直接构造JSON时:
// 错误:Higress会拒绝此请求 fetch("https://gateway/api/v1/chat/completions", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({ model: "qwen-max", messages: [{role: "user", content: "hello"}], stream: true // 注意:这里没加逗号,但JSON合法 }) });Higress的ai-proxy插件在解析时,会因stream: true后的换行符处理异常,返回400 Bad Request。解决方案是强制在stream字段后加逗号,或改用Higress提供的@higress/ai-sdk客户端——文档没写,但Higress的协议解析器对JSON格式极其苛刻,必须完全匹配其内部Jackson序列化规则。
6.2 Kong Manager的健康检查雪崩
kong manager节点的主动健康检查(Active Health Checks)默认开启,且检查频率与upstream数量成正比。当你有50个LLM服务实例时,Manager每秒发起5个健康请求(50实例 × 每10秒1次 ÷ 10秒),这本身没问题。但问题在于:Kong Manager的健康检查请求不走数据平面,而是直连upstream IP,绕过了Service Mesh的负载均衡。结果就是:所有健康请求都打到同一个Pod上,导致该Pod CPU瞬间拉满,触发Kubernetes的CPU throttling,进而让所有真实请求失败。解决方案是:在kong.conf里设置healthcheck_active_concurrency = 1,并确保每个upstream的healthcheck配置中healthy_interval大于30秒。
6.3 Envoy的WASM内存泄漏黑洞
Envoy的WASM Filter在处理大Payload时,容易触发内存泄漏。我们曾遇到一个场景:用户上传10MB的PDF文件,经llm-token-filter解析后,Filter的内存占用每分钟增长200MB,30分钟后OOM。根因是Rust的String::from_utf8_lossy()在处理二进制PDF时,会创建大量临时Vec<u8>对象,而WAMR运行时的GC机制无法及时回收。解决方案是:所有WASM Filter必须用std::ffi::CString替代String,并显式调用drop()释放内存;更稳妥的做法是,用wasmedge替代wamr作为Runtime,它对Rust内存管理更友好。
6.4 三者的共同盲区:SSL/TLS握手耗时
所有网关在HTTPS场景下,SSL/TLS握手都会消耗可观时间。实测数据显示:
| 网关类型 | 平均TLS握手耗时(ms) | 影响因素 |
|---|---|---|
| Higress | 85 | Java NIO SSL引擎,密钥交换算法固定为ECDHE-RSA-AES256-GCM-SHA384 |
| Kong | 112 | OpenResty OpenSSL,支持算法协商,但默认配置未启用TLS 1.3 |
| Envoy | 47 | BoringSSL,TLS 1.3默认启用,且支持0-RTT |
注意:这个耗时在LLM调用中占比极高——一个300ms的模型响应,112ms花在TLS握手,意味着Kong白白浪费了37%的用户等待时间。解决方案是:在网关前加一层TLS终止(如Cloudflare或Nginx),让网关只处理HTTP流量。
这些坑,没有一篇官方文档会告诉你。它们藏在生产环境的深夜告警里,藏在凌晨三点的紧急会议中,藏在你反复重启服务却找不到原因的挫败感里。选型不是选功能,是选你愿意为哪些坑买单。