← 返回博客

用 OpenResty 搭一个轻量 LLM 网关

从运维视角出发,用 Nginx/OpenResty 为多个大模型后端做统一鉴权、限流与可观测,避免每个服务各搞一套。

把大模型接入生产环境时,最先暴露的往往不是模型本身,而是入口:鉴权散落在各处、没有统一限流、调用量和成本无法观测。与其在每个业务里重复造轮子,不如在入口加一层薄薄的网关。

为什么选 OpenResty

OpenResty 本质是 Nginx 加上 LuaJIT,既保留了 Nginx 的高并发反向代理能力,又能用 Lua 在请求生命周期里插入自定义逻辑。对运维来说,它的好处是:

  • 复用现有的 Nginx 运维经验与配置习惯;
  • access_by_lua 阶段做鉴权与限流,几乎零额外延迟;
  • 共享内存字典 lua_shared_dict 天然适合做计数器。

统一鉴权

最小可用的做法是校验一个内部 API Key,并把调用方身份写入变量,供后续日志使用。

location /v1/ {
    access_by_lua_block {
        local key = ngx.var.http_x_api_key
        if not key or key == "" then
            return ngx.exit(401)
        end
        -- 这里可换成查 Redis / 内存表
        ngx.var.caller = key
    }
    proxy_pass http://llm_upstream;
}

按调用方限流

用共享字典做一个简单的滑动窗口计数,超限直接 429

local limit = ngx.shared.rate
local k = "rl:" .. ngx.var.caller
local count = limit:incr(k, 1, 0, 60)  -- 60 秒窗口
if count > 600 then
    return ngx.exit(429)
end

把成本变可观测

LLM 调用的成本和 token 强相关,因此日志里一定要带上 token 数。可以在 log_by_lua 阶段解析上游返回的 usage 字段,写入结构化日志,再交给 Loki / Prometheus 聚合:

维度用途
caller区分调用方、做成本分摊
model不同模型单价不同
prompt/completion tokens估算费用
latency发现慢模型与超时

小结

一层薄网关就能把鉴权、限流、可观测三件事收口。先做最小可用版本,再按需要往里加灰度、缓存和熔断 —— 这正是运维擅长的渐进式演进。