Vibe新开源项目 - Vaala AI Gateway
先说两句
AI也是越来越热了,从去年的Vibe Coding、Spec Coding,到今年和Harness。概念也真的是层出不穷。
作为一位热爱Coding的VaalaCat当然不能落下这波浪潮。
其实从很早开始本Vaala就开始实验、维护很多自有 AI 工具相关的服务,包括但不限于AI Trace、网关、推理、搜索等基础设施。
其中 VaalaAI - https://ai.vaa.la 是可以供大伙预览的入口,另外的组件都或多或少在支持 Vaala AI的运行。
本次开源的 Vaala AI Gateway 就是这个系统的重要组成部分之一。
由于AI造成的生产力爆棚,只抽了一些小小的周末,完成了该开源项目的开发
另外首先声明,本项目非VaalaCat古法编程开发的娱乐项目,100%由AI生成,用户对代码质量的信任取决于你对VaalaCat技术审美和某魔怔公司模型的信任程度,VaalaCat不对该项目造成的任何问题负责。
背景
也许大伙会有疑问🤔,为什么现在有这么成熟的 AI 网关,非要自己开发一个呢?哎你别说,还真是问到点上了。
现在的AI网关随着火热的中转站市场逐渐越来越成熟,有中转老祖,某知名同司同事开发的 One-API;还有因为弃坑fork继续维护做大做强的 New-API;以及现在号池羊毛党的最爱Sub2API、Claude Code Hub,还有很多如专注于LLM Trace的Axon、正规军Litellm等等,这里就不一一列举了;
只是想让大伙知道,本VaalaCat并非闭门造车,而是有自己的思考,以上的很多工具都有真实上手使用。但是都有各种各样的问题无法满足咱们VaalaCloud的企业灵车级高标准严要求。
以下是一些在我的场景的需求,但已有的开源LLM网关无法同时满足的:
- 原生支持跨国分布式部署,数据面和控制面分离
- 轻量、易部署、干净
- 架构设计代码实现现代、优雅
- 弱化计费、付费功能,只做观测,不做强卡点
- 支持常见协议的相互转换
- 支持自定义转换逻辑修改
- 支持供应商的负载均衡和降级
- 支持模型降级、智能路由(就向openrouter一样)
咋一看这些需求还真是很常见,理由也很好理解,下面我来做一些说明。
技术方案
分布式部署
很多产品都说自己支持分布式部署,那为什么我这里要放到第一点呢?
比如New-API,文档中说支持集群部署。分为主、从两种节点,通过Redis和Mysql集群来实现数据同步,节点间不直接同步。
那这样的架构设计,有什么问题呢?
想象这样一个场景,在A国有模型供应商 A 、O、G,在C国有D、M、Z供应商。他们的服务分别在本地提供最佳的服务。
用户分别存在于A国和C国。会存在下图中的调用模式(跨域调用我们暂且称之为Cross)
红色线条为速度较慢的Cross调用,耗时5秒。
黑色、绿色线条为本地调用,耗时1秒。
黄色线条为优化网络Cross,耗时2秒。
很显然,最快速、稳定的调用显然是全本地调用,也就是不Cross。
但是其中有些步骤,是不得不Cross的。如:
C国用户想要通过网关使用A国供应商的模型,有如下两种调用方式
- C国用户调用C国网关,C国网关调用最近的A国供应商,简称 CCA,这一步的Cross由用户完成
- C国用户调用A国网关,A国网关调用较远的A国供应商,简称 CAA,这一步的Cross由网关完成
并且某些魔怔的模型厂商还有地理位置封锁,因此CCA模式无法直接生效,只能通过C国网关联系A国网关,再由A国网关调用A国供应商。也就是CCA模式的实现其实是CCAA模式。 即图中绿丝+橙色链路
那么话说回来。如果我们想要用New-API实现突破模型厂商的封锁,并且为各地用户提供较好的体验,显然是要使用「集群部署」模式的。
事实1
- api接入点离用户越近,后续的各种优化都能更早的在系统内生效,也就是越好做优化。
很显然,我们应该选择 CCAA 模式。
New-API应该如何实现呢?首先我们要在 A、C选一个处搭建Master节点,然后要在A、C建立Redis和Mysql集群,数据在节点间的同步完全依赖Redis和Mysql的数据同步机制。
事实2
- 优化在越接近业务的地方去做,成本越低,效果越好,但是覆盖范围越小;反之依然
由于依赖底层基建(Redis、Mysql)去做Cross数据同步,这就决定了它一定是非常难做好优化的,会受到各种业界遇到的难以解决的复杂问题。
另外一个重要场景就是CCC(网关主节点在A国),在C国网关要验证token可用性、获取供应商信息时,也可能会发生回到A国主节点Cross的情况,会造成本该很低的延迟、很稳定的请求,发生了高延迟甚至错误。
除了New-API,其他网关我也没有看到有主动想要解决这种问题。也许他们都是大公司,不怕「事实2」中的成本问题,可以用更多的人力去维护基建层面的数据同步和优化。
对于Vaala这种人力较少的场景来说,只能走精细化业务定制的方案来降低成本提升效果。
架构设计
既然现有方案无法完美满足要求,而且AI,我们就要开始设计架构了。
由于我们最重要的目标就是轻量级实现分布式部署,我们首先要考虑的就是不可能三角:CAP
CAP 不可能三角,点击展开
- Consistency 一致性
- Availability 可用性
- Partition Tolerance 分区容错性
所有的分布式系统都必须在这三者之间权衡取舍(三选二)。
在分布式系统中,网络分区(P)是必然会发生的客观物理现实。因此我们必须在 CA 和 AP 之间做出选择。PACELC指导我们如何做出选择:
如果发生网络分区 (P),权衡可用性 (A) 与一致性 (C);否则 (E),权衡延迟 (L) 与一致性 (C)
ScyllaDB也有文章详细介绍这部分:https://www.scylladb.com/glossary/pacelc-theorem/
根据 PACELC 理论,现有的分布式数据库可以划分为以下四种架构类型:
PC / EC (例如:MongoDB、Riak、HBase)
-
分区时选择一致性,正常时也选择一致性。数据完全同步,会牺牲一部分读取或写入的延迟。 PA / EL (例如:Dynamo、Cassandra)
-
分区时选择可用性,正常时选择延迟。采用最终一致性,数据写入极快,响应延迟低。 PC / EL (例如:PNUTS)
-
分区时选择一致性,正常时选择低延迟。无分区时注重速度,出现分区则严格保证一致性。 PA / EC (例如:Megastore、Spanner)
-
分区时选择可用性,正常时选择一致性。这类系统在常规状态下尽力保障一致性,但会在网络异常时动态调整容错策略。
出于我对我需求的理解,我们选择最大的可用性和最低的延迟,因此必定会大幅牺牲一致性。
实现低延迟和可用性最佳的方式就是数据复制,又由之前的分析可知从业务层实现复制效果最好。
接下来一个重要的选择就是数据同步的方式。
由于我们大部分数据不考虑强一致性(如上游信息基本不怎么变,token一般也不怎么变,一致性没那么重要),那异步复制就是必然的选择:需要同步的数据由主节点定期、按需、异步同步到从节点,只要从节点有处理当前请求的所有信息,我们就能只在从节点完成这个请求,对于纯本地的CCC模式就能非常快。
但是统计、计费信息等数据需要总是写回在主节点,以便做统一的观测和管理。但由于我对付费机制不敏感,所以我们也选择异步上报。
虽然这里分析了很多,说是牺牲了一致性,实际上在我的测试和使用中发现,这种一致性的丢失对于不严格付费的内部使用可以忽略不计,事实证明,即便是跨国场景,只要机器稳定,几乎不会遇到数据丢失的情况,计费延迟也控制在一分钟以内
角色设计
既然是分布式系统,又想统一管理,我们使用经典的主从架构。从节点尽可能的无状态、轻量,主节点存储所有数据作为控制面,不直接处理业务请求。
所以我们设计两个角色,Master和Agent。Master存储所有的数据,Agent处理用户的代理请求。
对于Master,主要任务是处理更多常见的业务逻辑,数据增删查改、统计、管理、同步;
对于Agent,主要从Master缓存同步来的数据,利用数据处理客户端LLM请求;
Master没啥说的,就是一个大Hub,接受所有Agent的长连接,出于兼容考虑,使用VaalaCat最喜欢的WebSocket和JsonRPC实现。这个长连接通道负责同步极少数的业务数据,由于wss可以经过cdn和反向代理,也可以当链路优化通道来使用。
Agent需要处理我最常用的三种协议:
- OpenAI Response/OpenAI Chat/Claude Messages。
- 如果做3*3的直接转换,我们要写9种代码。很容易想到我们要做一种中间协议,用于兼容所有协议,这样每增加一种,只需要对中间协议做适配即可。
- 另外,New-API的协议转换也做的非常的好。更妙的是,New-API使用的是我最喜欢的Go语言开发,天上掉下来的馅饼当然要吃,所以我们和frp-panel一样,直接把New-API拉过来,import就能实现无痛兼容。
Quick Start
说了这么多,不如先跑起来看看。
Vaala AI Gateway 部署极其简单,Master 和 Agent 都是单二进制,没有外部依赖
具体的部署请参考 https://github.com/VaalaCat/ai-gateway
代码实现
对于代码,既然有了AI,当然要狠狠的Vibe,对于AI这种变更非常快的东西,古法编程跟AI相关的东西简直是最不划算的想法。
所以具体实现我就不多说了,懂得都懂。
另外说一句,随着大Vibe时代的到来,代码迎来了生产力爆发,但同样的模型,依据不同作者的想法,依旧能写出或烂或好的代码。
因此代码和架构的审美会变的尤其重要。也许一个完全不懂代码的人,现在能靠各种工具写出精美炫酷的前端和后端,但随着项目向生产产品级的迭代,代码质量会越来越影响项目能走多远。
以本项目为例,整个开发流程大概是这样的:
- 先想清楚 Master/Agent 的职责划分、数据同步策略、协议中间层的设计。这部分 AI 帮不上太多忙,可以帮你做方案对比,但做不了决策。
- 骨架生成:把设计文档喂给模型,让它生成项目骨架。Go 的项目结构、接口定义、核心数据模型,这里 AI 非常高效。大概 10 分钟就拿到了一个能编译的空壳项目。
- 逐模块开蹬:每个模块(Provider 适配、协议转换、WebSocket 同步、缓存层等)分开对话,给清楚上下文和接口约束,让 AI 逐个实现。
- 缝合:模块之间的集成、边界情况的处理、实际部署测试,只要设计好环境和操作方式,AI 就能高效地完成。
- 重构:通读架构和模块以来以及重要代码,干掉不必要的抽象、统一命名风格、补充注释。AI在上下文不足的情况下很容易写重复代码,有时也很容易过度设计。在这个生产力爆炸的时代,应该尽早重构,以保持代码质量和开发效率。
一些 Vibe 心得
AI 擅长的:
- 样板代码(Provider 适配、Protocol Buffer、错误处理)
- 生成测试用例(虽然你需要判断哪些 case 是有意义的)
- 快速原型验证
AI 不擅长的:
- 架构决策
- 性能敏感的代码
- 复杂的并发和状态管理
- 克制
AI 生成的代码看起来都能跑。这其实是最危险的,掩盖了设计层面的问题
所以VaalaCat的建议是:在让 AI 写代码之前,先花足够的时间想清楚设计。Vibe Coding 省的是手,不是脑。