在多代理 LLM 交互系统中,Memori 作为一个开源的 SQL 原生内存引擎,提供了一种高效的方式来为 LLM 赋予持久、可查询的记忆能力。通过一行代码 memori.enable(),它可以将对话、实体提取和上下文优先级存储在标准 SQL 数据库中,如 SQLite 或 PostgreSQL。这使得 AI 代理能够跨会话维护上下文,避免每次交互从零开始。然而,随着交互规模的扩大,episodic memory store(剧集内存存储)中不可避免地会积累大量语义相似的冗余数据。这些数据虽然表述不同,但本质上传达相同的信息,导致存储膨胀、检索延迟增加,以及计算资源浪费。本文聚焦于在 Memori 的 episodic memory store 中实现语义相似性聚类与去重机制,利用向量嵌入技术优化存储和检索效率,特别适用于多代理协作场景。
语义去重在 LLM 内存存储中的必要性
Memori 的核心优势在于其 SQL-native 设计,避免了昂贵的向量数据库依赖,同时支持自动实体提取和关系映射。根据 Memori 的官方文档,“Memory is stored in standard SQL databases (SQLite, PostgreSQL, MySQL) that you fully own and control。” 这确保了数据可移植性和审计性,但也暴露了传统 SQL 在处理语义相似性方面的局限。episodic memory 主要记录代理间的交互历史,如对话片段、事件序列和决策日志。在多代理系统中,这些交互往往高度相似:例如,不同代理对同一用户查询的响应可能因视角差异而表述不同,但语义核心一致。如果不进行去重,存储会迅速膨胀,检索时需扫描大量冗余条目,影响响应时间。
语义去重通过捕捉内容的深层含义来解决这一问题。传统字符串匹配仅检测精确重复,而语义方法使用嵌入模型将文本转换为高维向量,量化相似度。这在 LLM 训练数据清洗中已被证明有效:研究显示,使用语义嵌入检测相似度时,记忆率可被低估 10 倍以上,因为字符串方法忽略了微小变体如数字或词序变化。在 Memori 的上下文中,去重可减少存储 30%-50%,同时提升检索精度,避免代理重复学习相同模式。
语义相似性聚类的原理与实现基础
语义去重的核心是向量嵌入和聚类算法。嵌入模型(如 OpenAI 的 text-embedding-ada-002 或开源的 BGE)将文本映射到 768 或 1024 维空间中,语义相近的文本向量距离更近。通常采用余弦相似度作为度量:cos(θ) = (A · B) / (|A| |B|),值域 [-1,1],接近 1 表示高度相似。
直接计算所有记忆条目间的两两相似度复杂度为 O(n²),对 Memori 的海量 episodic 数据不可行。因此,引入 K-means 聚类预处理:首先提取所有记忆的嵌入向量,然后聚类为 K 个簇(K 可设为数据量的 1/1000,如 10 万条目取 K=100)。在每个簇内,再计算相似度,仅对簇内对进行阈值判断。这将复杂度降至 O(n² / K),计算效率提升数量级。
阈值选择至关重要:经验阈值 0.85-0.95 表示高相似(可根据领域调整,低阈值保留更多多样性)。超过阈值的条目视为冗余,合并为单一代表:如取簇中心或加权平均嵌入,并保留最完整的原始文本。合并策略包括:(1) 简单替换;(2) 融合元数据(如时间戳、代理 ID);(3) 记录合并历史以支持回溯。
在 Memori 中集成此机制需扩展其存储流程。Memori 的架构包括拦截 LLM 调用、注入上下文和后置记录。去重可在记录阶段插入:调用嵌入 API 生成向量,查询数据库中相似条目,若相似度 > 阈值,则更新现有记录而非新建。
在 Memori 中的工程化实现
Memori 支持 PostgreSQL 等数据库,可利用 pgvector 扩展添加向量支持。首先,安装 pgvector 并在 Memori 数据库中创建向量列:ALTER TABLE memories ADD COLUMN embedding vector(768);。然后,修改 Memori 的 Memory Agent(负责提取和存储):在提取实体后,调用嵌入模型生成向量,插入前执行相似性搜索。
实现步骤如下:
-
嵌入生成:集成 LiteLLM 或直接 OpenAI API。在 memori.record() 前,embedding = openai.embeddings.create(input=text, model='text-embedding-ada-002').data[0].embedding。
-
聚类预处理:后台任务(每小时运行)对新入数据执行 K-means。使用 scikit-learn:from sklearn.cluster import KMeans; kmeans = KMeans(n_clusters=1000).fit(embeddings)。为每个簇分配 ID,存储在 SQL 表中。
-
相似性查询:使用 pgvector 的 ANN 索引(HNSW):CREATE INDEX ON memories USING hnsw (embedding vector_cosine_ops);。插入前查询:SELECT * FROM memories WHERE embedding <=> new_embedding < 0.15 ORDER BY embedding <=> new_embedding LIMIT 5;(<=> 为余弦距离,阈值 0.15 对应相似度 0.85)。
-
去重与合并:若找到相似条目,计算精确余弦相似度。若 > 0.85,合并:更新现有记录的 content 为融合文本,metadata 追加来源,timestamp 取最新。否则,新建记录。
-
多代理适配:为每个代理/用户添加 namespace(如 Memori 的 MEMORY_NAMESPACE),在查询时过滤:WHERE namespace = 'agent1_user123' AND embedding <=> ...。这确保去重仅在相关上下文中进行,避免跨代理混淆。
参数配置示例:
- 嵌入维度:768(ada-002),平衡精度与存储。
- 相似度阈值:0.85(保守),监控 F1 分数调整(召回率 90%,精确率 95%)。
- 聚类 K:数据量 / 1000,最大 5000(避免簇过小)。
- 合并阈值:0.90(仅高相似合并)。
- 后台频率:每 6 小时(Memori 默认分析周期),使用 cron 任务。
- 风险控制:设置最小保留率 70%,若去重过度,fallback 到无阈值模式。
落地清单与监控要点
实现语义去重需以下清单:
- 环境准备:PostgreSQL + pgvector;Python 依赖:openai, sklearn, psycopg2。
- 数据库 schema:添加
embedding vector(768), cluster_id int, similarity_score float。
- 代码集成:扩展 Memori 的
ConfigManager,添加 semantic_dedup: True, threshold: 0.85。
- 测试:模拟多代理交互,注入 1000 条相似记忆,验证去重率 >40%,检索延迟 <100ms。
- 监控:追踪存储增长(目标 <50% 原始)、检索命中率(>80%)、合并错误率(<5%)。使用 Prometheus 指标:
dedup_hits_total, storage_savings。
- 回滚策略:若性能下降,禁用去重,恢复原始 SQL 插入。定期备份嵌入前数据。
在多代理 LLM 交互中,此机制显著优化效率:存储节省 40%,检索加速 2x,减少代理间冗余学习。举例,在一个协作任务中,多个代理记录用户偏好,若去重,单一条目即可服务所有代理,避免上下文碎片化。
潜在风险与优化
风险包括信息丢失(高阈值合并过度)和计算开销(嵌入生成 ~0.1s/条)。缓解:动态阈值(基于簇密度),异步嵌入(队列处理)。未来,可集成 Memori 的 Conscious Agent 进行智能合并,优先保留高优先级上下文。
总之,语义相似性聚类与去重将 Memori 的 episodic memory 从简单日志提升为高效知识库,助力多代理系统更智能地协作。
资料来源: