1. 核心存储架构:ES 的"混合双打"模式
我们放弃了独立的向量数据库,转而利用 Elasticsearch (ES) 作为统一的存储和检索引擎。ES 在这里扮演了双重角色:
- 向量检索(语义大脑) :利用 ES 的
dense_vector字段和 KNN 算法,负责处理"意思相近"的查询(如:搜"水果"能联想到"苹果")。 - 关键词检索(精准索引):利用 ES 传统的倒排索引,负责处理精确匹配(如:搜"订单号 123"必须精准命中)。
- 元数据过滤(记忆管家) :利用 ES 的
keyword字段存储session_id、user_id、timestamp等标签,确保在检索时能快速隔离不同用户或会话的数据。
2. 数据流转与生命周期
记忆数据在系统中经历了一个完整的生命周期,确保了"热数据"实时响应,"冷数据"低成本存储:
- 热数据(短期记忆)
- 位置:内存或高速缓存。
- 内容:当前会话的最近几轮对话。
- 作用:保证对话的流畅性和即时上下文。
- 固化与写入(记忆沉降)
- 触发:当对话轮数达到阈值或会话结束时,后台异步任务启动。
- 处理:将热数据进行总结、压缩,并调用 Embedding 模型将其转化为向量。
- 存储 :将向量 (用于检索)、原始文本 (用于阅读)、元数据(用于过滤)打包存入 ES。
- 冷数据(长期记忆)
- 位置:ES 主存储。
- 内容:历史对话精华、用户偏好、关键事实。
- 归档:对于极久远的记忆,可进一步沉降到低成本的对象存储(如 S3/文件存储)中,实现成本与性能的平衡。
3. 检索逻辑:语义与隔离的完美配合
在读取记忆时,系统执行了一套严密的逻辑,解决了"混淆"和"精准度"问题:
- 向量化查询(制作钥匙) :将用户当前的提问通过 Embedding 模型转化为向量。这个向量仅作为检索钥匙,不会被存入数据库。
- 带过滤的相似度搜索(精准开门) :ES 接收查询请求,执行两步操作:
- 过滤 :根据
session_id或user_id锁定当前用户的记忆范围(防止记忆错乱)。 - 匹配:在锁定范围内,计算向量相似度,找出 Top-K 条最相关的记忆。
- 过滤 :根据
- 原文重组(交付货物) :系统从 ES 中提取匹配到的原始文本(而非向量),将其组装成上下文(Context),投喂给大模型。
4. 模型依赖与工程落地
针对 Embedding 模型的依赖问题,我们确立了"把复杂度留给开发者,把简单留给用户"的工程原则:
- 核心认知 :ES 只是容器和计算器,Embedding 模型是不可或缺的"翻译官"。无论使用何种数据库,将文本转化为向量的步骤无法省略。
- 落地策略 :
- 内置轻量模型 :软件默认内置一个极小的开源 Embedding 模型(如
all-MiniLM-L6或nomic-embed-text),实现"开箱即用",无需用户配置。 - 异步处理:Embedding 的转换过程在后台异步队列中完成,不阻塞用户的主线程,消除延迟感。
- 灵活配置 :允许高级用户在开启长期记忆地方设置中替换为自定义的 Embedding 服务(如 OpenAI 或本地 Ollama 大模型),以满足更高精度的需求。
- 内置轻量模型 :软件默认内置一个极小的开源 Embedding 模型(如
5. 最终架构图谱
整个系统形成了一个闭环:
用户提问 → Embedding模型(转向量) → ES(带Session过滤的语义搜索) → 提取原始文本 → 组装上下文 → 大模型(LLM)生成回答