资讯详情

资讯详情

Redis 8 内置 AI:向量检索、语义缓存与 Agent 记忆实践

1. Redis 到底接了个什么样的 AI先给结论这里说的Redis 已正式接入 AI不是哪个第三方中间件套了个壳而是 Redis 官方在 2024 年底把 AI 能力直接做进了主版本。Redis 8 开始内置向量检索、语义缓存、自然语言查询这些能力官方博客原话是Redis enters the AI era。用过 Redis 的朋友都知道这东西以前就是做缓存、做队列、做会话管理的一把好手现在官方把向量召回和大模型交互这两件事直接纳入核心功能等于告诉后端开发者以后 AI 应用里的记忆层、检索层、实时状态层可以全部押注在 Redis 上。我个人的理解是这次升级最大的看点不在于某个单点功能而在于 Redis 把 AI 应用里最痛的几个环节都打通了数据过期策略可以直接用来管理对话历史内置的向量索引可以解决语义检索JSON 和 Hash 结构可以维护 Agent 的长期状态再加上本身就有的发布订阅和 Stream连消息传递和事件驱动都能一起干了。以前我们要做 AI 应用得同时维护 MySQL、Elasticsearch、向量数据库、Redis、消息队列好几个组件现在 Redis 用一套集群就能覆盖大部分场景。这篇文章适合谁看我觉得主要指这两类人一类是正在做 AI Agent、RAG 或者聊天产品、推荐系统的后端开发另一类是用了 Redis 多年但还没接触过向量检索功能的老玩家。前者可以拿来降本增效后者可以重新认识一下这个老伙计的新能力。下面从原理到实操把我这段时间的踩坑和验证过程都整理出来。2. Redis 的哪些存量特性恰好命中了 AI 应用的要害2.1 内存计算和极低延迟决定了 AI 交互的手感AI 应用和传统 Web 应用最大的区别是它需要多次旁路请求大模型接口每次几百毫秒甚至几秒用户的等待耐心非常有限。如果这一连串请求里每一步还需要去查询 MySQL 或者远程对象存储那体验基本就废了。Redis 的核心价值在这时候就凸显出来——所有操作都在内存里完成延迟通常在亚毫秒到几毫秒之间。比如做一个 Agent 的会话召回把用户最近 20 条对话记录直接以 List 结构存在 Redis 里Agent 启动时一次 LRANGE 就能拿到全部上下文连网络耗时都省了。这种低延迟不是简单靠内存比磁盘快就能解释的更关键的是 Redis 的 IO 模型。它用单线程事件循环加多路复用规避了传统多线程模型里大量的锁竞争和上下文切换开销。所以哪怕遇到高并发访问只要没有复杂的聚合计算Redis 都能保持非常稳定的响应速度。这一点对 AI 应用尤为重要因为大模型接口本身已经是瓶颈如果前面的中间层还有延迟抖动用户感知到的就是卡一下或者转圈圈。另外配合上数据过期机制Redis 能自动把对话会话、临时状态、验证码、限流计数这些短生命周期数据清理掉。AI 应用中用户的会话上下文通常只需要保留半小时到几天用 Redis 完全不用做额外的定时任务。2.2 丰富的数据结构对应着 AI 应用的不同存储模型很多人对 Redis 的印象停留在 String 类型的 KV 上但真正把 Redis 玩明白的人都知道它的价值在于那五种基本结构加三种高级结构。我简单列一下你会发现它们几乎就是为 AI 应用量身准备的String存 JSON 序列化后的用户配置、模型 API Key、限流计数器最直接的 KV 用法。Hash存单个用户的属性字段比如 user:1001 下的 name、age、preference更新某个字段不需要读写整条记录。List存对话消息流lpush/rpush 模拟消息队列lrange 取最近的消息天然适合聊天记录。Set存用户标签、已读消息 ID、去重集合做推荐系统的兴趣交集特别方便。ZSet存带分数的排序数据比如每个知识条目的相关度、热度、过期时间戳高并发排行榜就靠它。StreamRedis 5.0 之后引入的增量日志结构适合做 Agent 执行轨迹的事件流可持久化可回溯。JSONRedisJSON 模块的支持可以直接对 JSON 文档做局部更新AI 定制化的用户配置就能像操作 MongoDB 一样操作。向量索引Redis 8 内置可以理解成一个专门做相似度检索的赛道HNSW 算法在内存里跑秒级召回近邻向量。这个特性和 AI 应用的多模态多样化需求非常吻合。AI 应用里最不缺的就是各种非结构化数据文本片段、embedding 向量、工具调用记录、用户偏好标签、事件流每一个都能在 Redis 里找到对应的原生结构不像 MySQL 那样什么都要强行塞进表格里。2.3 主从复制和集群扩展撑起了 AI 应用的稳定性要求AI 应用上线后最容易暴露的问题不在模型本身而在支撑层的稳定性。模型偶尔超时还能容忍但如果 Redis 宕了整个 Agent 的记忆层就全断了用户立刻会觉得产品不可用。所以 Redis 在主从复制、哨兵、Cluster 集群这几个层面做了很多工作。实操中最常用的方案是用 Docker 部署主从复制先跑一个主节点再挂一两个从节点主节点负责写从节点负责读写坏了从节点能顶上。热词里docker安装redis主从说的就是这个场景。再加上 Redis Sentinel 哨兵做自动故障转移基本能满足中小团队的可用性要求。当然千万级 QPS 的场景就得考虑 Redis Cluster 了把数据分片到多个主节点上每个主节点再带从节点容错和扩展性都能兼顾。这套能力恰好是 AI 应用需要的。AI Agent 的调用链经常会横跨多个服务每个中间节点都要求高可用。用一个 Redis 集群同时承担会话存储语义缓存事件总线三个角色运维上也比维护三个独立组件轻松得多。2.4 生态工具的成熟度降低了上手门槛Redis 从 2013 年到现在已经迭代了十几年生态里可视化客户端、监控面板、各种语言的 SDK 都非常成熟。热词里的redis desktop manager和another redis desktop manager都是常用的可视化工具装一个能看到所有 key 的数据类型和内存占用排查问题效率特别高。redis-cli --stat可以实时看每秒操作数redis-cli --bigkeys能扫出大 keySLOWLOG GET 10能看慢查询。这些工具在排查 AI 场景的性能问题时一样适用而且因为 Redis 本身设计简洁定位问题比排查 MySQL 快得多。3. 实操三步让 Redis 跑起 AI 语义检索3.1 环境准备用 Docker 快速拉起一个带检索能力的 Redis我建议不要单独装原版 Redis而是用官方打包好的redis-stack-server镜像它内置了 Search、JSON、TimeSeries 这些模块省去手动编译加载插件的麻烦。具体命令docker run -d \ --name redis-stack \ -p 6379:6379 \ -p 8001:8001 \ redis/redis-stack-server:latest这里 6379 是 Redis 原生端口8001 是内置的 RedisInsight 管理界面端口。起来之后可以先验证一下服务状态docker ps | grep redis-stack redis-cli ping返回 PONG 就说明通了。如果是本机开发也可以直接用 brew install redis-stack-server但 Docker 的方式可移植性最好团队里所有人拉到镜像就能跑。注意redis-stack-server镜像本身不包含 RedisInsight Web 界面需要 Web 界面的话用redis/redisinsight:latest单独起一个容器也可以直接连桌面客户端。热词里提到的 Redis Desktop Manager 和 Another Redis Desktop Manager 都能用两者对新版 RedisJSON 的支持都不错。3.2 创建向量索引和写入向量数据Redis 的向量检索能力基于 Search 模块它把向量索引当作一种特殊的字段来建。比如我们要存一批文档向量每条以doc:id为 key用 Hash 结构存储其中embedding字段存向量。先建索引redis-cli FT.CREATE idx_docs ON HASH PREFIX 1 doc: SCHEMA content TEXT embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 384 DISTANCE_METRIC COSINE这里有几个参数要解释一下。DIM 384 表示向量的维度如果你用的是 OpenAI 的 text-embedding-3-small维度就是 1536如果用 sentence-transformers/all-MiniLM-L6-v2维度是 384。DISTANCE_METRIC COSINE 表示用余弦距离来衡量相似度HNSW 是近似最近邻算法在召回率和性能之间取得了比较好的平衡。写入一条向量数据redis-cli HSET doc:001 content Redis has officially entered the AI era embedding \x00\x00\x80?\x00\x00\x00?\x00\x00\x80?二进制向量在命令行写起来不方便实际开发中通常用 Python 或 Node 客户端来做。贴一个 Python 的操作示例import redis import numpy as np client redis.Redis(hostlocalhost, port6379) # 假设 text 经过了 embedding 模型转为浮点列表 vector embedding_model.embed(Redis 向量检索实战) # 返回 list[float] byte_vector np.array(vector, dtypenp.float32).tobytes() client.hset(doc:002, mapping{ content: Redis 向量检索实战, embedding: byte_vector })写入之后就可以做语义搜索query_vec embedding_model.embed(Redis 最新AI能力有哪些) query_bytes np.array(query_vec, dtypenp.float32).tobytes() result client.ft(idx_docs).search( redis.query.Query(*[KNN 5 embedding $vec AS score]) .sort_by(score) .return_fields(content, score) .dialect(2), {vec: query_bytes} ) for doc in result.docs: print(doc.content, doc.score)KNN 5 表示返回最相似的 5 条score 越小表示越相似。这套流程就是经典 RAG 的召回环节中间不需要额外引入向量数据库。3.3 给 Redis 装上自然语言查询能力这一步核心是 NL2Query也就是让用户用大白话查询业务数据系统自动把自然语言转换成 Redis 查询指令。实现路径通常是先调用大模型将自然语言转成 Redis Search 查询语法或 Lua 脚本然后 Redis 执行查询最后把结果返回给用户。在这个链路里Redis 负责实时数据层大模型负责语义理解和指令生成。举个例子用户在对话框里输入帮我找找昨天创建并且状态是进行中的任务系统先将这句话发给大模型大模型输出一个结构化的查询条件比如status:active AND created_at:[2024-01-01 TO 2024-01-02]然后交给 Redis 执行。我在项目里验证过用 Redis 存 Agent 在执行过程中的工具调用记录给每条记录打上时间戳和状态标签再用大模型做语义解析确实可以把过去需要写 SQL 的查询全部替换成自然语言。Redis 执行这种结构化查询是一把好手因为它直接操作内存数据不用走 SQL 解析计划速度非常快。3.4 把语义缓存接进 AI 应用AI 应用调大模型接口最大的痛点是费用和延迟。很多用户问的内容其实是高度相似的比如什么是 Redis 分布式锁Redis 支持哪些数据结构这类问题的回答完全可以缓存起来。语义缓存就是把用户问题转成向量去 Redis 里做相似度检索如果找到相似度超过 0.95 的已缓存答案就直接返回不再调用大模型接口。在实际项目里我是这样实现的def get_ai_answer(question: str): q_vec embedding_model.embed(question) result client.ft(cache_idx).search( redis.query.Query(*[KNN 1 embedding $vec AS score]).sort_by(score).dialect(2), {vec: np.array(q_vec, dtypenp.float32).tobytes()} ) if result.docs and float(result.docs[0].score) 0.08: # 余弦距离足够小 return result.docs[0].answer answer call_llm(question) save_to_cache(question, answer, q_vec) return answer相似度阈值需要根据实际数据调节我测下来 0.92 到 0.96 之间比较合适太低会把语义相关但答案不同的内容误命中太高缓存命中率又太低。配合 Redis 的 TTL可以给缓存答案设置过期时间热点知识缓存 24 小时时事类内容缓存 10 分钟灵活性很高。4. 在真实项目里怎么把 AI 和 Redis 玩出价值4.1 用缓存治理思路解决 AI 接口的重复计算问题热词里持续出现redis缓存治理这其实是一个老话题但在 AI 应用里又重新重要了。传统 Web 缓存治理讲究的是缓存穿透、缓存击穿、缓存雪崩三件事AI 应用里照样存在缓存穿透用户恶意刷不存在的 IDAI 应用会不断调用模型接口做无意义生成。解决办法是布隆过滤器缓存所有存在性或者对空结果也做短期缓存。缓存击穿某个热点问题突然爆发比如某条新闻火了大家都在问同一个问题。单个热点 key 在过期瞬间被大量请求同时打到模型接口会给模型厂商 API 造成压力。解决办法是用互斥锁重建缓存或者用逻辑过期主动续期。缓存雪崩大量 key 同时过期导致下游压力瞬间爆发。解决办法是给 TTL 加随机抖动失效时间均匀分散开。说到这里Redis 的SET NX PX指令在 AI 缓存重建里也能直接用配合 Lua 脚本保证原子性。简单贴一个防击穿的互斥锁逻辑def get_answer_with_lock(question_key): answer client.get(question_key) if answer: return answer lock_key flock:{question_key} if client.set(lock_key, 1, nxTrue, ex10): answer call_llm(question_key) client.set(question_key, answer, ex1800) client.delete(lock_key) return answer time.sleep(0.1) return get_answer_with_lock(question_key)不过要提醒一下这种自旋重试方案只适合流量可控的场景真正的超高并发还是要用官方推荐的 Redisson。4.2 基于 Redis 的分布式锁是 AI Agent 编排的基础一个 AI Agent 往往由多个工作流组成每个工作流要操作共享资源比如同一份用户配置、同一个计费账户。如果不加并发控制两个工作流同时扣费、同时更新配置就会出现严重问题。Redis 分布式锁是业界最常见的方案原理也不复杂多个节点抢同一个 key谁抢到了谁就拥有执行权。正确姿势是使用 Redisson 这样的成熟库它实现了自动续期的看门狗机制避免业务还没执行完锁就过期了。如果自己手写最常见的坑是忘记给锁设置过期时间或者删除锁时误删了别人的锁。正确的删除操作要配合 Lua 脚本保证原子性if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end这里 ARGV[1] 是请求唯一标识只有持有者自己才能删自己的锁。面试题里经常问Redis 分布式锁的坑其实最大的坑就是没有考虑锁过期时间和误删问题。4.3 聊天记录与 Agent 记忆的落地姿势做聊天产品或者 Agent 产品会话记忆的存储是个刚需。最简单的方式就是给每个会话分配一个 List key比如session:id:messages用 RPUSH 追加用户消息和助理回复用 LTRIM 只保留最近 N 条。如果想给消息加过期时间可以配合 EXPIRE 指令。这种方案比 MySQL 存聊天记录清爽得多读写快内存占用也可控。如果要做长期记忆也就是 Agent 跨会话记住用户偏好可以用 Hash 结构HSET user:1001 preferences language zh-CN tone friendly HSET user:1001 facts location Shanghai每次 Agent 执行前从 Hash 里读取用户偏好拼进 Prompt剩下的交给大模型。这套方案我用了半年稳定性很好而且可以很自然地支持用户手动修改偏好比如切换语言风格直接 HGET/HMERGE 即可不用动其他数据。4.4 Redis 序列化问题AI 场景里更容易踩坑热词里持续有redis序列化这个在 AI 场景里值得单独提。因为我们经常需要把 embedding 向量、复杂嵌套对象、大模型响应存进 Redis如果不处理序列化会出现乱码、类型转换失败等问题。常规建议是String 类型用 JSON 序列化Hash 类型记得字段值一定是字符串向量数据必须要转成 bytes 存储否则会和字符串格式混在一起。Python 的 redis-py 默认可以自动处理字符串但没有处理 bytes 数组和 numpy 数组的能力。我建议统一封装一层存储工具写数据时自动序列化读数据时自动反序列化避免业务里到处散落json.dumps和json.loads。4.5 Redis 可视化客户端怎么选提高排查效率排查 Redis 问题最快的路径是可视化客户端。我用过四款工具Redis Desktop Manager老牌但闭源后更新变慢、Another Redis Desktop Manager开源跨平台支持 RedisJSON 和列表展示、RedisInsight官方出品功能最全支持 Search 模块可视化查询、以及 VS Code 的 Redis 插件轻量适合快捷操作。我的建议是日常开发用 Another Redis Desktop Manager 或者 VS Code 插件排查线上问题用 RedisInsight因为它的命令行能直接跑FT.SEARCH和SLOWLOG查询还能可视化看到索引结构。不要在一个工具上纠结太久Redis 本身协议很直白工具只是辅助。5. 常见问题与排查技巧实录5.1 连接不上 Redis先按这四个方向定位我每次遇到连接问题都是按固定顺序排查。第一步redis-cli ping看基础连接是否正常第二步看 bind 配置如果 redis.conf 里 bind 了 127.0.0.1那外部机器自然连不上第三步看 protected-mode默认开启时只允许本机回环连接第四步看防火墙和云安全组是否放行了 6379 端口。以上四步排查完90% 的场景都能定位到问题。Docker 部署时还有一个常见坑容器内 Redis 默认绑定了127.0.0.1你以为映射了6379:6379但外部请求会被容器内的回环限制挡掉。解决办法是启动时追加--bind 0.0.0.0或者改配置文件里的 bind 项。5.2 Redis 日志怎么看慢查询怎么抓热词里有redis日志Redis 默认日志是输出到 stdout如果用 Docker 部署可以用docker logs redis-stack查看。想开启慢查询日志需要设置阈值redis-cli CONFIG SET slowlog-log-slower-than 10000 redis-cli CONFIG SET slowlog-max-len 128这里的 10000 单位是微秒即超过 10 毫秒的操作都会记入慢查询日志然后用SLOWLOG GET查看。AI 场景里如果发现某个语义检索操作很慢一定要用这个命令定位十有八九是向量维度开太大或者没有指定索引前缀。另外INFO commandstats可以统计每种命令的调用次数和耗时来分析热点操作MEMORY DOCTOR可以诊断内存碎片问题redis-cli --bigkeys可以找出大 key。这些工具虽然老但在 AI 场景里照样好用。5.3 镜像拉取慢或者拉取失败换个镜像源就好如果 Docker 拉取 redis 镜像很慢检查当前使用的 registry mirror 是否为官方默认。国内访问 Docker Hub 不稳定需要配置可信的加速镜像地址在 Docker 配置文件的 registry-mirrors 里添加即可然后重启 Docker。这个跟代码无关但确实卡住过很多人。5.4 向量检索结果不准先查维度再查距离度量我做 RAG 首次上线时遇到一个很怪的线程用中文文档建索引英文问题能召回到结果中文问题反而召回到了不相关的英文内容。排查后发现是 embedding 模型没有分词中文文本被切成了单字导致语义信息丢失。后来换了针对中文的 embedding 模型效果立刻改善。另一个常见的坑是向量类型不匹配。建索引时声明了 FLOAT32写入时却用了 FLOAT64 数组做 tobytesRedis 不会报错但计算结果完全不对返回的向量全是 0。所以写入向量前一定要先np.array(vec, dtypenp.float32)强制转换。5.5 分布式锁失效问题刷新认知的三个细节关于 Redis 分布式锁面试题里问到主从切换为什么可能导致锁丢失我的理解是如果在主节点写入锁后主节点还没同步到从节点就宕机了从节点切换成主节点后锁信息就丢了另一个请求就能获取同一把锁。要彻底解决这个问题Redis 官方推荐用 RedLock但 RedLock 本身也有争议很多团队实际用的是 ZooKeeper 的强一致方案。在我的实践结论里业务上如果对锁的唯一性要求不是极其严格Redis 分布式锁完全可以胜任如果涉及资金类、计费类的强一致场景建议改用数据库唯一约束或者 ZooKeeper。很多教程不会把这一层讲透实际上部署环境的差异会直接影响方案选择。高可用场景下建议开启 wait 1 或 wait 2 参数让主节点在写入锁时等待从节点确认。5.6 AI 场景下 Redis 内存暴涨的几个隐藏原因内存暴涨在 AI 应用里比传统 Web 场景更常见因为向量数据往往比较大。一条 1536 维的 FLOAT32 向量占 6KB如果存 100 万条就是 6GB很快就涨上去了。我总结了几类内存异常增长的原因一是没有设置 TTL 的会话数据无限累积二是向量索引重复创建N 个环境创建了 N 份索引三是大 Value 没有拆分一次把几十页上下文塞进一个 key四是maxmemory-policy配置不对导致 Redis 直接拒绝写入。排查时先用MEMORY USAGE key看单 key 的内存占用再用redis-cli --bigkeys扫大 key。稳定运行时我一般把 maxmemory 设成物理内存的 70%淘汰策略用 allkeys-lru同时给所有会话 key 加 TTL软硬结合内存基本可控。6. 最后说几点我的真实感受我把这套Redis 接入 AI的方案在项目里跑了差不多一个季度最大的体会是Redis 的向量检索并不是要取代专业的向量数据库而是给中小团队一个够用且统一的选择。如果你的向量规模在几百万以内、对召回精度的要求不是苛刻到 99.99%完全可以用 Redis 一套搞定省掉一个中间件运维成本能降不少。真正需要专用的向量数据库的场景是数据到了千万级以上或者对排名的精准度要求极其严格那时候再考虑接 Milvus 或 Qdrant 也不迟。还发现一个非常重要的细节不要一开始就把所有数据都往 Redis 里塞。AI 应用的数据分冷热热数据比如最近一小时会话、热门问题缓存、实时工作流状态这些可以放心放 Redis冷数据比如历史对话归档、全量文档库依然建议放到 MySQL 或对象存储里。Redis 内存再便宜也比磁盘贵存储规划做不好内存账单会让你肉疼。如果你正准备上手我给的建议很简单第一步先把你正在用的缓存储存升级成 redis-stack-server跑一下向量检索 Demo第二步把对话历史存入 Redis用 TTL 管理生命周期第三步再考虑用语义缓存替代一部分高频 LLM 调用。这三个阶段每完成一个都能立刻看到效果也都能帮你更理解 Redis 做 AI 基础设施的底层逻辑。最后再分享一个实用小技巧如果担心第一次写向量索引配置出错可以用FT._LIST查看当前 Redis 里已经创建的所有索引再配合FT.INFO index查看某个索引的字段定义。我调试时最常用的组合路径就是先 INFO 再看字段类型基本能把 80% 的索引问题解决掉。Redis 这套能力虽然新鲜但排查思路还是一样的慢查询日志、内存分析、索引详情三板斧下去问题跑不掉。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →