Files
mnote/design/07-ai/done/7-52-lightrag-image-ocr-search-chain-hardening-v1.md
T

149 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 7-52 LightRAG 图片 OCR 与搜索召回链路加固 v1
> 创建时间:2026-06-07
>
> 当前状态:`DONE`
>
> Owner07-ai / knowledge-rag / local-search
>
> 上位依据:`design/07-ai/done/7-50-lightrag-knowledge-rag-provider-v1.md`
## 1. 问题结论
这不是 Page AI 某次回答措辞错误,而是 LightRAG 集成链路同时暴露了三层缺口:
- 图片 ingest 缺口:MNote 对图片 source 写入 LightRAG input 时使用 Markdown wrapper,当前 indexed chunk 只有 `![image](...)` 占位,没有把 MinerU OCR 文本写入 LightRAG chunk / reference。
- 工具契约缺口:`mnote_knowledge_rag_query``rawMetadata.keywords`、实体和关系计数暴露给 agent,但没有明确这些只是查询处理元数据,agent 容易把它误判为“source OCR 成功且已返回原文”。
- 搜索召回缺口:`/api/search/documents` 仍是普通 local search`includeOcr=true` 目前不代表会查 LightRAG OCR 文本,因此搜索“线程作用域”不会命中目标图片。
## 2. 现场证据
目标 source
```text
/mnt/Data1T/Mnote_data/users/mnote-e2e/workspaces/my-space/新页面233155/image copy 6.png
```
已确认的事实:
- LightRAG source registry 中该图片为 `processed``lightRagDocId=doc-781c4b5f39f135886eb6062d8606058e``lightRagFilePath=mnote-d0985c21239b677d-image copy 6.png.md`
- `kv_store_text_chunks.json` 中对应 chunk 内容只有 `# image copy 6.png` 和 Markdown 图片占位。
- 直接调用 LightRAG 的 MinerU parser CLI 解析原 PNG 可以识别出包含“线程作用域”的文本,并生成 `blocks.jsonl` 与 bbox。
- `/query/data` 能在 metadata 里返回 `rawMetadata.keywords.high_level=["线程作用域"]`,但 references/chunks 没有返回这段 OCR 原文;这只能证明查询分析或图谱元数据命中,不能证明引用文本已暴露。
- `/api/search/documents` 查询 `线程作用域` 返回 0;代码中 `include_ocr` 只进入 meta,没有参与搜索。
## 3. 目标边界
本修复继续保持 7-50 的边界:
- LightRAG 是知识库 OCR / parse / chunk / vector / graph / query provider。
- MNote 不复制 LightRAG 图谱,不把 LightRAG chunk 当正文真相。
- MNote 必须负责 source registry、权限、引用打开、普通搜索入口的边界标注,以及 agent 工具契约。
- 普通搜索可以显示“资料库 OCR 命中”,但不能变成必须依赖 LightRAG 服务才能打开页面或搜索普通 Markdown。
## 4. 修复方案
### P0:工具契约防误判
`mnote_knowledge_rag_query` 返回给 agent 的 compact result 必须明确:
- `rawMetadata.keywords`、entity count、relation count 只是 provider 查询处理 / retrieval bookkeeping。
- OCR 是否真正暴露,以 `references[].quote``references[].contentDiagnostics.ocrTextExposed` 为准。
- 当 quote 为空或只有 Markdown 图片占位时,agent 必须说明“返回引用未暴露 OCR 原文”,不能声称 OCR 成功。
验收:
- 图片 wrapper quote `# image.png\n\n![image.png](<image.png>)` 被标记为 `quoteOnlyImagePlaceholder=true``ocrTextExposed=false`
- Agent 工具 compact result 不再把 raw metadata 当 OCR 成功证据;真实 Page AI 回答必须以该工具契约为准。
### P1:图片 ingest 让 OCR 文本进入 LightRAG 可引用内容
图片 source 不能只靠 Markdown wrapper 占位入库。需要二选一并以真实探针定案:
1. 优先方案:扩展 LightRAG `/documents/scan` 支持 `.png/.jpg/.jpeg/.webp/.bmp/.tif/.tiff`,并让 parser routing 对图片走 MinerU。MNote 对图片直接 symlink 原图入 `inputs/`registry 记录真实图片 source 和 LightRAG basename。
2. 兼容方案:如果上游 scan 暂不支持图片,MNote connector 调用 LightRAG parser 能力为图片生成 provider sidecar,并写入包含 OCR 文本的受控 `.md` ingestion document,同时保留图片 openAction 指向原 source。该 `.md` 是 LightRAG staging 派生物,不进入 MNote 文件树正文。
无论选哪条,必须保证:
- LightRAG chunk/reference 中能返回 OCR 文本,不只是图片占位。
- `blocks.jsonl` 能通过 registry 反查到原图并生成 `EvidenceLocator`
- reindex 会删除旧 wrapper doc,避免同一图片同时存在“占位 doc”和“OCR doc”。
验收:
- 重新索引目标图片后,`/query/data` 查询 `线程作用域` 的 references/chunks 至少一项包含 OCR 文本。
- `sourceRootRelativePath` 仍映射到 `新页面233155/image copy 6.png`
- citation/openAction 打开原图资源,而不是打开派生 wrapper。
### P1reference enrichment 与诊断
当 LightRAG 返回的 reference quote 为空、缺失或仅为图片占位时,MNote connector 应做有界补全:
- 先按 `chunk_id``kv_store_text_chunks.json`
- 再按 registry 的 `lightRagFilePath``inputs/__parsed__/<file>.parsed/*.blocks.jsonl`
- 对图片占位类 quote,不能直接拿占位去匹配 sidecar;应允许按 query terms / block text 补最相关 OCR block。
- 返回 `contentDiagnostics`,标明 `quoteSource=chunk|sidecar|missing|placeholder``ocrTextExposed``locatorSource`
验收:
- OCR sidecar 已存在但 chunk 未带内容时,工具仍能返回一段真实 OCR quote,并标记来源为 `sidecar`
- 若 sidecar 不存在,工具返回明确诊断,不把 metadata 当证据。
### P1:普通搜索 `includeOcr=true` 语义落地
`includeOcr=true` 不能继续是 no-op。推荐先做“普通搜索 + 资料库 OCR 有界补充”:
- 普通 Markdown / title / resource metadata 仍走本地轻索引。
-`includeOcr=true` 且普通结果不足 limit 时,追加查询 LightRAG source registry + sidecar/chunk 的 OCR 文本结果。
- 搜索结果必须标注 `boundary.kind=ordinary_local_search_with_knowledge_ocr`,单条结果标注 `matchSource=knowledge_rag_ocr`
- LightRAG 不可用时普通搜索不失败,只设置 `degraded=true``degradedReason=knowledge_rag_unavailable`
验收:
- `/api/search/documents` 查询 `线程作用域``includeOcr=true` 能返回目标图片或 owner page。
- `includeOcr=false` 保持原普通搜索语义。
- 返回结果包含可打开的 resource locator/citation,不只是一条不可点击文本。
### P2:健康检查与 UI 暴露
资料库状态面板需要区分:
- source 是否 registered。
- LightRAG doc 是否 processed。
- OCR text 是否进入 chunk/reference。
- sidecar 是否存在且可用于 locator。
- 普通搜索是否能通过 `includeOcr` 召回。
验收:
- 对目标图片能显示“processed but OCR text not exposed in reference/chunk”这类可操作状态,而不是只有绿灯。
## 5. 执行 Checklist
- [x] P0 工具契约:compact reference 增加 `contentDiagnostics` 并补单测。
- [x] P0 agent 工具契约 smoke:确认 compact result 不再把 raw metadata 当 OCR 成功证据。
- [x] P1 ingest spike:验证 LightRAG 直接 scan 图片扩展 vs MNote 调 parser 生成 OCR ingestion doc,选择一条实现。
- [x] P1 reindex migration:删除旧图片 wrapper doc 后重新索引目标图片。
- [x] P1 reference enrichmentsidecar/chunk/query term 补 quote,返回明确 `quoteSource`
- [x] P1 搜索:`includeOcr=true` 追加 knowledge OCR 命中,并保持 LightRAG 不可用时普通搜索降级。
- [x] P1 browser/API smoke`线程作用域` 在 knowledge-rag 和 `/api/search/documents` 两条入口都可召回并可打开来源。
- [x] P2 状态 UI:把 OCR 文本是否真正进入 reference/chunk 暴露成诊断项。
## 7. 验收证据
2026-06-07 已完成目标图片重建索引:
- registry`新页面233155/image copy 6.png` -> `lightRagDocId=doc-ac03e578a6c6af7eb0a3224276e4b954``lightRagFilePath=mnote-d0985c21239b677d-image copy 6.[mineru].png``lightRagStatus=processed`
- LightRAG status diagnostics`directImageScan=true``sidecarExists=true``ocrTextExposed=true``sidecarMeaningfulBlocks=2`
- `/api/knowledge-rag/query` 查询 `线程作用域`:首条 reference 映射到 `新页面233155/image copy 6.png``quoteSource=sidecar``contentDiagnostics.ocrTextExposed=true``locatorDegraded=false`quote 含 `线程作用域`
- `/api/search/documents` 查询 `线程作用域``includeOcr=true`:返回 1 条 `knowledge_rag_ocr` 命中,path 为 `新页面233155/image copy 6.png`snippet 含 `线程作用域`boundary 为 `ordinary_local_search_with_knowledge_ocr`
- `/api/search/documents` 查询 `线程作用域``includeOcr=false`:返回 0 条,boundary 保持 `ordinary_local_search`,证明普通搜索未被强依赖 LightRAG。
## 8. 当前禁止事项
- 不把 `rawMetadata.keywords` 当 source OCR 证据。
- 不恢复 LiteParse 为默认 fallback。
- 不把 OCR 文本写回用户 Markdown 正文。
- 不让普通搜索强依赖 LightRAG 才能返回 Markdown 页面结果。
- 不保留同一图片的旧占位 wrapper doc 与新 OCR doc 双索引状态。