Skip to main content
Glama
masaki-kato-119

hybrid-rag-memory

English | 日本語

Hybrid RAG — 智能体长期记忆系统

一个混合 RAG 系统,结合了稠密检索和稀疏检索,并在重排序中内置了基于标签的记忆机制(重要性、每种 knowledge_type 的过时率、访问频率)。设计原理见 hybrid_rag_agent_spec.en.md

将其作为 MCP 服务器运行,Claude Code 等智能体即可直接将其用作“长期记忆”。

该机制的工作原理

按照规范,处理分为两类。

类别

内容

实现方式

① 依赖模型(推理)

重要性标注、查询扩展/充分性判断、编排

智能体侧(LLM 判断)

② 依赖结构(确定性处理)

分块、嵌入生成、混合搜索、分阶段重排序、遗忘/归档

RAG 侧(本库 / MCP 服务器)

“重要性”和“每种 knowledge_type 的过时率”被视为独立的轴;并非简单的线性组合,而是分阶段应用:① 按重要性截断 → ② 按 knowledge_type 进行时间衰减 → ③ 按访问频率提升(详见规范第 2.3 节)。

principle  : no decay (MBSE design principles, math/algorithms)
paper      : re-evaluated roughly every half year (papers, technical articles)
news       : decays significantly over weeks to months (news, model-release info)
experiment : decays according to project duration (experiment logs, run records)

knowledge_type 的设计是从摄取来源确定性确定,而不是由 LLM 根据块内容判断(例如,人类明确注册的设计文档 → principle;arXiv 论文/技术文章 → paper;新闻/网络搜索结果 → news;执行日志 → experiment)。

注意principle(无衰减)并不保证某个块“永远不会被 run_forgetting_batch 遗忘”。由于分阶段重排序首先应用 ① 重要性截断,如果 knowledge_type=principle 的块的 importance 设置较低且低于 importance_threshold,它仍可能成为归档目标(由 tests/test_archival.py 确认)。“无衰减”仅适用于 ② 时间衰减阶段——它并不是整个 ①②③ 流程中的“永不遗忘”保证。

注意:记忆机制(knowledge_type/importance/分阶段重排序/遗忘批处理/MCP 服务器)仅针对 FAISS 后端(HybridRAGSystem)实现。Qdrant/Chroma/PostgreSQL 版本仅作为纯混合搜索库提供。

Related MCP server: mnemostack

安装

pip install -r requirements.txt

用于开发/测试:

pip install -r requirements-dev.txt

用法 ① 作为 MCP 服务器(推荐)

启动服务器

python mcp_server/server.py

存储位置可通过环境变量设置(默认值:hybrid_rag.db / indices)。

HYBRID_RAG_DB_PATH=my_memory.db HYBRID_RAG_INDEX_PATH=my_indices python mcp_server/server.py

注册到 Claude Code

项目根目录下的 .mcp.json 已按如下方式配置。Claude Code 在打开此仓库时会自动拾取它。

{
  "mcpServers": {
    "hybrid-rag-memory": {
      "type": "stdio",
      "command": "python",
      "args": ["mcp_server/server.py"],
      "env": {
        "HYBRID_RAG_DB_PATH": "hybrid_rag.db",
        "HYBRID_RAG_INDEX_PATH": "indices"
      }
    }
  }
}

如果使用虚拟环境,请将 command 重写为 venv 中 Python 解释器的绝对路径(例如 "command": "./.venv/Scripts/python.exe")。

提供的工具

除了规范第 5 节要求的 3 个最小工具(①–③)外,此服务器还提供 10 个工具(④–⑬,规范扩展),用于数据摄取、标注、去重、遗忘批处理和健康检查。

#

工具

描述

embed(text)

使用固定嵌入模型对文本进行向量化(确定性处理)

hybrid_search(query, tags?, filters?, top_k?, include_stats?)

混合向量+BM25 搜索。返回已经过相关性重排序(Cross-encoder)的块。当 include_stats=True 时,返回形状变为 {"chunks": [...], "stats": {...}},在计时信息之外增加 orphan_index_entries(作为索引碎片丢弃的条目)和 duplicate_contents(因正文相同而合并的条目)[include_stats 是规范扩展,添加于 2026-08-08]

rerank(chunks, time_weight?, freq_weight?, importance_threshold?)

分阶段重排序:重要性截断 → 按 knowledge_type 时间衰减 → 访问频率提升

ingest(file_paths, metadata?, rebuild_index?)

摄取文档。rebuild_index=True(默认)在内部执行轻量级增量更新(update_index[规范扩展]

set_chunk_tags(doc_id, chunk_index, importance?, knowledge_type?, tags?)

分配重要性标签 / 重新标注 knowledge_type(用于人工门控)[规范扩展]

find_by_tag(tag)

精确匹配标签查找(绕过语义搜索)。用于检查来自同一来源的文档是否已被摄取**[规范扩展]**

get_document_chunks(doc_id, chunk_index?, window?)

获取同一文档中的相邻块(绕过语义搜索的直接查找)。补偿块边界处丢失的上下文**[规范扩展]**

delete_document(doc_id, rebuild_index?)

删除文档及其所有块。用于重新摄取时的“替换”流程**[规范扩展]**

update_index()

轻量级索引更新,仅增量合并自上次索引更新以来新增的块**[规范扩展,添加于 2026-07-30]**

rebuild_index()

从数据库中的所有块对 FAISS/BM25 索引进行完整重建。删除(⑧ 或 run_forgetting_batch)后必须执行,因为增量更新无法处理删除**[规范扩展]**

run_forgetting_batch(time_weight?, freq_weight?, importance_threshold?, score_threshold?, dry_run?)

遗忘/归档批处理作业。仅用于低频执行**[规范扩展]**

index_health()

检查索引与数据库之间的一致性并报告(不做任何更改)。检测“索引中存在但数据库中不存在”的碎片(删除后忘记调用 rebuild_index)以及“数据库中存在但索引中不存在”的缺口(ingest(rebuild_index=False) 后忘记调用 update_index[规范扩展,添加于 2026-08-08]

get_system_stats()

报告数据库的记忆机制标注覆盖率(不做任何更改)。index_health 关注索引与数据库之间的结构一致性,而此工具关注“记忆轴实际能发挥多大作用”——按 knowledge_type 计数、重要性设置率、标签覆盖率等。[规范扩展,添加于 2026-08]

如果没有 ④–⑬,仅靠 ①–③ 工具既无法摄取数据、最终确定重要性标签,也无法避免同一来源的重复注册——这使得系统不实用,因此添加了这些工具。

关于连续摄取多个文件的注意事项(重要)

背景(已于 2026-07-30 修复的过往问题)ingest 过去默认"每次调用都对数据库中的每个分块重新嵌入并重建索引",因此单次调用的成本随语料库规模线性增长,逐文件连续摄取时会出现超时。ingest(rebuild_index=True)(默认值)现在会在内部调用 update_index()——这是一种增量方案,只对自上次更新以来新增的分块进行嵌入,并通过 .add() 将其加入 FAISS 索引——因此无论语料库整体规模多大,现在都很快(BM25 侧每次仍会做一次轻量级全量重建,因为其 IDF 统计依赖整个语料库,但由于不涉及神经嵌入,成本很低)。

话虽如此,对每个文件都执行增量更新仍然是浪费的开销,因此在连续摄取大量文件时,更好的做法是给每次 ingest 调用传 rebuild_index=False,并在批次结束时调用一次 update_index() 来一次性统一处理。.claude/agents/doc-to-memory.md.claude/agents/session-to-memory.md 已经按此模式实现。通过 find_by_tag 检查数据库(用于去重/进度验证)是直接查询 SQLite 的,因此无需等待索引跟上即可工作。

何时需要完整的 rebuild_index():只要批次中包含哪怕一次 delete_document 调用,或来自 run_forgetting_batch 的归档操作(即任何向量删除),就需要完整重建。增量添加(update_index)只支持向 FAISS 添加,不支持从中移除,因此任何包含删除操作的批次都必须以完整的 rebuild_index() 结尾。纯新增的批次用 update_index() 即可。

重新注册同一来源时防止重复

由于 ingestdoc_id 是从文件内容的哈希推导出来的,逐字节相同的内容重新摄取会被自动跳过(基于差异的更新)。然而,在同一个来源(例如同一个会话)每次都被 LLM 重新总结并重新摄取的情况下,每次总结文本的细微差异会导致其被视为不同的文档——从而产生重复。

为避免这种情况,请使用唯一标识标签(例如 session_id:xxx)和更新时间标签(例如 session_last_activity:2026-07-28T15:59:49Z)进行摄取,并在后续运行时:

  1. 通过 find_by_tag("session_id:xxx") 检查文档是否已存在

  2. 如果现有的更新时间标签与当前值一致,则跳过——不做任何操作

  3. 仅当值不同时(来源已变更),在 ingest 新内容之前先用 delete_document(doc_id, rebuild_index=False) 删除旧文档

建议实现这种"未变更则跳过,已变更则替换"的模式。.claude/agents/session-to-memory.md 是该模式的参考实现。

使用示例(概念性)

1. ingest(["design_doc.md"], metadata={"knowledge_type": "principle", "tags": ["mbse"]})
2. hybrid_search("about consistency between requirements and architecture", top_k=5)
   -> [{"doc_id": ..., "chunk_index": ..., "content": ..., "knowledge_type": "principle",
        "importance": null, "access_count": 0, "score": 0.87}, ...]
3. set_chunk_tags(doc_id, chunk_index, importance=0.9)
4. rerank(chunks, time_weight=0.5, freq_weight=0.1, importance_threshold=0.3)
   -> chunks reordered along the memory axis (staleness, frequency, importance)

用法 ② 作为 Claude Code 代理

.claude/agents/rag-memory.md 提供了一个子代理定义,负责该记忆机制的"代理侧(类别 ①)"。注册 .mcp.json 后,你可以像这样从 Claude Code 中调用它:

Use the rag-memory agent to look into past design decisions

需要人工确认意图的操作规则——重要性标记、knowledge_type 重新标记、决定何时运行遗忘批次——也已写入该代理定义中。

此外,.claude/agents/session-to-memory.md 是一个专用代理,负责总结过去的 Claude Code 会话(聊天记录)并将其作为 knowledge_type="experiment" 摄取到长期记忆中。它运行在 Haiku 模型上以控制成本,并且在重新处理同一会话时,会通过 session_id/更新时间标签与现有条目进行比较——未变更则跳过,已变更则替换(参见上一节)。调用方必须明确指定要处理哪些会话;它绝不会无限制地处理所有会话。

用法 ③ 直接作为 Python 库使用

你也可以不经过 MCP 服务器,直接从 Python 代码中调用它。

from hybrid_rag import HybridRAGSystem

rag = HybridRAGSystem(db_path="hybrid_rag.db", index_path="indices")

rag.ingest_documents(
    ["design_doc.md"],
    metadata={"knowledge_type": "principle", "importance": 0.9, "tags": ["mbse"]},
)

result = rag.query(
    "about consistency between requirements and architecture",
    top_k=5,
    enable_memory_rerank=True,   # enable the memory mechanism's staged reranking
    memory_time_weight=0.5,
    memory_freq_weight=0.1,
    memory_importance_threshold=0.3,
)
print(result["context"])

# assign an importance tag after the fact (no vector rebuild needed)
rag.set_chunk_tags(doc_id="design_doc_xxxx", chunk_index=0, importance=0.9)

# forgetting/archival batch (normally run infrequently)
report = rag.run_forgetting_batch(score_threshold=0.05, dry_run=True)

从 CLI 运行遗忘批次

一个面向低频批量执行的脚本——例如按 3 个月周期运行,或在新模型发布时运行(绝不会在服务器内部自动运行)。

python scripts/run_forgetting_batch.py --dry-run
python scripts/run_forgetting_batch.py --score-threshold 0.1 --time-weight 0.8

主要选项:--db-path --index-path --archive-path --time-weight --freq-weight --importance-threshold --score-threshold --dry-run

被归档的分块会被转移到 archive/chunks_archive.jsonl(原始文本 + 元数据 + 分数 + 删除原因 + 删除时间戳),其向量表示会被丢弃。

从 CLI 自动评估检索准确率

一个针对黄金查询集测量检索准确率(Precision@k/Recall@k/MRR/NDCG@k/Hit Rate@k、权威文档排名、噪声率)的脚本,以可复现的方式进行,而不是依赖手动查询和通过 Cursor/Claude Code 目测结果。

cp eval/golden_queries.example.yaml eval/golden_queries.yaml  # once, at first use — rewrite the doc_ids for your own corpus
python scripts/run_evaluation.py --db-path mcp_server/hybrid_rag.db --index-path mcp_server/hybrid_rag_indices

主要选项:--db-path --index-path --golden-set(默认 eval/golden_queries.yaml--k-values(默认 1,3,5,10--authority-window(默认 20--output

审计近似重复的摄取

ingest 的重复检测无法捕获相同内容通过不同文件(不同路径/文件名)进入的情况——参见上文"重新注册同一来源时防止重复"。此脚本仅列出已进入现有语料库的近似重复项。它绝不会删除任何内容。

python scripts/find_near_duplicates.py --db-path mcp_server/hybrid_rag.db
python scripts/find_near_duplicates.py --db-path mcp_server/hybrid_rag.db --output eval/duplicates_report.json

它按规范化内容哈希(documents.content_hash)对文档进行分组。保留哪一个——以及是否删除任何内容——由用户决定;请手动调用 delete_document(doc_id, rebuild_index=False)(并务必在批次结束时调用 rebuild_index)。

eval/golden_queries.yaml 已被 .gitignore 忽略,因为它是包含你实际语料库特有 doc_id 的个人数据。报告写入 eval/eval_report_<date>.md(以及同名的 .json),这些文件同样被 .gitignore 忽略(它们保留在你的机器上用于持续跟踪)。

记忆机制字段

ingest/Python API 的 metadata 中携带的字段,或每个分块的字段:

字段

类型

描述

knowledge_type

str

principle / paper / news / experiment。根据摄取来源确定性推导

importance

float (0.0–1.0)

由代理事后分配的重要性。未设置(None)时始终通过阈值

tags

list[str]

任意标签。用于通过 hybrid_searchtags 参数缩小结果范围

access_count

int

访问频率。每次分块实际被查询返回时自动递增

last_accessed_at / created_at

str

最后访问/创建时间戳。作为时间衰减的基础

测试

pytest tests/ -v
  • test_metadata_pipeline.py:回归测试,验证 knowledge_type/importance/tags 在 ingest → build_index → query 管道中完整保留

  • test_memory_scoring.py:分阶段重排序(阈值、衰减、频率提升)的单元测试

  • test_archival.py:遗忘/归档批次的单元测试

  • test_index_health.pyindex_health(索引/数据库一致性检查)的单元测试

其他测试文件的完整列表及作用请参见文件布局

基础库功能(各后端通用)

基础 RAG 功能——稠密/稀疏混合搜索、RRF、Cross-encoder 重排序、MMR 多样性选择、查询扩展、缓存等——对所有后端(FAISS/Qdrant/Chroma/PostgreSQL)通用。

from hybrid_rag import create_rag_system

rag = create_rag_system(backend="faiss")   # "qdrant" / "chroma" / "postgres" are also available
rag.ingest_documents(["document1.pdf", "document2.md"])
result = rag.query("What is machine learning?", top_k=5)

方面

FAISS

Qdrant

ChromaDB

PostgreSQL

过滤搜索

后处理

快速(单阶段)

后处理

后处理

需要服务器

规模

最高 ~20M

最高 ~50M

中等

大规模

记忆机制(本 README)

可选安装:本仓库没有 pyproject.toml/setup.py,因此不以 pip install hybrid-rag[...] 的形式分发。要使用 Qdrant/Chroma/PostgreSQL 版本,请直接安装对应的客户端库(pip install qdrant-client / pip install chromadb / pip install "psycopg[binary]" pgvector——这些都已列在 requirements.txt 中,因此仅执行 pip install -r requirements.txt 即可覆盖)。

关键附加设置(FAISS 版本 HybridRAGSystem 构造函数参数的一个子集):

rag = HybridRAGSystem(
    dense_model="paraphrase-multilingual-MiniLM-L12-v2",
    rerank_model="BAAI/bge-reranker-v2-m3",
    max_chunk_size=512,
    index_type="hnsw",           # "flat" / "ivf" / "hnsw"
    enable_mmr=True, mmr_lambda=0.6,
    enable_cache=True, cache_ttl_seconds=3600,
    query_expander=None,          # pass a QueryExpander instance for LLM-based query expansion
    memory_half_life_overrides=None,  # override the half-life (days) per knowledge_type
    enable_guaranteed_candidates=True,  # always add principle/high-importance chunks to the candidate pool (default True)
    guaranteed_knowledge_types=None,    # defaults to ["principle"]
    guaranteed_importance_threshold=0.7,
    guaranteed_candidates_limit=50,
)

enable_guaranteed_candidates(默认 True)解决了一个问题:knowledge_type=principle 的分块(或 importance>=0.7 的分块)一开始就从未进入搜索候选池,分阶段重排序也无法挽救它们(即 RAG_EVALUATION_REPORT_2026-07-30.md/RAG_精度テスト_2026-07-31.md 中报告的"principle 文档被埋没"问题)。它的工作方式是在检索后立即将匹配的分块加入候选池,并让 Cross-encoder 对其相关性进行评分——它不会强制将它们置顶。传入 metadata_filtersfilters)的 query()/hybrid_search 调用会跳过此合并。

文档(Sphinx)/ 图表(PlantUML)

pip install sphinx sphinx-rtd-theme
python -m sphinx -b html docs/source docs/build

docs/uml/ 用于存放类图、时序图和状态机图的 PlantUML 源文件(截至撰写本文时尚未填充)。

文件布局

hybrid_rag_agent_spec.md   # design spec for the memory mechanism
.mcp.json                  # MCP server registration for Claude Code
.claude/agents/rag-memory.md  # sub-agent definition for Claude Code

mcp_server/
└── server.py              # the MCP server itself (13 tools, see the table above)

scripts/
├── run_forgetting_batch.py       # CLI for the forgetting/archival batch
├── run_evaluation.py             # CLI that automatically evaluates retrieval accuracy against a golden query set
├── find_near_duplicates.py       # CLI that audits near-duplicate ingests in the existing corpus (report-only, never deletes)
├── backfill_source_date.py       # bulk-backfills source_date on existing chunks
├── list_md_files.py              # lists candidate Markdown files for ingestion
├── manage_ingest_status.py       # tracks ingest progress against list_md_files.py's listing
├── manage_conv_ingest_status.py  # tracks ingest progress against convert_conversations.py's output
└── convert_conversations.py      # converts a Claude.ai export (JSON) into Markdown

hybrid_rag/
├── __init__.py
├── ingestion.py            # document processing
├── chunking.py             # semantic chunking
├── indexing.py             # dense & sparse index (FAISS)
├── indexing_bm25.py        # BM25 index
├── indexing_sparse_tfidf.py  # TF-IDF sparse index (shared by the Chroma/Postgres/Qdrant backends)
├── indexing_qdrant.py / indexing_chroma.py / indexing_postgres.py
├── retrieval.py            # RRF search
├── reranking.py            # Cross-encoder reranking (relevance axis)
├── memory_scoring.py        # staged reranking (memory axis: importance/decay/frequency)
├── archival.py              # forgetting/archival batch processing
├── index_health.py          # index/DB consistency checking (backs the ⑫ index_health tool)
├── caching.py / embedding_cache.py
├── context.py / diversity.py / evaluation.py
├── storage.py               # SQLite database (including memory-mechanism fields)
├── query_expansion.py
├── rag_system.py            # main orchestrator (FAISS version, implements the memory mechanism)
├── _rag_system_indexing.py  # ^ ingest/build/incremental-update/load (mixin)
├── _rag_system_query.py     # ^ query pipeline (mixin)
├── _rag_system_memory.py    # ^ tags/neighboring chunks/forgetting batch (mixin)
├── _rag_system_stats.py     # ^ stats & cache management (mixin)
├── _rag_system_docops.py    # ^ embedding/delete/lightweight search (mixin)
├── rag_system_base.py       # base class shared by the Chroma/Postgres/Qdrant backends
├── rag_system_qdrant.py / rag_system_chroma.py / rag_system_postgres.py
└── rag_system_factory.py

tests/
├── test_metadata_pipeline.py   # metadata regression test across ingest → build_index → query
├── test_memory_scoring.py      # unit tests for staged reranking
├── test_archival.py            # unit tests for the forgetting/archival batch
├── test_incremental_index.py   # unit/integration tests for update_index (incremental updates)
├── test_index_health.py        # unit tests for index_health (index/DB consistency check)
├── test_result_dedup.py        # unit tests for RRF fusion-key stability and search-result dedup
├── test_diversity.py           # unit tests for MMR diversity selection
├── test_reranking.py           # unit tests for Cross-encoder reranking stats
├── test_retriever_shutdown.py  # tests for RRFRetriever resource cleanup (thread leaks)
├── test_indexing_bm25.py       # unit tests for the BM25 index
├── test_storage_concurrency.py # unit tests for concurrent SQLite writes
├── test_source_date.py         # unit tests for source_date derivation (time-decay reference point)
├── test_document_chunks.py     # unit tests for get_document_chunks (fetching neighboring chunks)
├── test_evaluation.py          # unit tests for RAGEvaluator (Precision@k, etc.)
├── test_database_stats.py      # unit tests for get_database_stats / duplicate-ingest detection
├── test_guaranteed_candidates.py  # unit tests for guaranteed candidate-pool merging (the fix for principle burial)
├── test_rag_system_factory.py  # unit tests for create_rag_system (backend switching)
└── conftest.py                 # shared pytest configuration

许可证

MIT License

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Durable hybrid memory for AI agents. Combines vector search, BM25, temporal retrieval, and optional Memgraph knowledge graph via reciprocal rank fusion. 6 MCP tools: health, search, answer, feedback, graph_query, graph_add_triple. Self-hosted with Qdrant backend.
    7
    7
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides AI agents with persistent knowledge storage, enabling them to store, search, and retrieve text, documents, and files using semantic and keyword search via MCP tools.
    32
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Local-first AI memory layer with hybrid retrieval and brain-inspired namespaces. Enables agents to save, search, and manage memories directly via MCP tools.
    5
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/masaki-kato-119/hybrid-rag-memory'

If you have feedback or need assistance with the MCP directory API, please join our Discord server