2026-06-08 20:35:49 +08:00
|
|
|
|
# 7-54 RAG-Anything 对照后的多模态检索设计 v1
|
|
|
|
|
|
|
2026-07-21 05:13:05 +08:00
|
|
|
|
> 2026-07-19 归类说明:当前知识库主线是 LightRAG + Pi Rust Page AI。本文保留为多模态索引与失败模式的参考材料,不作为当前可直接执行的实施稿。
|
2026-06-28 18:35:56 +08:00
|
|
|
|
|
2026-06-08 20:35:49 +08:00
|
|
|
|
> 创建时间:2026-06-08
|
|
|
|
|
|
>
|
2026-07-21 05:13:05 +08:00
|
|
|
|
> 当前状态:`reference`
|
2026-06-08 20:35:49 +08:00
|
|
|
|
>
|
|
|
|
|
|
> Owner:07-ai / 03-rust-web / knowledge-rag / search
|
|
|
|
|
|
>
|
|
|
|
|
|
> 取代:`7-53` 已放弃,不再作为搜索方案依据。
|
|
|
|
|
|
>
|
|
|
|
|
|
> 参考代码:
|
|
|
|
|
|
> - `reference-code/RAG-Anything`
|
|
|
|
|
|
> - repo:`https://github.com/HKUDS/RAG-Anything`
|
|
|
|
|
|
> - commit:`1bbca28`
|
|
|
|
|
|
> - CodeGraph:`codegraph init && codegraph index . --force --quiet`,49 files / 922 nodes / 2308 edges
|
|
|
|
|
|
> - 关键文件:`raganything/query.py`、`raganything/processor.py`、`raganything/utils.py`、`raganything/config.py`、`README.md`、`docs/multimodal_rag_failure_modes.md`
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 新结论
|
|
|
|
|
|
|
|
|
|
|
|
7-53 的问题是仍在围绕“普通搜索是否混入 OCR”打转,设计重心不对。
|
|
|
|
|
|
|
|
|
|
|
|
RAG-Anything 的检索设计说明:成熟的 PDF / DOCX / Office / 图片检索,不应该依赖 MNote 自己扫 OCR sidecar 做字符串匹配,而应该把多模态内容作为一等内容写进 RAG 索引:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
PDF / DOCX / Office / Image
|
|
|
|
|
|
-> parser content_list
|
|
|
|
|
|
-> text content -> LightRAG text insert
|
|
|
|
|
|
-> image/table/equation -> multimodal processor
|
|
|
|
|
|
-> templated multimodal chunks
|
|
|
|
|
|
-> LightRAG text_chunks + chunks_vdb + entities_vdb + graph
|
|
|
|
|
|
-> query uses vector + graph retrieval
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
所以 MNote 的目标应改为:
|
|
|
|
|
|
|
|
|
|
|
|
1. 默认普通搜索仍可保持轻量本地搜索。
|
|
|
|
|
|
2. 必须有明确的“资料库检索 / 全盘资料库检索”入口,覆盖用户显式纳入资料库索引范围的 PDF、DOCX、Office、图片 OCR。
|
|
|
|
|
|
3. 全盘资料库检索必须走 LightRAG 的 chunk/reference 检索,不再走 MNote 侧 OCR sidecar 字符串补结果。
|
|
|
|
|
|
4. 多模态资料的 ingest 要尽量变成 RAG-Anything 式的结构化 chunk / entity / relation,而不是只生成 wrapper Markdown。
|
|
|
|
|
|
5. 搜索结果必须是可打开的来源命中;问答答案是另一层能力。
|
|
|
|
|
|
6. “全盘”只表示在已配置资料库索引目录内全盘检索,不表示自动索引整个 local folder。
|
|
|
|
|
|
|
|
|
|
|
|
## 2. RAG-Anything 是怎么做检索的
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 查询入口分三种
|
|
|
|
|
|
|
|
|
|
|
|
`raganything/query.py` 提供三类 query。
|
|
|
|
|
|
|
|
|
|
|
|
第一类是纯文本查询:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
query_param = QueryParam(mode=mode, **kwargs)
|
|
|
|
|
|
result = await self.lightrag.aquery(query, param=query_param, system_prompt=system_prompt)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
它直接复用 LightRAG 的 `local/global/hybrid/naive/mix/bypass` 模式。README 推荐示例里人工检索常用 `mode="hybrid"`。
|
|
|
|
|
|
|
|
|
|
|
|
第二类是 VLM enhanced query:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
query_param = QueryParam(mode=mode, only_need_prompt=True, **kwargs)
|
|
|
|
|
|
raw_prompt = await self.lightrag.aquery(query, param=query_param)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
它先只拿 LightRAG 检索出来的 prompt/context,不直接生成最终答案;然后从检索上下文中提取 `Image Path:`,做安全目录校验,编码图片为 base64,再把文本 context + 图片一起交给 VLM 回答。
|
|
|
|
|
|
|
|
|
|
|
|
第三类是显式 multimodal query:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
enhanced_query = await self._process_multimodal_query_content(query, multimodal_content)
|
|
|
|
|
|
result = await self.aquery(enhanced_query, mode=mode, system_prompt=system_prompt, **kwargs)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
用户把表格、公式、图片等内容作为 query 附件传入时,它先用对应 processor 生成描述,再把描述拼回查询文本,最后仍走 LightRAG 检索。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 ingest 不是 OCR sidecar,而是一等 chunk
|
|
|
|
|
|
|
|
|
|
|
|
`raganything/utils.py` 先把 parser 的 `content_list` 分成:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
text_content
|
|
|
|
|
|
multimodal_items
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
文本走 LightRAG 原生 `ainsert(...)`,并传 `file_paths` 用于引用。
|
|
|
|
|
|
|
|
|
|
|
|
多模态内容走 `raganything/processor.py`:
|
|
|
|
|
|
|
|
|
|
|
|
1. 图片、表格、公式先用对应 processor 生成增强描述。
|
|
|
|
|
|
2. `_apply_chunk_template(...)` 把原始路径、caption、footnote、邻近文本、章节路径、表格 body、公式文本、增强描述拼成可检索 chunk。
|
|
|
|
|
|
3. `_convert_to_lightrag_chunks_type_aware(...)` 生成 LightRAG 标准 chunk:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
{
|
|
|
|
|
|
"content": formatted_chunk_content,
|
|
|
|
|
|
"tokens": tokens,
|
|
|
|
|
|
"full_doc_id": doc_id,
|
|
|
|
|
|
"chunk_order_index": chunk_order_index,
|
|
|
|
|
|
"file_path": file_ref,
|
|
|
|
|
|
"is_multimodal": True,
|
|
|
|
|
|
"modal_entity_name": entity_info["entity_name"],
|
|
|
|
|
|
"original_type": data["content_type"],
|
|
|
|
|
|
"page_idx": data["item_info"].get("page_idx", 0),
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
4. chunk 同时写入:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
lightrag.text_chunks
|
|
|
|
|
|
lightrag.chunks_vdb
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
5. 多模态主实体写入:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
knowledge graph
|
|
|
|
|
|
entities_vdb
|
|
|
|
|
|
full_entities
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
6. 对多模态 chunk 调 LightRAG `extract_entities(...)`,再追加 `belongs_to` 关系,最后调用 `merge_nodes_and_edges(...)` 合并回 graph。
|
|
|
|
|
|
7. `doc_status.chunks_list/chunks_count` 追加多模态 chunk id。
|
|
|
|
|
|
|
|
|
|
|
|
这才是“全盘资料库可检索”的关键:图片、表格、公式不是旁路 OCR 文件,而是进入 LightRAG 的 chunk 向量库和图谱。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.3 检索失败排查也围绕多模态索引
|
|
|
|
|
|
|
|
|
|
|
|
RAG-Anything 的 failure checklist 不是让 UI 再补一层字符串搜索,而是检查:
|
|
|
|
|
|
|
|
|
|
|
|
- parser Markdown / `content_list.json` 是否可信。
|
|
|
|
|
|
- table block 的 `table_body` 是否保留结构。
|
|
|
|
|
|
- image path / caption / page index 是否对齐。
|
|
|
|
|
|
- multimodal processing flags 是否启用。
|
|
|
|
|
|
- embedding path 是否看到 enriched text,而不是只看到 raw OCR。
|
|
|
|
|
|
|
|
|
|
|
|
这对 MNote 很重要:搜索不准时,第一诊断点应该是“资料有没有以正确 chunk 进入 LightRAG”,不是前端结果列表怎么融合。
|
|
|
|
|
|
|
|
|
|
|
|
## 3. MNote 当前差距
|
|
|
|
|
|
|
|
|
|
|
|
当前 MNote 已经有:
|
|
|
|
|
|
|
|
|
|
|
|
- `/api/knowledge-rag/ingest`
|
|
|
|
|
|
- `/api/knowledge-rag/query`
|
|
|
|
|
|
- source registry
|
|
|
|
|
|
- LightRAG `/documents/scan`
|
|
|
|
|
|
- `/query/data` + references 映射
|
|
|
|
|
|
- citationUrl / citationMarkdown / locator enrich
|
|
|
|
|
|
|
|
|
|
|
|
但普通搜索仍有一条不成熟路径:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
/api/search/documents
|
|
|
|
|
|
-> local_search_index
|
|
|
|
|
|
-> includeOcr 时追加 query_knowledge_rag_ocr_sidecar_results
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这条 `knowledge_rag_ocr_sidecar_results` 是 MNote 遍历 registry sidecar 后做文本匹配,不是 LightRAG vector/graph retrieval。它会让搜索看起来“用了 OCR”,但排序、召回、语义、图谱关系和多模态 chunk 都不是一套成熟系统。
|
|
|
|
|
|
|
|
|
|
|
|
另一个差距是 ingest。MNote 当前对 LightRAG scan 支持文件直接 symlink;对非 scan 支持文件生成 Markdown wrapper:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
# file
|
|
|
|
|
|

|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这对图片入口有帮助,但不等于 RAG-Anything 的 multimodal chunk / entity / relation 管线。后者会把图片、表格、公式的描述、上下文、页码、路径都写进 LightRAG chunk 和 graph。
|
|
|
|
|
|
|
|
|
|
|
|
另一个必须保留的边界是索引范围。MNote 是 local-folder 产品,不能默认把整个本地目录都纳入 LightRAG。用户需要人工控制哪些目录参与资料库检索,否则会带来:
|
|
|
|
|
|
|
|
|
|
|
|
- 大目录首次索引成本不可控。
|
|
|
|
|
|
- 隐私和权限边界不清。
|
|
|
|
|
|
- 搜索噪音扩大,资料库结果质量下降。
|
|
|
|
|
|
- 删除/移动/重建的 watcher 压力过高。
|
|
|
|
|
|
|
|
|
|
|
|
因此资料库检索依赖显式索引目录,而不是自动覆盖整个 workspace。
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 新搜索边界
|
|
|
|
|
|
|
|
|
|
|
|
### 4.1 默认搜索
|
|
|
|
|
|
|
|
|
|
|
|
默认搜索只做快速定位:
|
|
|
|
|
|
|
|
|
|
|
|
- Markdown 页面标题
|
|
|
|
|
|
- Markdown 正文
|
|
|
|
|
|
- 路径
|
|
|
|
|
|
- 最近打开 / 最近修改
|
|
|
|
|
|
- 本地轻索引资源元信息
|
|
|
|
|
|
|
|
|
|
|
|
默认不混入 OCR sidecar,也不混入 LightRAG 语义结果。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.2 全盘资料库检索
|
|
|
|
|
|
|
|
|
|
|
|
搜索弹窗必须有明确入口:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
范围:当前页 / 工作区 / 全盘资料库
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
选择 `全盘资料库` 后:
|
|
|
|
|
|
|
|
|
|
|
|
- 调 LightRAG retrieval,而不是 MNote sidecar grep。
|
|
|
|
|
|
- 覆盖已纳入资料库索引目录的 PDF、DOCX、Office、图片 OCR、表格、公式、Markdown。
|
|
|
|
|
|
- 返回 references/chunks 作为搜索结果。
|
|
|
|
|
|
- 不默认生成 answer。
|
|
|
|
|
|
- 每条结果有来源、snippet、类型、页码 / bbox / block / resource fallback。
|
|
|
|
|
|
- 结果能直接打开对应 resource tab。
|
|
|
|
|
|
- 对未入库目录明确显示“未纳入资料库索引”,而不是让用户误以为 LightRAG 漏检。
|
|
|
|
|
|
|
|
|
|
|
|
建议协议:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
POST /api/knowledge-rag/search
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
请求:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"workspaceId": "...",
|
|
|
|
|
|
"rootUri": "file:///...",
|
|
|
|
|
|
"query": "压缩率 Canterbury corpus",
|
|
|
|
|
|
"mode": "hybrid",
|
|
|
|
|
|
"topK": 12,
|
|
|
|
|
|
"chunkTopK": 24,
|
|
|
|
|
|
"includeChunkContent": true,
|
|
|
|
|
|
"includeReferences": true,
|
|
|
|
|
|
"answer": false
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
实现上可以先复用 `/api/knowledge-rag/query` 的 `/query/data` 调用,只是响应包装成 search results,不展示 answer。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.2.1 资料库索引范围
|
|
|
|
|
|
|
|
|
|
|
|
MNote 需要把“全盘资料库检索”建立在显式索引范围上:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
Knowledge Search Scope
|
|
|
|
|
|
includeRoots:
|
|
|
|
|
|
- docs/research
|
|
|
|
|
|
- resources/papers
|
|
|
|
|
|
excludePatterns:
|
|
|
|
|
|
- "**/draft-private/**"
|
|
|
|
|
|
- "**/.git/**"
|
|
|
|
|
|
- "**/node_modules/**"
|
|
|
|
|
|
runOnChange: true|false
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
产品语义:
|
|
|
|
|
|
|
|
|
|
|
|
- `includeRoots` 是用户主动加入资料库索引的目录或文件。
|
|
|
|
|
|
- `excludePatterns` 后期必须支持,用于排除私密目录、临时目录、构建产物、大型无关资产。
|
|
|
|
|
|
- LightRAG 只保证检索这些已入库范围。
|
|
|
|
|
|
- 普通本地搜索仍可搜索 Markdown / 本地轻索引,不要求 LightRAG 入库。
|
|
|
|
|
|
- 如果用户在全盘资料库模式下搜不到某文件,UI 要能提示它是否未入库、入库中、失败、已排除或已删除。
|
|
|
|
|
|
|
|
|
|
|
|
实现上,source registry 需要从“单个 source 列表”升级为“索引范围 + source 状态”:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
.mnote/index/lightrag-source-registry.json
|
|
|
|
|
|
indexedRoots[]
|
|
|
|
|
|
rootRelativePath
|
|
|
|
|
|
recursive
|
|
|
|
|
|
excludes[]
|
|
|
|
|
|
runOnChange
|
|
|
|
|
|
updatedAt
|
|
|
|
|
|
entries[]
|
|
|
|
|
|
sourceRootRelativePath
|
|
|
|
|
|
sourceHash
|
|
|
|
|
|
lightRagDocId
|
|
|
|
|
|
chunkIds
|
|
|
|
|
|
status
|
|
|
|
|
|
excludedBy
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
这保留了当前“人工控制哪些需要全盘搜索”的价值,同时给后续自动 watcher / 增量重建留出边界。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.3 Knowledge Ask
|
|
|
|
|
|
|
|
|
|
|
|
Knowledge Ask / Page AI 才生成答案:
|
|
|
|
|
|
|
|
|
|
|
|
- 用同一套 LightRAG references。
|
|
|
|
|
|
- 展示 `Context used`。
|
|
|
|
|
|
- 引用使用 `citationMarkdown` / `citationUrl`。
|
|
|
|
|
|
- 可选 VLM enhanced:先拿 retrieved context,再把命中的图片资源交给 VLM 参与回答。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.4 当前页搜索
|
|
|
|
|
|
|
|
|
|
|
|
当前页内查找仍不走 LightRAG:
|
|
|
|
|
|
|
|
|
|
|
|
- Markdown:editor / PageAggregate 内查找。
|
|
|
|
|
|
- PDF:viewer 文本层 / sidecar locator。
|
|
|
|
|
|
- Office:预览/解析层查找。
|
|
|
|
|
|
|
|
|
|
|
|
这是局部查找,不是全盘检索。
|
|
|
|
|
|
|
|
|
|
|
|
## 5. MNote 应参考 RAG-Anything 的实施方案
|
|
|
|
|
|
|
|
|
|
|
|
### Phase A:放弃 7-53,移除 sidecar 补结果主路径
|
|
|
|
|
|
|
|
|
|
|
|
目标:先停止把 sidecar grep 当成熟 OCR 搜索。
|
|
|
|
|
|
|
|
|
|
|
|
改动:
|
|
|
|
|
|
|
|
|
|
|
|
1. 默认搜索关闭 `includeOcr`。
|
|
|
|
|
|
2. `includeOcr` 不再调用 `query_knowledge_rag_ocr_sidecar_results` 作为普通结果补充。
|
|
|
|
|
|
3. UI 增加 `全盘资料库` scope,先复用 `/api/knowledge-rag/query` 的 references 返回。
|
|
|
|
|
|
4. 结果标注 `provider=lightrag`、`matchSource=lightrag_reference`。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- 默认搜索短词不出现 PDF/OCR 假阳性。
|
|
|
|
|
|
- 选择全盘资料库后可以搜到 PDF/DOCX/OCR 资料。
|
|
|
|
|
|
- 搜索结果能打开对应 resource tab。
|
|
|
|
|
|
|
|
|
|
|
|
### Phase B:新增 references-only retrieval facade
|
|
|
|
|
|
|
|
|
|
|
|
目标:把问答和人工检索分开。
|
|
|
|
|
|
|
|
|
|
|
|
新增:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
POST /api/knowledge-rag/search
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
内部:
|
|
|
|
|
|
|
|
|
|
|
|
- 调 LightRAG `/query/data`。
|
|
|
|
|
|
- `include_references=true`。
|
|
|
|
|
|
- `include_chunk_content=true`。
|
|
|
|
|
|
- `mode=hybrid` 或 `mix`,后续用 benchmark 决定默认值。
|
|
|
|
|
|
- 不把 answer 放入搜索结果。
|
|
|
|
|
|
- 对 references 做 registry mapping、locator enrich、ranking。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- API 返回 `mnote.knowledge_rag.search_results.v1`。
|
|
|
|
|
|
- 每条 result 有 `citationUrl` / `citationMarkdown` / `locatorPrecision`。
|
|
|
|
|
|
- 对无 locator 的命中明确降级到文件级打开。
|
|
|
|
|
|
|
|
|
|
|
|
### Phase C:RAG-Anything 式多模态 chunk 入库
|
|
|
|
|
|
|
|
|
|
|
|
目标:让图片、表格、公式、Office/PDF 结构进入 LightRAG retrieval,而不是只存在 sidecar。
|
|
|
|
|
|
|
|
|
|
|
|
设计:
|
|
|
|
|
|
|
|
|
|
|
|
1. MNote parser 输出统一 `content_list`:
|
|
|
|
|
|
- `text`
|
|
|
|
|
|
- `image`
|
|
|
|
|
|
- `table`
|
|
|
|
|
|
- `equation`
|
|
|
|
|
|
- `generic`
|
|
|
|
|
|
2. text 走 LightRAG 文本 insert / scan。
|
|
|
|
|
|
3. multimodal items 生成 templated chunk:
|
|
|
|
|
|
- source path
|
|
|
|
|
|
- page index
|
|
|
|
|
|
- block id / bbox
|
|
|
|
|
|
- caption / footnote
|
|
|
|
|
|
- table body
|
|
|
|
|
|
- equation text / latex
|
|
|
|
|
|
- neighbor text / section path
|
|
|
|
|
|
- enhanced description
|
|
|
|
|
|
4. 写入 LightRAG chunk/vector/graph,或通过扩展 LightRAG/RAG-Anything adapter 实现。
|
|
|
|
|
|
5. registry 保存 `sourceHash -> lightRagDocId -> chunkIds -> locator map`。
|
|
|
|
|
|
|
|
|
|
|
|
验收:
|
|
|
|
|
|
|
|
|
|
|
|
- 查询“图 3 展示了什么”能召回图片 chunk,而不是只召回邻近正文。
|
|
|
|
|
|
- 查询表格中的指标能召回 table chunk,snippet 包含表格 body。
|
|
|
|
|
|
- query result 能通过 chunkId 映射回 MNote resource tab 的 page/bbox/block。
|
|
|
|
|
|
|
|
|
|
|
|
### Phase D:VLM enhanced Ask
|
|
|
|
|
|
|
|
|
|
|
|
目标:回答中真正看图,而不是只读图片 caption。
|
|
|
|
|
|
|
|
|
|
|
|
参考 RAG-Anything:
|
|
|
|
|
|
|
|
|
|
|
|
1. 先让 LightRAG 返回 retrieval prompt/context。
|
|
|
|
|
|
2. 从 context 中提取命中图片路径或 MNote resource id。
|
|
|
|
|
|
3. 做 allowed roots / resource permission 校验。
|
|
|
|
|
|
4. 把图片编码或转为可访问 asset URL。
|
|
|
|
|
|
5. 文本 context + image 一起交给 VLM。
|
|
|
|
|
|
|
|
|
|
|
|
这一步只用于 Ask,不用于普通搜索结果。
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 关键约束
|
|
|
|
|
|
|
|
|
|
|
|
- 全盘资料库检索是必需能力,不能因为默认关闭 OCR 而消失。
|
|
|
|
|
|
- 默认搜索和全盘资料库检索必须是两个明确模式,不能暗中混合。
|
|
|
|
|
|
- 不再把 sidecar grep 当成熟资料库搜索。
|
|
|
|
|
|
- locator 不足时只能声明降级,不能伪造页码/bbox。
|
|
|
|
|
|
- `file_path` 不能作为唯一真相;MNote registry 必须维护绝对路径、root-relative path、source hash、LightRAG doc id、chunk id、locator map。
|
|
|
|
|
|
- 多模态 chunk 的 source path / image path 必须做权限和安全目录校验。
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 立即建议
|
|
|
|
|
|
|
|
|
|
|
|
下一步不要继续修 7-53。
|
|
|
|
|
|
|
|
|
|
|
|
应直接做:
|
|
|
|
|
|
|
|
|
|
|
|
1. 删除/停用普通搜索里的 OCR sidecar 补结果。
|
|
|
|
|
|
2. 新增 `资料库索引范围` 设置,至少支持 include roots;excludes 先设计协议,后续实现。
|
|
|
|
|
|
3. 新增 `全盘资料库` 搜索 scope,只检索已入库范围,调用 LightRAG references。
|
|
|
|
|
|
4. 写 `7-54 Phase A/B` 的 smoke:默认搜索不混 OCR;未入库 PDF/DOCX 在资料库检索中明确提示未入库;加入索引目录后可搜到并打开。
|
|
|
|
|
|
5. 后续再做 RAG-Anything 式多模态 chunk 入库。
|
|
|
|
|
|
|
|
|
|
|
|
这样既保留 MNote 的核心价值,也把检索系统拉回成熟 RAG 项目的设计方向。
|
|
|
|
|
|
|
|
|
|
|
|
## 8. Phase A/B 实施记录
|
|
|
|
|
|
|
|
|
|
|
|
时间:2026-06-08
|
|
|
|
|
|
|
|
|
|
|
|
已完成:
|
|
|
|
|
|
|
|
|
|
|
|
1. 普通搜索不再把 `includeOcr=true` 转成 `query_knowledge_rag_ocr_sidecar_results` 补结果;`/api/search/documents` 的边界固定回 `ordinary_local_search`,`knowledgeRag=false`,`ocrSidecarFallback=false`。
|
|
|
|
|
|
2. 新增 `POST /api/knowledge-rag/search`,作为 references-only retrieval facade:
|
|
|
|
|
|
- 调 LightRAG `/query/data`
|
|
|
|
|
|
- `include_references=true`
|
|
|
|
|
|
- 默认保留 `include_chunk_content=true`
|
|
|
|
|
|
- 复用 registry mapping / locator enrich / citationUrl / citationMarkdown
|
|
|
|
|
|
- 返回 `mnote.knowledge_rag.search_results.v1`
|
|
|
|
|
|
- 搜索结果标记 `provider=lightrag`、`matchSource=lightrag_reference`
|
|
|
|
|
|
3. source registry 增加兼容字段 `indexedRoots[]`,ingest 显式 source 时记录 include root:
|
|
|
|
|
|
- `rootRelativePath`
|
|
|
|
|
|
- `recursive`
|
|
|
|
|
|
- `excludePatterns`
|
|
|
|
|
|
- `runOnChange`
|
|
|
|
|
|
- `updatedAtMs`
|
|
|
|
|
|
旧 registry JSON 缺少 `indexedRoots` 时默认空数组。
|
|
|
|
|
|
4. 搜索弹窗新增 `全盘资料库`开关;默认工作区搜索发送 `includeOcr=false`,打开开关后调用 `/api/knowledge-rag/search`。
|
|
|
|
|
|
5. `scripts/task538-knowledge-rag-source-scope-api-smoke.js` 增加 `/api/knowledge-rag/search` 验证,确认 sourcePaths post-filter 后只返回目标 source,且结果来自 LightRAG references 并可打开来源。
|
|
|
|
|
|
|
|
|
|
|
|
验证:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
node --check rust/crates/mnote-web/browser/sidebar-tree-runtime.js
|
|
|
|
|
|
node --check scripts/task538-knowledge-rag-source-scope-api-smoke.js
|
|
|
|
|
|
cargo check --manifest-path rust/Cargo.toml -p mnote-web
|
|
|
|
|
|
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_documents_route_is_owned_by_mnote_web -- --nocapture
|
|
|
|
|
|
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_documents_local_folder_does_not_promote_evidence_sqlite_body_hits -- --nocapture
|
|
|
|
|
|
cargo test --manifest-path rust/Cargo.toml -p mnote-web indexed_root -- --nocapture
|
|
|
|
|
|
cargo test --manifest-path rust/Cargo.toml -p mnote-web references_only_search_result -- --nocapture
|
|
|
|
|
|
node scripts/task125-rust-web-search-server-first-smoke.js
|
|
|
|
|
|
node scripts/task538-knowledge-rag-source-scope-api-smoke.js
|
|
|
|
|
|
Playwright 登录态验证:默认搜索 includeOcr=false;全盘资料库开关调用 /api/knowledge-rag/search
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`scripts/task128-rust-web-wolai-search-modal-smoke.js` 未作为本次验收依据:当前默认登录态要求下它直接访问 `/` 等待 topbar,曾因未建立登录态而超时。已用登录态 Playwright 脚本覆盖本次新增搜索 scope 行为。
|
|
|
|
|
|
|
|
|
|
|
|
未完成:
|
|
|
|
|
|
|
|
|
|
|
|
- `excludePatterns` 仅进入 registry 协议,尚未实现 UI 编辑和 glob 过滤。
|
|
|
|
|
|
- RAG-Anything 式 multimodal chunks / entities / relations 入库仍是 Phase C,未标完成。
|
|
|
|
|
|
|
|
|
|
|
|
## 9. Phase B.1:chunk 上下文段落级定位
|
|
|
|
|
|
|
|
|
|
|
|
时间:2026-06-08
|
|
|
|
|
|
|
|
|
|
|
|
新增结论:
|
|
|
|
|
|
|
|
|
|
|
|
当前用户需要的是“搜索结果点击后落到对应段落”,不是必须文字级 bbox。对 DOCX / Office 这类当前缺少 page/bbox 的资料,短期不应强制改成 DOCX -> PDF viewer 管线;更低风险的路径是复用 LightRAG 已返回的 chunk 上下文做段落级定位。
|
|
|
|
|
|
|
|
|
|
|
|
参考 `rag-knowledge-system` 的可采用点:
|
|
|
|
|
|
|
|
|
|
|
|
- 检索结果必须保留稳定 chunk metadata。
|
|
|
|
|
|
- 点击定位不能只用 query 短词,应使用 chunk/snippet 上下文作为 anchor。
|
|
|
|
|
|
- 目录/文件夹 scope 是 retrieval 层的过滤条件,不是 UI 结果列表后处理。
|
|
|
|
|
|
|
|
|
|
|
|
不直接照搬的点:
|
|
|
|
|
|
|
|
|
|
|
|
- `rag-knowledge-system` 的 PDF highlight 先有 `page_num`,再在页内 `search_for(anchor)`;MNote 当前 DOCX sidecar 没有页码,所以只能先做到文档内段落级定位。
|
|
|
|
|
|
- 对 DOCX 缺 page/bbox 时,不能伪造页码或 bbox,应返回 `locatorPrecision=paragraph` / `locatorDegraded=true`。
|
|
|
|
|
|
|
|
|
|
|
|
设计:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
LightRAG /query/search
|
|
|
|
|
|
-> chunk content / occurrence
|
|
|
|
|
|
-> MNote registry mapping
|
|
|
|
|
|
-> sidecar block match
|
|
|
|
|
|
-> locator:
|
|
|
|
|
|
blockId
|
|
|
|
|
|
sourceMapPath
|
|
|
|
|
|
evidenceText = query-centered block/chunk context
|
|
|
|
|
|
locatorPrecision = bbox | paragraph | file
|
|
|
|
|
|
-> office-preview:
|
|
|
|
|
|
clean evidenceText
|
|
|
|
|
|
generate multiple anchors
|
|
|
|
|
|
score rendered paragraphs/tables by context overlap
|
|
|
|
|
|
scroll/highlight best paragraph
|
|
|
|
|
|
fallback to old short text candidates only after paragraph scoring fails
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
验收样例:
|
|
|
|
|
|
|
|
|
|
|
|
- `吡咯烷`:不应因为短词优先命中 `N-甲基吡咯烷酮`,应优先选择与 returned chunk 上下文整体重合最高的段落。
|
|
|
|
|
|
- `三乙基硅` / `三甲基硅`:存在 bbox 时仍使用 bbox;没有 bbox 时段落级定位,不伪造页码。
|
|
|
|
|
|
- 同一已打开 DOCX 点击不同搜索结果时,resource tab 不重新加载,只通过 `postMessage` 更新 locator 并重新定位。
|
|
|
|
|
|
|
|
|
|
|
|
降级语义:
|
|
|
|
|
|
|
|
|
|
|
|
- `locatorPrecision=bbox`:有 page + bbox,可页内精确框选。
|
|
|
|
|
|
- `locatorPrecision=paragraph`:有 block/context,但缺 page/bbox,只保证段落级定位。
|
|
|
|
|
|
- `locatorPrecision=file`:只能打开文件,定位信息不足。
|