背景
基于对 Kestrel Agent (KA) 和 Hermes Agent 两套记忆系统的深入对比分析,提出将 KA 的 kestrel-memory crate 从 LanceDB 向量数据库全面转向 tantivy + tantivy-jieba 一体化全文倒排索引方案。
前序 issue #157 已关闭 — 原方案将 BM25 和 jieba 分开考虑,本 issue 改为采用 tantivy(内置 BM25 scorer)+ tantivy-jieba(内置 jieba-rs 分词)的一体式方案。
两大记忆系统对比分析
Kestrel Agent(当前)
组件
实现方式
L1 HotStore
LRU 内存缓存 + JSONL 文件持久化
L2 WarmStore
LanceDB 向量数据库 + Arrow 列式存储
搜索
KNN 余弦相似度(embedding)+ 词边界文本匹配
嵌入
HashEmbedding(随机投影哈希占位符,256-dim→1536-dim 不匹配)
分类
10 个 MemoryCategory(UserProfile, AgentNote, Fact, Preference, Environment, ProjectConvention, ToolDiscovery, ErrorLesson, WorkflowPattern, Critical)
安全
写入前安全扫描(prompt injection、XSS 检测)
已知的 LanceDB 问题:
CPU 尖峰(Bug: CPU spike to ~175%% when processing Telegram messages due to LanceDB query blocking tokio workers #139 ):LanceDB 查询阻塞 tokio worker,175% CPU
零向量(fix(memory): warm store vectors are all zeros — semantic search broken #155 ):Learning insights 跳过嵌入生成,语义搜索失效
维度不匹配:HashEmbedding 默认 256-dim vs WarmStore 期望 1536-dim
重依赖:arrow-array、arrow-schema、lancedb、futures ≈ +50MB 二进制体积
谓词注入([Memory][P2] LanceDB predicate injection risk in warm_store.rs #127 ):字符串拼接 SQL-like 谓词需手动 ID 验证
并发写入竞态([Memory][P2] WarmStore store() race condition under concurrent writes #128 ):需 Mutex<()> 序列化
Hermes Agent(参考)
组件
实现方式
内置记忆
纯文件存储(MEMORY.md + USER.md),§分隔
外部记忆
MemoryProvider 插件架构(Honcho, Mem0 等)
搜索
SQLite FTS5 全文搜索 + BM25 排名
分类
双目标:user(用户画像)+ memory(Agent 笔记)
会话搜索
SQLite 跨会话历史检索
安全
内容注入/泄露检测 + Unicode 过滤
上下文管理
字符预算控制 + 上下文围栏(XML 标签隔离)
关键差异洞察
Hermes 的双目标分类启发 KA :KA 的 10 个 MemoryCategory 过于细粒度,可归并为两大类(用户侧 vs Agent 侧),内部保留子分类用于过滤
Hermes 证明纯文本搜索足够 :不需要 embedding,不需要向量数据库,BM25 + CJK 分词即可满足记忆检索需求
Hermes 的插件架构值得借鉴 :MemoryProvider 抽象允许热插拔后端
Hermes 的上下文围栏 :<memory-context> XML 标签隔离记忆注入,防止模型混淆
提案:tantivy + tantivy-jieba
为什么选 tantivy?
内置 BM25 scorer :无需自实现 BM25 算法
tantivy-jieba 适配器 (v0.19.0):一行注册 jieba-rs 中文分词
纯 Rust :无 protoc 依赖,编译快,二进制小
成熟的持久化 :Tantivy 自带磁盘索引格式,无需额外数据库
Block-Max WAND 加速 :高效 Top-K 查询
架构设计
┌─────────────────────────────────────┐
│ MemoryStore trait │
│ store / recall / search / delete │
└──────────┬──────────────────────────┘
│
┌──────┴──────┐
│ │
┌───▼───┐ ┌────▼────────────────────┐
│HotStore│ │TantivyStore (新 L2) │
│L1 LRU │ │tantivy index │
│JSONL │ │+ jieba CJK tokenizer │
│ │ │+ BM25 scoring │
│ │ │+ 文件持久化 │
└───────┘ └──────────────────────────┘
│ │
└──────┬──────┘
┌──────▼──────┐
│TieredStore │
│write-through│
│read-fallback│
└─────────────┘
接口变更
MemoryStore trait 不变 :search/recall/store/delete/len/clear 保持一致
移除 embedding 相关接口 :
MemoryEntry.embedding 字段移除(或标记为 #[deprecated])
MemoryQuery.embedding 移除
EmbeddingGenerator trait 和 HashEmbedding 移除
MemoryConfig.embedding_dim 移除
新增 TantivyStore :替代 WarmStore,实现 MemoryStore trait
MemoryError::LanceDb → MemoryError::SearchEngine :泛化错误类型
依赖变更
# Cargo.toml (kestrel-memory)
- lancedb = "0.27"
- arrow-array = "57"
- arrow-schema = "57"
- futures = { workspace = true }
+ tantivy = "0.26"
+ tantivy-jieba = "0.19"
+ jieba-rs = "0.9"
实现计划
步骤
内容
影响文件
1
添加 tantivy/tantivy-jieba 依赖
Cargo.toml, workspace Cargo.toml
2
创建 TantivyStore 实现 MemoryStore
新文件 tantivy_store.rs
3
实现统一 tokenizer(Latin 词边界 + jieba CJK)
tantivy_store.rs 内
4
实现 BM25 索引构建和搜索
tantivy_store.rs 内
5
更新 TieredMemoryStore:L2 从 WarmStore 切换到 TantivyStore
tiered.rs
6
移除 WarmStore 和 LanceDB 相关代码
删除 warm_store.rs
7
移除 embedding 相关代码
删除 embedding.rs,清理 types.rs
8
更新 MemoryConfig:移除 embedding_dim,更新路径
config.rs
9
更新 MemoryError:LanceDb → SearchEngine
error.rs
10
迁移所有 WarmStore 测试到 TantivyStore
tantivy_store.rs tests
11
更新上层 crate 依赖(kestrel-tools, kestrel-learning)
上层 Cargo.toml
12
清理 workspace Cargo.toml:移除 lancedb/arrow
workspace Cargo.toml
测试策略
所有现有 WarmStore 测试迁移为 TantivyStore 测试
新增中文分词搜索测试
新增混合中英文搜索测试
持久化跨重启测试
并发写入安全测试
TieredMemoryStore 集成测试更新
风险与缓解
风险
缓解措施
tantivy-jieba 与 tantivy 版本兼容性
锁定 tantivy 0.26 + tantivy-jieba 0.19
上层 crate 依赖 embedding 类型
渐进式移除,先标记 deprecated
索引文件格式迁移
重新索引即可(数据量小)
搜索质量回归
BM25 对短文本已有成熟调优经验
署名 : [CC-Main]
背景
基于对 Kestrel Agent (KA) 和 Hermes Agent 两套记忆系统的深入对比分析,提出将 KA 的
kestrel-memorycrate 从 LanceDB 向量数据库全面转向 tantivy + tantivy-jieba 一体化全文倒排索引方案。两大记忆系统对比分析
Kestrel Agent(当前)
已知的 LanceDB 问题:
Hermes Agent(参考)
user(用户画像)+memory(Agent 笔记)关键差异洞察
MemoryProvider抽象允许热插拔后端<memory-context>XML 标签隔离记忆注入,防止模型混淆提案:tantivy + tantivy-jieba
为什么选 tantivy?
架构设计
接口变更
MemoryStoretrait 不变:search/recall/store/delete/len/clear 保持一致embedding相关接口:MemoryEntry.embedding字段移除(或标记为#[deprecated])MemoryQuery.embedding移除EmbeddingGeneratortrait 和HashEmbedding移除MemoryConfig.embedding_dim移除TantivyStore:替代WarmStore,实现MemoryStoretraitMemoryError::LanceDb→MemoryError::SearchEngine:泛化错误类型依赖变更
实现计划
Cargo.toml, workspaceCargo.tomlTantivyStore实现MemoryStoretantivy_store.rstantivy_store.rs内tantivy_store.rs内TieredMemoryStore:L2 从 WarmStore 切换到 TantivyStoretiered.rswarm_store.rsembedding.rs,清理types.rsMemoryConfig:移除 embedding_dim,更新路径config.rsMemoryError:LanceDb → SearchEngineerror.rstantivy_store.rstestsCargo.toml测试策略
风险与缓解
署名:
[CC-Main]