Kong 作为 AI 网关:LLM 驱动架构详解
前置知识
- ›第 1 篇:架构与 Nginx 集成
- ›第 4 篇:插件系统与迭代器(插件 handler 模式)
- ›对 LLM API 的基本了解(Chat Completions、流式传输、Token 计数)
Kong 作为 AI 网关:LLM 驱动架构详解
Kong 近期最重要的新能力是 AI 网关功能——一个专门用于代理、转换和观测大型语言模型(LLM)请求的子系统。Kong 没有另起炉灶构建一个独立的 AI 代理,而是将 LLM 支持直接嵌入其插件架构,复用了本系列文章中反复介绍的 phase 管道、配置系统和可观测性基础设施。
整个设计的核心是驱动模式(driver pattern):每个 LLM provider(OpenAI、Anthropic、Azure、AWS Bedrock、Google Gemini、Cohere、Hugging Face)都以一个驱动模块实现,并遵循统一的接口规范。公共的 HTTP 转换逻辑由共享工具模块处理,云平台认证则被解耦到独立的 adapter 模块中。
LLM 模块架构与格式检测
LLM 子系统位于 kong/llm/ 目录下,入口文件为 kong/llm/init.lua。该模块的首要职责是格式检测——判断传入请求是 chat completion 还是 text completion:
local function identify_request(request)
local formats = {}
if type(request.messages) == "table" and #request.messages > 0 then
table.insert(formats, "llm/v1/chat")
end
if type(request.prompt) == "string" then
table.insert(formats, "llm/v1/completions")
end
-- ...
end
Kong 的标准格式与 OpenAI 兼容:基于消息数组的请求对应 llm/v1/chat,单一提示词请求对应 llm/v1/completions。第 67–82 行 的 is_compatible 函数用于检查请求是否与预期的路由类型匹配,还支持一种特殊的 preserve 模式,可跳过格式验证直接透传请求。
目前已支持的驱动模块涵盖主流 LLM provider:
| 驱动 | 文件 | Provider |
|---|---|---|
openai |
kong/llm/drivers/openai.lua |
OpenAI API |
anthropic |
kong/llm/drivers/anthropic.lua |
Anthropic Claude |
azure |
kong/llm/drivers/azure.lua |
Azure OpenAI |
bedrock |
kong/llm/drivers/bedrock.lua |
AWS Bedrock |
gemini |
kong/llm/drivers/gemini.lua |
Google Gemini |
cohere |
kong/llm/drivers/cohere.lua |
Cohere |
huggingface |
kong/llm/drivers/huggingface.lua |
Hugging Face |
mistral |
kong/llm/drivers/mistral.lua |
Mistral AI |
llama2 |
kong/llm/drivers/llama2.lua |
Llama 2(自托管) |
flowchart TD
A[Incoming Request] --> B{Format Detection}
B --> C["llm/v1/chat<br>(messages array)"]
B --> D["llm/v1/completions<br>(prompt string)"]
C --> E{Route Type Match?}
D --> E
E -->|Compatible| F[Select Driver]
E -->|Incompatible| G[400 Error]
F --> H[Transform to Provider Format]
H --> I[Send to LLM Provider]
I --> J[Transform Response to Kong Format]
驱动模式:Provider 抽象
每个驱动模块都实现了包含 to_format 和 from_format 转换函数的标准接口。kong/llm/drivers/openai.lua 是其中最简洁的——因为 Kong 的标准格式本身就与 OpenAI 格式一致:
local transformers_to = {
["llm/v1/chat"] = function(request_table, model_info, route_type)
request_table.model = model_info.name or request_table.model
request_table.stream = request_table.stream or false
request_table.top_k = nil -- unsupported by OpenAI
return request_table, "application/json", nil
end,
}
相比之下,kong/llm/drivers/anthropic.lua 驱动需要在格式之间进行实质性转换。对于旧版 Claude 模型,它会将 Kong 的消息数组转换为 Anthropic 的 Human:/Assistant: 提示词格式:
local function kong_messages_to_claude_prompt(messages)
local buf = buffer.new()
for _, v in ipairs(messages) do
if v.role == "assistant" then
buf:put("Assistant: ")
elseif v.role == "user" then
buf:put("Human: ")
end
buf:put(v.content)
buf:put("\n\n")
end
buf:put("Assistant:")
return buf:get()
end
kong/llm/drivers/shared.lua 中的共享驱动工具模块提供了所有驱动共用的基础能力:HTTP 客户端管理、流式内容类型检测、SSE 解析,以及用于可观测性的日志条目键常量。该模块定义了追踪用量的标准键:
local log_entry_keys = {
USAGE_CONTAINER = "usage",
PROMPT_TOKENS = "prompt_tokens",
COMPLETION_TOKENS = "completion_tokens",
TOTAL_TOKENS = "total_tokens",
TIME_PER_TOKEN = "time_per_token",
COST = "cost",
}
classDiagram
class SharedDriver {
+_CONST: SSE_TERMINATOR, etc.
+_SUPPORTED_STREAMING_CONTENT_TYPES
+log_entry_keys
+HTTP utilities
}
class OpenAIDriver {
+to_format(request, model_info)
+from_format(response, model_info)
+DRIVER_NAME: "openai"
}
class AnthropicDriver {
+to_format(request, model_info)
+from_format(response, model_info)
+kong_messages_to_claude_prompt()
+DRIVER_NAME: "anthropic"
}
class BedrockDriver {
+to_format(request, model_info)
+from_format(response, model_info)
+DRIVER_NAME: "bedrock"
}
SharedDriver <|-- OpenAIDriver
SharedDriver <|-- AnthropicDriver
SharedDriver <|-- BedrockDriver
云 Adapter 与认证
云托管 LLM 服务的认证逻辑与驱动逻辑解耦,由专用的云 adapter 负责凭证管理,不会污染格式转换代码。
Adapter 模块位于 kong/llm/adapters/ 目录:
bedrock.lua— 使用resty.aws进行 AWS SigV4 请求签名gemini.lua— 通过resty.gcp处理 Google Cloud 服务账号认证
kong/llm/drivers/shared.lua 在模块加载时初始化云 SDK:
local GCP = require("resty.gcp.request.credentials.accesstoken")
local aws_config = require "resty.aws.config"
local AWS = require("resty.aws")
local AWS_REGION = os.getenv("AWS_REGION") or os.getenv("AWS_DEFAULT_REGION")
kong/llm/schemas/init.lua 中的认证 schema 提供了灵活的认证配置,支持基于请求头的认证(API key)、查询参数认证以及云原生认证方式:
local auth_schema = {
type = "record",
fields = {
{ header_name = { type = "string", referenceable = true }},
{ header_value = { type = "string", encrypted = true, referenceable = true }},
{ param_name = { type = "string", referenceable = true }},
{ param_value = { type = "string", encrypted = true, referenceable = true }},
},
}
注意 encrypted = true 和 referenceable = true 这两个注解。encrypted 标志表示该字段在数据库中静态加密存储(企业版功能)。referenceable 标志则表示字段值可以是 Kong Vault 引用,例如 {vault://env/OPENAI_API_KEY},从而与 Kong 的密钥管理系统集成。
提示: 对于 AWS Bedrock 等云 provider,无需显式配置 API key。Adapter 会遵循标准的 AWS SDK 凭证链——环境变量、IAM Role 或实例配置文件均可。只需设置
AWS_REGION并确保 Kong 实例具备相应的 IAM 权限即可。
AI 插件家族
kong/plugins/ai-proxy/handler.lua 中的 ai-proxy 插件出乎意料地简洁——仅有 19 行。这是因为它将所有逻辑委托给基于 ai_plugin_base 模块的过滤器架构:
local ai_plugin_base = require("kong.llm.plugin.base")
local NAME = "ai-proxy"
local PRIORITY = 770
local AIPlugin = ai_plugin_base.define(NAME, PRIORITY)
local SHARED_FILTERS = {
"parse-request", "normalize-request", "enable-buffering",
"normalize-response-header", "parse-sse-chunk", "normalize-sse-chunk",
"parse-json-response", "normalize-json-response",
"serialize-analytics",
}
for _, filter in ipairs(SHARED_FILTERS) do
AIPlugin:enable(AIPlugin.register_filter(require("kong.llm.plugin.shared-filters." .. filter)))
end
return AIPlugin:as_kong_plugin()
kong/llm/plugin/base.lua 模块提供了一套元插件框架,内部定义了一套映射到 Kong phase 的"阶段(stages)"系统:
local STAGES = {
SETUP = 0,
REQ_INTROSPECTION = 1,
REQ_TRANSFORMATION = 2,
REQ_POST_PROCESSING = 3,
RES_INTROSPECTION = 4,
RES_TRANSFORMATION = 5,
STREAMING = 6,
RES_PRE_PROCESSING = 7,
RES_POST_PROCESSING = 8,
}
每个共享过滤器注册到特定的阶段。parse-request 过滤器在 REQ_INTROSPECTION 阶段运行,负责解码传入的请求体;normalize-request 过滤器在 REQ_TRANSFORMATION 阶段运行,将 Kong 标准格式转换为目标 provider 的格式;serialize-analytics 过滤器在 RES_POST_PROCESSING 阶段运行,负责上报用量指标。
这种可组合的过滤器架构使不同的 AI 插件(ai-proxy、ai-request-transformer、ai-response-transformer)能够共享通用逻辑,同时各自实现不同的高层行为。ai-proxy 启用所有标准过滤器;ai-request-transformer 则可能只启用请求侧过滤器加上一个 LLM 内省过滤器。
sequenceDiagram
participant Client
participant AIProxy as ai-proxy (access)
participant ParseReq as parse-request filter
participant NormReq as normalize-request filter
participant LLM as LLM Provider
participant ParseRes as parse-json-response filter
participant NormRes as normalize-json-response filter
participant Analytics as serialize-analytics filter
Client->>AIProxy: POST /llm/v1/chat
AIProxy->>ParseReq: STAGE: REQ_INTROSPECTION
ParseReq->>ParseReq: Decode JSON body
ParseReq->>NormReq: STAGE: REQ_TRANSFORMATION
NormReq->>NormReq: Transform to provider format
NormReq->>LLM: Forward transformed request
LLM-->>ParseRes: Provider response
ParseRes->>ParseRes: Decode provider JSON
ParseRes->>NormRes: STAGE: RES_TRANSFORMATION
NormRes->>NormRes: Normalize to Kong format
NormRes->>Analytics: STAGE: RES_POST_PROCESSING
Analytics->>Analytics: Record token usage
Analytics-->>Client: Normalized response
kong/llm/plugin/observability.lua 中的可观测性模块与 Kong 现有的指标基础设施无缝集成。每个请求的 token 计数、延迟和费用均被追踪,并通过 Kong 标准的日志插件暴露出来——无需额外配置,即可使用 http-log、datadog 或 prometheus 监控 AI 网关流量。
kong/llm/plugin/ctx.lua 中的上下文模块提供了命名空间隔离的请求级状态管理。每个 AI 插件拥有独立的上下文命名空间,避免多个 AI 插件在同一请求上运行时(例如 ai-prompt-guard 后接 ai-proxy)产生状态冲突。
完整的 AI 请求流程
一次完整的 AI 网关请求在 Kong 中的处理流程如下:
- 客户端向
POST /ai/chat发送一个与 OpenAI 兼容的请求体 - Kong 的路由器将请求匹配到配置了
ai-proxy插件的路由 - ai-proxy 的
accesshandler 执行:parse-request:解码 JSON,将格式识别为llm/v1/chatnormalize-request:选择已配置的驱动(如anthropic),对请求进行转换enable-buffering:为非流式请求启用响应缓冲
- Kong 的负载均衡器将转换后的请求发送至 LLM provider 端点
- ai-proxy 的响应 handler 依次执行:
normalize-response-header:调整 content-type 响应头parse-json-response或parse-sse-chunk:解析 provider 的响应normalize-json-response或normalize-sse-chunk:将响应翻译回 Kong 格式serialize-analytics:记录 token 用量、延迟和费用
- 将标准化后的响应返回给客户端
对于流式响应,STREAMING 阶段的过滤器会在 body_filter phase 中对每个 SSE chunk 执行——这也是 REPEATED_PHASES 将流式阶段标记为可重复执行的原因。
提示:
kong/llm/schemas/init.lua中的 LLM schema 定义了 provider 专属选项,例如bedrock_options_schema(AWS 区域覆盖)和gemini_options_schema(Vertex AI 项目/位置)。这些选项均为可选——当 schema 未设置时,adapter 模块会自动回退到环境变量。
系列总结
在这七篇文章中,我们从 Nginx 基础出发,依次深入了解了 Kong 的初始化流程、请求处理、插件执行、基于 schema 的数据管理、分布式集群机制,以及 AI 网关能力。贯穿始终的主线,是 Kong 对几个核心抽象的坚守:用于生命周期管理的 phase、用于数据建模的 schema、用于插件执行的迭代器,以及用于 provider 抽象的驱动模式。
无论你是在为 Kong 开发自定义插件、排查生产问题,还是评估 Kong 能否承载你的 API 基础设施,理解这些内部机制都能让 Kong 从一个黑盒变成一个清晰可读的系统。代码库体量庞大——仅 kong/init.lua 就接近 2000 行——但模式始终一致,命名清晰直观,深入阅读源码会让你收获颇丰。