Redis AI Challenge参赛作品,通过实时AI路由和缓存优化API性能的开源方案。
这是提交给 Redis AI Challenge: Beyond the Cache 的项目。
一个请求,一个意图,KeyPilot 就能知道精确调用哪个 API。
想象你在使用五个不同的 AI 服务。每个都有自己的 API 密钥、自己的端点和自己的怪癖。现在,每次你想构建什么东西时,都得停下来想:「我应该用哪个密钥?哪个服务对这个请求最便宜?哪一个甚至支持我需要的功能?」
这就是 KeyPilot 介入的地方....
我构建了一个语义 API 网关,它会听你实际想做什么——「总结这份文档」或「生成一张山村的图像」——然后立即为你挑选合适的 API 密钥和端点。不用翻阅文档。不用手动切换。
Redis Vector Search 理解你请求背后的意图。
Redis Caching 记住我们是否之前回答过这个问题,然后在几毫秒内将其返回,而不再次调用 API。
你省时间,你省金钱,你的集成运行速度更快。
借助 KeyPilot,我不仅在路由请求,而是让 API 集成构建更快、运行成本更低,并且每次使用时变得更聪明。
我知道你在想什么……「Joel,直接给我直链,我现在就点击开始玩!」😏
但这里有个问题——没有登录凭证,你只会盯着登录页面想知道哪里出错了。然后……你又得回到这里找详情。
所以让我们为你省掉这个尴尬的额外步骤,好吗?😉
👉 Live App - https://smartkeypilot.vercel.app/
这是个演示应用,快速构建来展示核心想法。不是锁定的、生产级别的堡垒。把它看作一个酷炫的原型——足以给人留下深刻印象,但不是你会用来管理银行业务的。
不要使用个人 API 密钥,拜托。🙅♂️ 我已经为你准备好了演示友好的密钥。
如果你非要用自己的,确保它们是临时的且可以撤销的。
Demo 会话持续 8 分钟。时间一到,所有密钥都会被清除。
好好对待这个系统 ❤️ ——不要垃圾消息,不要滥用,让我们为每个人保持流畅的体验。
遵循这个简单的模式:
Username: demo + 1–3 digits → (Example: demo123)
Password: pass + the same digits → (Example: pass123)
选择任何数字组合你想,只要坚持这个格式。一旦你进去了,你可以自由地用内置的演示 API 密钥探索。✅ 无需设置。✅ 无风险。✅ 即时快乐。
应用已经内置了演示 API 密钥,所以你可以立即尝试所有功能——语义意图匹配、路由、缓存。如果你确实添加了自己的密钥,记住——一旦你的会话过期,它们就会消失。
如果你在敲击 demo 链接前就登陆这里……我已经喜欢你了。🤝
为了最佳性能,把它连接到 Redis Cloud,用你的连接字符串——这给你超快的向量搜索和缓存(快速且简单)。
Frontend repo: https://github.com/Joeljaison391/KeyPilot-Frontend
Backend repo: https://github.com/Joeljaison391/KeyPilot
没问题,我有你。这是一个快速介绍视频,所以你可以看演示而不费力气:
这是我们的登陆页——干净、简洁、邀请人。目标是立即告诉你 KeyPilot 是什么,并给你一个方式直接深入。
这是登录页——没有麻烦,没有困惑。只需登录,或用演示模式跳入来探索而不创建账户。
刚来这里?我们的入门教程会引导你了解基本知识,从找到你的 API 密钥到使用测试游乐场,这样你可以立即提高生产力。
一旦进入,仪表板是你的命令中心。看你的密钥、使用统计和快速操作都在一个地方。
需要一个新 API 密钥?"Add Key"模态框让它变得简单。选择一个提供商模板,设置限制,定义允许的源,你就完成了。密钥已加密,并在应该时自动过期。
幕后,Redis Cloud 驱动一切——从存储加密密钥到缓存 API 响应。这是 Redis Cloud 仪表板让一切运行闪电般快速。
欢迎来到 API 测试游乐场——调整有效载荷,改变你的意图,观看 KeyPilot 用语义匹配选择最佳模板。
好奇你的请求会触发哪个模板,但不想调用真实 API?意图测试工具让你检查而不作真实 API 调用。
为什么要为同一个 API 调用付两次钱?KeyPilot 使用语义缓存——如果之前做过类似请求,它会立即提供存储的响应,节省成本和时间。
最后,用 API 使用监控跟踪一切——从使用的令牌到正常运行时间/停机时间,再到成功率和缓存命中。
Frontend ---------- 我选择了 Vite + React,因为我想要闪电般快速的开发速度和流畅的生产构建。样式?Tailwind CSS,因为在凌晨 3 点写原始 CSS 不是氛围。一切都托管在 Vercel,所以部署只是一推之遥。
Backend ---------- 服务器运行在 Node.js + Express.js 上,用 TypeScript 编写,这样可以获得甜蜜的类型安全。我把它托管在 Render,这意味着我可以专注于编码而不用照看服务器。
Data Layer ---------- 这就是事情变得有趣的地方。Redis Cloud 是我的主数据库,处理向量搜索和缓存就像冠军一样。对于超低延迟操作,我也保留了一个 Redis 内存实例,因为毫秒很重要。
Workflow ---------- 版本控制?显然是 Git。头脑风暴和团队计划?Notion,这是想法从「如果……」变成「发货」的地方。
大多数人在构建应用时会想到 PostgreSQL、MySQL 和 MongoDB 这样的数据库。它们对于长期的结构化存储很好,但对于这个项目,我需要不同的东西。
⚡ 速度高于一切——我想要亚毫秒级的查找。
🕒 内置过期——会话和 API 密钥应该在几分钟后自我销毁,无需 cron 作业。
🔐 简单、原子操作——设置它、获取它、删除它。没有复杂的连接。
🧠 既可作为缓存也可作为 DB——为什么要在两个系统之间杂耍,当一个可以做两个事情?
如果我使用了普通数据库:
我需要编写额外的代码来删除过期的会话。
由于基于磁盘的查询,每个 API 调用都会更慢。
缓存无论如何都需要单独的 Redis 实例。
所以,与其陷入这个两系统的麻烦,我全力投入 Redis 8 作为这个应用的完全成熟的主数据库。
当我说 Redis 是支柱时,我的意思是它从字面上运行一切——从让你登录,到存储你的 API 密钥,到确保你的会话在 8 分钟后礼貌地消失,我无需动手。
我们使用 Redis Strings & Hashes 来存储用户会话和加密的 API 密钥,设置 TTL 自动过期,所以当不再需要时它们会消失。这意味着没有手动清理,没有陈旧登录,瞬间访问。
await redis.setEx(`user:${userId}`, 480, JSON.stringify(sessionData));
await redis.expire(`keys:${userId}:${template}`, 480);
每个 API 密钥都存储在一个 Redis Hash 中,带有创建时间和描述等元数据。没有重复密钥,没有过期的条目——只是干净、加密的存储。
await redis.hSet(`keys:${userId}:${template}`, {
encrypted_key: encrypted,
description,
created_at: Date.now()
});
Redis RediSearch + Vector Index 让我们根据含义而不仅仅关键词来匹配正确的 API 密钥与正确的请求。一旦取回,响应被缓存以便闪电般的重放。
const results = await redis.ft.search(
'idx:intents',
'*=>[KNN 1 @vector $query_vector]',
{ PARAMS: { query_vector } }
);
await redis.setEx(`cache:${userId}:${intentHash}`, 3600, JSON.stringify(apiResponse));
我们结合了 Redis Pub/Sub、Streams 和 Counters 来实时跟踪每个请求。
Pub/Sub 立即广播「received」和「completed」事件给仪表板。
Streams 保持活动和缓存请求的时间排序历史。
Counters 聚合每日和每周统计以便快速总结。
// Live event broadcasts
await redis.publish('channel:request:received', JSON.stringify({ userId, intent, ts: Date.now() }));
await redis.publish('channel:request:completed', JSON.stringify({ userId, latency, cacheHit, ts: Date.now() }));
// Activity stream (last 50 events)
await redis.xAdd(`analytics:activity:${userId}`, '*', { event: 'request:success', intent, latency: String(ms) });
await redis.xTrim(`analytics:activity:${userId}`, 'MAXLEN', 50);
// Daily counters
await redis.incr(`analytics:daily_requests:${userId}:${date}`);
用户触发的每个意图都使用 Sorted Sets 计数。这给了我们即时的热门请求排行榜——非常适合发现模式。
await redis.zIncrBy(`intent_trends:${userId}:daily`, 1, intent);
const topIntents = await redis.zRange(`intent_trends:${userId}:daily`, -5, -1, { REV: true });
Redis 使得批量查找和擦除旧缓存密钥变得容易。没有混乱的 SQL 查询,只是快速扫描和删除。
const keys = await redis.scanIterator({ MATCH: `cache:${userId}:*` });
for await (const key of keys) await redis.del(key);
我们用 Sorted Sets 保持了用户意图的周计数。这帮助我们预测用户接下来会要求什么——几乎像读心术。
await redis.zIncrBy(`intent_trends:${userId}:weekly`, 1, detectedIntent);
通过结合多个 Redis 8 特性,我们取代了五个不同的系统:
我的规则很简单:如果有人需要手册,我就搞糟了。所以我持续削减多余的文本,在随机的小时移动东西,用小图标交换长解释。我只想让人打开应用,立即知道该做什么。
时钟声比我的键盘声更大。每个决策都是同一个问题:我应该让它完美还是让它工作?我选择了「让它工作」。
想法很简单:用纯英文输入你想要什么,应用找出要调用哪个 API。听起来容易……但不是。我必须为不同服务创建灵活的模板,同时保持它们精确。到我完成时,我听了超过 150 首歌,坐过 60+ 次 Spotify 🎧 广告同时编码。
说「亚毫秒级」很容易。让它发生?不那么容易。我花了几个小时调优 Redis 查询,减小数据大小,设置缓存,同时确保没有其他东西坏了。
特别感谢 abelboby 对前端开发的贡献,帮助让用户体验栩栩如生。
如果你读到这里,谢谢你!🚀 我真诚地感谢你花时间探索这个项目并跟随这段旅程。
一些评论可能仅对登录访问者可见。登录查看所有评论。
如需进一步操作,你可能要考虑屏蔽此人和/或举报滥用。