Files
mengyanote-rag/README.md
shumengya c410d69970 feat: 初始提交 mengya-rag 知识库项目
轻量级 Obsidian Markdown RAG 系统,包含:
- Markdown 结构感知分块(标题层级 + 代码块/表格整体保留)
- FastEmbed + BAAI/bge-small-zh-v1.5 本地向量化
- SQLite + sqlite-vec 向量库(无需外部服务)
- BM25 + 向量混合检索,RRF 融合
- 盘点模式(有哪些/列表/目录类问题)
- DeepSeek API 生成回答
- mengya-rag CLI 工具(ask/search/context/read/sync/index/status)
- docs/RAG优化方案.md 待实施优化计划

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:12:06 +08:00

8.8 KiB
Raw Permalink Blame History

萌芽 RAG 知识库

轻量版 Obsidian 笔记 RAG 项目,基于 LlamaIndex 和 DeepSeek API。 检索使用 Markdown 结构感知分块 + 本地小 embedding + BM25 的混合检索,适合个人 Obsidian 笔记这种规模。

项目结构

mengya-rag/
├── data/
│   ├── notes/          # 从 bigmengya 同步来的 Obsidian Markdown 笔记(不入库)
│   └── index/bm25/     # 本地索引目录(不入库)
│       └── rag.sqlite3 # SQLite + sqlite-vec 本地向量库
├── docs/
│   └── RAG优化方案.md  # 下一步优化计划
├── scripts/
│   ├── sync_notes.sh   # 同步 bigmengya 笔记
│   ├── sync_notes.py
│   ├── build_index.sh  # 构建索引
│   ├── build_index.py
│   ├── ask.sh          # 命令行问答
│   └── ask.py
├── src/mengya_rag/
│   ├── config.py           # 配置读取
│   ├── markdown_chunker.py # Markdown 结构感知分块
│   ├── embeddings.py       # Embedding 生成FastEmbed / SentenceTransformers
│   ├── vector_store.py     # SQLite + sqlite-vec 向量存储
│   ├── indexing.py         # 建索引(分块 + 向量写入)
│   ├── retrieval.py        # 混合检索、RRF 融合、盘点模式
│   ├── qa.py               # DeepSeek 生成回答
│   └── cli.py              # CLI 命令入口
├── .env.example
├── pyproject.toml
└── README.md

技术栈

  • RAG 基础框架LlamaIndex
  • 本地 embeddingBAAI/bge-small-zh-v1.5
  • embedding 运行FastEmbed + ONNX
  • 大模型回答DeepSeek API
  • 当前推荐模型:deepseek-v4-flash
  • 检索方式BM25 + 向量检索
  • 融合方式RRF 类融合 + 原始相似度过滤 + 同文件去重
  • 数据库:无
  • 向量库SQLite + sqlite-vec
  • 服务端:无,当前是命令行工具

初始化

cd /shumengya/project/agent/mengya-rag
cp .env.example .env

编辑 .env,填入:

DEEPSEEK_API_KEY=你的 DeepSeek API Key

安装依赖:

uv sync

同步笔记

笔记源路径:

bigmengya:/shumengya/docker/mengyanote-backend/data/mengyanote/

同步到本地:

./scripts/sync_notes.sh
# 或
uv run python scripts/sync_notes.py

构建索引

./scripts/build_index.sh
# 或
uv run python scripts/build_index.py

提问

./scripts/ask.sh "萌芽笔记是什么"
# 或
uv run python scripts/ask.py "萌芽笔记是什么"

也可以直接使用安装后的命令:

uv run mengya-ask "Docker 常用命令有哪些"

Agent 调用推荐

统一入口是 mengya-rag。给大模型 Agent 或脚本调用时,推荐固定使用 --json,输出是一行 JSON便于解析。

# 查看配置、索引和笔记数量
uv run mengya-rag status --json

# 只检索,不调用大模型,返回命中文档和内容
uv run mengya-rag search "Docker 常用命令" -k 5 --json

# 返回可直接注入上游大模型的 context 字段
uv run mengya-rag context "WireGuard 怎么配置" -k 4 --json

# 按 search/context 返回的 source 读取完整笔记
uv run mengya-rag read "Docker/Docker常用命令总结.md" --json

# 本项目自己调用 DeepSeek 生成回答
uv run mengya-rag ask "Docker 常用命令有哪些" -k 4 --json

# 同步笔记并重建索引
uv run mengya-rag reindex --json

Agent 优先使用这几个命令:

  • status --json:检查索引是否存在、笔记数、节点数、模型配置。
  • search --json:拿结构化检索结果,包含 results[].sourcetitleheading_pathscorecontent
  • context --json:拿拼好的 context 字符串,适合直接放进其他大模型提示词。
  • read --json:按 source 读取完整 Markdown 原文,适合检索命中后补充上下文。
  • ask --json:让本项目完成 RAG + DeepSeek 回答,返回 answersources
  • reindex --json:一条命令完成同步笔记和重建索引。

常用参数:

--mode auto|hybrid|inventory   # auto 默认hybrid 普通语义检索inventory 盘点/目录类检索
-k, --top-k 数字               # 控制返回条数
--env-file /path/.env          # 指定配置文件
--notes-dir /path/notes        # 覆盖笔记目录
--index-dir /path/index        # 覆盖索引目录

查询模式

项目会自动区分两类问题:

  • 普通问答例如“WireGuard 命令怎么用”,走 Markdown 分块 + 向量/BM25 混合检索。
  • 盘点列表:例如“查一下我目前博客文章有哪些”“查一下安卓 Gradle 相关笔记”,走文件级目录检索,优先列出相关 Markdown 文件和内容预览。

技术原理

Markdown 分块

项目不使用固定字符数暴力切割,而是使用结构感知分块:

Markdown 文件
  ↓
解析 frontmatter
  ↓
识别 H1-H6 标题
  ↓
按标题层级组织分块
  ↓
代码块和表格整体保留
  ↓
长块使用滑动窗口兜底

每个 chunk 前会附加上下文前缀:

文件: AI/控制台Agent工具安装教程.md
标题: 控制台Agent工具安装教程
标题路径: H1 > H2 > H3

每个 chunk 会保存这些元数据:

source_file
rel_path
file_name
folder_path
title
heading_path
h1
h2
h3
h4
h5
h6
chunk_index
tags
created_at

索引构建

执行:

./scripts/build_index.sh

构建流程:

Markdown 文件
  ↓
结构感知分块 → TextNode
  ↓
bge-small-zh-v1.5 生成 embedding → 归一化
  ↓
写入 SQLite + sqlite-vecrag.sqlite3

当前索引规模参考:

笔记文件数: 495
分块数: ~1800
rag.sqlite3: ~10MBchunk 表 + sqlite-vec 向量表)

普通问答检索

普通问答适合“怎么做”“是什么”“原理是什么”这类问题。

用户问题
  ↓
query 清洗
  ↓
BM25 关键词检索
  ↓
本地向量语义检索
  ↓
RRF 融合
  ↓
同文件去重
  ↓
相关性过滤
  ↓
top-k chunk 注入 DeepSeek
  ↓
生成回答和来源

盘点列表检索

盘点列表适合“有哪些”“查一下”“相关笔记”“目录”“清单”这类问题。

用户问题
  ↓
识别为盘点类问题
  ↓
构建文件级摘要节点
  ↓
文件级 BM25 检索
  ↓
关键词覆盖过滤
  ↓
输出 Markdown 文件列表、路径和内容预览

重新更新知识库

笔记变更后按顺序执行:

./scripts/sync_notes.sh
./scripts/build_index.sh

设计取舍

  • Markdown 笔记按结构感知分块:识别 frontmatter、H1-H6、代码块、表格。
  • H1-H6 标题会写入 h1h6 元数据,同时保存 heading_path 面包屑。
  • 代码块和表格整体保留,不跨块切割;长块再用滑动窗口兜底。
  • 每个 chunk 都带 source_fileheading_pathchunk_indextagscreated_at
  • 本地 embedding 使用 BAAI/bge-small-zh-v1.5,通过 FastEmbed/ONNX 运行,不依赖 PyTorch 和 GPU。
  • 检索采用 BM25 + 向量召回,再用 RRF 融合和同文件去重,避免只靠关键词或只靠语义。
  • 使用 DeepSeek 只负责生成回答:减少 API 调用,只在提问时调用大模型。
  • 本地向量库使用 SQLite + sqlite-vec无需 Qdrant、Milvus、Postgres 等额外服务。

当前效果

目前比较适合处理:

  • 某类笔记有哪些
  • 某个教程在哪里
  • 根据笔记总结某个主题
  • 列出博客文章
  • 列出 Agent 安装教程
  • 查 Gradle 构建相关内容

示例:

./scripts/ask.sh '查一下我目前博客文章有哪些'
./scripts/ask.sh '查一下我的安卓gradle构建相关笔记'
./scripts/ask.sh '查一下我的Agent安装教程'

当前限制

  • 当前是 SQLite + sqlite-vec 单机向量库,数据量很大后可以换 Qdrant 或 Chroma。
  • 没有 reranker复杂问题可能还会有弱相关内容混入。
  • embedding 模型是轻量中文模型,效果够用但不是最强。
  • build_index 每次是全量重建,还没有增量索引。
  • frontmatter 解析是轻量手写版,不是完整 YAML 解析。
  • 当前是 CLI 工具,没有 Web 页面和 API 服务。

后续优化方向

详见 docs/RAG优化方案.md,主要方向:

  • 中文分词换 jiebaBM25 召回率最大瓶颈)
  • 放宽文件去重(当前每文件只取 1 chunk长文章不友好
  • QA Prompt 加强引用约束,降低幻觉
  • 注入上下文加 token 预算(节省费用 + 提升精度)
  • 可选:换 BAAI/bge-m3 嵌入模型(中英混合效果更好)
  • 增量索引,只重建变更文件
  • 加 reranker例如 bge-reranker-v2-m3
  • 数据量变大后接 Qdrant

调参

.env 中可调整:

TOP_K=6
EMBED_MODEL=BAAI/bge-small-zh-v1.5
EMBED_BATCH_SIZE=32
VECTOR_WEIGHT=0.65
BM25_WEIGHT=0.35