内容入库流程
入库是检索与语义加工的上游:内容只有先过了这条管线,才谈得上被搜到、被答到、被织进图谱。Molore的四类内容——笔记(note)、剪藏(clip)、知识单元(knowledge)、文档(document)——共用同一条入库管线:统一的全文/向量索引、统一的打标范围、统一的图谱语料口径。文档类多一段抽取前置。本页按数据流向讲这条管线。
管线总览
写入内容表
→(仅文档)文本抽取:pymupdf / RapidOCR / XLSX·DOCX 表格管道化 / 图片后台 OCR
→ 向量前拦门:active + extraction_status=success + 正文 ≥200 字(图片 ≥20 字)
→ FTS5 全文索引(虚拟表 + 触发器)
→ sqlite-vec 向量索引(bge-m3,1024 维,分块)
→ 自动打标(本地 0.8b,零成本)
→ 图谱语料 / wiki 素材(语义加工层)| 阶段 | 模块 | 关键机制 | 代码位置 |
|---|---|---|---|
| 写入 | 各域端点 | 四类内容分表,统一内容 id 体系 | app/api/v1/endpoints/notes.py 等 |
| 文档抽取 | 文档服务 | 文字层优先,扫描件 OCR 降级,表格结构化 | app/services/document_service.py、app/services/document_ocr.py |
| 前拦门 | 嵌入服务 | 长度 + 状态门,不过门不进向量 | app/services/note_embedding_service.py |
| 全文索引 | FTS | FTS5 虚拟表 + 触发器,BM25 | app/services/fts_index.py |
| 向量索引 | vec | sqlite-vec 影子索引,分块嵌入 | app/services/vec_index.py |
| 自动打标 | 打标服务 | 本地模型零成本,事件监听 + 定时兜底 | app/services/autotag_service.py |
| 语义加工 | 图谱/wiki | 语料口径 = 前拦门 + index_only 过滤 | app/services/graphify_service.py、app/services/wiki_service/ |
文档抽取(仅 document 类)
抽取把上传文件转成 content_text 文本层,原始文件不动;extraction_status 记录 pending / success / error(app/models/content.py)。
- PDF:pymupdf 抽文字层;文字层里的线框表格用
find_tables()结构化成 Markdown 表(单页失败只丢结构不丢文字,回落纯文本)。扫描件无文字层时走 RapidOCR,信号量_ocr_semaphore = threading.Semaphore(1)限 1 并发,OCR 不可用时优雅降级不阻塞入库。 - XLSX:每个工作表输出
## 工作表:{名}章节前缀 + Markdown 管道表(首个 ≥2 非空行的行作表头,无够格表头不硬造);单元格批注内联为「值(批注:…)」。 - DOCX:按 body 顺序遍历段落与表格,表格同样转管道表——此前实现只取段落、整表丢弃,属已修复的实捕缺陷。
- 图片:后台 OCR,产物进同一文本层。
- 表格结构化的价值在检索侧兑现:表格行会生成
row::带章节前缀 + 列名的结构化行条目(500 行限帽),供枚举/整表补全通道直取(见检索问答)。
向量前拦门
不是一切内容都进向量。过门条件(note_embedding_service.py):
- 正文 ≥
MIN_EMBED_TEXT_LEN = 200字;图片文档放宽到MIN_EMBED_TEXT_LEN_IMAGE = 20字(OCR 文本常不足 200 字,200 字门会把绝大多数图片文档永远拦在向量通道外); - 内容处于 active 状态;
- 文档类要求
extraction_status = success。
个人与团队内容同口径过门,空间隔离不在此处分流,而在检索侧内容行收口。不过门的内容仍可被 FTS 与 SQL 直查命中。
全文与向量索引
- FTS5(
app/services/fts_index.py):虚拟表 + 触发器随内容事务同步,BM25 排序,启动钩子负责探测与回填。 - sqlite-vec(
app/services/vec_index.py):影子向量索引,嵌入统一 bge-m3 1024 维;长文按块嵌入(chunk 行带父内容引用),/health端点回报vec_index可用性。
两路索引是检索问答的双通道底座,召回侧如何融合见检索问答。
自动打标
过门内容进自动打标范围(note/clip/knowledge/document 四类):
- 全程本地模型
qwen3.5:0.8b,零成本,绝不自动扣费;本地模型不可用就跳过,不回落计费通道。 - 长文抽样取「头 1200 + 中 400 + 尾 400」送模型,避免纯头部样本代表不了全文。
- 触发链 = 内容变更事件监听 + 启动 120s 首扫 + 每小时兜底扫描(
autotag_service.py);事件驱动必须配定时兜底,这是云端打标曾静默死过三周换来的纪律。 - 标签关联带
source(auto/manual),手动重打只清 auto;模型失败文本([Error: ...])不会被当成标签挂上。
存量回填机制
管线升级(如 XLSX/DOCX 表格管道化上线)后,存量内容靠一次性回填追平,机制统一:
- 启动后延迟约 120s 后台执行,让启动主链路先就绪;
- 完成标记落
system_configs(如表格抽取回填的 markerextract_md_tables_v1),全成才落 marker,重跑幂等; - 有差异才更新:比对抽取结果,变了才写回文本层并重走 FTS 重同步 + 向量重嵌,零差异零写入。
仓库模式门禁(index_only)
notes/browser_clips/documents 三表有 index_only 列(迁移 DEFAULT 0)。置位表示「仅入库检索」:
- 只进检索层——FTS/向量/SQL 直查照常,RAG 照常可答;
- 不进语义加工层——图谱语料、自动打标、复盘素材、wiki 代表标题、成本估算统一经
app/core/tenant_scope.py的semantic_visible()过滤(NULL 兼容老库); - 站内统计与存储计费不滤;
- 取消标记即回归全加工,由打标兜底扫描、下次建图、wiki 编译等周期机制自然接管,无专门入口。
下一步
- 检索问答全流程 —— 入库产物如何在问答时被召回
- 异步任务与定时调度 —— 打标兜底、回填任务的调度口径
- FastAPI 后端设计 —— 迁移与播种的通用纪律
- 认知生产管线 —— 入库之后的人工加工五阶段
- 搜索与标签 —— 用户视角的检索与标签用法