主题
Redis 与 AI
一句话:Redis 在 AI 链路里首先不是向量库,而是模型外面的低延迟状态层——语义缓存、会话记忆、限流、事件总线;向量检索是 Redis 8 新增的能力,适合中小规模。
适用版本:Redis 8.0+(Query Engine 与 Vector Sets 进入核心),8.2 引入 SVS-VAMANA 索引(以官方文档为准)。
为什么需要
一次 LLM 调用通常几百毫秒到几秒,成本按 token 计。工程上能省的环节几乎都落在 Redis:
- 语义缓存:相似问题直接返回上次答案,省一次模型调用。
- 会话记忆:多轮对话的短期上下文、用户画像,要求毫秒级读写和 TTL。
- 限流:按用户/租户限制模型调用速率,防止打爆配额。
- 事件总线:Agent 的工具调用、子任务结果用 Stream 传递。
- 召回层:中小规模的向量相似度检索,作为向量数据库的补充。
这些负载的共同点是「小对象、高并发、可过期」,正好是 Redis 的主场。向量检索只是其中一项,不是 Redis 在 AI 里的全部。
核心机制:访问模式变了
AI 带来的变化不是「多存一种数据类型」,而是访问模式变了:
- 读远多于写,且 key 是语义的。传统缓存 key 是确定的 ID;语义缓存的 key 是 embedding,命中判断从「相等」变成「相似度超过阈值」。
- 单 value 变大。一条 1536 维 float32 embedding 约 6 KB,比普通缓存 value 大一个数量级,内存规划要先于功能设计。
- 写入带生命周期。会话记忆要按用户过期,模型调用配额要按时间窗口重置,事件要被消费组 ACK。
- 一致性要求分层。缓存答案可以旧几秒;限流计数必须原子;会话记忆不能丢。
这决定了 Redis 的用法:缓存和状态用 String/Hash/List/Stream,向量召回用 Vector Sets 或 Query Engine,限流用 Lua 保证「读-判断-写」原子。
核心机制:两条路线与判定链
两条向量路线
Vector Sets(VADD/VSIM) | Query Engine(FT.*) | |
|---|---|---|
| 定位 | 轻量向量集合,API 简单 | 完整检索:向量 + 全文 + 标签/数值过滤 |
| 索引 | HNSW | HNSW / FLAT / SVS-VAMANA(8.2+) |
| 过滤 | 元素属性表达式 | Schema 字段过滤、聚合 |
| 适合 | 语义缓存、推荐召回 | 多条件检索、混合检索 |
Vector Sets 是 Redis 8 的新数据类型,默认 Q8 量化,内存约为 float32 的 1/4;首次 VADD 时确定量化方式(Q8/BIN/NOQUANT),之后不能改。它不是通用向量数据库:一个 Vector Set 本身不跨分片拆分,也没有复杂聚合。Query Engine 才能做「向量 + 标签过滤」的混合检索。
语义缓存的判定链
命中与否只由「相似度阈值 + 是否过期」两个条件决定,未命中必须回写,否则缓存永远不会热起来。
阈值不能拍脑袋:取一批真实问题做离线评测,画「相似度—正确率」曲线,选业务能接受的误答率。阈值过低会把不同问题判成同一个,这是语义缓存最主要的线上事故。缓存的 key 要带模型版本和索引版本,模型升级后能整体失效。
记忆与事件
- 短期记忆:
HSET session:{id}+EXPIRE,或LPUSH+LTRIM保留最近 N 轮。 - 长期记忆:结构化事实存 Hash/JSON,检索走 Query Engine。
- Agent 事件:
XADD写、XREADGROUP消费,支持多消费者与 PENDING 重投。 - 限流:用 Lua 做令牌桶,保证「读计数—判断—写回」原子,不要拆成多条命令。
最小上手
bash
docker run -d --name redis-ai -p 6379:6379 redis:8
redis-cliVector Sets(默认 Q8):
VADD docs VALUES 3 0.10 0.20 0.30 doc:1
VADD docs VALUES 3 0.90 0.10 0.10 doc:2
VSIM docs VALUES 3 0.10 0.20 0.31 COUNT 2 WITHSCORESQuery Engine(向量 + 标签过滤):
FT.CREATE idx ON HASH PREFIX 1 chunk: SCHEMA \
tenant TAG content TEXT \
embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 3 DISTANCE_METRIC COSINE
HSET chunk:1 tenant t1 content "退款政策" embedding "<binary>"
FT.SEARCH idx "@tenant:{t1}=>[KNN 5 @embedding $vec AS score]" \
PARAMS 2 vec "<binary>" SORTBY score DIALECT 2二进制向量的编码容易出错,实际项目用 redis-py/Jedis 等客户端构造,不要手拼。
生产动作
- 先算内存再建索引:
条数 × 单条向量字节 × 索引放大系数。1536 维 float32 约 6 KB/条,HNSW 经验上再乘 1.5–2;Q8 量化按 1/4 估。算完再决定用不用 Redis。 - 显式设置淘汰策略:纯语义缓存用
allkeys-lru;会话记忆和限流计数不能丢,用noeviction并监控used_memory与写入错误。默认就是noeviction,写满会直接报错。 - 给缓存 key 加版本:
sem:{model_version}:{index_version}:{hash}。模型或知识库升级时改版本号即可整体失效,不要靠逐个删 key。 - 监控命中率与相似度分布:除了
keyspace_hits/misses,还要抽样记录 top1 相似度。阈值附近请求变多,说明缓存开始大量误判或几乎不命中。 - 限流用 Lua 或客户端原子脚本:
INCR+EXPIRE分开写会在两步之间留下没有 TTL 的 key;令牌桶的读-判断-写必须在一次脚本里完成。 - 向量数据要可重建:AOF
everysec仍可能丢约 1 秒,索引重建成本又高。原始文本和 embedding 要落在可重放的存储里,Redis 只做检索副本。
边界
- 内存是唯一硬约束:1536 维 float32 约 6 KB/条;HNSW 图结构经验上再乘 1.5–2 倍,Q8 量化可降到约 1/4。1000 万条就是百 GB 级,先算内存再谈索引。
- 持久化不是备份:AOF
everysec仍可能丢约 1 秒;向量索引重建成本高,重要数据要能重放。 - 语义缓存会放大模型错误:缓存的是旧答案,模型或知识更新后要能按版本号整体失效。
- 不适合当向量主库:没有独立的分片/副本索引管理,内存成本高,持久化弱于数据库。
- 集群限制:多 key 操作用 hash tag 落到同一 slot;开源 Cluster 下 Query Engine 的分片与能力边界以官方文档为准,规模化检索通常需要 Redis Enterprise/Cloud。
maxmemory-policy要显式配:纯缓存用allkeys-lru;会话不能丢用noeviction并告警——默认就是noeviction,写满直接报错。- 不适合复杂分析:聚合、join、跨租户统计交给 SQL/ES。
选型判断
| 场景 | 选择 |
|---|---|
| 已经在用 Redis,百万级以内,要低延迟、可接受内存成本 | Redis(Vector Sets 或 Query Engine) |
| 需要向量 + 标签/全文混合过滤,规模中等 | Redis Query Engine |
| 上千万条、要高压缩比、独立扩缩容、专用索引管理 | Milvus 等专用向量库 |
| 需要强一致、复杂事务、长期归档 | 关系库/专用系统,Redis 只做缓存层 |
判断标准很简单:如果 AI 只是给现有业务加一个「相似问答」或「会话状态」,Redis 足够;如果向量检索本身是核心业务、数据量持续上亿,就不要把 Redis 当主库。
讲清楚
Redis 在 AI 系统里最重要的角色不是「向量数据库」,而是「模型外面那层低延迟状态」。模型慢且贵,所以要有语义缓存;对话要有记忆;调用要限流;Agent 之间要传事件——这些都在 Redis 里,因为它们是毫秒级、可过期、允许丢的小对象。
Redis 8 把 Query Engine 并进核心,又加了 Vector Sets,所以它确实能存向量、做相似度检索。但要分清两条路线:Vector Sets 简单,适合缓存和召回;Query Engine 才能做向量加标签过滤的混合检索。共同约束是内存——向量很占地方,先算内存再选型。百万级以内、已经在用 Redis,直接用;上千万条或要独立扩缩容,交给 Milvus。