13 KiB
13 KiB
Mindmap AI v2 实施计划(文档大纲 / 小结带引用 / 搜索补全)
目标:把当前“仅能对话并返回 Markdown 列表”的 AI,升级为可读可用的“文档驱动思维导图”能力:
- PDF/Word/PPT 按目录与大纲生成思维导图,并且节点可跳转到对应页/幻灯片;
- 基于文档内容生成小结/知识点,并附带可点击引用(页码/链接);
- 支持在节点上“搜索/查询后补完内容”(RAG + 可选联网检索)。
0. 现状与问题
0.1 当前实现(代码落点)
wolai-frontend/src/components/editor/blocks/MindmapSidebar.tsx:AI 面板目前是“本地 Ollama /api/chat 流式输出 + Markdown 解析为节点”。services/ingest_service:已具备 Supabase -> MinerU -> LightRAG 的自动入库链路(用于全文检索/RAG)。services/rag_gateway:封装了对 LightRAG 的 HTTP 调用(/query、/query/data),可作为统一 RAG 网关。wolai-frontend/src/app/onlyoffice/page.tsx:OnlyOffice 文档查看/编辑入口(目前用于 docx/pptx/xlsx 等)。wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx:节点超链接通过SET_NODE_HYPERLINK直接写入 URL。
0.2 为什么“离想象差很远”
当前 AI 只有“生成文本 -> 解析成节点”的能力,缺少:
- 与文档绑定:没有把 PDF/Word/PPT 的结构(目录/标题层级)变成导图;
- 可验证的引用:没有“这句话来自第几页/哪一段”,因此难以沉浸式阅读与回溯;
- 补全的检索依据:没有把“补完节点”变成“基于检索结果 + 引用”输出,容易胡编;
- 工程化形态:没有任务、进度、缓存、失败重试、可复用数据结构。
1. 用户故事与验收标准(以你的测试文件为准)
1.1 文档按目录/大纲生成导图(PDF/Word/PPT)
用户故事
- 我上传(或选中)一个文档(PDF/Word/PPT),点击“按大纲生成思维导图”,自动生成多级节点。
- 我点击任意节点,可以跳转到该文档对应页(PDF)或对应位置(Word/PPT 至少能定位页/提示页码,理想是直接跳转)。
验收
- 对
wolai-frontend/test/卤化反应原理_1-9.pdf:- 能生成至少 2 级结构(中心主题 -> 章节 -> 小节)。
- 至少章节级节点带可点击引用(页码/链接)。
- 点击节点后打开的 URL 包含
#page=<n>(PDF 以浏览器内建查看器为准)。
1.2 小结/知识点生成(带链接引用)
用户故事
- 我选中“生成小结”,AI 输出“关键结论/反应机理/注意点”,每条结论附带引用(页码链接或文档片段来源)。
验收
- 对
wolai-frontend/test/卤化反应原理测试.pdf:- 生成不少于 N(建议 8)条要点;
- 每条要点至少 1 个引用(页码/链接);
- 引用能点击打开对应 PDF 页。
1.3 搜索/查询后补完节点内容
用户故事
- 我选中一个/多个节点,输入“补完方向/问题”,AI 基于检索结果补充子节点或备注,附带引用。
验收
- 对同一 PDF 文档:
- “补完”后的内容至少包含 3 个子节点或 1 段结构化备注;
- 结论带引用(页码/链接);
- 不允许“无引用的长篇自由发挥”(默认强制引用)。
2. 总体方案(推荐架构)
核心原则:先结构化,再生成;先检索证据,再写结论;引用是第一公民。
2.1 三层能力拆分
- 文档解析层(Document -> Outline/Chunks)
- 输出:
DocOutline(层级标题 + 页码/位置)与DocChunks(可引用文本块)。
- 输出:
- RAG/生成层(Outline/Chunks -> Mindmap/Summary/Expansion)
- 输出:思维导图节点树(含引用)、小结节点(含引用)、补全子节点(含引用)。
- 渲染/交互层(Mindmap UI)
- 节点点击:打开引用的文档页/位置;支持“查看引用”“展开更多证据”。
2.2 数据来源优先级(PDF)
按可靠性排序:
- PDF 自带书签/目录(
pypdfoutline)→ 最靠谱(本次卤化反应原理_1-9.pdf没有 outline) - MinerU 解析结果(建议开启
return_content_list/return_middle_json)→ 可拿到更结构化的块,并可能带页信息 pypdf分页提取文本 + 标题检测(规则 + LLM 辅助)→ 兜底方案
3. 关键数据结构(建议新增/统一)
3.1 引用结构 NodeRef
用于节点的“可点击跳转”和“可追溯引用”:
export type NodeRef = {
kind: "pdf" | "docx" | "pptx" | "url";
assetId?: string; // 优先用 assetId,避免 URL 过期
fileUrl?: string; // public URL 或 signed URL(兜底)
page?: number; // PDF 页码(1-based)
slide?: number; // PPT 页码/幻灯片序号(1-based)
title?: string; // 引用标题(例如“2.1 卤化机理”)
snippet?: string; // 可选:引用片段
};
3.2 节点存储方式
- 短链(推荐):
node.data.refs: NodeRef[](自定义字段) - 展示用超链接:仍使用
SET_NODE_HYPERLINK写入一个可点击 URL(例如 PDF...#page=3) - 引用详情:写入
node.data.note或node.data.data.note(保持兼容)为 Markdown:- [p3] 证据片段...- [p5] ...
说明:simple-mind-map 对 data 的自定义字段容忍度较高,但要确保序列化/反序列化后不丢字段。
4. 具体功能方案
4.1 “按目录/大纲生成思维导图”
4.1.1 API(建议新增)
新增 Next Route(前端同域,避免跨域/鉴权麻烦):
POST /api/mindmap-ai/outline-to-mindmap- 入参:
{ assetId, documentId?, prefer: "bookmark" | "mineru" | "heuristic" } - 出参:
{ mindmapData, outline, refsSummary }
- 入参:
后台实现可以优先走 services/ingest_service 或直接复用其逻辑(后续可沉到 wolai-backend)。
4.1.2 解析策略(对测试 PDF 友好)
因为 卤化反应原理_1-9.pdf 没有书签:
- 使用
pypdf逐页提取文本(已有代码可参考services/ingest_service/app/services/auto_indexer.py); - 对每页文本做标题候选抽取(规则:编号标题如
1.1.1(一)等 + 行长/标点密度); - 用 LLM(可走 Ollama)把候选标题整理为层级结构,并返回
{title, level, page}; - 转换为 mindmap:中心主题=文件名/第一页大标题,子节点=章节;每个章节节点写入 hyperlink
fileUrl#page=<page>。
4.1.3 Word/PPT
阶段 1 先保证:
- Word/PPT 也能“生成大纲导图”,但跳转能力允许降级:
- 若 OnlyOffice 支持跳转 API:实现真实跳转;
- 若不支持:点击节点打开文档,并弹出“建议跳转页码/幻灯片序号”的提示(至少可用)。
(后续再把 Word/PPT 的“位置”提升为可跳转锚点)
4.2 “小结/知识点生成(带引用)”
4.2.1 证据来源:优先 LightRAG,其次本地分页文本
优先走 services/rag_gateway:
POST /rag/query:拿到response + references(LightRAG 会返回引用列表)POST /rag/graph:拿结构化分块/引用(用于“点开看证据/更多片段”)
如果 LightRAG 返回引用信息不足以映射到页码,需要补齐“页码映射”:
- 方案 A(推荐):在入库时把“每页”作为 chunk,并把
file_source + page写入可回传字段(需要改 ingest_service 装饰文本或分块入库方式) - 方案 B(兜底):在本地用
pypdf重新做“分页文本”,对引用片段做模糊匹配定位页码
4.2.2 输出形态
在 Mindmap 里提供两种落地方式:
- 生成到“备注”(适合长文本 + 引用列表)
- 生成到“子节点”(每条要点一个子节点,子节点携带
refs和 hyperlink)
默认要求:每条要点至少 1 个引用(无引用则标记为“待核验”,并提示用户继续检索)。
4.3 “搜索/查询后补完节点内容”
4.3.1 两种检索源(可配置)
- 本地文档库检索:LightRAG(默认)
- 联网检索:SearxNG(本仓库已存在 Docker 服务,可直接用)
4.3.1.1 SearxNG 接入约定(基于仓库现状)
仓库已存在 services/searxng-docker/.env,其中包含:
SEARXNG_BASE_URL=http://127.0.0.1:8889SEARXNG_API_TOKEN=...
建议接入方式:
- 前端不要直连 searxng(避免 token 暴露),通过 Next Route 代理:
POST /api/search/searxng- 入参:
{ q: string, count?: number, lang?: string } - 出参:
{ results: Array<{ title: string, url: string, snippet?: string, engine?: string }>}
SearxNG 查询接口(推荐 JSON):
GET ${SEARXNG_BASE_URL}/search?q=<query>&format=json&language=zh-CN&categories=general&safesearch=1
鉴权策略(需要实际跑通后确定,做成可配置):
- 方案 A:不加鉴权(本地内网服务)
- 方案 B:携带 token(例如
X-API-Key/Authorization: Bearer之一;以你当前 searxng 配置为准)
注意:SearxNG 返回结果字段不同版本略有差异,后端代理层要做一次“结果归一化”和去重(按 url)。
4.3.2 交互与输出
- 输入:用户选中节点 + “补完问题/方向”
- 系统 prompt 固定:强制输出结构化(Markdown 列表)+ 引用
- 输出策略:
- 子节点补全:把回答拆成 3~8 个子节点追加
- 备注补全:写入 note,并附引用列表
5. 前端 UI 改造建议(MindmapSidebar 的 AI 面板)
把当前“模型/地址/系统提示”改为“面向功能的工作流”,保留“高级设置”折叠:
- 从文档生成
- 选择文档资产(assetId)+ 生成按钮 + 进度(解析中/生成中/完成)
- 生成小结
- 可选:作用范围(整篇/选中节点对应章节)+ 要点数量 + 输出到(子节点/备注)
- 补完节点
- 输入框 + 检索源选择 + 输出到(子节点/备注)
同时在节点右键/工具栏增加:
- “打开引用”
- “查看引用(弹窗列出页码/片段)”
6. 工程落地步骤(里程碑)
建议按“先可用,再做强”的顺序推进。
M1(1~2 天):PDF 大纲导图(可跳页)
- 新增
/api/mindmap-ai/outline-to-mindmap(仅支持 PDF) - 实现 “pypdf 分页文本 + 标题候选 + LLM 整理层级”
- MindmapSidebar 增加“从 PDF 生成导图”入口(基于 assetId)
- 节点写入 hyperlink:
publicFileUrl#page=<n> - pw-tests:导入
卤化反应原理_1-9.pdf,断言生成节点数与#page=链接存在,并截图
M2(2~3 天):小结生成(强制引用)
- 接入
services/rag_gateway的/rag/query(前端通过 Next Route 代理) - 让小结输出“要点 + 引用”
- 引用映射到
#page=(先用本地分页匹配兜底) - pw-tests:对
卤化反应原理测试.pdf生成 N 条小结并截图
M3(2~4 天):搜索补全节点(RAG)
- AI 面板增加“补完节点”模式
- 选中节点作为上下文,拼接检索 query:LightRAG(文档内)+ SearxNG(联网)
- 新增
POST /api/search/searxng作为代理(隐藏 token + 统一返回格式) - 将 searxng 的
title/url/snippet作为“外部证据”,与 LightRAG 引用一起喂给模型生成 - 防胡编:无引用则提示“需要更多证据/换关键词”
- pw-tests:选中某节点补完,校验新增子节点与引用
M4(可选):Word/PPT 真跳转
- 调研 OnlyOffice 是否支持跳页/跳幻灯片 API(不支持则维持降级)
- 若支持:在
/onlyoffice页面接收page/slide参数并调用 DocsAPI 跳转
7. 风险与对策
- PDF 无书签(当前测试文件就是):必须做“文本标题抽取 + LLM 结构化”的兜底。
- 页码引用难:短期先用“本地分页匹配”;中期把“页级分块”纳入入库,引用直接带页码。
- URL 过期/权限:优先存
assetId,点击时再换取可用 URL(必要时扩展/api/media/signed-url支持 assetId)。 - 性能:解析/生成尽量放到后端(Next Route 或 wolai-backend),前端只跑轻量 UI;长任务使用 job 表/轮询。
8. 与 BlockNote 的集成点(后续)
- Slash Menu 可加入口(例如
/mind ai、/mind from pdf),插入/更新块可用 BlockNote 的insertOrUpdateBlockForSlashMenu与editor.updateBlock(见 BlockNote 官方文档的 Suggestion Menus 示例)。