From 39d1aa0fe9ac094356ff850d90ce6733c1b4ccdb Mon Sep 17 00:00:00 2001 From: yxx <2412119399@qq.com> Date: Thu, 27 Aug 2026 19:26:58 +0800 Subject: [PATCH] =?UTF-8?q?docs(retrieval):=20=E5=A2=9E=E5=8A=A0=20Knowled?= =?UTF-8?q?ge/Retrieval=20Core=20=E5=BC=80=E5=8F=91=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- backend/README.md | 2 + docs/Knowledge与Retrieval-Core开发说明.md | 230 ++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 docs/Knowledge与Retrieval-Core开发说明.md diff --git a/backend/README.md b/backend/README.md index a0e495c..25cfbc0 100644 --- a/backend/README.md +++ b/backend/README.md @@ -17,3 +17,5 @@ uv run uvicorn app.main:app --reload --host 127.0.0.1 --port 8000 团队接口清单见 `../docs/后端接口契约-开发版.md`,机器可读契约以运行时的 `/openapi.json` 为准。 AI Core 与 Agent Core 的模块边界、Mock Provider 和 Tool Calling 调试方式见 `../docs/AI-Core与Agent-Core开发说明.md`。 + +Knowledge Core 与 Retrieval Core 的模块边界、数据模型、接口与检索流程见 `../docs/Knowledge与Retrieval-Core开发说明.md`。 diff --git a/docs/Knowledge与Retrieval-Core开发说明.md b/docs/Knowledge与Retrieval-Core开发说明.md new file mode 100644 index 0000000..edb51cd --- /dev/null +++ b/docs/Knowledge与Retrieval-Core开发说明.md @@ -0,0 +1,230 @@ +# Knowledge Core 与 Retrieval Core 开发说明 + +> 本文档用于团队开发和模块联调,记录 Knowledge Core / Retrieval Core 已经落地的 +> 模块边界、数据模型、接口与使用方式,对应分工表中的杨星萱。 + +## 当前实现 + +当前已经建立第一条可运行的检索链路: + +```text +Markdown Vault +→ Markdown Parser(Block 切分 / heading_path / offset) +→ SQLite(notes / blocks / FTS5)+ sqlite-vec(vec_blocks) +→ FTS5(BM25) + Vector(cosine) 双路召回 +→ RRF 融合 → Reranker 精排 → Metadata Filter → 分页 +→ Citation + Snippet +``` + +对应代码: + +```text +backend/app/ +├── constants.py EMBEDDING_DIM = 128 +├── config.py Settings(data_dir / db_path / vault_path) +├── textutils.py 分词、FTS 查询串、摘要片段 +├── repository.py notes / blocks / blocks_fts 读写(领域记录层) +├── database/ +│ ├── db.py SQLite 连接 + 事务 + 加载 sqlite-vec +│ └── migrations.py 轻量迁移(建 notes / blocks / blocks_fts / vec_blocks) +├── knowledge/ +│ └── parser.py Markdown → ParsedNote / NoteBlock +├── retrieval/ +│ ├── embedding.py EmbeddingProvider 接口 + HashEmbeddingProvider +│ ├── reranker.py RerankerProvider 接口 + LexicalReranker +│ ├── vectorstore.py VectorStore 接口 + SqliteVecStore +│ ├── hybrid.py RRF 融合、分数归一化 +│ └── engine.py RetrievalEngine(编排检索全流程) +└── services/ + ├── note_service.py Note CRUD + 索引编排 + └── index_service.py 全量重建、索引状态、任务查询 +``` + +Router(`backend/app/routes.py`)只负责 HTTP 与错误转换;`/api/notes`、`/api/search`、 +`/api/index/*` 已接入上述服务,其余端点仍由对应模块负责。 + +## 模块边界 + +本模块负责(杨星萱): + +- Markdown Vault、Note / NoteBlock 数据模型与解析; +- SQLite 元数据、FTS5 全文检索、sqlite-vec 向量检索; +- Embedding、Hybrid RAG、RRF、Reranker、Metadata Filter; +- Citation 与笔记定位; +- 检索测试数据。 + +以下内容保持接口,不在本模块实现: + +- Agent Runtime、Tool Registry、Permission:由 Agent Core 提供; +- Provider Adapter、多模型协议:由 Model Core 提供; +- Skill / Plugin 生命周期:由 Extension Core 提供; +- 文件系统与 API Key 明文读取:由 Rust Host 提供。 + +## 数据模型与稳定 ID + +- 笔记元数据存 `notes` 表;正文切成 Block 存 `blocks` 表;`blocks_fts` 是 FTS5 虚拟表; + `vec_blocks` 是 sqlite-vec 的 `vec0` 虚拟表。 +- 稳定 ID(内容/路径不变则 ID 不变): + +```text +note_id = "note_" + sha256(rel_path)[:16] +block_id = "blk_" + sha256(note_id | heading_path | content)[:16] +citation_id = "cit_" + block_id +``` + +> 注意:MVP 阶段 `note_id` 由相对路径派生,移动文件会改变 ID;后续 `move` 流程会保留原 ID。 + +每个 Block 记录 `heading_path`(章节路径)、`start_offset` / `end_offset`(相对原文的 +字符偏移,用于前端跳转高亮)、`content_hash`、`token_count`。 + +## 分层依赖 + +按团队约定,依赖方向为: + +```text +Router(HTTP/错误转换) + → Service(note_service / index_service 编排) + → Repository(notes/blocks/FTS5 访问) ← 只在此层访问 SQLite + → Retrieval Infra(embedding/reranker/vectorstore) ← vec0 只在 vectorstore 层访问 +``` + +- 检索 Executor 调用 `RetrievalEngine`,不直接拼接 FTS5 或 sqlite-vec SQL; +- 向量实现只在 `retrieval/vectorstore.py`;DB 访问只在 `repository.py`。 + +## 分词与中文检索 + +FTS5 默认 `unicode61` 不切分中文,因此统一预分词:ASCII 单词 + CJK 单字 + CJK 相邻双字。 +写入与查询走同一套拆分(`textutils.segment` / `textutils.match_query`),实现中文子串/词级召回。 + +## Embedding / Reranker(轻量实现,接口可替换) + +当前是「统一接口 + 轻量实现」,后续接入真实模型时替换实例即可,不改变上层调用: + +- `EmbeddingProvider`(`embed_documents` / `embed_query`)→ `HashEmbeddingProvider`: + 确定性特征哈希 + L2 归一化,`dim = 128`,`model_id = "hash-v1"`。 +- `RerankerProvider`(`rerank`)→ `LexicalReranker`:分数归一化 + 词重叠加权, + `model_id = "lexical-v1"`。 +- `VectorStore`(`upsert` / `delete` / `search` / `clear`)→ `SqliteVecStore`: + sqlite-vec `vec0`,相似度取余弦 `score = 1 - distance² / 2`。 + +## 检索流程 + +`RetrievalEngine.search(request)`: + +1. 按 `mode` 收集候选:`fts` / `vector` 各取 Top `CANDIDATE_POOL = 50`; +2. `hybrid` 用 RRF(`k = 60`)融合两路排序; +3. Metadata Filter:`folders` / `note_ids` / `tags` / 时间范围; +4. `hybrid` 再经 Reranker 精排,其余模式按分数排序; +5. 分数归一化 → 分页 → 组装 `Citation` 与 `Snippet`。 + +模块级单例 `engine = RetrievalEngine(HashEmbeddingProvider(), LexicalReranker(), SqliteVecStore())`, +检索入口统一为 `engine.search(request)`。 + +## 接口清单 + +### Note + +```text +GET /api/notes?limit=&offset=&folder=&tag= +POST /api/notes +GET /api/notes/{note_id} +PATCH /api/notes/{note_id} +DELETE /api/notes/{note_id} +POST /api/notes/{note_id}/move (501,待定语义) +``` + +创建笔记: + +```json +POST /api/notes +{"title": "Python 基础", "markdown": "# 变量\n\nPython 是动态类型语言。", "folder": "编程", "tags": ["python"]} +``` + +### Search + +```text +POST /api/search +``` + +```json +{"query": "向量数据库", "mode": "hybrid", "limit": 10} +``` + +`mode` 取 `fts` / `vector` / `hybrid`;可选 `folders` / `note_ids` / `tags` / 时间范围 / +`include_snippet`。结果项含 `score`、`snippet` 与 `citation`(`citation_id`、`file_path`、 +`heading_path`、`start_offset`、`end_offset`)。 + +### Index + +```text +GET /api/index/status +POST /api/index/rebuild +GET /api/index/jobs/{job_id} +``` + +重建(MVP 同步执行,直接返回 `completed`): + +```json +POST /api/index/rebuild +{"scope": "all"} +``` + +## 检索测试数据 + +样例 Vault 位于 `backend/data/vault/`,覆盖中英文、多级标题、frontmatter、子目录与不同 tags: + +```text +项目说明.md +编程/Python 基础语法.md +编程/向量数据库与相似度检索.md +产品/RAG 检索增强与引用定位.md +日记/2026-08-27 周会.md +``` + +示例查询: + +```text +POST /api/search {"query": "向量数据库", "mode": "hybrid"} → 命中《向量数据库与相似度检索》 +POST /api/search {"query": "检索", "mode": "fts", "folders": ["产品"]} → 只返回 产品/ 下笔记 +POST /api/search {"query": "向量", "mode": "hybrid", "tags": ["向量"]} → 按 tag 过滤 +``` + +## 测试 + +```powershell +cd backend +uv run pytest -q +``` + +当前 26 个用例通过(单元 + 端到端)。测试通过 `tests/conftest.py` 的 autouse fixture 把 +数据目录/DB/Vault 重定向到临时目录,不读写真实 `backend/data`,任何本机状态下结果确定。 + +## 配置 + +```text +APP_DATA_DIR 默认 backend/data +APP_DB_PATH 默认 backend/data/app.db +APP_VAULT_PATH 默认 backend/data/vault +``` + +运行期生成的 `backend/data/*.db*` 已被 `.gitignore` 忽略,vault 下的 Markdown 测试数据会提交。 + +## 接入约定(Agent / 其他模块) + +Agent 通过注册 Tool 接入本模块,不让 Agent Runtime 直接依赖具体实现: + +```text +notes.search / notes.read / notes.create / notes.update / notes.list / notes.move +rag.search +``` + +- 写操作 Executor 调用 `note_service`,不直接访问 SQLite; +- 检索 Executor 调用 `engine.search(request)`,不直接拼接 FTS5 或 sqlite-vec SQL。 + +## 当前限制与下一步 + +- `move` 接口未实现(需确认移动后 `note_id` 是否保持稳定)。 +- Embedding / Reranker 为轻量实现,后续替换为真实模型(接口不变)。 +- 小语料下 hybrid 检索召回偏宽(向量 Top-K 覆盖全部 block),可加相关性阈值收紧。 +- 重建为同步 + 全量,后续接入增量索引与异步任务队列。 +- 检索 Benchmark 待建立。