Redis 宣布正式接入 AI

大家好,我是Java1234_小锋老师。

那个我们用了十几年的"缓存中间件",这次把自己重新定义成了 AI 应用的记忆层。

一、先聊聊 Redis:它到底是个什么东西

如果你写过三年以上的后端,大概率跟 Redis 打过交道。它的经典形象是这样的:一个跑在内存里的键值数据库,读写延迟在微秒级,用来扛住数据库前面的流量。

Redis 的全称是 RE mote DI ctionary Server,2009 年由 Salvatore Sanfilippo 开源。它最出名的设计是"数据结构服务器"这个定位------它不只是存字符串,还原生提供 List、Hash、Set、Sorted Set、Stream、Bitmap、HyperLogLog 这些结构。

所以过去十几年里,Redis 在项目里的角色大致是这么几类:

  • 缓存:挡在 MySQL 前面,抗读流量;
  • 分布式锁 :SET key value NX PX 30000,几乎是标配;
  • 消息队列:早期用 List,后来用 Stream;
  • 排行榜/计数器:Sorted Set 和 INCR 的主场;
  • 会话存储:把 Session 从单机内存挪出来。

共同点很明显:快,而且结构灵活。而这两个特点,恰好是 AI 应用最缺的东西。


二、为什么是 Redis?AI 时代的"记性问题"

大模型有个天生的毛病:它没有记忆。

每一次调用 LLM,本质上都是无状态的。你上一轮说"我叫张三,不吃辣",下一轮它就忘了,除非你把这句话重新塞进 prompt 里。于是所有 AI 应用都在干同一件事------在调用模型之前,把相关的上下文找出来、拼进去。

这件事拆开看,就三个动作:

  1. 用户问了个问题,把问题变成向量;
  2. 去一堆知识/历史里找出语义最接近的几条;
  3. 拼成 prompt 丢给模型。

第 2 步要在几十毫秒内完成,否则用户就会觉得"这 AI 怎么这么卡"。而"低延迟 + 海量数据 + 结构化查询"这几个词凑在一起,正是 Redis 十几年来最擅长的活。

于是 Redis 做了一件很自然的事:把向量能力做进内核,然后顺着往上,把智能体记忆这一层也接管了。


三、核心基石:把向量能力做进内核

3.1 原生 Vector Set 数据类型

Redis 8.0 引入了 Vector Set,这是继 Sorted Set 之后少有的"一等公民"级新数据类型。

理解它最快的方式是类比:Sorted Set 里每个元素关联一个分数 (标量),Vector Set 里每个元素关联一个向量。前者按分数排序,后者按向量的相似度排序。

底层用的是 HNSW(分层可导航小世界图)算法,这是目前近似最近邻检索里最主流的方案之一------它在图上分层跳跃,能在对数级的时间里找到近似最近邻。

用起来相当朴素,就是几条命令:

bash 复制代码
# ========== 向量集合基础操作 ==========

# VADD:往向量集合 movies 里添加元素
# FP32/VALUES 用于指定向量格式,这里用 VALUES 直接传浮点数
# 语法:VADD key VALUES <维度> <v1> <v2> ... <元素名>
VADD movies VALUES 4 0.12 0.88 0.35 0.91 "流浪地球"
VADD movies VALUES 4 0.15 0.85 0.31 0.88 "星际穿越"
VADD movies VALUES 4 0.91 0.12 0.77 0.05 "疯狂动物城"

# SETATTR:给元素挂上标量属性,用于后续过滤
VSETATTR movies "流浪地球"   '{"year": 2019, "type": "科幻"}'
VSETATTR movies "星际穿越"   '{"year": 2014, "type": "科幻"}'
VSETATTR movies "疯狂动物城" '{"year": 2016, "type": "动画"}'

# VSIM:相似性搜索,找出与给定向量最接近的 2 个元素
# WITHSCORES 会一并返回相似度得分
VSIM movies VALUES 4 0.13 0.86 0.33 0.90 COUNT 2 WITHSCORES
# 返回:1) "流浪地球" 2) "0.998"  3) "星际穿越" 4) "0.995"

# 关键能力:向量检索 + 标量过滤 一步到位
# 只在 2015 年之后的科幻片里做相似度检索
VSIM movies VALUES 4 0.13 0.86 0.33 0.90 COUNT 2 \
     FILTER '.year > 2015 and .type == "科幻"'

最后那个 FILTER 是重点。向量检索 + 标量过滤在一次调用里完成,不用先查一遍再回到应用层过滤,这在推荐系统、权限隔离的语义搜索场景里能省掉大量往返。

3.2 内置的向量搜索引擎

以前想在 Redis 里做向量检索,得单独装 RediSearch 模块。现在这个模块已经整合进 Redis 核心,开箱即用。

它比 Vector Set 更"重"一些,但能力也更全:支持 HNSW 和 FLAT 两种索引类型,并且能和全文检索、数值范围、标签过滤组合成混合查询。

bash 复制代码
# ========== 创建一个向量索引 ==========
# ON HASH:索引 Hash 类型的数据
# PREFIX 1 doc::只索引 key 以 doc: 开头的数据
FT.CREATE idx:docs ON HASH PREFIX 1 doc: SCHEMA
  title      TEXT                      # 标题,支持全文检索
  category   TAG                       # 分类,支持精确过滤
  views      NUMERIC SORTABLE          # 浏览量,支持范围查询与排序
  embedding  VECTOR HNSW 6             # 向量字段,使用 HNSW 索引
    TYPE FLOAT32                       # 元素类型
    DIM 1536                           # 向量维度(对应 embedding 模型输出)
    DISTANCE_METRIC COSINE             # 距离度量:余弦相似度

# ========== 混合查询 ==========
# 含义:在 category 为"技术"且浏览量大于 1000 的文档里,
#       找出与查询向量最相似的 5 条
FT.SEARCH idx:docs
  "(@category:{技术} @views:[1000 +inf])=>[KNN 5 @embedding $vec AS score]"
  PARAMS 2 vec "<二进制向量>"
  SORTBY score ASC
  RETURN 2 title score
  DIALECT 2

这种"过滤条件写在前面,KNN 跟在后面"的语法,是 Redis 向量查询的标准写法。它意味着你可以把业务过滤和语义检索写在同一个查询里,而不是在应用层做两次拼接。

3.3 量化:用一点精度换 32 倍内存

向量很吃内存。一个 1536 维的 FLOAT32 向量占 6KB,一千万条就是 60GB------对内存数据库来说这个数字相当扎眼。

Redis 给的答案是量化(Quantization):

量化方式 存储压缩 召回精度 适用场景
不量化(FP32) 1× 最高 数据量小、精度要求极高
8 位量化(Q8) 约 4× 损失很小 大多数生产场景的默认选择
二进制量化(BIN) 最高 32× 有明显损失 超大规模、可接受粗召回

实践中常见的做法是两段式:先用 BIN 量化做一轮粗召回捞出几百条候选,再用原始精度向量做精排。既省了内存,精度也基本保住了。

bash 复制代码
# 建索引时开启 8 位量化,内存占用直接降到约 1/4
VADD movies Q8 VALUES 4 0.12 0.88 0.35 0.91 "流浪地球"

# 二进制量化,内存压到极致
VADD movies BIN VALUES 4 0.12 0.88 0.35 0.91 "流浪地球"

四、智能体记忆与上下文引擎:Redis Iris

如果说向量能力是基石,那 Iris 就是 Redis 这次真正想讲的故事。

Iris 是一个专门给 AI 智能体设计的上下文与记忆平台 。它要解决的是一个很具体的生产问题:Demo 里跑得好好的 Agent,一上线就开始胡说八道。原因通常不是模型不行,而是数据碎片化 和信息过时------Agent 拿到的上下文本身就是错的。

Iris 由三个组件拼起来:

① Redis Context Retriever

让开发者对业务数据做语义建模------把"客户""订单""商品"这些实体以及它们之间的关系描述清楚,然后系统自动生成一批安全的数据获取工具(基于 MCP 协议)暴露给 Agent。

它的价值在于:Agent 不再自己拼 SQL。让大模型直接写 SQL 去查生产库,这件事在 Demo 里很酷,在生产里很危险------语法错误、全表扫描、越权访问,每一样都够运维喝一壶。

② Redis Agent Memory

双层记忆架构,这个设计其实很贴近人脑:

  • 会话记忆(Working Memory):短期的,存当前对话的来龙去脉,会话结束后可以按 TTL 自动过期;
  • 长期记忆(Long-term Memory):持久化的,存用户偏好、历史结论、关键事实,跨会话可复用。

有了长期记忆,用户三个月前说过的"我对花生过敏",今天下单时 Agent 还记得。

java 复制代码
import com.redis.vl.extensions.session.ChatMessage;
import com.redis.vl.extensions.session.SemanticSessionManager;
import redis.clients.jedis.JedisPooled;

import java.util.List;

/**
 * 智能体双层记忆示例
 * 演示会话记忆的写入,以及按语义相关性检索历史
 */
public class AgentMemoryDemo {

    /**
     * 主方法:完整演示一次"写入记忆 ------ 检索记忆"的过程
     *
     * @param args 启动参数,本示例未使用
     */
    public static void main(String[] args) {
        JedisPooled client = new JedisPooled("localhost", 6379);

        // 创建会话管理器,sessionTag 用于区分不同用户的会话
        SemanticSessionManager session = SemanticSessionManager.builder()
                .name("assistant_session")
                .sessionTag("user:1001")
                .redisClient(client)
                .build();

        // 写入会话记忆:一问一答成对存储
        session.addMessage(new ChatMessage("user", "帮我推荐一家附近的川菜馆"));
        session.addMessage(new ChatMessage("llm", "推荐「蜀香居」,评分 4.8"));
        session.addMessage(new ChatMessage("user", "提醒一下,我对花生过敏"));

        // 语义检索历史:只捞出与当前问题相关的记忆,而不是把全部历史塞进 prompt
        // distanceThreshold 控制相关性阈值,值越小要求越严格
        List<ChatMessage> context = session.getRelevant(
                "今晚吃什么比较合适",   // 当前问题
                3,                      // 最多返回 3 条相关记忆
                0.3                     // 语义距离阈值
        );

        // 检索结果会包含"对花生过敏"这条,Agent 因此能给出安全的推荐
        for (ChatMessage item : context) {
            System.out.println(item.getRole() + " : " + item.getContent());
        }
    }
}

这里最值得注意的是 getRelevant():它不是把所有历史一股脑塞进 prompt,而是按语义相关性挑出最有用的那几条。上下文窗口是有限且昂贵的,这一步直接决定了成本和效果。

③ Redis Data Integration

负责从企业的数据库、数仓等源系统近实时地把数据同步进 Redis。听起来不性感,但它解决的是 Agent 最致命的问题:拿旧数据办新事。库存早就清零了,Agent 还在热情推荐。


五、开发者工具与生态集成

5.1 RedisVL:给 AI 应用准备的客户端库

RedisVL(Redis Vector Library)是官方为 AI 场景封装的客户端库,Java 版本可以直接用 Maven 引入。它把建索引、写向量、查相似这些事都包装成了顺手的 API。

xml 复制代码
<!-- pom.xml 引入 RedisVL 的 Java 客户端 -->
<dependency>
    <groupId>com.redis</groupId>
    <artifactId>redis-vl-java</artifactId>
    <version>0.4.0</version>
</dependency>
java 复制代码
import com.redis.vl.index.SearchIndex;
import com.redis.vl.query.VectorQuery;
import com.redis.vl.schema.IndexSchema;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 基于 RedisVL 的最小可用 RAG 检索层
 * 流程:定义索引 ------ 创建索引 ------ 写入文档 ------ 语义检索
 */
public class RagRetrieverDemo {

    /** Redis 连接地址 */
    private static final String REDIS_URL = "redis://localhost:6379";

    /**
     * 主方法:串起 RAG 检索层的完整流程
     *
     * @param args 启动参数,本示例未使用
     */
    public static void main(String[] args) {
        // 1. 定义索引结构(也可以从 yaml 文件加载)
        IndexSchema schema = IndexSchema.builder()
                .name("kb_index")                       // 索引名称
                .prefix("kb")                           // 只索引 key 以 kb 开头的数据
                .storageType(IndexSchema.StorageType.HASH)
                .addTextField("content")                // 原文内容,支持全文检索
                .addTagField("source")                  // 来源标签,用于过滤
                .addVectorField("embedding", builder -> builder
                        .dims(1536)                     // 向量维度
                        .algorithm("hnsw")              // 使用 HNSW 索引
                        .distanceMetric("cosine")       // 余弦距离
                        .dataType("float32"))
                .build();

        // 2. 创建索引(false 表示已存在则复用,不覆盖)
        SearchIndex index = new SearchIndex(schema, REDIS_URL);
        index.create(false);

        // 3. 批量写入文档,embedding 由你选用的模型生成
        index.load(List.of(
                buildDoc("Redis 8.0 引入了原生 Vector Set 数据类型", "release-note"),
                buildDoc("HNSW 是一种基于图的近似最近邻算法", "wiki")
        ));

        // 4. 语义检索:返回最相关的 3 条,并限定来源
        VectorQuery query = VectorQuery.builder()
                .vector(embed("Redis 的向量类型叫什么"))
                .vectorFieldName("embedding")
                .returnFields("content", "source")
                .numResults(3)
                .filterExpression("@source:{release-note}")  // 标量过滤与向量检索同时生效
                .build();

        for (Map<String, Object> doc : index.query(query)) {
            System.out.println("[" + doc.get("vector_distance") + "] " + doc.get("content"));
        }
    }

    /**
     * 组装一条待写入的文档
     *
     * @param content 文档原文
     * @param source  文档来源标签
     * @return 可直接写入索引的文档字段集合
     */
    private static Map<String, Object> buildDoc(String content, String source) {
        Map<String, Object> doc = new HashMap<>();
        doc.put("content", content);
        doc.put("source", source);
        doc.put("embedding", embed(content));
        return doc;
    }

    /**
     * 文本向量化,实际项目中替换为你选用的 embedding 模型调用
     *
     * @param text 待向量化的文本
     * @return 向量数组
     */
    private static float[] embed(String text) {
        // TODO 接入 OpenAI、通义千问或本地部署的 embedding 模型
        return new float[1536];
    }
}

5.2 LangCache:语义缓存,省钱的那一环

这大概是最容易讲清楚 ROI 的一个功能。

传统缓存靠 key 精确匹配。但用户问问题时,"怎么退货""退货流程是什么""我想退货咋办"是三个不同的字符串,传统缓存全都会 miss,于是你付了三次 LLM 的钱。

语义缓存换了个思路:比的不是字符串,是语义相似度。三句话的向量足够接近,第二、三次请求直接命中缓存返回。

官方给出的数字是:LLM 成本最多降低 70%,缓存命中时响应速度提升约 15 倍。
#mermaid-svg-erTSP1ZsELgjAUAl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-erTSP1ZsELgjAUAl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-erTSP1ZsELgjAUAl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-erTSP1ZsELgjAUAl .error-icon{fill:#552222;}#mermaid-svg-erTSP1ZsELgjAUAl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-erTSP1ZsELgjAUAl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-erTSP1ZsELgjAUAl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-erTSP1ZsELgjAUAl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-erTSP1ZsELgjAUAl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-erTSP1ZsELgjAUAl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-erTSP1ZsELgjAUAl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-erTSP1ZsELgjAUAl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-erTSP1ZsELgjAUAl .marker.cross{stroke:#333333;}#mermaid-svg-erTSP1ZsELgjAUAl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-erTSP1ZsELgjAUAl p{margin:0;}#mermaid-svg-erTSP1ZsELgjAUAl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-erTSP1ZsELgjAUAl .cluster-label text{fill:#333;}#mermaid-svg-erTSP1ZsELgjAUAl .cluster-label span{color:#333;}#mermaid-svg-erTSP1ZsELgjAUAl .cluster-label span p{background-color:transparent;}#mermaid-svg-erTSP1ZsELgjAUAl .label text,#mermaid-svg-erTSP1ZsELgjAUAl span{fill:#333;color:#333;}#mermaid-svg-erTSP1ZsELgjAUAl .node rect,#mermaid-svg-erTSP1ZsELgjAUAl .node circle,#mermaid-svg-erTSP1ZsELgjAUAl .node ellipse,#mermaid-svg-erTSP1ZsELgjAUAl .node polygon,#mermaid-svg-erTSP1ZsELgjAUAl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-erTSP1ZsELgjAUAl .rough-node .label text,#mermaid-svg-erTSP1ZsELgjAUAl .node .label text,#mermaid-svg-erTSP1ZsELgjAUAl .image-shape .label,#mermaid-svg-erTSP1ZsELgjAUAl .icon-shape .label{text-anchor:middle;}#mermaid-svg-erTSP1ZsELgjAUAl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-erTSP1ZsELgjAUAl .rough-node .label,#mermaid-svg-erTSP1ZsELgjAUAl .node .label,#mermaid-svg-erTSP1ZsELgjAUAl .image-shape .label,#mermaid-svg-erTSP1ZsELgjAUAl .icon-shape .label{text-align:center;}#mermaid-svg-erTSP1ZsELgjAUAl .node.clickable{cursor:pointer;}#mermaid-svg-erTSP1ZsELgjAUAl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-erTSP1ZsELgjAUAl .arrowheadPath{fill:#333333;}#mermaid-svg-erTSP1ZsELgjAUAl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-erTSP1ZsELgjAUAl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-erTSP1ZsELgjAUAl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-erTSP1ZsELgjAUAl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-erTSP1ZsELgjAUAl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-erTSP1ZsELgjAUAl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-erTSP1ZsELgjAUAl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-erTSP1ZsELgjAUAl .cluster text{fill:#333;}#mermaid-svg-erTSP1ZsELgjAUAl .cluster span{color:#333;}#mermaid-svg-erTSP1ZsELgjAUAl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-erTSP1ZsELgjAUAl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-erTSP1ZsELgjAUAl rect.text{fill:none;stroke-width:0;}#mermaid-svg-erTSP1ZsELgjAUAl .icon-shape,#mermaid-svg-erTSP1ZsELgjAUAl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-erTSP1ZsELgjAUAl .icon-shape p,#mermaid-svg-erTSP1ZsELgjAUAl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-erTSP1ZsELgjAUAl .icon-shape .label rect,#mermaid-svg-erTSP1ZsELgjAUAl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-erTSP1ZsELgjAUAl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-erTSP1ZsELgjAUAl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-erTSP1ZsELgjAUAl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 相似度超过阈值

命中
未命中
用户提问
把问题转成向量
在语义缓存中

检索相似问题
直接返回缓存答案
检索知识库

拼装 Prompt
调用 LLM 生成答案
把 问题向量 + 答案

写入语义缓存
返回答案给用户

代码上就是加一层包装:

java 复制代码
import com.redis.vl.extensions.cache.CacheHit;
import com.redis.vl.extensions.cache.SemanticCache;

import java.util.List;

/**
 * 语义缓存示例
 * 对语义相近的问题直接复用历史答案,避免重复调用大模型
 */
public class SemanticCacheDemo {

    /** 语义缓存实例 */
    private final SemanticCache cache;

    /**
     * 构造方法:初始化语义缓存
     * distanceThreshold 为语义距离阈值,越小要求越相似才算命中
     * 0.1 ~ 0.2 是比较常用的区间,太大容易答非所问
     */
    public SemanticCacheDemo() {
        this.cache = SemanticCache.builder()
                .name("llm_cache")
                .redisUrl("redis://localhost:6379")
                .distanceThreshold(0.15)
                .ttl(3600)                  // 缓存有效期 1 小时
                .build();
    }

    /**
     * 带语义缓存的问答:先查缓存,未命中才调用大模型
     *
     * @param question 用户提出的问题
     * @return 问题对应的答案
     */
    public String ask(String question) {
        // 1. 先查语义缓存
        List<CacheHit> hits = cache.check(question, 1);
        if (!hits.isEmpty()) {
            System.out.println("缓存命中,省下一次 LLM 调用");
            return hits.get(0).getResponse();
        }

        // 2. 未命中则真正调用 LLM
        String answer = callLlm(question);

        // 3. 回写缓存,供后续语义相似的问题复用
        cache.store(question, answer);
        return answer;
    }

    /**
     * 调用大模型生成答案,实际项目中替换为你选用的模型接口
     *
     * @param question 用户问题
     * @return 模型返回的答案
     */
    private String callLlm(String question) {
        // TODO 接入 OpenAI、通义千问等大模型接口
        return "这里是大模型返回的答案";
    }

    /**
     * 主方法:演示缓存未命中与命中的两种情况
     *
     * @param args 启动参数,本示例未使用
     */
    public static void main(String[] args) {
        SemanticCacheDemo demo = new SemanticCacheDemo();
        demo.ask("Redis 怎么做向量检索?");      // 未命中,调用 LLM
        demo.ask("Redis 如何实现向量搜索?");    // 语义相近,直接命中缓存
    }
}

5.3 LangChain4j / Spring AI 集成

Redis 与主流的 AI 应用框架都做了深度集成。在 Java 生态里,LangChain4j 和 Spring AI 都把 Redis 作为官方支持的向量存储与对话记忆实现,它可以同时充当向量存储、语义缓存和对话历史持久化三种角色。

xml 复制代码
<!-- pom.xml 引入 LangChain4j 的 Redis 集成 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-redis</artifactId>
    <version>0.36.0</version>
</dependency>
java 复制代码
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.store.memory.chat.redis.RedisChatMemoryStore;

import java.util.List;

/**
 * LangChain4j 与 Redis 的集成示例
 * 演示 Redis 同时承担向量存储与对话历史持久化两种角色
 */
public class LangChain4jRedisDemo {

    /** Redis 主机地址 */
    private static final String REDIS_HOST = "localhost";

    /** Redis 端口 */
    private static final int REDIS_PORT = 6379;

    /**
     * 主方法:演示两种角色的典型用法
     *
     * @param args 启动参数,本示例未使用
     */
    public static void main(String[] args) {
        // 角色一:向量存储(知识库检索)
        RedisEmbeddingStore embeddingStore = RedisEmbeddingStore.builder()
                .host(REDIS_HOST)
                .port(REDIS_PORT)
                .indexName("langchain_kb")
                .dimension(1536)                 // 向量维度需与 embedding 模型一致
                .build();

        EmbeddingModel embeddingModel = OpenAiEmbeddingModel.withApiKey("你的-API-KEY");

        // 把知识片段向量化后写入 Redis
        List<String> docs = List.of(
                "Redis 8.0 支持原生向量类型",
                "Iris 是面向智能体的上下文平台"
        );
        for (String doc : docs) {
            TextSegment segment = TextSegment.from(doc);
            Embedding embedding = embeddingModel.embed(segment).content();
            embeddingStore.add(embedding, segment);
        }

        // 角色二:对话历史持久化(服务重启也不丢)
        RedisChatMemoryStore memoryStore = RedisChatMemoryStore.builder()
                .host(REDIS_HOST)
                .port(REDIS_PORT)
                .ttl(86400L)                     // 会话保留 1 天
                .build();

        MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
                .id("user:1001")                 // 按用户区分会话
                .maxMessages(20)                 // 最多保留最近 20 条消息
                .chatMemoryStore(memoryStore)
                .build();

        memory.add(UserMessage.from("介绍一下 Vector Set"));
        memory.add(AiMessage.from("Vector Set 是 Redis 8.0 引入的原生向量数据类型......"));

        for (ChatMessage message : memory.messages()) {
            System.out.println(message);
        }
    }
}

5.4 MCP 服务器:让 AI 助手直接操作 Redis

Redis 还提供了官方的 MCP(Model Context Protocol)服务器。配好之后,Claude 这类 AI 助手就能用自然语言直接跟你的 Redis 数据对话------"帮我看看有哪些 key 快过期了""把这个 Hash 的结构展示出来",不用手写命令。

json 复制代码
{
  "mcpServers": {
    "redis": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-e", "REDIS_HOST=host.docker.internal",
        "-e", "REDIS_PORT=6379",
        "-e", "REDIS_PWD=123456",
        "mcp/redis"
      ]
    }
  }
}

此外,Redis 的 AI Incubator 还在持续放出一些实验性项目,比如把整个文件系统存进 Redis、为 Google ADK 和 Microsoft Agent Framework 提供集成支持等,虽然还带着实验性质,但方向很清楚。


六、一个完整的 RAG 请求长什么样

把上面这些能力串起来,一个生产级的 AI 应用请求链路大致是这样:
#mermaid-svg-39Y6pK4P5xyBIwya{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-39Y6pK4P5xyBIwya .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-39Y6pK4P5xyBIwya .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-39Y6pK4P5xyBIwya .error-icon{fill:#552222;}#mermaid-svg-39Y6pK4P5xyBIwya .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-39Y6pK4P5xyBIwya .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-39Y6pK4P5xyBIwya .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-39Y6pK4P5xyBIwya .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-39Y6pK4P5xyBIwya .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-39Y6pK4P5xyBIwya .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-39Y6pK4P5xyBIwya .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-39Y6pK4P5xyBIwya .marker{fill:#333333;stroke:#333333;}#mermaid-svg-39Y6pK4P5xyBIwya .marker.cross{stroke:#333333;}#mermaid-svg-39Y6pK4P5xyBIwya svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-39Y6pK4P5xyBIwya p{margin:0;}#mermaid-svg-39Y6pK4P5xyBIwya .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-39Y6pK4P5xyBIwya .cluster-label text{fill:#333;}#mermaid-svg-39Y6pK4P5xyBIwya .cluster-label span{color:#333;}#mermaid-svg-39Y6pK4P5xyBIwya .cluster-label span p{background-color:transparent;}#mermaid-svg-39Y6pK4P5xyBIwya .label text,#mermaid-svg-39Y6pK4P5xyBIwya span{fill:#333;color:#333;}#mermaid-svg-39Y6pK4P5xyBIwya .node rect,#mermaid-svg-39Y6pK4P5xyBIwya .node circle,#mermaid-svg-39Y6pK4P5xyBIwya .node ellipse,#mermaid-svg-39Y6pK4P5xyBIwya .node polygon,#mermaid-svg-39Y6pK4P5xyBIwya .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-39Y6pK4P5xyBIwya .rough-node .label text,#mermaid-svg-39Y6pK4P5xyBIwya .node .label text,#mermaid-svg-39Y6pK4P5xyBIwya .image-shape .label,#mermaid-svg-39Y6pK4P5xyBIwya .icon-shape .label{text-anchor:middle;}#mermaid-svg-39Y6pK4P5xyBIwya .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-39Y6pK4P5xyBIwya .rough-node .label,#mermaid-svg-39Y6pK4P5xyBIwya .node .label,#mermaid-svg-39Y6pK4P5xyBIwya .image-shape .label,#mermaid-svg-39Y6pK4P5xyBIwya .icon-shape .label{text-align:center;}#mermaid-svg-39Y6pK4P5xyBIwya .node.clickable{cursor:pointer;}#mermaid-svg-39Y6pK4P5xyBIwya .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-39Y6pK4P5xyBIwya .arrowheadPath{fill:#333333;}#mermaid-svg-39Y6pK4P5xyBIwya .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-39Y6pK4P5xyBIwya .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-39Y6pK4P5xyBIwya .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-39Y6pK4P5xyBIwya .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-39Y6pK4P5xyBIwya .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-39Y6pK4P5xyBIwya .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-39Y6pK4P5xyBIwya .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-39Y6pK4P5xyBIwya .cluster text{fill:#333;}#mermaid-svg-39Y6pK4P5xyBIwya .cluster span{color:#333;}#mermaid-svg-39Y6pK4P5xyBIwya div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-39Y6pK4P5xyBIwya .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-39Y6pK4P5xyBIwya rect.text{fill:none;stroke-width:0;}#mermaid-svg-39Y6pK4P5xyBIwya .icon-shape,#mermaid-svg-39Y6pK4P5xyBIwya .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-39Y6pK4P5xyBIwya .icon-shape p,#mermaid-svg-39Y6pK4P5xyBIwya .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-39Y6pK4P5xyBIwya .icon-shape .label rect,#mermaid-svg-39Y6pK4P5xyBIwya .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-39Y6pK4P5xyBIwya .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-39Y6pK4P5xyBIwya .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-39Y6pK4P5xyBIwya :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Redis 统一承载
命中
未命中
用户
应用服务
语义缓存

LangCache
返回答案
读取智能体记忆

会话记忆 + 长期记忆
向量检索知识库

Vector Set / RediSearch
组装 Prompt

问题 + 记忆 + 知识
调用大模型
写回语义缓存

并更新长期记忆

注意虚线框圈起来的部分------语义缓存、智能体记忆、向量检索,全部落在同一个 Redis 里。

这正是 Redis 这次转身的核心逻辑:过去你可能需要 Pinecone 存向量、PostgreSQL 存会话、Redis 做缓存,三套系统三份运维成本,数据还要来回搬。现在这些活可以收敛到一个组件里,延迟统一在毫秒级,技术栈也简单了一大截。


七、写在最后

Redis 这次"接入 AI",说到底不是追热点贴标签,而是把自己一直以来的长处------低延迟、结构灵活、离业务最近------重新对准了 AI 应用的痛点。

几句话概括这次升级:

  • 向量能力进内核:Vector Set 成为一等公民数据类型,RediSearch 整合进核心,不用再装模块;
  • 量化省内存:Q8 约 4 倍压缩、BIN 最高 32 倍压缩,让大规模向量存储的成本变得可接受;
  • Iris 管记忆:双层记忆架构 + 安全的数据获取工具 + 近实时数据同步,把 Agent 上下文这件事系统化了;
  • 生态很齐全:RedisVL for Java、LangCache、LangChain4j / Spring AI 集成、MCP 服务器,接入成本很低。

对开发者来说,最实在的一点可能是:你不需要学一个全新的系统。还是那个 Redis,还是熟悉的连接方式和运维习惯,只是多了几个命令和几个库。

如果你手上正好有个 AI 项目在纠结向量库选型,不妨先看看已经跑在你集群里的那个 Redis------它可能已经能干这个活了。

相关推荐
布吉岛的石头1 小时前
海外AI众包入门:英语要什么水平,钱怎么收回来
人工智能·副业·数据标注·众包·海外兼职
行百里er1 小时前
Redis 持久化——RDB 快照 vs AOF 日志
redis·后端
这个DBA有点耶1 小时前
数据融合平台的下一代形态:数据库内核自己就能融合,为什么还要ETL?
数据库·架构·aigc
zhikouai1 小时前
一边撤掉3千元入门款,一边在别处悄悄卖
人工智能
数据库小学妹1 小时前
MySQL大表怎么优化?2亿行表的分区归档与冷热分离实战
数据库·mysql·分库分表·分区表·数据库运维·冷热分离
Rocky Ding*1 小时前
Hi-DiT:一文读懂Hybrid Latent-Pixel Diffusion Transformer的本质与技术细节
论文阅读·人工智能·深度学习·机器学习·aigc·ai-native·hi-dit
91刘仁德1 小时前
RAG实战 - 向量数据库(Milvus)
数据库·milvus
勤劳X码农1 小时前
2026年学生配音软件怎么选?免费AI配音指南
人工智能
鬼手点金1 小时前
opencode组件详解-安装方式
人工智能·python·优化器·分析器·nanogpt