跳到主要内容

aidy-gateway V2 设计与实现状态

状态:当前实现状态 + 精简路线图(更新于 2026-04-10)


0. 实现状态

当前仓库已经落地的 V2 子集:

  • V2 运行时已切换为 PG-only runtime,不再支持 fileredis-v1redis-v2 作为运行时动态配置源。
  • 静态启动配置位于 pkg/staticconfig,并使用 dynamic-config.pg_ro / dynamic-config.pg_rw 区分运行时读库与管理面写库。
  • 管理端口同时提供基础 HTTP 路由与 ConnectRPC 管理面 API。
  • 管理面当前已覆盖这些资源:
    • tenants
    • providers
    • provider_pricings
    • routes
    • route_plugin_configs
    • upstreams
    • upstream_models
    • consumers
    • consumer_api_keys
    • request_logs
  • 管理面当前还已暴露这些非纯 CRUD 操作:
    • DisableUpstreamAPIKey / EnableUpstreamAPIKey
    • AdjustConsumerCredit / AdjustConsumerAPIKeyCredit
    • DisableConsumerAPIKey / EnableConsumerAPIKey
  • 数据面主流程已切换为 typed request pipeline,当前按顺序执行路由匹配、认证、访问约束校验、模型解析、候选 upstream 排序与转发构建。
  • route 级认证链当前已固定为 disable_auth / passthrough_auth_token / legacy_bearer_auth_tokens / consumer_api_keys
  • 已实现基于 routes.groupsconsumers.groupsconsumer_api_keys.groupsupstreams.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 做协议转换,并按原始入站协议回组装响应。
  • 已增加 seed CLI,支持 dev / demo / mock profile,以及自定义 --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 的核心变化:

  1. 运行时配置统一收敛到 PostgreSQL
    • 数据面通过 dynamic-config.pg_ro 读取当前配置;
    • 管理面通过 dynamic-config.pg_rw 写入当前配置;
    • V2 运行时不再兼容 fileredis-v1redis-v2
  2. 管理面切换为 protobuf + ConnectRPC
    • 当前管理资源与写路径围绕 protobuf message / service 定义展开;
    • 管理面与文档、seed、DB 设计围绕同一套 V2 领域模型收敛。
  3. 租户模型升级
    • 从“tenant 只有基础限速”升级为“tenant 拥有 providers、upstreams、consumers、consumer API keys 与 pricing 归属”。
  4. 路由模型升级
    • 从“route 绑定唯一 upstream”升级为“route 负责入口治理与访问限制,模型到上游的映射在 tenant 资源层完成”。

2. 现状梳理:V1 能力与 V2 目标

2.1 当前仓库里仍保留的 V1 兼容能力

结合当前 proto、数据库设计与运行时实现,V1 兼容层主要保留在以下位置:

租户级

  • inbound_rate_limit_qps
  • detect_rate_limit_cpm

这两个字段当前仍直接落在 tenants 表上。

路由级

  • disable_auth
  • legacy_bearer_auth_tokens
  • passthrough_auth_token

其中:

  • legacy_bearer_auth_tokens 用于承接 V1 的 route 级 bearer token 兼容能力;
  • passthrough_auth_token 当前仍保留,但仅作为 legacy 兼容开关;

2.2 当前已经成型的 V2 能力

全局 / Provider 级

  • provider 模板支持 global / tenant 两种来源;
  • provider_pricings 已作为独立资源落地;
  • provider 当前按 protocolbase_urlheaderscompatrequest_header_overridescapabilitiescheck_model 驱动默认运行时行为。 其中 headers 只表示静态 string -> string header 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 粒度的全量读写

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 主业务表”的模型:

  1. 管理面直接写入 PostgreSQL 主业务表;
  2. 数据面在请求时直接通过 RO PG 读取;
  3. 配置可见性取决于数据库提交与读可见性;
  4. 当前不做进程内配置快照;
  5. 当前不做 runtime 表拆分;
  6. 当前不保存历史配置版本。

3.3 一致性模型

当前一致性语义可以概括为:

  • 配置事务提交成功后,由后续请求通过 RO PG 读取新配置;
  • 当前运行时路径主要是“读配置 + 转发”,尚未引入复杂缓存一致性问题;
  • Credit 扣减与 usage 写入尚未真正落入主路径,因此强一致写语义仍属于后续能力。

4. 领域模型与工程约束

4.1 核心实体

当前 V2 领域模型已经围绕以下实体稳定下来:

  • Tenant
  • Route
  • Provider
  • ProviderPricing
  • Upstream
  • UpstreamAPIKey
  • UpstreamModel
  • Consumer
  • ConsumerAPIKey

这些实体的数据库设计与字段语义以 Database(数据库设计) 为准。

补充说明:

  • Protocol 当前不是独立资源,而是 Provider.protocol 字段;
  • Provider / Upstream / Protocol 的职责边界见 Upstream / Provider / Protocol
  • 三种协议的路径、base_urlcompat 规则见 Protocols

4.2 配置归属原则

当前归属边界已经较为明确:

  • 属于 Global / Provider 的:
    • provider 模板
    • provider pricing
  • 属于 Tenant 的:
    • upstreams
    • upstream models
    • consumers
    • consumer API keys
  • 属于 Route 的:
    • path prefix
    • 认证兼容字段
    • labels
    • plugin_configs 聚合得到的 runtime plugin_config 视图

4.3 配置优先级与合并规则

当前运行时已经固定的优先级包括:

  1. route 认证优先级:
    • disable_auth
    • passthrough_auth_token
    • legacy_bearer_auth_tokens
    • consumer_api_keys
  2. upstream 运行时参数合并:
    • provider 提供默认 base_url / headers / compat / request_header_overrides
    • upstream 可以覆盖这些默认值
    • protocol 仍以 provider 为准
    • request_header_overrides 当前不支持 Host 覆盖或透传
  3. 分组约束:
    • 先看 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. 请求执行链路设计

当前数据面主路径可以概括为:

  1. 路由匹配
    • 根据 path prefix 命中 route;
    • 取得 route 绑定的 tenant。
  2. 认证
    • 当前只支持 Authorization: Bearer <token>
    • 认证优先级依次为 disable_authpassthrough_auth_tokenlegacy_bearer_auth_tokensconsumer_api_keys
  3. 入口访问限制
    • 校验 route 是否禁用;
  4. 模型解析
    • 从请求中提取 model
    • 以当前请求模型名去匹配 upstream_modelsprovider_pricings
  5. 请求治理
    • 当前通过 route 聚合后的 plugin_config 视图承载 Guard / 限速等能力;
    • 更完整的 policy 规范化仍未完成。
  6. 上游选择
    • 按 groups、priority、alias、协议与 capability 解析候选;
    • 把 upstream 的可用 API key 展开成 key 级候选;
    • 先按 upstream.priority 从高到低分层,再只在同优先级内做加权随机无放回排序;最多保留前 route.max_attempts 个进入转发计划,默认 2
  7. 转发
    • 根据 provider protocol 选择当前已支持的 forwarder;
    • 生成最终发往上游的请求;
    • 按候选顺序执行请求与 fallback,并返回成功响应或最终失败结果。

当前已固定的认证兼容字段语义

  • 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_qpstenants.inbound_rate_limit_qps当前仍直接落在 tenant 字段上
tenant.detect_rate_limit_cpmtenants.detect_rate_limit_cpm当前仍直接落在 tenant 字段上
route.upstreamproviders + upstreams + upstream_models从“路由唯一上游”改为“provider 模板 + upstream + model 映射”
route.auth.bearer.tokensroutes.legacy_bearer_auth_tokensconsumers + consumer_api_keys长期建议迁移到 tenant 级 consumer 模型
route.passthrough_auth_tokenroutes.passthrough_auth_token当前保留,仅作 legacy 兼容
route.capabilitiesproviders.capabilities + upstreams.capabilitiesforwarder 能力已迁移到 provider / upstream
route.labelsroutes.labels当前仍保留在 route 表上
route.plugin_config.*plugin_configs 聚合后的 plugin_config当前作为运行时与管理面的聚合视图暴露

7.2 迁移策略

由于 V2 运行时只支持 PG,当前建议的迁移方式仍是“离线导入 + 一次切换”:

  1. 从旧 file / redis source 导出快照;
  2. 转换为 V2 的 PG 实体;
  3. 使用 seed 或管理面写入;
  4. 切换到 PG-only runtime;
  5. 停用旧动态配置源。

8. 数据库表设计原则

数据库设计原则已迁移到 Database(数据库设计)

常用入口:

9. 核心业务表设计

核心业务表设计已迁移到 Database(数据库设计)

常用入口:


10. 数据面直查设计

当前 V2 运行时不引入额外的 runtime 表集,也不做业务表 / runtime 表双轨拆分。 aidy-gateway 数据面直接通过 RO PG 读取当前业务表。

10.1 直查原则

  • 不做进程内缓存;
  • 不做 runtime bundle
  • 对禁用、过期、撤销状态做统一过滤;
  • 配置变更提交后,由后续请求通过 RO PG 读取;
  • 读取可见性取决于数据库复制与读可见性。

10.2 关键查询路径

Route 查询

  • 按请求路径做最长前缀匹配;
  • 读取 tenant_iddisable_authlegacy_bearer_auth_tokenspassthrough_auth_tokengroups

API Key 鉴权查询

当前认证分支为:

  1. routes.disable_auth = true
  2. routes.passthrough_auth_token = true
  3. routes.legacy_bearer_auth_tokens 非空
  4. consumer_api_keys Bearer 鉴权

其中 consumer auth 查询路径为:

  • 直接取 Bearer token 原文;
  • 查询 consumer_api_keys
  • 关联 consumerstenants
  • 过滤 disabled_atrevoked_atexpires_atstatus

Tenant / Provider / Upstream / Model 查询

  • 查询 tenants
  • 查询 providers
  • 查询 upstreams
  • 查询 upstream_models
  • 按 groups、priority、alias、协议与 capability 等规则筛选目标;
  • upstreams.api_keys 展开成 key 级候选;
  • 对候选做加权随机无放回排序,并保留 fallback 顺序。

当前已实现的选择规则:

  • routes.groupsconsumers.groupsconsumer_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_modelsis_alias = true 的独立行表达;
  • provider_pricingsupstream_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 主路径跨协议转换与原始协议回组装
  • 初始化能力:
    • seed CLI
    • dev / demo / mock seed profile
    • 自定义 --seed-file

当前仍待补齐的关键闭环

  • consumer / API key 余额预检查;
  • 请求结束后的 Credit 扣减;
  • usage / billing ingestion;
  • 审计、preview、diff。

14. 已确认决策

  • aidy-gateway 的 V2 运行时只支持 PG,不兼容 fileredis-v1redis-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