Grok Build · 记忆检索
从文件变更到混合排序
查询前先同步脏文件,再结合 FTS5 BM25 与可选的 sqlite-vec KNN。合并分数经过时间衰减、来源权重与访问增益,最后可选择启用 MMR 多样性重排。
课程目标按真实顺序复述 sync-on-search、FTS、embedding、KNN、合并加权与 MMR,并能说明 embedding 失败和 MMR 关闭时各自发生什么。
核心视觉 · 完整检索路径
教学化结构图:失败分支回到 FTS-only;MMR 是 opt-in,默认不会重排。
流水线中的真实机制
01 · SYNC
查询前同步
MemoryFileWatcher 累积变化的 Markdown 路径。backend 在 search 开始时重新索引新增或修改文件,并删除已移除文件的旧 chunk。
02 · FTS
BM25 候选
先执行普通 FTS,再补充 global 与 workspace 来源查询,降低 session 数量过多造成的挤出。
03 · VECTOR
可选 KNN
仅在 sqlite-vec 与 provider 可用时嵌入 query。embedding 报错会记录 warning,并传入 None 继续 FTS-only。
04 · SCORE
归一化与合并
BM25 分数与向量 L2 距离分别归一化。双路命中时按权重合并,同时保证结果不低于该 chunk 的 FTS 分数。
05 · WEIGHT
时间与来源
session 按半衰期指数衰减,global 与 workspace 视为 evergreen。随后乘 source weight 与适度的 access boost。
06 · DIVERSITY
可选 MMR
开启后按相关性与 snippet 的 Jaccard 差异做贪心重排。最后截断到 max_results。
两个容易误读的开关
Embedding 失败
向量路径停止,FTS 结果仍进入 hybrid_search_merge。页面或调用方无需把 embedding 故障当成整次搜索失败。
MMR 默认状态
MmrConfig::default() 设置 enabled: false 与 lambda: 0.7。0.7 只在显式开启 MMR 后生效。
真实源码证据
crates/codegen/xai-grok-memory/src/search.rs · 第 146 至 190 行节选
pub async fn hybrid_search(
index: &MemoryIndex,
embedding_provider: Option<&dyn EmbeddingProvider>,
query: &str,
config: &MemorySearchConfig,
) -> Result<Vec<SearchResult>, Box<dyn std::error::Error>> {
let candidate_limit = config.max_results * 3;
let mut fts_results =
index.search_fts(query, candidate_limit).unwrap_or_default();
/* 补充 evergreen FTS 候选的源码在此处 */
let vec_available = index.vec_available();
let query_embedding = if vec_available {
if let Some(provider) = embedding_provider {
match provider.embed_batch(&[query]).await {
Ok(embeddings) if !embeddings.is_empty() =>
Some(embeddings.into_iter().next().unwrap()),
Ok(_) => None,
Err(e) => {
tracing::warn!(error = %e,
"embedding query failed, falling back to FTS-only");
None
}
}
} else { None }
} else { None };
hybrid_search_merge(index, fts_results, query_embedding.as_deref(), config)
}
crates/codegen/xai-grok-memory/src/backend.rs:search() 中执行 watcher 同步与查询
crates/codegen/xai-grok-memory/src/watcher.rs:MemoryFileWatcher
crates/codegen/xai-grok-memory/src/mmr.rs:mmr_rerank
crates/codegen/xai-grok-config-types/src/memory.rs:MmrConfig 默认值
源码快照说明:依据本地仓库
grok-build-main,核对日期 2026-07-17。代码块保留真实函数与分支,唯一的折叠处已用注释说明;流程图明确标为教学化结构图。课堂练习
06
推演一次降级查询
假设 watcher 发现一个文件被修改,query embedding 随后失败,MMR 保持默认配置。请按顺序写出索引更新、候选生成、加权排序与最终截断,并标出没有发生的两个步骤。
Takeaway:记忆检索具备可降级与可同步两条关键保障。FTS 始终提供基础候选,向量搜索按可用性增强;时间衰减和来源权重调整排序;MMR 需要显式开启;watcher 让外部 Markdown 修改在下一次查询前进入索引。