本地模型接入网关:我们在三次 502 之后学会的事
上个月我们给内部知识库加了一个本地 Qwen 推理服务,第一次联调很顺,第二次开始出问题:同样的请求,有时 8 秒返回,有时挂 60 秒后直接 502。把日志翻出来看,不是模型的问题,是我们接入方式的问题。

本地模型接入网关:我们在三次 502 之后学会的事
上个月我们给内部知识库加了一个本地 Qwen 推理服务,第一次联调很顺,第二次开始出问题:同样的请求,有时 8 秒返回,有时挂 60 秒后直接 502。把日志翻出来看,不是模型的问题,是我们接入方式的问题。
**第一个坑:把直连地址写死在业务代码里。** 第一次我们让三个业务模块各自 `http://192.168.x.x:port/v1/chat/completions` 直连推理容器。重启一次容器、换一个端口,三处代码全要改。后来我们加了一个本地网关(单端口代理,负责鉴权、模型路由、超时控制),业务侧只认一个地址。网关挂掉是显性故障,直连挂掉是隐性故障——每个业务模块自己默默超时,最后表现为"功能偶尔不可用",排查要翻三个项目的日志。
**第二个坑:超时设得太宽。** 最初超时给的是 120 秒,一次 OOM 重启期间,请求全部卡满 120 秒才失败,上游连接池被打满,连不依赖模型的功能都变慢了。我们把推理调用超时压到 15 秒,配一个同模型的备用路由(云端),15 秒内没返回就切备用。切流以后整体 P95 反而降了,因为慢请求不再占用线程。
**第三个坑:没有最小验证用例。** 联调时我们用了一句"你好"测通了就上线。但"你好"走的是最短路径:没有工具调用、没有长上下文、没有流式输出。真正出问题的是流式响应——推理容器在长输出中途断开时,网关没有正确关闭上游连接,客户端拿到半截 JSON。后来我们固定了一个五用例的冒烟脚本:短问、长上下文、流式、工具调用、超长输出截断,每次改网关配置后先跑冒烟再切流量。
**第四个坑:健康检查是假的。** 最初的"健康检查"只是看容器是不是在跑。容器活着不代表模型可用——权重加载失败、显存碎片化、后端 worker 卡死,容器状态都显示 Up。我们改成每 30 秒发一个 8 token 的最小真实推理请求,连续两次失败就摘除该路由并告警。真实探针上线的第二天,就抓到一次"容器 Up 但 60 秒无响应"的假健康状态。
**第五个坑:重试把故障放大。** 网关早期对超时请求自动重试 3 次,一次后端变慢,请求量瞬间翻三倍,直接把本来就慢的后端压垮,故障范围从"偶尔超时"扩大到"全面不可用"。后来我们把重试策略收紧:只对明确的 429/503 重试一次,超时不重试,直接走备用路由。
共同的教训:**推理服务是依赖,不是功能**。它和数据库一样,要做超时、重试、降级和监控,而不是假设它永远在线。现在网关侧就四块东西:鉴权、路由表、超时与切流、真实请求探针。核心只是一个代理进程加一个配置页。
真正复杂的是认清楚:本地推理的优势是成本可控、数据不出内网,代价是它也会挂,而且经常挂得悄无声息。把它当一个会失效的依赖来设计接入层,比纠结模型本身能省下大部分排查时间。
留言区
欢迎分享你的想法!
加载留言中…