Hotdry.
ai-systems

基于LSM的多代理记忆引擎实现:分层合并、Bloom去重与跨会话优化

面向多代理AI系统,基于LSM树设计记忆引擎,支持分层日志追加、Bloom过滤去重、leveled compaction及跨会话优先级召回,提供工程参数与监控要点。

在多代理 AI 系统中,代理间的交互频繁产生海量记忆日志,如对话上下文、决策记录和知识更新。这些日志写入密集、顺序性强,传统 SQL 或向量存储难以高效持久化。LSM 树(Log-Structured Merge-Tree)作为日志结构合并树,正适合此类场景:通过内存 MemTable 缓冲顺序追加、后台分层 compaction 合并,实现高吞吐写入与可控读取放大。

LSM 核心架构适配多代理记忆

多代理记忆引擎以代理 ID + 会话 ID 为键前缀(e.g., "agent1:session123:entity"),将记忆条目(包含时间戳、类别如 facts/preferences、内容嵌入)追加为日志。核心组件:

  1. WAL + MemTable:每代理独立 MemTable(跳表或红黑树有序),容量阈值 64MB。先追加 WAL(SQLite/PostgreSQL append-only),再入 MemTable。崩溃恢复从 WAL 重建,确保零丢失。

  2. Flush 到 L0 SSTable:MemTable 满时冻结为 Immutable MemTable,后台异步 flush 为 L0 SSTable(有序键值文件,含数据块 + 索引块)。每个 SSTable 附 Bloom 过滤器(false positive 率 <0.1%,位数约 10 * 键数 /log2 (1/FP))。

  3. Leveled Compaction:L0(最多 12 文件,重叠键)→L1+(每层键范围不重叠,L1 总量 10L0,Ln=10L (n-1))。触发:Ln 文件 > 4 个或总大小超阈值。合并时,逐层归并排序,删除 tombstone(逻辑删),保留最新值。参数:L0→L1 阈值 4 文件,L1 + 重叠文件最多 10 个 / 层。

  4. 跨代理隔离与召回:命名空间前缀隔离(e.g., "/agent1/"),全局索引层(稀疏 B 树)跨会话查询。优先级 eviction:热度分数 = 访问频 * 新鲜度(exp (-age/τ),τ=7 天),低优先级移至冷层(L7+)。

证据显示,此设计在 LevelDB/RocksDB 中经工业验证:写入 QPS>10 万,P99 延迟 < 5ms。"LSM-Tree 通过牺牲部分写入放大换取极高的写入吞吐,是 LevelDB、RocksDB 等知名存储引擎的基础架构。"

Bloom 去重与召回优化

Bloom 过滤器每 SSTable 独立,k=7 哈希函数(murmur3+fnv1a)。查询前查 Bloom:不存在即 miss,存在概率 > 99.9% 命中则二分索引 + 数据块读。去重:compaction 中 Bloom 辅助检测冗余键,节省空间 20-30%。

跨会话召回:Retrieval Agent 动态查询。流程:

  • 输入嵌入→语义 / 全文 / 类别混合搜索(MemTable 优先)。
  • 逐层 SSTable:Bloom 预滤 + L1 二分(O (log N / 层))。
  • Top-K 融合(热度 + 相似度),注入 LLM 上下文(限 4K token)。

参数清单:

组件 参数 推荐值 说明
MemTable 容量 64MB 平衡内存 /flush 频
WAL 缓冲 16MB 顺序写批次
Bloom FP 率 0.1% 位 / 键≈14
Compaction L0 阈值 4 文件 读放大控制
Levels 总数 7 写放大 < 10x
Eviction τ 7 天 新鲜度衰减

监控要点:compaction 队列 > 10、写放大 > 15x、L0 文件 > 8→扩容 / 调阈值。回滚:暂停 compaction,切换 readonly MemTable。

工程落地参数与伪代码

伪实现(Python+RocksDB):

import rocksdb  # 或自定义LSM
db = rocksdb.DB("multi_agent_mem.db", rocksdb.Options(create_if_missing=True))
db.put(b"agent1:session1:fact:user_pref", b"FastAPI")  # WAL+MemTable

# 召回
def retrieve(agent_id, query_emb):
    bloom_cache = {}  # LRU
    candidates = []
    for level in range(7):
        for sst in level_ssts(level):
            if bloom_might_contain(sst.bloom, key_prefix(agent_id, query_emb)):
                val = db.get(key_prefix(agent_id, query_emb))
                if val: candidates.append((score(val), val))
    return top_k(candidates, 5)

风险缓解:

  • 写放大:Leveled 策略 < 10x,限 compaction CPU<20%。
  • 读放大:Bloom + 块缓存(LRU 256MB),最坏 7 层 < 50ms。
  • 一致性:MVCC 序列号,snapshot 读跨会话。

Memori 项目启发此设计:"Memori enables any LLM to remember conversations, learn from interactions, and maintain context across sessions with a single line: memori.enable ()." 结合 LSM,实现高效多代理记忆。

来源:

查看归档