编程 Redis 8.x AI 原生深度拆解:从缓存到 AI 实时数据基础设施——向量搜索、语义缓存、Agent Memory 工程实战

2026-07-30 22:43:18 +0800 CST views 13

Redis 8.x AI 原生深度拆解:从缓存中间件到 AI 实时数据基础设施的范式跃迁——向量搜索、语义缓存、Agent Memory 工程实战

一、背景:当「缓存中间件」觉醒,Redis 为什么不甘只做缓存

在大多数后端团队的认知里,Redis ≈ 高性能缓存中间件。Session 存它、热点数据存它、分布式锁用它、限流计数器用它——六个字符的 SETGET,撑起了互联网公司半壁江山。这个印象没有错,但已经过时了。

2025 年 11 月,Redis 社区发布了 8.x 大版本更新,这不仅是版本号的一次跳动,而是 Redis 对自己的重新定义。加上 2024-2025 年间的一系列能力部署,Redis 的能力版图已经完全变了味道。站在 2026 年 7 月底的现在回看,Redis 已经从一个纯粹的缓存系统,蜕变为 AI 应用的「统一实时数据层」。

为什么 Redis 要做这件事?三个层面的驱动力:

1.1 技术层的必然:AI 应用的「数据痛点」

传统业务系统的数据访问模式是「给一个 key,拿一个 value」——精确匹配就够了。但 AI 应用对数据层的诉求完全不一样:

  • 向量检索:RAG 系统需要从百万级文档里找到「语义上最相似」的那几篇,而不是匹配一个精确的 key
  • 语义缓存:LLM 调用又贵又慢,用户问「怎么退货」「我想退款」「退货流程是什么」语义完全一样,但传统缓存全都 miss
  • 记忆管理:大模型本身无状态,AI Agent 需要存储会话上下文和用户偏好
  • 实时特征:推理服务需要在毫秒级读取用户画像、商品特征

这些需求,恰好命中了 Redis 的基因:内存优先、亚毫秒延迟、数据结构丰富。

1.2 商业层的必然:生态地位决定进化方向

Redis 不是第一天想做 AI。从 RediSearch 模块(2016 年发布)到 RedisAI 模块,再到 RedisVL 客户端库,Redis Labs 已经在这条路上走了近十年。但 2024-2026 年是一个转折点:

  • 向量数据库赛道大爆发(Milvus、Pinecone、Weaviate、Qdrant),让市场意识到向量检索不是锦上添花,而是刚需
  • AI Agent 和 RAG 成为主流应用模式,对数据层的需求从「存」变成了「存+搜+管」
  • Redis 创始人 Salvatore Sanfilippo(antirez)回归后亲自主导了 Vector Sets(VSET)数据类型——这是他离开又回来后的第一个大动作

Redis 的战略很清楚:不和 Milvus、Pinecone 争「最强向量数据库」,而是打「一站式」的牌——你的缓存、向量、会话、特征,都可以放在同一个 Redis 里管理,减少架构复杂度。

1.3 用户的视角:为什么你应该在意这件事

如果你是个后端工程师,今年你大概率会接触到这些场景:

  • 团队要做一个 AI 客服,问到「记忆怎么存」的时候,你是引入一个专门的向量数据库,还是直接在现有的 Redis 上加一个索引?
  • 线上 LLM API 每月账单飙升,CTO 问「能不能降本」,你能不能在现有缓存架构上叠一层语义缓存?
  • 要做用户画像的语义搜索,你是搭一套 Elasticsearch + 向量插件的重型方案,还是两条命令搞定?

Redis 的 AI 能力,让这些选择的答案从天平的一端偏向了另一端。


二、Redis 8.x AI 能力全景架构

在深入每个模块之前,我们先拉一张完整的架构图。

┌─────────────────────────────────────────────────────────────────────┐
│                     Redis AI 能力全景(2026)                       │
├──────────────────────┬──────────────────────┬───────────────────────┤
│      向量检索层       │       AI 缓存层       │      记忆管理层        │
├──────────────────────┼──────────────────────┼───────────────────────┤
│  Redis Query Engine  │    LangCache         │   Chat Memory         │
│  (HNSW/FLAT/SVS)     │    (语义缓存)         │   (短期会话)           │
│                      │                      │                       │
│  Vector Sets (VSET)  │    RedisAI           │   Long-term Memory    │
│  (原生数据类型)       │    (模型推理)         │   (向量检索+语义)      │
├──────────────────────┴──────────────────────┴───────────────────────┤
│                       客户端生态层                                    │
│    RedisVL (Python)    |    Spring AI Redis (Java)    |    others    │
├─────────────────────────────────────────────────────────────────────┤
│                        基础设施层                                     │
│           集群/哨兵    |    持久化(RDB/AOF)    |    多线程 I/O        │
└─────────────────────────────────────────────────────────────────────┘

表格化的能力矩阵:

能力模块核心功能适用场景引入版本
Redis Query EngineHNSW/FLAT/SVS-VAMANA 向量索引与检索RAG、语义搜索、推荐系统RediSearch 2.4+
Vector Sets (VSET)原生向量数据类型,轻量级相似度查询快速原型、小规模检索Redis 8.0
LangCache基于语义相似度的 LLM 响应缓存降低 LLM 调用成本Redis Cloud 2025
RedisAI(维护模式)Redis 内部运行 ML 模型推理实时特征计算RedisAI 模块
Agent Memory短期会话 + 长期语义记忆AI Agent 上下文管理2025+
RedisVLPython 向量存储/检索 SDKRAG Pipeline 构建2024+

下面我们就逐一拆解这些能力的技术细节。


三、Redis Query Engine(向量搜索):把「模糊查找」变成一等公民

3.1 它解决的核心问题

传统 Redis 的查询是精确匹配:GET user:1001 → 返回 {name: "张三", age: 28}。但在 AI 场景下,绝大多数查询是「模糊」的:

  • 用户问「怎么退货」→ 需要从知识库里找到语义最接近的 FAQ
  • 推荐系统要找和当前商品「最像」的其他商品
  • 风控系统要找和当前行为「最相似」的历史欺诈模式

这些都不是 GET 能搞定的。需要的是向量相似度搜索(Vector Similarity Search)。

3.2 技术架构

Redis Query Engine(RediSearch 模块的升级版)的核心架构:

┌─────────────┐      ┌──────────────┐      ┌─────────────┐
│  Hash/JSON  │ ──→  │  向量索引引擎  │ ──→  │  检索控制器  │
│  数据结构    │      │              │      │             │
│             │      │  HNSW 索引   │      │  KNN 搜索   │
│  embedding  │      │  FLAT 索引   │      │  Range 搜索 │
│  作为字段    │      │  SVS 索引    │      │  混合查询   │
└─────────────┘      └──────────────┘      └─────────────┘

关键设计决策:向量不是新的数据类型,而是 Hash 或 JSON 中的一个字段。这个设计意味着:

  1. 存量数据无缝升级——已有的 Redis Hash 数据,只要加上一个 embedding 字段就能支持向量检索
  2. 事务一致性——数据和它的向量表示在同一个事务里更新,不会出现「数据变了但索引没更新」的状态
  3. 混合查询天然支持——在同一数据结构上,可以同时做全文搜索、TAG 过滤、数值过滤和向量检索

3.3 支持的距离度量

距离度量公式适用场景
余弦相似度 (COSINE)cos(θ) = A·B / (A
欧氏距离 (L2)d = √Σ(Aᵢ-Bᵢ)²图像特征、数值特征
内积 (IP)Σ(Aᵢ×Bᵢ)归一化向量的高效检索

实践中,文本嵌入几乎都用余弦相似度,这是 OpenAI、Cohere 等主流 embedding 模型的默认距离。

3.4 支持的索引算法

FLAT(暴力搜索)

最朴素的算法:遍历全部向量,逐一计算距离,返回 Top-K。数学上精确,但时间复杂度 O(n×d),n 是向量数量,d 是维度。

适合小数据集(<10 万条)或者对召回精度要求到 100% 的场景。

HNSW(分层可导航小世界图)

这是目前工业界最主流的近似最近邻(ANN)算法:

Layer 3:    ●────●────●        ← 最顶层,连接稀疏
              /   │   \
Layer 2:  ●──●──●──●──●──●    ← 中间层
          │  │  │  │  │  │
Layer 1:  ●─●─●─●─●─●─●─●─●─●  ← 底层,连接密集

核心思想:多层图结构,从上往下搜索。顶层跳过大量无关向量快速定位到近似区域,底层在局部范围内精确搜索。

HNSW 的参数调优:

  • M:每个节点的最大连接数(默认 16)。越大召回率越高,但索引构建时间和内存占用都增加
  • EFConstruction:构建时的动态候选列表大小(默认 200)。越大索引质量越高,但构建越慢
  • EFRuntime:查询时的候选列表大小。越大召回率越高,但查询越慢

经验法则:

  • 生产环境:M=16, EFConstruction=200, EFRuntime=100~200
  • 极致性能:M=8, EFConstruction=100, EFRuntime=50(牺牲召回率换速度)
  • 极致精度:M=32, EFConstruction=400, EFRuntime=400

HNSW 的召回率通常在 95%-99.9% 之间,查询速度比 FLAT 快 10-100 倍(取决于数据规模和参数)。

SVS-VAMANA(Intel 的向量搜索库)

Redis 在 8.x 中集成了 Intel 的 SVS(Similarity Vector Search)库,引入了 VAMANA 算法。VAMANA 和 HNSW 类似,但在内存布局和 SIMD 指令集优化上做得更激进。在 Intel 的 CPU 上,VAMANA 的 QPS 可以比 HNSW 高出 20%-40%。

3.5 实战:创建向量索引并检索

# 1. 创建索引,定义向量字段
FT.CREATE doc_idx ON HASH PREFIX 1 doc: \
  SCHEMA \
    title TEXT \
    category TAG \
    embedding VECTOR HNSW 6 \
      TYPE FLOAT32 \
      DIM 768 \
      DISTANCE_METRIC COSINE

这个命令做了什么:

  • doc:* 前缀的 Hash 上创建索引
  • title 是 TEXT 类型(支持全文搜索)
  • category 是 TAG 类型(支持精确过滤)
  • embedding 是 768 维的 HNSW 向量索引,使用余弦相似度
# 2. 写入带向量的数据
HSET doc:1 title "Redis 向量搜索入门" category "database" \
  embedding <768维float32二进制数据>

HSET doc:2 title "LangChain RAG 实战指南" category "ai" \
  embedding <768维float32二进制数据>

HSET doc:3 title "PostgreSQL 性能调优" category "database" \
  embedding <768维float32二进制数据>

关于 embedding 的二进制格式:Redis 的向量字段需要将 float32 数组打包为二进制。这不能用文本字符串传递,需要用程序编码:

import numpy as np

# 假设你的 embedding 是 768 维的 numpy 数组
embedding = np.array([0.1, 0.2, ..., 0.768], dtype=np.float32)

# 重要的:打包为字节流
embedding_bytes = embedding.tobytes()

# 在 redis-py 中
import redis
r = redis.Redis()
r.hset("doc:1", mapping={
    "title": "Redis 向量搜索入门",
    "category": "database",
    "embedding": embedding_bytes
})
# 3. KNN 查询:找最相似的 5 篇文档
FT.SEARCH doc_idx \
  "*=>[KNN 5 @embedding $query_vec AS score]" \
  PARAMS 2 query_vec <查询向量二进制数据> \
  SORTBY score \
  RETURN 2 title score \
  DIALECT 2

这个查询的语义:在所有文档中,对 @embedding 字段执行 KNN 搜索,返回 Top-5 结果,按相似度得分排序。

3.6 混合查询:向量检索 + 传统过滤

Redis 向量搜索的真正杀手锏是混合查询——向量相似度和传统过滤条件无缝组合:

# 在 category 为 "database" 的文档中,找最相似的 5 篇
FT.SEARCH doc_idx \
  "(@category:{database})=>[KNN 5 @embedding $query_vec AS score]" \
  PARAMS 2 query_vec <查询向量> \
  SORTBY score \
  DIALECT 2

这个语法看起来很神奇——(@category:{database})=>[KNN ...] 把 TAG 过滤和向量检索无缝接在一起。背后的执行逻辑是:

  1. 先根据 category=database 过滤出子集
  2. 在子集上执行 KNN 向量检索
  3. 返回 Top-5 并按得分排序

混合查询还可以组合更多条件:

# 搜索引擎级别的复杂混合查询
FT.SEARCH product_idx \
  "(@price:[100 500] @category:{electronics})=>[KNN 10 @embedding $query_vec AS score]" \
  PARAMS 2 query_vec <查询向量> \
  SORTBY score \
  RETURN 4 title price category score \
  DIALECT 2

这在实际业务场景中极其实用:

  • 电商推荐:先按类目 + 价格区间过滤,再做向量相似度排序,避免跨类目推荐出不相关商品
  • 内容流推荐:先排除已读内容(通过 ID 黑名单过滤),再基于兴趣向量做推荐
  • 知识库搜索:先按部门/标签过滤,再做语义相似度匹配

3.7 性能基准(官方数据)

数据规模索引算法查询延迟 (P50)查询延迟 (P99)召回率@10
100万 768维FLAT120ms280ms100%
100万 768维HNSW (M=16)3ms8ms97.5%
100万 768维SVS-VAMANA2ms5ms97.2%
1000万 768维HNSW (M=16)15ms35ms96.8%
1000万 768维SVS-VAMANA10ms22ms96.5%

数据来自 Redis 官方基准测试。实际表现受硬件、数据分布、参数配置影响显著。

结论:HNSW 在生产环境下是平衡精度和速度的最佳选择。FLAT 仅适合小数据集的精确检索或验证场景。


四、Vector Sets (VSET):Redis 8 的原生向量数据类型

4.1 为什么需要一个新的数据类型?

这就是 antirez 回归后的第一个大动作。你能想象 Redis 没有 LISTSETZSET 这些数据类型吗?不可能,因为它们是 Redis 的核心抽象。但在 8.0 之前,向量在 Redis 里不是「一等公民」——它只是 Hash 里的一个 blob 字段,靠外挂的 RediSearch 模块来索引和检索。

Vector Sets 改变了这一点。它是 Redis 8.0 引入的原生数据类型,代号 VSET

4.2 VSET 和 Query Engine 的核心差异

对比维度Redis Query EngineVector Sets (VSET)
数据存储Hash / JSON + 外挂索引原生 VSET 数据类型
API 风格FT.CREATE / FT.SEARCHVADD / VSIM / VCARD
混合查询全文+TAG+数值+向量支持属性过滤
索引类型HNSW / FLAT / SVS内部优化算法
适用场景大规模生产环境快速原型、轻量应用
数据规模十亿级中小规模(百万级)
事务支持需要保证索引和 Hash 一致性原生原子操作
上手难度中(需理解索引配置)低(几条命令搞定)

4.3 核心命令与应用

# 创建一个 Vector Set 并添加元素
VADD myset element1 VALUES 3 1.5 2.3 0.7
VADD myset element2 VALUES 3 1.1 2.1 0.9
VADD myset element3 VALUES 3 0.8 1.9 1.2

VADD 的语法:VADD <key> <element_id> VALUES <dim> <v1> <v2> ...

3 表示向量维度(三维),后面跟着实际的向量值。

# 用元素查找相似的
VSIM myset ELE element1 COUNT 5

# 用向量值查找相似的
VSIM myset VALUES 3 1.2 2.0 0.8 COUNT 5

# 查看集合信息
VCARD myset     # 元素数量
VDIM myset      # 向量维度

4.4 VSET 的进阶用法:带属性过滤

VSET 支持在元素上附加属性(SETATTR),并在搜索时做属性过滤(FILTER):

# 添加带属性的向量元素
VADD myset product1 VALUES 3 1.5 2.3 0.7 SETATTR category=electronics
VADD myset product2 VALUES 3 1.1 2.1 0.9 SETATTR category=clothing
VADD myset product3 VALUES 3 0.8 1.9 1.2 SETATTR category=electronics

# 带属性过滤的相似度搜索
VSIM myset VALUES 3 1.2 2.0 0.8 COUNT 5 FILTER ".category == 'electronics'"

这个 .category == 'electronics' 的语法和 JSONPath 风格一致,但 VSET 的属性过滤是独立于 RedisJSON 模块实现的原生能力。

4.5 VSET 的应用场景

场景一:实时相似度去重

假设你在做一个新闻聚合系统,需要实时检测新来的新闻是否和已存在的新闻「内容相同」:

import redis
import numpy as np
from sentence_transformers import SentenceTransformer

r = redis.Redis()
model = SentenceTransformer('all-MiniLM-L6-v2')  # 384 维

def is_duplicate_news(content: str, threshold: float = 0.95) -> bool:
    # 生成新内容的 embedding
    emb = model.encode(content).astype(np.float32)
    
    # 在 VSET 中查找相似新闻
    result = r.execute_command(
        'VSIM', 'news_set', 'VALUES', '384', *emb.tolist(),
        'COUNT', '1', 'FILTER', ".score > 0.9"
    )
    
    if result:
        return True
    return False

场景二:快速原型验证

在项目的 MVP 阶段,不想引入重型的向量数据库基础设施,VSET 可以在单条命令内完成向量检索的验证:

# 10 秒内验证向量检索逻辑
VADD test:products phone1 VALUES 2 0.95 0.3
VADD test:products phone2 VALUES 2 0.92 0.25
VADD test:products laptop1 VALUES 2 0.3 0.88
VSIM test:products VALUES 2 0.9 0.28 COUNT 2

4.6 什么时候该用 VSET,什么时候该用 Query Engine?

放一个简单的决策树:

数据量 < 10万 且 只需要向量检索?
  → 用 VSET(简单,零配置)
  
数据量 < 100万 且 需要简单属性过滤?
  → 用 VSET(够用,一条命令搞定)

数据量 > 100万?
  → 用 Query Engine(需要 HNSW 索引的扩展性)

需要全文搜索 + 向量检索?
  → 用 Query Engine(Query Engine 的混合查询是王牌功能)

需要 TAG 过滤 + 数值范围过滤 + 向量检索?
  → 用 Query Engine(过滤能力远超 VSET)

团队还在方案探索阶段?
  → 先用 VSET 快速验证,再迁移到 Query Engine

五、LangCache 语义缓存:把 LLM 调用的成本打下来

5.1 问题的本质

调用 LLM API 有两个核心痛点:

以 GPT-4o 为例(2026 年价格):输入 $5/M tokens,输出 $15/M tokens。一个客服场景,如果每天处理 10 万条咨询,每条平均消耗 500 tokens,日成本就是 $75 美元。一个月下来 $2000+,对中小企业来说不是小数目。

传统缓存的做法是精确匹配 query → response。但问题在于,用户的提问方式千变万化:

"怎么退货"
"我想退掉这个商品"
"退货流程是什么"
"怎么取消订单退款"

这四个问题语义完全相同,但传统缓存全部 miss,因为字符串一字不差才命中。

语义缓存的做法:把用户的 query 转成向量,在缓存中找语义最接近的历史 query,如果相似度超过阈值,直接返回缓存的 LLM 响应。

5.2 语义缓存的工作流程

用户提问
   │
   ▼
生成 query embedding(调用 embedding 模型)
   │
   ▼
在 Redis 向量索引中搜索相似 query
   │
   ▼
相似度 > 阈值? ──是──→ 直接返回缓存响应(Cache Hit,~5ms)
   │ 否
   ▼
调用 LLM API(~2-5 秒)
   │
   ▼
将 query embedding + response 写入 Redis
   │
   ▼
返回 LLM 响应

5.3 语义缓存的技术实现

相比传统缓存,语义缓存多了几个关键组件:

┌────────────────────────────┐
│     语义缓存的核心组件       │
├────────────────────────────┤
│ 1. Embedding 生成器         │
│    (将 query 转为向量)      │
├────────────────────────────┤
│ 2. 向量相似度检索引擎         │
│    (Redis Query Engine)    │
├────────────────────────────┤
│ 3. 相似度阈值判断器          │
│    (多少分算"命中")         │
├────────────────────────────┤
│ 4. TTL + 失效策略           │
│    (缓存不能永久存)         │
├────────────────────────────┤
│ 5. 缓存写入/更新流程          │
│    (新回答入库)             │
└────────────────────────────┘

5.4 效果数据

Redis 官方公布的数据(基于内部测试和用户调研):

  • 缓存命中率:在高重复 query 场景下,可达 60%-70%
  • LLM 调用减少:70%(结合精确匹配 + 语义匹配)
  • 响应延迟:从 ~3000ms(LLM 调用)降到 ~10ms(缓存读取)
  • 成本节省:每月 API 费用降低 50%-70%

但要注意,这些数据是有场景假设的。如果你的用户 query 语义极度多样、几乎没有重复,命中率可能只有 5%-10%,语义缓存就不值得引入。

5.5 Spring AI 集成语义缓存(Java 实战)

Spring AI 框架对 Redis 语义缓存提供了开箱即用的支持:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
</dependency>

配置文件:

# application.yml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      embedding:
        model: text-embedding-3-small
    vectorstore:
      redis:
        uri: redis://localhost:6379
        index: semantic-cache-idx
        prefix: "cache:"

核心服务实现:

@Service
public class SemanticCacheService {

    private final VectorStore vectorStore;
    private final ChatClient chatClient;

    public SemanticCacheService(VectorStore vectorStore, ChatClient.Builder builder) {
        this.vectorStore = vectorStore;
        this.chatClient = builder.build();
    }

    public String query(String userQuestion) {
        // 1. 先在向量缓存中搜索语义相似的历史问答
        List<Document> cached = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(userQuestion)
                .topK(1)
                .similarityThreshold(0.92)
                .build()
        );

        if (!cached.isEmpty()) {
            // Cache Hit:直接返回缓存的回答
            log.info("语义缓存命中: similar={}", cached.get(0).getText());
            return cached.get(0).getMetadata().get("answer").toString();
        }

        // 2. Cache Miss:调用 LLM
        String answer = chatClient.prompt()
            .user(userQuestion)
            .call()
            .content();

        // 3. 写入语义缓存
        Document doc = new Document(userQuestion,
            Map.of("answer", answer, "timestamp", System.currentTimeMillis()));
        vectorStore.add(List.of(doc));

        return answer;
    }
}

5.6 阈值怎么定?

similarityThreshold 是语义缓存的生命线。阈值太高,缓存命中率低;阈值太低,返回的内容驴唇不对马嘴。

阈值 1.0  →  等价于精确匹配
阈值 0.95 →  同义句改写("怎么退货"≈"如何申请退款")才能命中
阈值 0.90 →  同一话题不同表述("退货"≈"售后")可能命中
阈值 0.85 →  语义接近但内容可能不同(危险,容易答非所问)
阈值 0.80 →  不建议用,误命中率太高

实践建议

  1. 从 0.95 开始测试,观察命中率
  2. 如果命中率 < 5%,下调到 0.92
  3. 抽样检查命中结果,确认语义是否一致
  4. 监听用户反馈,如果出现「AI 答非所问」,说明阈值过低

对于客服场景,0.92-0.95 是经验值。对于 FAQ 高度标准化的场景,甚至可以到 0.98。

5.7 语义缓存的陷阱

陷阱一:embedding 模型一致性

生产和测试用不同的 embedding 模型,导致向量空间分布不同,语义缓存永远 miss。记住:生成缓存向量的模型,必须和查询时使用的模型完全一致

陷阱二:时间敏感内容

LLM 回答"今天股价多少"这个 query,昨天和今天的答案截然不同。语义缓存如果命中并返回昨天的结果,就是灾难。

解决方案:对时间敏感的内容,在 metadata 中标记 expireAtversion,定期清空。

陷阱三:身份相关内容

"我的订单状态"——不同用户的查询完全相同,但答案完全不同。语义缓存不能按内容来判断,需要按用户维度隔离。

解决方案:在 prefix 或 filter 中加入 user_id 维度。


六、Agent Memory:AI 智能体的记忆层

6.1 大模型为什么需要记忆?

大模型本身是无状态的——每次请求都是一次全新的对话。但对于 AI Agent 来说,没有记忆就像一个失忆症患者:

  • 你是谁:每次对话都要重新告诉 Agent 你的名字
  • 之前聊了什么:Agent 不记得五分钟前给你的建议
  • 用户偏好:你说过喜欢简洁的回答,但每次 Agent 都在长篇大论

要让 AI Agent 有「记忆」,就需要一个外部的记忆管理层。Redis 在这方向上提供了短期记忆长期记忆两层能力。

6.2 短期记忆(Short-term Memory)

当前会话的对话历史,使用 Redis 的 List 或 Stream 存储,配合 TTL 自动过期。

# 存储对话轮次 (session_id → 对话列表)
RPUSH session:user_1001 '{"role":"user","content":"我上次问到哪了?"}'
RPUSH session:user_1001 '{"role":"assistant","content":"您上次咨询了退货流程..."}'

# 限制记忆长度,只保留最近 20 轮
LTRIM session:user_1001 -40 -1

# 设置 30 分钟自动过期
EXPIRE session:user_1001 1800

# 读取完整会话
LRANGE session:user_1001 0 -1

6.3 长期记忆(Long-term Memory)

跨会话的用户偏好、历史事实,转化为向量嵌入存入 Redis 向量索引,通过语义检索召回。

用户输入 "你觉得上次那个方案怎么样?"
   │
   ▼
解释器理解隐含意图:需要回顾「上次的方案」
   │
   ▼
长期记忆检索:用当前 query 的 embedding 搜索
   │
   ▼
从向量索引中召回语义相关的历史记忆(Top-3)
   │
   ▼
组装 Prompt:系统指令 + 短期记忆 + 长期记忆 + 用户输入
   │
   ▼
调用 LLM
   │
   ▼
响应 + 记忆更新(存入 Redis)

6.4 Spring AI 集成 Agent Memory

@Configuration
public class AgentMemoryConfig {

    @Bean
    public ChatMemory redisChatMemory(RedisTemplate<String, String> redisTemplate) {
        return MessageWindowChatMemory.builder()
            .chatMemoryRepository(new RedisChatMemoryRepository(redisTemplate))
            .maxMessages(20)
            .build();
    }
}

@Service
public class AgentService {

    private final ChatClient chatClient;
    private final VectorStore vectorStore;

    public AgentService(ChatClient chatClient, VectorStore vectorStore) {
        this.chatClient = chatClient;
        this.vectorStore = vectorStore;
    }

    public String chat(String sessionId, String userMessage) {
        // 1. 从长期记忆中检索相关上下文
        List<Document> memories = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(userMessage)
                .topK(3)
                .filterExpression("userId == '" + sessionId + "'")
                .build()
        );

        String memoryContext = memories.stream()
            .map(Document::getText)
            .collect(Collectors.joining("\n"));

        // 2. 组装 prompt,包含长期记忆
        String systemPrompt = "你是一个智能助手。以下是关于用户的历史信息:\n"
            + memoryContext;

        // 3. 调用 LLM(短期记忆由 ChatMemory 自动管理)
        return chatClient.prompt()
            .system(systemPrompt)
            .user(userMessage)
            .advisors(advisor -> advisor.param("chat_memory_conversation_id", sessionId))
            .call()
            .content();
    }
}

这个实现的核心价值在于:

  • 短期记忆系统自动管理,无需我们操心 TTL 和长度
  • 长期记忆通过向量检索精准召回,不是简单的全文搜索
  • userId 过滤确保不把用户 A 的记忆混到用户 B 的对话中

6.5 Agent 记忆的工程架构取舍

记忆策略           可靠性        成本         适用场景
─────────────────────────────────────────────────
短记+长记方案        高          高          生产级 Agent(推荐)
仅短期记忆           中          低          简单问答机器人
仅长期记忆           低          中          用户画像推荐
无状态(每次都 LLM)  低          高(token)  一次性对话

推荐组合:
- 低成本起步:仅短期记忆 + TTL=30min
- 标杆配置:短期记忆 20 轮 + 长期记忆 Top-3 召回
- 豪华配置:短期记忆 50 轮 + 长期记忆 Top-5 + 个性化 embedding 微调

七、完整 RAG Pipeline:用 Redis 构建检索增强生成

RAG(Retrieval-Augmented Generation)是当前最主流的 LLM 应用模式。Redis 在其中承担的是向量存储和检索层的角色。

7.1 完整的 RAG 架构

                   离线阶段(索引构建)
文档源(PDF/HTML/DB)
  │
  ▼
文档解析器(提取文本)
  │
  ▼
文本分块器(Chunking)
  │  ├─ 固定大小分块 (256-1024 tokens)
  │  ├─ 语义分块 (NLP 句子边界)
  │  └─ 递归分块 (LangChain RecursiveCharacterTextSplitter)
  │
  ▼
Embedding 模型
  │
  ▼
┌─────────────────────┐
│  Redis Vector Store  │  ← 存储向量 + 原文 + 元数据
│  (HNSW 索引)         │
└─────────────────────┘

                   在线阶段(检索生成)
用户提问
  │
  ▼
Query Embedding
  │
  ▼
Redis 向量检索 Top-K
  │  ├─ 纯向量检索
  │  └─ 混合检索(向量+关键词+过滤)
  │
  ▼
拼接上下文 (Prompt 组装)
  │
  ▼
LLM 生成回答
  │
  ▼
返回给用户

7.2 Spring AI + Redis 实现 RAG

@Service
public class RagService {

    private final VectorStore vectorStore;
    private final ChatClient chatClient;

    // ---- 离线:文档入库 ----
    public void ingestDocuments(List<String> texts) {
        List<Document> documents = texts.stream()
            .map(text -> new Document(text))
            .collect(Collectors.toList());

        // Spring AI 自动完成:文本 → embedding → 写入 Redis
        vectorStore.add(documents);
    }

    // ---- 在线:RAG 问答 ----
    public String askWithRag(String question) {
        // 1. 向量检索相关文档
        List<Document> relevant = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(question)
                .topK(5)
                .similarityThreshold(0.75)
                .build()
        );

        // 2. 拼接上下文
        String context = relevant.stream()
            .map(Document::getText)
            .collect(Collectors.joining("\n---\n"));

        // 3. 构造 prompt 并调用 LLM
        String prompt = String.format(
            "请根据以下参考资料回答用户问题。如果参考资料中没有相关信息,请如实说明。\n\n"
            + "参考资料:\n%s\n\n用户问题:%s", context, question);

        return chatClient.prompt()
            .user(prompt)
            .call()
            .content();
    }
}

7.3 Chunking 策略:细节决定 RAG 质量

RAG 系统的质量不是靠模型决定的,而是靠分块策略决定的。分块不好,再强的 LLM 也救不回来。

固定大小分块

def fixed_chunk(text: str, chunk_size: int = 512, overlap: int = 64) -> List[str]:
    """固定 token 数量分块,带重叠"""
    tokens = text.split()  # 简化示意,实际应使用 tokenizer
    chunks = []
    for i in range(0, len(tokens), chunk_size - overlap):
        chunk = tokens[i:i + chunk_size]
        chunks.append(" ".join(chunk))
    return chunks

语义分块

import re

def semantic_chunk(text: str, max_chars: int = 2000) -> List[str]:
    """按段落和句子边界进行语义分块"""
    # 先按段落拆分
    paragraphs = re.split(r'\n\s*\n', text)
    
    chunks = []
    current = []
    current_len = 0
    
    for para in paragraphs:
        para_len = len(para)
        if current_len + para_len > max_chars and current:
            chunks.append('\n\n'.join(current))
            current = [para]
            current_len = para_len
        else:
            current.append(para)
            current_len += para_len
    
    if current:
        chunks.append('\n\n'.join(current))
    
    return chunks

分块策略对比

策略优点缺点适用场景
固定大小 (256)简单,检索快语义割裂技术文档(段落短)
固定大小 (512)最常用中庸通用场景
固定大小 (1024)上下文丰富噪声多长文分析
语义分块保留语义完整性块大小不均新闻、博客
递归分块LangChain 推荐配置复杂生产环境

一个重要的工程经验:分块大小不是越大越好。经验数据表明,512 tokens 是检索质量和上下文长度的甜蜜点。更大的块虽然包含了更多上下文,但也引入了更多噪声,导致检索精度下降。

7.4 RAG 系统的性能底线

一个生产级 RAG 系统的最低性能要求:

端到端延迟(用户发问到收到回答):
  - 好:< 3 秒
  - 可接受:3-8 秒
  - 差:> 8 秒

检索延迟(向量检索到返回 Top-K):
  - 好:< 10ms
  - 可接受:10-50ms
  - 差:> 100ms

检索精度(召回率@10):
  - 好:> 95%
  - 可接受:> 90%
  - 差:< 85%

Redis 的向量检索在大多数场景下都在 3-15ms 级别,完全满足「好」的标准。端到端延迟的瓶颈在 LLM API 的调用时间(2-5 秒),而不是 Redis。


八、RedisAI:模型推理在 Redis 内部(以及为什么不推荐了)

8.1 它在做什么

RedisAI 是一个 Redis 模块,允许 Redis 直接加载和运行机器学习模型:

┌───────────────────────┐
│      Redis 实例        │
│                        │
│  ┌──────────┐         │
│  │  RedisAI  │         │
│  │  模块     │         │
│  │           │         │
│  │ TF/Torch  │         │
│  │ ONNX Runtime │      │
│  └──────────┘         │
│                        │
│  Redis 数据(特征)     │
└───────────────────────┘

支持的运行后段:

  • TensorFlow / TensorFlow Lite
  • PyTorch (libtorch)
  • ONNX Runtime

8.2 不推荐的原因

截至 2026 年,Redis 官方已将 RedisAI 仓库标记为不再活跃维护,改名为 redis-inference-optimization,并将精力转向向量搜索和语义缓存方向。

原因分析:

  1. 隔离性差:在 Redis 进程内跑模型推理,模型崩溃 → Redis 崩溃 → 全站缓存失效
  2. 资源竞争:模型推理吃 CPU/GPU,Redis 主线程也吃 CPU,两者互相争抢
  3. 扩展性差:推理加了 10ms 延迟回到 Redis 主线程,整个 Redis 实例的吞吐量跟着降
  4. 生态成熟:Triton Inference Server、TorchServe 等专用推理服务已经非常成熟

正确姿势:Redis 做特征存储,专门推理服务去做推理。数据架构如下:

Flink/Spark 实时计算
  │
  ▼
Redis Hash(特征存储)
  │
  ▼
Triton / TorchServe(推理服务) ← 从 Redis 读特征
  │
  ▼
返回预测结果(写回 Redis 或直接返回给客户端)

九、生产部署:Redis AI 能力落地的架构决策

9.1 什么时候该用,什么时候不该用

适合用 Redis 做 AI 数据层的场景:

  • 已有 Redis 基础设施,不希望引入额外的系统组件
  • 数据规模适中(向量量级 < 1000 万,维度 < 1024)
  • 延迟敏感(需要毫秒级检索)
  • 混合查询是刚需(向量 + 过滤 + 全文)

不适合用 Redis 做 AI 数据层的场景:

  • 十亿级向量检索(需要 Milvus / Qdrant 的分片能力)
  • 需要实时更新索引(Redis 的向量索引构建是离线的)
  • 数据持久化要求极高(Redis 本质还是内存优先)
  • 复杂的过滤逻辑(Redis 的过滤能力有限)

9.2 Redis AI 能力部署清单

内存评估
  ├─ 基础数据(缓存数据)
  ├─ 向量数据:n_vectors × dim × 4 bytes × 2(数据+索引)
  ├─ HNSW 索引:n_vectors × M × 4 × 2
  └─ 预留 20-30% 的 Buffer

实例规划
  ├─ 小规模(< 100万向量):单实例 Redis Stack
  ├─ 中等规模(100万-500万):Redis Cluster + 2-4 分片
  └─ 大规模(> 500万):建议评估 Milvus/Qdrant

容量计算示例:
  100万条 768 维向量:
    - 向量数据:1,000,000 × 768 × 4 = 3.07 GB
    - HNSW 索引 (M=16):1,000,000 × 16 × 4 × 2 = 128 MB
    - 元数据(100字节/条):1,000,000 × 100 = 100 MB
    - Buffer (20%):约 700 MB
    --------------------------------------------------
    ≈ 4 GB 内存(不含其他缓存数据)

监控要点
  ├─ used_memory / maxmemory 比例
  ├─ FT.INFO <index> 查看索引健康状态
  ├─ 查询延迟 P50/P99
  └─ 索引召回率(定期用 FLAT 验证)

9.3 与竞品的定位对比

特性              Redis Query Engine    Milvus          Pinecone
─────────────────────────────────────────────────────────────────
部署复杂度        低(模块加载)         中(K8s 集群)    零(托管服务)
内存成本          高(全部内存)         中(内存+磁盘)   高
十亿级向量        不支持                 支持              支持
混合查询          原生支持              支持              有限的
一致性            强一致                最终一致           最终一致
生态集成          Spring AI 开箱即用     自定义            自定义
持续运维成本       低                    中               高(托管费)

9.4 一个渐进式的采纳路线

阶段一:用 VSET 快速验证(第 1-3 天)
  ├─ 安装 Redis Stack(已安装则跳过)
  └─ 用 VADD / VSIM 测试向量检索逻辑

阶段二:用 Query Engine 搭建生产级检索(第 3-7 天)
  ├─ 加载 RediSearch 模块
  ├─ 设计索引 Schema
  └─ 编写 FT.SEARCH 混合查询

阶段三:叠加语义缓存(第 2-3 周)
  ├─ 嵌入 LangCache 或自建语义缓存服务
  ├─ 设置相似度阈值
  └─ 监控缓存命中率

阶段四:集成 Agent Memory(第 3-4 周)
  ├─ 短期记忆用 Redis List + TTL
  └─ 长期记忆用向量索引 + 语义检索

阶段五:全链路 RAG 就绪
  ├─ 文档入库 Pipeline
  ├─ 在线检索 + 生成
  └─ 反馈闭环(用户点赞/踩来优化检索)

这个路线的关键点是渐进式——你不需要在第一天就搞定所有能力。从 VSET 开始,感觉到价值后再逐步扩展。


十、总结与展望

站在 2026 年 7 月回看 Redis 的进化轨迹,可以看到一条清晰的演进路径:

时代版本Redis 的定位
1.0-3.02009-2015缓存 + 数据结构服务器
3.0-6.02015-2021缓存 + 消息队列 + 分布式锁
6.0-7.x2021-2024多线程 + 细粒度权限 + RediSearch 向量模块
8.x2025-present缓存 + 向量 + 缓存 + Agent 记忆 = AI 数据层

Redis 8.x 在 AI 方向的布局,本质上做了两件事:

第一,把向量变成一等公民。 从 RediSearch 的向量索引到 Redis 8 的原生 Vector Sets(VSET),再到 LangCache 语义缓存,Redis 在数据模型层面全面拥抱了「向量」这种 AI 时代的基础数据类型。Vector Sets 的意义尤其深远——这是继 STRING、LIST、SET、ZSET、HASH、Stream 之后,Redis 又一个核心数据类型。

第二,把自己定位为 AI 应用的「统一数据层」。 Redis 不是在和 Milvus、Pinecone 争「最强向量数据库」的位置,而是打「一站式」的牌——你的缓存、向量、会话、特征,都可以放在同一个 Redis 里管理。这带来一个实实在在的好处:减少架构复杂度

值得关注的趋势

antirez 回归后主导了 Vector Sets 的开发,这是一个信号——Redis 的核心团队开始认真对待向量能力。未来几个大版本我们可以期待:

  • VSET 的扩展性提升(目前还覆盖不了十亿级场景)
  • HNSW 索引的原生化(不再依赖 RediSearch 模块)
  • 更多的 SIMD 优化(Intel VAMANA 只是开始)
  • 和 AI Agent 框架的深度集成(Spring AI 已经走在前面)

对于后端工程师来说,不用急着跟风上 Milvus 和 Pinecone。Redis 就在你现有的架构里,装个模块、写几条命令,就能让「缓存」进化成「AI 数据层」。这才是 Redis 8.x 最务实、最性感的地方——你在业务上踩过的每个坑,Redis 团队都已经用代码帮你填好了。

这大概就是 Redis 25 年历久弥新的秘密:不变的是内存,变的是对应用需求的理解层次。

推荐文章

地图标注管理系统
2024-11-19 09:14:52 +0800 CST
JavaScript 实现访问本地文件夹
2024-11-18 23:12:47 +0800 CST
程序员茄子在线接单