别让AI患上“金鱼记忆”:我用Redis给RAG装了个短期大脑(MySQL)
写在前面:
在开发企业级AI知识库问答系统时,我遇到了一个普遍但容易被忽视的问题——多轮对话的上下文记忆。传统的RAG(检索增强生成)架构往往只处理单轮问答,用户每次提问都像是“第一次见面”,导致对话缺乏连贯性。为了解决这个问题,我在项目中设计了一套基于Redis + MySQL的混合上下文存储方案。本文将分享其中的技术选型、实现细节以及踩坑经验,希望能为同样在探索RAG工程化的朋友提供一些参考。
一、短期记忆与长期记忆:Redis + MySQL 分层架构
对话上下文的存储面临一个经典矛盾:既要快,又要省;既要全,又要准。如果将所有历史对话都存入Redis,随着对话轮数增加,内存消耗会急剧膨胀;如果只依赖MySQL,每次检索都需要查询数据库,响应延迟又会显著上升。
我的解决方案是分层存储:
-
短期记忆层(Redis):存储最近10~20轮对话,TTL设置为1小时。这覆盖了绝大多数用户连续对话的场景,保证响应速度。Redis的List或String结构都可以实现,我选择了Hash + 时间戳排序的方式,方便按顺序拉取。
-
长期记忆层(MySQL):新增
conversation_context表,存储对话摘要、元数据以及每条消息的importance_score(重要性评分)。当Redis中的上下文过期或被淘汰后,系统会从MySQL中加载摘要信息,实现“记忆唤醒”。
这种设计的核心权衡在于:用Redis的短暂存储换速度,用MySQL的结构化存储换容量。实际压测中,Redis命中率稳定在85%以上,平均响应时间控制在150ms以内。
二、对话连贯性:智能滑动窗口与顺序保证
技术实现上,最大的坑是消息乱序。在高并发场景下,用户快速连续提问,后端服务可能因为异步处理导致消息写入顺序错乱。一旦顺序颠倒,AI生成的回答就会前言不搭后语。
我的处理策略包含三个层面:
-
前端时间戳 + 后端序列号:每条消息入库时记录服务端统一时间戳,并在会话内自增
seq_id,查询时严格按照seq_id排序。 -
滑动窗口管理:窗口大小不是固定的。我会根据消息的
importance_score动态调整——高重要性消息(如用户明确要求“记住这个设定”)保留更多轮数,低价值消息(如“嗯”、“好的”)提前丢弃。窗口最多保留20轮,最少不低于8轮。 -
格式化上下文:从Redis读取消息后,统一转换为
role: content格式(例如user: 李白是谁?、assistant: 李白是唐代诗人…),直接拼接到Prompt中。这一步看似简单,但要注意对特殊字符(换行、引号)的转义,避免破坏Prompt结构。
三、从冗长到简洁:优化AI回答格式,提升用户体验
早期版本中,AI的回答常常带着大段的“思考过程”:
需要说明的是:用户询问了李白的身份,根据历史对话可知用户对唐代文学感兴趣,因此我应该提供简洁但准确的介绍。结论:李白是唐代诗人,被后人誉为“诗仙”。
这种回答虽然逻辑完整,但用户阅读体验极差。问题根源在于系统提示词(System Prompt)中包含了“请逐步思考”的指令,同时上下文拼接方式导致模型倾向于输出解释性内容。
我做了两处改进:
-
重构System Prompt:明确要求“直接给出最终答案,不要输出思考过程,不要使用‘需要说明的是’、‘综上所述’等过渡词”。
-
上下文压缩:在拼接历史对话时,去除冗余的元数据(如时间戳、消息ID),只保留纯净的
role: content对。同时,对于过长的历史消息(超过200字符),调用LLM进行摘要压缩,再存入上下文。
最终效果对比如下:

四、测试验证与数据库设计:小步快跑,持续迭代
功能测试是检验方案有效性的关键。我设计了三个核心用例:
-
上下文连贯性:用户问“你知道李白吗?” → AI正确回答。
-
上下文记忆:用户接着问“他有哪些诗词?” → AI基于上一轮的“李白”给出《将进酒》《静夜思》等,而不是反问“他指谁?”
-
回答格式:所有回答均无思考过程,直接简洁输出。
数据库层面,除了conversation_context表,我还为message表增加了importance_score字段(默认值0,范围0~1),并创建了复合索引 (conversation_id, seq_id, importance_score)。这个分数目前由规则引擎计算(例如用户重复提问同一主题时加分,消息长度过短时减分),未来可以接入小模型自动评估。
注:相关的SQL脚本已随项目发布,感兴趣的朋友可以直接参考 GitHub仓库 中的
docs/schema.sql。
五、后续改进:向量化检索与流式输出
目前的方案虽然稳定运行,但仍有四个值得深挖的方向:
-
流式输出:当前AI回答是一次性返回完整内容,长回答时用户等待焦虑。下一步将改造为SSE或WebSocket流式传输,首字延迟可降至300ms以内。
-
上下文压缩:对于超过20轮的长对话,即使只保留高重要性消息,Token消耗仍然较大。计划引入记忆蒸馏技术,定期调用LLM将历史对话压缩为结构化摘要(例如“用户偏好短答案”、“对Java并发感兴趣”等)。
-
向量化搜索:目前加载长期记忆时,仅通过
importance_score排序截取。更优雅的做法是将历史对话片段向量化存入Milvus,根据当前问题语义检索相关历史,实现“联想式记忆”。 -
多轮对话优化:改进摘要生成算法,从简单的拼接抽取升级为图式记忆(Graph-based Memory),捕捉对话中实体间的隐含关系。
总结
在RAG系统中引入对话上下文存储,本质上是在内存开销、响应速度、体验连贯性之间寻找平衡。通过Redis构建短期记忆、MySQL沉淀长期记忆,并辅以智能滑动窗口和重要性评分,我成功解决了“AI失忆”问题。当然,工程没有银弹,这套方案在高并发、超长对话场景下仍有优化空间。未来随着向量检索和流式技术的成熟,我相信“有记忆、懂偏好”的AI助手会离我们越来越近。
最后,所有代码均已开源在 Enterprise-AI-Copilot,欢迎交流讨论。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)