设计文档:多协议适配器架构
作者: vLLM Semantic Router 团队
状态: 待实现
创建: 2026 年 2 月
最后更新: 2026 年 2 月
概述
本文描述 vLLM Semantic Router 的多协议适配器架构设计与实现思路,在 Envoy ExtProc 之外抽象 API 层,以支持多种前端协议。
背景
Semantic Router 曾通过 gRPC 与 Envoy External Processor(ExtProc)紧耦合。这虽能与 Envoy 深度集成,但对以下用户形成门槛:
- 希望在不部署 Envoy 的情况下使用路由器
- 偏好直接 HTTP/REST 集成
- 使用 Nginx 或其他反向代理
- 在开发或测试时需要更简化的部署拓扑
动机
- 灵活性:无需 Envoy 基础设施即可获得直连 HTTP API
- 测试:无需完整 Envoy 部署即可轻量测试
- 可扩展性:支持 nginx、原生 gRPC 与自定义协议
- 可复用性:所有协议共享同一路由引擎
- 部署形态:支持 serverless、边缘与简化部署
目标
主要目标
- 协议抽象:将路由逻辑与协议相关代码分离
- 多协议支持:允许多种协议同时工作
- 向后兼容:保留现有 ExtProc 能力
- 共享状态:缓存、重放与路由决策的单一事实来源
- 易于扩展:新增协议适配器的固定模式
非目标
- 替换或弃用 Envoy ExtProc
- 改变路由决策算法或分类逻辑
- 除适配器相关节外修改配置格式
- 支持破坏抽象层的协议专属特性
设计原则
1. 单一路由流水线
关键约束: 所有路由逻辑必须流经 RouterEngine.Route(),无一例外。
- 适配器将协议翻译为
RouteRequest→ 调用RouterEngine.Route() RouterEngine.Route()返回RouteResponse→ 适配器再翻译回协议- 适配器不得重复实现分类、安全、缓存、重放逻辑
- 适配器不得直接调用分类器、缓存或重放记录器
2. 薄适配器层
适配器仅做协议翻译:
- 解析协议专属请求格式
- 转换为
RouteRequest - 调用
RouterEngine.Route() - 将
RouteResponse转换为协议格式 - 返回给客户端
3. RouterEngine 拥有全部路由
RouterEngine.Route() 是唯一发生以下行为之处:
- 分类
- PII/越狱检测
- 缓存读/写
- 工具选择
- 重放记录
- 后端选择
- 代理(或返回代理信息)
设计
架构概览
┌────────────────────────────────────────────────────────────┐
│ Application Layer │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Adapter Manager │ │
│ │ - Reads adapter config │ │
│ │ - Creates protocol adapters │ │
│ │ - Manages lifecycle │ │
│ └──────┬────────┬─ ───────┬───────────┬──────────────┘ │
│ │ │ │ │ │
│ ┌──────▼──┐ ┌───▼─── ┐ ┌─▼──────┐ ┌──▼─────┐ │
│ │ ExtProc │ │ HTTP │ │ gRPC │ │ Nginx │ │
│ │ Adapter │ │Adapter │ │Adapter │ │Adapter │ │
│ │ ┌─────┐ │ │ ┌─────┐│ │ ┌─────┐│ │ ┌─────┐│ │
│ │ │Parse│ │ │ │Parse││ │ │Parse││ │ │Parse││ │
│ │ │ExtP │ │ │ │HTTP ││ │ │gRPC ││ │ │NJS ││ │
│ │ └──┬──┘ │ │ └─┬───┘│ │ └─┬───┘│ │ └──┬──┘│ │
│ │ │Conv│ │ │Con │ │ │Con │ │ │Con│ │
│ │ ▼ │ │ ▼ │ │ ▼ │ │ ▼ │ │
│ │ ┌─────┐ │ │ ┌────┐ │ │ ┌────┐ │ │ ┌─────┐│ │
│ │ │Req │ │ │ │Req │ │ │ │Req │ │ │ │Req ││ │
│ │ └──┬──┘ │ │ └─┬──┘ │ │ └─┬──┘ │ │ └──┬──┘│ │
│ └────┼────┘ └───┼────┘ └───┼────┘ └────┼───┘ │
│ │ │ │ │ │
│ └──────────┴──────────┴──────────┘ │
│ Single Entry Point │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ RouterEngine.Route() │ │
│ │ 1. Classify request │ │
│ │ 2. Check PII / jailbreak │ │
│ │ 3. Check cache │ │
│ │ 4. Select tools │ │
│ │ 5. Select model/backend │ │
│ │ 6. Record replay │ │
│ │ 7. Proxy to backend (via Backend Layer) │ │
│ │ 8. Update cache │ │
│ └──────────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ RouteResponse │
│ │ │
│ ┌──────────────┼──────────────┬───────────┐ │
│ │ │ │ │ │
│ ┌─────▼─────┐ ┌──────▼────┐ ┌───────▼───┐ ┌─────▼─────┐ │
│ │ ExtProc │ │ HTTP │ │ gRPC │ │ Nginx │ │
│ │ Adapter │ │ Adapter │ │ Adapter │ │ Adapter │ │
│ │ ┌───────┐ │ │ ┌───────┐ │ │ ┌───────┐ │ │ ┌───────┐ │ │
│ │ │Convert│ │ │ │Convert│ │ │ │Convert│ │ │ │Convert│ │ │
│ │ │to gRPC│ │ │ │to HTTP│ │ │ │gRPC │ │ │ │to NJS │ │ │
│ │ └───────┘ │ │ └───────┘ │ │ └───────┘ │ │ └───────┘ │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │ │
└────────┼─────────────┼─────────────┼─────────────┼─────────┘
│ │ │ │
└─────────────┴─────────────┴─────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Backend Abstraction Layer │
└──────┬──────────────────┬───────────────┘
│ │
┌────────▼────────┐ ┌──────▼──────────┐
│ Envoy Proxy │ │ Direct Proxy │
│ (ExtProc mode) │ │ (HTTP/gRPC) │
│ - Dynamic fwd │ │ - HTTP client │
│ - Headers only │ │ - Full response │
└────────┬────────┘ └──────┬──────────┘
│ │
└──────────┬───────┘
▼
┌────────────────────────────┐
│ Inference Backends │
│ ┌──────── ┐ ┌────────┐ │
│ │ vLLM │ │Ollama │ │
│ │Server │ │Server │ │
│ └────────┘ └────────┘ │
└────────────────────────────┘
要点: 适配器是薄翻译层,智能全部在 RouterEngine。
组件设计
1. RouterEngine(核心)
位置: pkg/router/engine/
职责:
- 与协议无关的路由逻辑
- 请求分类与决策求值
- 语义缓存操作
- 工具选择与嵌入
- 路由器重放记录
- PII 与越狱检测
- 模型选择
主要方法:(与英文原文一致,见代码块)
type RouterEngine struct {
Config *config.RouterConfig
Classifier *classification.Classifier
PIIChecker *pii.PolicyChecker
Cache cache.CacheBackend
ToolsDatabase *tools.ToolsDatabase
ModelSelector *selection.Registry
ReplayRecorders map[string]*routerreplay.Recorder
}
func (e *RouterEngine) Route(ctx context.Context, req *RouteRequest) (*RouteResponse, error)
func (e *RouterEngine) ClassifyRequest(ctx context.Context, messages []Message) (*ClassificationResult, error)
func (e *RouterEngine) CheckCache(ctx context.Context, model, query, decisionName string) (string, bool, error)
func (e *RouterEngine) UpdateCache(ctx context.Context, model, query, response, decisionName string) error
func (e *RouterEngine) SelectTools(ctx context.Context, query string, topK int) ([]openai.ChatCompletionToolParam, error)
func (e *RouterEngine) RecordReplay(ctx context.Context, decisionName string, record *routerreplay.RoutingRecord) error
设计决策:
- 所有适配器共享单实例
- 有状态(维护缓存、重放记录器)
- 无协议专属逻辑
- 返回与协议无关的数据结构
2. 适配器接口
位置: pkg/adapter/manager.go
type Adapter interface {
Start() error // Start the adapter (blocks)
Stop() error // Graceful shutdown
GetEngine() *engine.RouterEngine // Access to shared engine
}
设计决策: 接口最小化以保留灵活性;各适配器自管生命周期;接口中无协议专属方法;适配器在独立 goroutine 中运行。
3. Adapter Manager
位置: pkg/adapter/manager.go
职责: 解析适配器配置、按配置实例化、在独立 goroutine 中启动、协调优雅关闭。
主要方法:
func (m *Manager) CreateAdapters(cfg *config.RouterConfig, eng *engine.RouterEngine, configPath string) error
func (m *Manager) StartAll() error
func (m *Manager) StopAll() error
func (m *Manager) Wait()
4. ExtProc 适配器
位置: pkg/adapter/extproc/
包装现有 Envoy ExtProc 实现,保持向后兼容,处理 gRPC/Envoy 细节,支持 TLS。
5. HTTP 适配器
位置: pkg/adapter/http/
提供 OpenAI 兼容 REST API,无需 Envoy,处理 CORS、请求头等 HTTP 关注点。
端点: POST /v1/chat/completions、POST /v1/completions(未来)、GET /v1/models、POST /v1/classify、POST /v1/route、GET /v1/router_replay、GET /v1/router_replay/{id}、GET /health、GET /ready。
6. gRPC 适配器
位置: pkg/adapter/grpc/
提供原生 gRPC API,较 ExtProc 直连 gRPC 客户端更高效,支持流式与一元 RPC。
服务定义示例:
service SemanticRouter {
rpc Route(RouteRequest) returns (RouteResponse);
rpc Classify(ClassifyRequest) returns (ClassifyResponse);
rpc StreamRoute(stream RouteRequest) returns (stream RouteResponse);
}
7. Nginx 适配器
位置: pkg/adapter/nginx/
通过 NJS(JavaScript)模块与 Nginx 集成,支持 OpenResty Lua,基于头的路由类似 ExtProc。
集成方式: NJS 模块、Lua/OpenResty、HTTP 子请求(内部调用 HTTP 适配器)、共享内存 IPC。
配置设计
adapters:
- type: "envoy" # ExtProc adapter
enabled: true
port: 50051
tls:
enabled: true
cert_file: "/path/to/cert.pem"
key_file: "/path/to/key.pem"
- type: "http" # HTTP REST API
enabled: true
port: 9000
- type: "grpc" # Native gRPC API
enabled: true
port: 50052
tls:
enabled: true
cert_file: "/path/to/cert.pem"
key_file: "/path/to/key.pem"
- type: "nginx" # Nginx integration
enabled: true
port: 9001
mode: "njs" # Options: njs, lua, http
config:
upstream_variable: "backend_upstream"
header_prefix: "x-vsr-"
数据流(HTTP 适配器示例)
- 客户端请求 → 2. HTTP 适配器接收
POST /v1/chat/completions→ 3. 解析 OpenAI 请求 → 4.RouterEngine.Route→ 5. 分类、缓存、工具、重放等 → 6. 返回RouteResponse→ 7. 代理到选定后端 → 8. 返回客户端。
共享状态: 多适配器共享同一缓存条目、重放记录器、分 类决策与模型选择状态。
实现细节
初始化顺序
- 加载配置 → 2. 初始化嵌入模型 → 3. 创建 RouterEngine → 4. 创建 Adapter Manager → 5.
CreateAdapters→ 6.StartAll→ 7.Wait()阻塞。
错误处理
- 适配器创建失败:致命,进程退出
- 适配器启动失败:致命,进程退出
- 运行时错误:记录日志,适配器在可能情况下继续
- RouterEngine 错误:返回适配器做协议相关处理
并发模型
- RouterEngine: 线程安全,多适配器可并发调用
- Cache: 由后端处理并发
- Replay Recorders: 线程安全 map + 按决策加锁
- Adapters: 独立 goroutine,无共享适配器状态