aidy-gateway V2 设计与实现状态
状态:当前实现状态 + 精简路线图(更新于 2026-04-10)
0. 实现状态
当前仓库已经落地的 V2 子集:
- V2 运行时已切换为 PG-only runtime,不再支持
file、redis-v1、redis-v2作为运行时动态配置源。 - 静态启动配置位于
pkg/staticconfig,并使用dynamic-config.pg_ro/dynamic-config.pg_rw区分运行时读库与管理面写库。 - 管理端口同时提供基础 HTTP 路由与 ConnectRPC 管理面 API。
- 管理面当前已覆盖这些资源:
tenantsprovidersprovider_pricingsroutesroute_plugin_configsupstreamsupstream_modelsconsumersconsumer_api_keysrequest_logs
- 管理面当前还已暴露这些非纯 CRUD 操作:
DisableUpstreamAPIKey/EnableUpstreamAPIKeyAdjustConsumerCredit/AdjustConsumerAPIKeyCreditDisableConsumerAPIKey/EnableConsumerAPIKey
- 数据面主流程已切换为 typed request pipeline,当前按顺序执行路由匹配、认证、访问约束校验、模型解析、候选 upstream 排序与转发构建。
- route 级认证链当前已固定为
disable_auth/passthrough_auth_token/legacy_bearer_auth_tokens/consumer_api_keys。 - 已实现基于
routes.groups、consumers.groups、consumer_api_keys.groups与upstreams.group的分组选路。 - 已支持 provider、upstream、upstream API key、upstream model、provider pricing、consumer、consumer API key 等核心 V2 资源的 PG 存储与查询。
- 已实现多 upstream 候选解析、按 key 展开、加权随机无放回排序与 fallback 编排。
- chat 路径已支持三种入站协议:
/v1/chat/completions/v1/responses/v1/messages
- chat 路径已支持按
upstream.provider.protocol做协议转换,并按原始入站协议回组装响应。 - 已增加
seedCLI,支持dev/demo/mockprofile,以及自定义--seed-file。 - 旧管理端点
/config/dynamic*、/config/validate、/api/request-log/history已废弃,当前返回404。
当前明确未完成的能力:
- 非 chat 路径的跨协议转换;
- 更完整的运行时 Credit 预检查、扣减主路径与 usage / billing ingestion;
- 配置变更审计、preview、diff;
- 基于规范化 policy 表的完整治理运行时。
Breaking Change
- 请求日志与日志事件中的
upstream_response.chat_completions_body已移除,不再输出该字段。 - 请求日志与日志事件中的单值
upstream_request/upstream_response已移除,统一改为upstream_requests数组。
1. 背景与设计目标
V2 的核心变化:
- 运行时配置统一收敛到 PostgreSQL
- 数据面通过
dynamic-config.pg_ro读取当前配置; - 管理面通过
dynamic-config.pg_rw写入当前配置; - V2 运行时不再兼容
file、redis-v1、redis-v2。
- 数据面通过
- 管理面切换为 protobuf + ConnectRPC
- 当前管理资源与写路径围绕 protobuf message / service 定义展开;
- 管理面与文档、seed、DB 设计围绕同一套 V2 领域模型收敛。
- 租户模型升级
- 从“tenant 只有基础限速”升级为“tenant 拥有 providers、upstreams、consumers、consumer API keys 与 pricing 归属”。
- 路由模型升级
- 从“route 绑定唯一 upstream”升级为“route 负责入口治理与访问限制,模型到上游的映射在 tenant 资源层完成”。
2. 现状梳理:V1 能力与 V2 目标
2.1 当前仓库里仍保留的 V1 兼容能力
结合当前 proto、数据库设计与运行时实现,V1 兼容层主要保留在以下位置:
租户级
inbound_rate_limit_qpsdetect_rate_limit_cpm
这两个字段当前仍直接落在 tenants 表上。
路由级
disable_authlegacy_bearer_auth_tokenspassthrough_auth_token
其中:
legacy_bearer_auth_tokens用于承接 V1 的 route 级 bearer token 兼容能力;passthrough_auth_token当前仍保留,但仅作为 legacy 兼容开关;
2.2 当前已经成型的 V2 能力
全局 / Provider 级
- provider 模板支持
global/tenant两种来源; provider_pricings已作为独立资源落地;- provider 当前按
protocol、base_url、headers、compat、request_header_overrides、capabilities、check_model驱动默认运行时行为。 其中headers只表示静态string -> stringheader map。
租户级
- 一个 tenant 可以拥有多个 upstream;
- upstream 必须绑定 provider;
- upstream 下可配置多个 API key;
- upstream model / alias 已独立建模;
- consumer 与 consumer API key 已独立建模;
- consumer / API key group 约束已参与 upstream 选择。
路由级
- route 当前负责:
- path prefix 入口匹配
- route 级认证兼容
- group 约束
- 运行时
plugin_config聚合后的治理配置
补充说明:
- 管理面
Route资源不再内嵌plugin_config plugin_configs已拆成独立的RoutePluginConfigService- 其中同时提供:
- route 资源 CRUD:面向
RoutePluginConfig.entries - 明细批量接口:面向
plugin_key/plugin_sub_key粒度的全量读写
- route 资源 CRUD:面向
2.3 V2 的核心产品定位
当前可以用一句话概括 V2:
route决定“请求能否从这个入口进入”,tenant及其下属资源决定“请求可以使用哪些上游、模型与凭证”,而provider_pricings为后续 Credit 计费提供定价基础。
3. 总体架构设计
3.1 组件拆分
当前 V2 已经形成两类核心能力:
A. Control Plane(管理面)
职责:
- 提供 ConnectRPC 管理面 API;
- 管理 tenants、providers、provider_pricings、routes、upstreams、upstream models、consumers、consumer API keys;
- 承担资源写入、校验与基础可用性检查;
- 使用
dynamic-config.pg_rw作为主写路径。
B. 数据面
职责:
- 通过
dynamic-config.pg_ro读取当前配置; - 在请求主路径上完成认证、授权、模型解析、upstream 选择与转发;
- 当前仍使用 Redis 处理高频限速计数;
- Credit 写路径与更完整的 usage / billing 仍未完全进入主链路;
- 多 upstream fallback 与 chat 多协议转换已经进入主链路。
存储与基础设施边界
- RW PG:管理面写路径,以及后续需要强一致写入的 Credit / usage 类能力;
- RO PG:当前请求路径上的配置读取;
- Redis:高频 rate limit 计数;
- HTTP / ConnectRPC:管理面暴露方式;
- Seed 文件:初始化 V2 资源的离线导入方式。
3.2 配置变更链路
当前实现已经采用“直接 CRUD 主业务表”的模型:
- 管理面直接写入 PostgreSQL 主业务表;
- 数据面在请求时直接通过 RO PG 读取;
- 配置可见性取决于数据库提交与读可见性;
- 当前不做进程内配置快照;
- 当前不做
runtime表拆分; - 当前不保存历史配置版本。
3.3 一致性模型
当前一致性语义可以概括为:
- 配置事务提交成功后,由后续请求通过 RO PG 读取新配置;
- 当前运行时路径主要是“读配置 + 转发”,尚未引入复杂缓存一致性问题;
- Credit 扣减与 usage 写入尚未真正落入主路径,因此强一致写语义仍属于后续能力。
4. 领域模型与工程约束
4.1 核心实体
当前 V2 领域模型已经围绕以下实体稳定下来:
TenantRouteProviderProviderPricingUpstreamUpstreamAPIKeyUpstreamModelConsumerConsumerAPIKey
这些实体的数据库设计与字段语义以 Database(数据库设计) 为准。
补充说明:
Protocol当前不是独立资源,而是Provider.protocol字段;Provider / Upstream / Protocol的职责边界见 Upstream / Provider / Protocol。- 三种协议的路径、
base_url与compat规则见 Protocols。
4.2 配置归属原则
当前归属边界已经较为明确:
- 属于 Global / Provider 的:
- provider 模板
- provider pricing
- 属于 Tenant 的:
- upstreams
- upstream models
- consumers
- consumer API keys
- 属于 Route 的:
- path prefix
- 认证兼容字段
- labels
- 由
plugin_configs聚合得到的 runtimeplugin_config视图
4.3 配置优先级与合并规则
当前运行时已经固定的优先级包括:
- route 认证优先级:
disable_authpassthrough_auth_tokenlegacy_bearer_auth_tokensconsumer_api_keys
- upstream 运行时参数合并:
- provider 提供默认
base_url/headers/compat/request_header_overrides - upstream 可以覆盖这些默认值
protocol仍以 provider 为准request_header_overrides当前不支持Host覆盖或透传
- provider 提供默认
- 分组约束:
- 先看 route groups
- 再叠加 consumer / API key groups
- 若没有任何显式组约束,则回落到
default
4.4 工程重构约束
当前已经明确采用 all in protobuf 的工程方向:
- 所有跨模块、跨进程、需要长期维护的数据契约,优先以 protobuf 作为 schema source;
- 管理面接口统一按 protobuf
service+ ConnectRPC 暴露; - AIDY V2 proto 使用 editions 体系,文档层面统一按“使用 edition 2023 或 2024”表述;
- 当前仓库中的 V2 proto 文件已采用 editions 语法,现有文件以
edition = "2023"为主。
5. 请求执行链路设计
当前数据面主路径可以概括为:
- 路由匹配
- 根据 path prefix 命中 route;
- 取得 route 绑定的 tenant。
- 认证
- 当前只支持
Authorization: Bearer <token>; - 认证优先级依次为
disable_auth、passthrough_auth_token、legacy_bearer_auth_tokens、consumer_api_keys。
- 当前只支持
- 入口访问限制
- 校验 route 是否禁用;
- 模型解析
- 从请求中提取
model; - 以当前请求模型名去匹配
upstream_models与provider_pricings。
- 从请求中提取
- 请求治理
- 当前通过 route 聚合后的
plugin_config视图承载 Guard / 限速等能力; - 更完整的 policy 规范化仍未完成。
- 当前通过 route 聚合后的
- 上游选择
- 按 groups、priority、alias、协议与 capability 解析候选;
- 把 upstream 的可用 API key 展开成 key 级候选;
- 先按
upstream.priority从高到低分层,再只在同优先级内做加权随机无放回排序;最多保留前route.max_attempts个进入转发计划,默认2。
- 转发
- 根据 provider
protocol选择当前已支持的 forwarder; - 生成最终发往上游的请求;
- 按候选顺序执行请求与 fallback,并返回成功响应或最终失败结果。
- 根据 provider
当前已固定的认证兼容字段语义
disable_auth- 显式跳过认证,优先级最高。
passthrough_auth_token- 保留用于 legacy 兼容;
- 命中后允许请求通过,并透传原始
Authorization。
legacy_bearer_auth_tokens- 用于承接旧 route 级 token 兼容行为。
consumer_api_keys- 当前主认证模型;
- 直接按 Bearer token 查询
consumer_api_keys.key。
当前未完成的主链路能力
- 非 chat 路径的 protocol conversion;
- Credit 预检查;
- 请求结束后的 Credit 扣减;
- usage / billing 写入。
6. 分阶段功能计划
为了控制复杂度,当前仍按能力依赖拆分阶段,但状态已经更新为与仓库实现一致的版本。
Phase 0:统一领域模型与迁移 / 废弃策略
状态:已完成
当前已确定:
- V2 运行时只支持 PG;
route.auth不再作为 V2 主模型;passthrough_auth_token仅保留为 legacy 兼容;- API key 当前只支持
Authorization: Bearer <token>; - protobuf + ConnectRPC 已成为管理面主契约。
Phase 1:管理面与主业务表写路径
状态:部分完成
当前已完成:
- tenants / providers / provider_pricings / routes / upstreams / upstream API keys / upstream models / consumers / consumer API keys 的管理面资源;
- 基础 CRUD;
- upstream API key 的创建、更新、删除、启用、禁用接口;
- consumer / consumer API key credit 调整接口;
- API key 启用 / 禁用接口;
- 管理端
/ready可检查 PG runtime store 可用性。
当前未完成:
- 配置变更审计;
- preview / validate-only 工作流;
- 结构化 diff;
- 更完整的控制面校验链路说明。
Phase 2:单表直写 + 数据面直查
状态:已完成
当前已完成:
- 控制面直接写 PostgreSQL 主业务表;
- 数据面按请求直查 RO PG;
- 不依赖旧 dynamic config manager;
- 不做进程内配置缓存;
- 不做
runtime表拆分; - 不保存历史配置;
- 不再兼容
file/redis-v1/redis-v2。
Phase 3:多 upstream + 模型路由
状态:已基本完成
当前已完成:
- provider / upstream / upstream model / alias 的建模与查询;
- provider 默认值与 upstream 覆盖项的运行时合并;
- 基于 groups 的多 upstream 候选解析;
- upstream API key 展开、优先级排序与加权随机无放回排序;
- fallback / retry;
- chat 路径 protocol conversion。
当前未完成:
- 非 chat 路径 protocol conversion;
- 更细粒度的健康探测 / 熔断。
Phase 4:消费者、API Key、Credit 配额
状态:部分完成
当前已完成:
- consumer / consumer API key 资源;
- Bearer token 鉴权;
- consumer / API key groups 参与 upstream 选择;
- 管理面 credit 调整接口。
当前未完成:
- 运行时 credit 预检查;
- 请求完成后的 credit 扣减;
- 更完整的 key rotation / revoke 流程说明;
- usage 与计费主路径接入。
Phase 5:路由治理能力
状态:部分完成
当前已完成:
- Guard / 限速的聚合配置承载方式;
- route labels 与 plugin_config 聚合模型。
当前未完成:
- 规范化 policy 表驱动;
- 治理结果审计闭环;
- 更细粒度的 response-side 治理能力。
Phase 6:计费、账单、审计与可观测性
状态:未完成
当前仍属于路线图:
- usage ingestion;
- pricing resolution 的完整主路径接入;
- credit aggregation;
- billable ledger;
- audit log;
- change diff summary。
7. V1 到 V2 的迁移建议
7.1 配置映射
| V1 能力 | V2 归宿 | 备注 |
|---|---|---|
tenant.inbound_rate_limit_qps | tenants.inbound_rate_limit_qps | 当前仍直接落在 tenant 字段上 |
tenant.detect_rate_limit_cpm | tenants.detect_rate_limit_cpm | 当前仍直接落在 tenant 字段上 |
route.upstream | providers + upstreams + upstream_models | 从“路由唯一上游”改为“provider 模板 + upstream + model 映射” |
route.auth.bearer.tokens | routes.legacy_bearer_auth_tokens 或 consumers + consumer_api_keys | 长期建议迁移到 tenant 级 consumer 模型 |
route.passthrough_auth_token | routes.passthrough_auth_token | 当前保留,仅作 legacy 兼容 |
route.capabilities | providers.capabilities + upstreams.capabilities | forwarder 能力已迁移到 provider / upstream |
route.labels | routes.labels | 当前仍保留在 route 表上 |
route.plugin_config.* | plugin_configs 聚合后的 plugin_config | 当前作为运行时与管理面的聚合视图暴露 |
7.2 迁移策略
由于 V2 运行时只支持 PG,当前建议的迁移方式仍是“离线导入 + 一次切换”:
- 从旧 file / redis source 导出快照;
- 转换为 V2 的 PG 实体;
- 使用 seed 或管理面写入;
- 切换到 PG-only runtime;
- 停用旧动态配置源。
8. 数据库表设计原则
数据库设计原则已迁移到 Database(数据库设计)。
常用入口:
9. 核心业务表设计
核心业务表设计已迁移到 Database(数据库设计)。
常用入口:
10. 数据面直查设计
当前 V2 运行时不引入额外的 runtime 表集,也不做业务表 / runtime 表双轨拆分。
aidy-gateway 数据面直接通过 RO PG 读取当前业务表。
10.1 直查原则
- 不做进程内缓存;
- 不做
runtime bundle; - 对禁用、过期、撤销状态做统一过滤;
- 配置变更提交后,由后续请求通过 RO PG 读取;
- 读取可见性取决于数据库复制与读可见性。
10.2 关键查询路径
Route 查询
- 按请求路径做最长前缀匹配;
- 读取
tenant_id、disable_auth、legacy_bearer_auth_tokens、passthrough_auth_token、groups。
API Key 鉴权查询
当前认证分支为:
routes.disable_auth = trueroutes.passthrough_auth_token = trueroutes.legacy_bearer_auth_tokens非空consumer_api_keysBearer 鉴权
其中 consumer auth 查询路径为:
- 直接取 Bearer token 原文;
- 查询
consumer_api_keys; - 关联
consumers与tenants; - 过滤
disabled_at、revoked_at、expires_at与status。
Tenant / Provider / Upstream / Model 查询
- 查询
tenants; - 查询
providers; - 查询
upstreams; - 查询
upstream_models; - 按 groups、priority、alias、协议与 capability 等规则筛选目标;
- 把
upstreams.api_keys展开成 key 级候选; - 对候选做加权随机无放回排序,并保留 fallback 顺序。
当前已实现的选择规则:
routes.groups、consumers.groups、consumer_api_keys.groups为空数组时表示“不限制任何组”;- 若最终没有任何显式组约束,则回落到
default; - 当前只在这些分组对应的
upstreams.group中继续选择; upstreams.api_keys会展开成 key 级候选;upstream_api_key.lb_weight优先,未设置时回退到upstream.lb_weight;- 候选按加权随机无放回排序,单次请求最多尝试 5 个;
- chat 当前已支持
/chat/completions、/responses、/messages三种入站协议,并可按上游provider.protocol做协议转换; - 任意非
2xx、transport error、assemble/parse error 都会触发 fallback;流式 chat 在写出首个 event 后锁定当前候选。
Pricing 查询
- 查询
provider_pricings; - 以请求模型名作为计费模型名;
- 基于命中的 upstream 解析
provider_id; - 在
(provider_id, model)上解析后续 Credit 单价基础。
10.3 查询索引关注点
当前重点关注这些查询路径:
routes(path_prefix);consumer_api_keys(key);providers(source_scope, source_ref_id, disabled_at);upstreams(tenant_id, disabled_at);upstreams(tenant_id, group, disabled_at);upstream_models(tenant_id);upstream_models(model)。
10.4 读取语义
- 控制面直接写主业务表;
- 数据面通过 RO PG 读取当前配置;
- 当前不保存历史
runtime snapshot; - 若后续出现性能瓶颈,再评估数据面缓存或额外的
runtime派生表。
11. 计量与账单相关能力
当前仓库尚未把 usage 聚合、账单记账链路真正接入运行时或管理面。
本期状态:
- 请求结束后的 usage 写入仍未落地;
- 聚合报表与账单追溯仍未落地;
provider_pricings已作为后续计费基础数据落地,但尚未形成完整扣费闭环。
12. 关键实现约束
12.1 API Key 校验
当前确认的入口规范:
- 只支持
Authorization: Bearer <token>; - 暂不支持
X-API-Key; - Bearer token 统一映射到
consumer_api_keys。
12.2 模型名与别名
当前模型相关约束为:
- 请求中的
model直接作为当前路由与计费使用的模型名; - alias 直接作为
upstream_models中is_alias = true的独立行表达; provider_pricings与upstream_models当前都围绕同一个模型名字工作。
12.3 Upstream 多 API Key
当前需要明确区分两层选择:
upstream_models+ 分组约束决定“请求应该落到哪个 upstream”;upstreams.api_keys决定“已选定 upstream 后具体使用哪个 key 出网”。
当前实现:
- runtime 查询阶段会把 upstream 的每个可用 API key 展开成独立候选;
- 若 upstream 没有任何 API key,则补一个“空 token 候选”;
- 候选顺序先按
upstream.priority从高到低分层,优先级越大越优先; upstream_api_key继承所属 upstream 的优先级;- 仅在同优先级内,按
upstream_api_key.lb_weight优先、否则回退到upstream.lb_weight做加权随机无放回排序; - 单次请求最多保留前
route.max_attempts个候选进入真正的转发计划,默认2; - 当前不回写
last_used_at; - chat 与 raw HTTP 路径都会按这组候选顺序做 fallback。
12.4 Provider / Protocol
当前职责边界为:
- route 表达入口与访问限制;
- upstream models + groups 表达应该去哪;
- provider 表达默认如何连接与解释协议;
- upstream 表达当前实际连接参数;
- forwarder 负责具体协议实现。
补充:
Protocol当前不是独立资源,而是provider.protocol;- chat 入站协议按请求路径判断;
- 出站协议按
selected upstream -> provider -> protocol判断; route.protocol_transformation_type当前仍会持久化,但不会切换 chat 主链路的协议转换行为。
12.5 直接写库避免半成品状态
当前如需批量更新相关配置,仍应尽量放在同一事务边界内,避免数据面读到半成品组合。
12.6 当前运行时姿势
V2 当前的运行方式是:
- 启动时初始化必要连接;
- 请求时通过 RO PG 查询当前业务表;
- 不做进程内缓存;
- Redis 继续承担高频 rate limit;
- 更复杂的 usage / billing 写路径保留为后续阶段。
13. 当前最小可落地版本(MVP)
这部分用于总结当前已经形成的 V2 最小闭环,而不是继续描述历史草案。
当前已经具备的 MVP 能力
- 管理面:
- ConnectRPC 管理资源已基本齐备
- PG-only readiness 检查已落地
- 旧管理端点已废弃并返回
404
- 数据面:
- route / tenant / API key 的 PG 直查
- route -> tenant -> consumer auth
- tenant 多 upstream 配置
- 基于 groups 的多 upstream 候选解析
- upstream API key 展开、加权随机无放回排序与 fallback
- chat 主路径跨协议转换与原始协议回组装
- 初始化能力:
seedCLIdev/demo/mockseed profile- 自定义
--seed-file
当前仍待补齐的关键闭环
- consumer / API key 余额预检查;
- 请求结束后的 Credit 扣减;
- usage / billing ingestion;
- 审计、preview、diff。
14. 已确认决策
aidy-gateway的 V2 运行时只支持 PG,不兼容file、redis-v1、redis-v2。- 全文档与产品命名继续统一使用
aidy-gateway,不使用新的独立产品名。 - AIDY V2 proto 使用 editions 体系,文档层面统一按“使用 edition 2023 或 2024”表述。
- 当前仓库中的 V2 proto 文件已采用 editions 语法,现有文件以
edition = "2023"为主。 - API key 当前只支持
Authorization: Bearer <token>。 route.auth不作为 V2 主模型继续扩展。passthrough_auth_token当前保留,但仅作 legacy 兼容。- upstream 与 API key 凭证首版仍在 PG 中明文存储,后续如需引入 KMS 再演进。
- 实时 rate limit 继续使用 Redis。
- 首版数据面不做内存缓存,不做
runtime表拆分。 - 当前管理面统一使用 protobuf + ConnectRPC。
- 旧
/config/dynamic*、/config/validate与/api/request-log/history路径已废弃,当前返回404。