# 知识库检索与分块增强 PRD ## 文档信息 | 项目 | 内容 | | --- | --- | | 状态 | 实施中 | | 版本 | 0.1 | | 日期 | 2026-08-11 | | 适用产品 | GoodBuddy 桌面端 | | 实施范围 | 第一阶段:可用、可见、可诊断;第二阶段:可调、可优化、可维护 | | 相关设计 | [本地文本向量模型与连接设计](../../architecture/local-text-embedding-model-design.md) | ## 1. 背景 GoodBuddy 已具备本地多知识库、文件与目录同步、网页导入、SQLite FTS5、 OpenAI 兼容向量模型、RRF 混合检索、知识图谱、任务状态和来源引用。现有实现 优先建立了本地数据主权、安全边界和跨 Runtime 工具授权,但用户仍难以稳定 获得“导入资料后即可准确问答”的体验。 当前主要问题不是缺少知识图谱,而是基础 RAG 链路缺少完整闭环: 1. 在对话中启用知识库只会开放搜索工具,是否检索仍由模型自行决定。 2. 默认向量检索关闭,中文全文检索对自然语言问法和同义表达的召回不足。 3. 向量请求失败会降级为全文检索,但知识库页面仍可能显示索引完成。 4. 大于 5,000 个向量分块的知识库会跳过向量召回。 5. 用户不能独立测试召回、查看各通道得分或确认实际送入模型的上下文。 6. 分块参数固定,缺少结构化、父子分块、分块预览和人工修正。 7. 引用只能阅读片段,不能查看完整上下文或打开原始来源。 本项目先完成稳定性和可观测性,再增加高级分块、重排与维护能力。知识图谱 继续作为可选召回通道,但不替代全文和向量检索的基础质量。 ## 2. 已确认的产品决策 1. 保持本地优先,不引入必须联网的托管知识库服务。 2. 保持 Electron Main、Preload、Renderer 的安全边界,Renderer 不直接读取 数据库、原文件或向量。 3. 保留“模型按需检索”,并新增“每次先检索”模式。后者必须由 Main 进程 预检索,不能只依赖提示词要求模型调用工具。 4. 知识库新建后不默认启用全部已有知识库;对话中的范围继续由用户显式选择。 5. 向量服务不可用时保留全文与中文检索,但必须返回明确降级状态。这是可见的检索通道 降级,不得自动切换应用托管模型、Ollama、云端 Provider 或其他向量模型。 6. 中文召回使用应用内可控的 CJK n-gram 索引,不新增远程服务依赖。 7. 混合检索保留 RRF 候选融合,并增加本地确定性重排、可选的 Cohere/Jina 兼容学习型重排、最低相关度和上下文预算。学习型重排失败时 安全降级,不影响全文、向量和图谱召回。 8. 向量搜索取消 5,000 分块静默失效,使用有界内存的分页扫描。在没有稳定 跨平台向量扩展前,接受本地 CPU 线性扫描,并持续显示性能诊断。 9. 向量索引兼容性同时校验 Provider、Model、维度和 Provider Fingerprint。 同名模型切换端点后,旧向量不能继续参与召回。Fingerprint 的完整模型、编码与 数据路径定义以[本地文本向量模型与连接设计](../../architecture/local-text-embedding-model-design.md) 为准。 10. 失败或取消的重建不能停用上一版已就绪索引。新索引只有完整校验成功后才 原子替换当前服务版本。 11. 分块设置属于知识库,修改后不会伪装为立即生效。用户需要显式重建索引。 12. 分块允许预览、编辑、启用、停用和删除。来源再次同步可能覆盖人工修改, UI 必须在修改前持续说明该行为。 13. 第一阶段和第二阶段均不新增付费或外部模型调用。现有 Embeddings 调用仍由 用户配置决定。 14. Ask 的运行时边界保持只读。知识库内容始终被标记为不可信证据, 不能成为系统指令。 ## 3. 目标 ### 3.1 用户目标 - 明确知道本次回答是否检索、检索了哪些知识库,以及是否发生降级。 - 在知识库页面输入真实问题,查看命中分块、通道、得分和最终上下文。 - 为不同文档选择适合的分块模式,并在导入前理解影响。 - 查看和修正错误分块,不需要删除并重新导入整个来源。 - 从回答引用查看完整上下文,并打开对应本地文件或网页。 - 在向量、解析或图谱失败时获得可恢复的状态和明确操作。 ### 3.2 产品目标 - 默认中文问法在没有向量模型时仍具有可用的关键词召回。 - 向量服务故障、大知识库和模型变更不再产生静默空结果。 - 建立可复现的检索调试入口,支持固定问题进行回归测试。 - 将解析、全文、向量和图谱状态拆分,避免“索引完成”误导。 - 为后续元数据过滤、远程 Rerank Provider 和自动评测保留稳定契约。 ### 3.3 质量目标 - 中文同义改写测试集的 Recall@5 相比现有全文检索基线提升至少 30%。 - 检索测试结果必须在本机重复执行时保持稳定排序。 - 任意向量失败都必须在检索诊断或任务状态中可见。 - 10,000 个分块的知识库不得因固定上限返回空向量结果。 - 每条展示引用都能找到仍存在且属于已授权知识库的分块和文档。 - 检索输出和上下文拼装均遵守字符、结果数和 IPC 大小上限。 ## 4. 非目标 本项目不包含: - 团队共享知识库、SSO、SCIM 或跨设备同步。 - 企业级 ACL、文档级角色继承和远程权限同步。 - 云端网站爬虫、Notion、飞书、语雀等第三方连接器。 - MinerU、PaddleOCR-VL 或其他远程文档解析服务。 - 专用向量数据库、外部 Elasticsearch 或打包平台原生向量扩展。 - 托管重排服务账户、计费或供应商绑定;仅提供通用兼容接口配置。 - 自动问题生成、FAQ 生成和训练数据标注平台。 - 完整 RAG 离线评测平台。第二阶段只提供手动检索测试与可导出的诊断信息。 - 在应用内高保真渲染所有原始 Office 和 PDF 文档。 ## 5. 竞品基线与 GoodBuddy 定位 截至 2026-08-11,Dify、FastGPT 和 RAGFlow 的公开文档均把检索测试、可配置 分块和可调检索参数作为知识库基础能力: | 能力 | Dify | FastGPT | RAGFlow | GoodBuddy 本期 | | --- | --- | --- | --- | --- | | 检索测试 | 支持 | 支持 | 支持 | 第一阶段支持 | | Top K / 阈值 | 支持 | 支持 | 支持 | 第一阶段支持 | | 全文 + 向量 | 支持 | 支持 | 支持 | 已有,第一阶段增强中文 | | Rerank | 模型 Rerank | 模型 Rerank | 模型 Rerank | 本地确定性与可选兼容模型重排 | | 父子分块 | 支持 | 可通过索引与大分块组合 | 支持多种切分策略 | 第二阶段支持 | | 分块维护 | 支持内容维护 | 支持数据维护 | 支持块级检查 | 第二阶段支持 | | 深度文档理解 | 中等 | 中等 | 强 | 继续复用本地解析与 OCR | | 本地目录监听 | 非核心 | 非核心 | 非核心 | GoodBuddy 差异化能力 | | 本地可编辑图谱 | 非核心 | 非核心 | 部分版本支持 GraphRAG | GoodBuddy 差异化能力 | 本期不复制竞品的云端工作流平台,而是将其成熟 RAG 交互映射为桌面、本地、 受控的数据链路。 参考公开文档: - Dify Knowledge: - Dify 检索测试: - Dify 分块设置: - FastGPT 知识库搜索方案和参数: - RAGFlow Dataset 配置: - RAGFlow 检索测试: ## 6. 信息架构 知识工作区继续使用主从布局和现有四个页签: ```text 知识库 ├─ 文档与来源 │ ├─ 来源管理 │ ├─ 检索测试入口 │ ├─ 文档状态 │ └─ 分块查看与维护 ├─ 知识图谱 ├─ 任务中心 └─ 设置 ├─ 检索设置 ├─ 分块设置 └─ 图谱设置 ``` “检索测试”是当前知识库的高频诊断操作,通过知识库标题区次操作打开独立 工作台,不新增第五个一级页签。 全局向量模型仍在“设置 → 模型连接 → 向量模型”中配置。应用托管本地模型、 用户自行安装的 Ollama/自托管服务和云端兼容服务的界面、数据路径及切换语义以 [本地文本向量模型与连接设计](../../architecture/local-text-embedding-model-design.md) 为准,知识库页面只显示当前模型、索引兼容性、覆盖率和重建操作。 对话输入区的知识范围弹层包含: 1. 已启用知识库多选。 2. 检索方式:模型按需检索、每次先检索。 3. 当前范围为空、索引降级或向量未配置时的短说明。 ## 7. 第一阶段:可用、可见、可诊断 ### 7.1 检索方式 新增请求级 `knowledgeRetrievalMode`: | 值 | 用户文案 | 行为 | | --- | --- | --- | | `auto` | 模型按需检索 | 保留当前 `knowledge_search` 工具,由模型决定是否调用 | | `always` | 每次先检索 | Main 在启动 Runtime 前使用原始用户问题检索一次,再把有界证据作为不可信上下文提供给 Runtime | 规则: - 没有启用知识库时不显示为“已检索”。 - `always` 预检索后仍保留 `knowledge_search`,模型可以改写查询再次检索。 - 预检索零结果不阻止回答,但必须显示“已检索,未找到相关内容”。 - 预检索失败不得自动扩大范围或访问未选知识库。 - 图片生成能力不执行知识预检索。 - Ask 和 Execute 使用相同的只读检索范围。 ### 7.2 中文全文检索 在现有 `unicode61` FTS 之外增加本地 CJK n-gram 检索文本: - 连续汉字生成二元词组,保留必要的单字符短查询回退。 - 拉丁字母和数字使用 NFKC、大小写归一化和现有 FTS。 - 多个查询词使用召回优先的 OR 候选,再通过覆盖率和短语命中重排。 - 不把整句中文问题转换成“所有汉字必须同时出现”的条件。 - 索引更新、分块编辑、停用和删除必须同步更新 CJK 索引。 - 数据库迁移必须为已有分块有界回填,不要求用户重新导入。 ### 7.3 检索设置 每个知识库保存以下设置: | 字段 | 范围 | 默认值 | | --- | --- | --- | | `topK` | 1 至 20 | 6 | | `minimumVectorSimilarity` | 0 至 1 | 0(不过滤低相似度结果) | | `ftsWeight` | 0 至 2 | 1 | | `vectorWeight` | 0 至 2 | 1 | | `graphWeight` | 0 至 2 | 0.8 | | `candidateMultiplier` | 2 至 10 | 4 | | `contextMaxCharacters` | 2,000 至 48,000 | 16,000 | | `adjacentChunkCount` | 0 至 2 | 0 | | `localRerankEnabled` | 布尔值 | false | 至少一个召回通道权重大于 0。图谱未启用时,图谱权重只读显示为不可用。 向量模型未启用或索引不兼容时,向量权重保留但当前请求降级。 ### 7.4 检索测试工作台 用户输入最多 4,000 字符的问题,工作台显示: - 当前知识库和生效设置。 - 总耗时、各通道耗时和候选数。 - 请求通道、实际使用通道和降级原因。 - 最终结果序号、文档、定位、片段和最终相关度。 - FTS、CJK、向量、图谱的独立排名与向量相似度。 - 本地重排前后排名。 - 相邻分块或父块合并后的实际上下文。 - “查看分块”“打开来源”操作。 检索测试不创建聊天消息、不写入会话历史、不调用 LLM,也不改变知识库内容。 ### 7.5 可扩展向量搜索 移除“超过 5,000 个候选则返回空结果”的逻辑: 1. 按稳定游标分页读取同一知识库、Provider、Model 和维度的向量。 2. 每批计算余弦相似度。 3. 内存中只保留候选上限所需的最佳结果。 4. 支持取消和应用关闭。 5. 维度、校验和或索引状态不匹配的向量不参与结果。 6. 诊断返回扫描数量和向量耗时。 7. Provider Fingerprint 不匹配时标记索引不兼容,不回退到同名旧模型向量。 线性扫描是本期跨平台保底实现。后续接入稳定向量扩展时不得改变上层契约。 ### 7.6 状态与降级 文档状态拆分为: | 状态 | 含义 | | --- | --- | | 解析 | 等待、运行、完成、失败 | | 全文索引 | 等待、完成、失败 | | 向量索引 | 未启用、等待、运行、完成、失败、不兼容 | | 图谱 | 未启用、按需、等待、运行、完成、失败 | 知识库汇总不得仅以“文档 metadata 不是 failed”计算完成。UI 至少显示: - 可用于全文检索的文档数。 - 已完成向量化的文档数。 - 失败文档数。 - 当前向量模型与索引是否兼容。 降级事件包括: - 未配置向量模型。 - 查询向量生成失败。 - 当前模型没有匹配索引。 - 部分文档向量失败。 - 图谱关闭或没有证据。 - 结果被相关度或上下文预算过滤。 ### 7.7 引用查看 每条引用增加稳定 `chunkId`、最终相关度和检索通道。用户展开引用后可以: 1. 查看命中分块。 2. 查看相邻分块或父块形成的完整上下文。 3. 查看知识库、文档、来源和定位。 4. 对本地文件调用 Main 校验后的 `shell.openPath`。 5. 对 HTTP(S) 来源调用 Main 校验后的外部打开。 Renderer 不能提交任意路径或 URL。Main 必须根据 `libraryId`、`documentId` 和 `chunkId` 重新读取已保存来源并验证归属。 界面把该列表描述为“本次检索证据”或“已查阅来源”,不把仅被召回的片段 自动宣称为回答中某个句子的精确出处。后续只有经过稳定 Citation ID 校验的 句级标注才能使用更强的“该句引用”语义。 ## 8. 第二阶段:可调、可优化、可维护 ### 8.1 分块模式 每个知识库选择一种模式: | 模式 | 行为 | 适用内容 | | --- | --- | --- | | 固定分块 | 按目标长度、重叠和自然边界切分 | 普通文本、日志、代码 | | 结构分块 | 优先保持解析 section、Markdown 标题和段落结构 | 手册、制度、长文档 | | 父子分块 | 小块用于召回,大块用于模型上下文 | 长篇说明、合同、研究资料 | 设置: | 字段 | 范围 | 默认值 | | --- | --- | --- | | `mode` | `fixed` / `structure` / `parent-child` | `structure` | | `targetCharacters` | 400 至 8,000 | 1,600 | | `overlapCharacters` | 0 至目标长度的 40% | 160 | | `parentCharacters` | 1,600 至 16,000 | 4,800 | | `childCharacters` | 300 至 4,000 | 900 | 父子分块要求: - 父块只作为上下文,不进入 FTS、CJK 或向量候选。 - 子块用于召回,并保存父块关联。 - 引用默认突出子块,同时允许查看父块全文。 - 父块和子块总输出仍受上下文预算限制。 ### 8.2 本地与学习型重排 第二阶段提供不调用外部模型的可选本地重排。评分特征包括: - 原始 RRF 排名。 - 中文和拉丁词覆盖率。 - 完整短语命中。 - 文档标题、分块标题和路径命中。 - 向量相似度。 - 同文档重复结果惩罚。 重排结果必须: - 归一化为 0 至 1 的 `relevance`。 - 对相同输入和索引保持确定性。 - 保留重排前排名和各特征得分用于诊断。 - 在关闭时完全保留原有 RRF 排序。 学习型模式使用 Main 进程中的 Cohere/Jina 兼容客户端,凭据只进入加密设置和 Main 进程。请求限制为 100 个候选、每个候选 8,000 字符,并具有 15 秒默认 超时、取消传播和有界响应。失败时可回退本地重排或 RRF,并只返回脱敏诊断。 ### 8.3 相邻分块合并与上下文预算 - 对最终候选按文档和 ordinal 合并相邻分块。 - 不把同一分块重复放入上下文。 - 保留每个命中分块的引用定位。 - 按相关度从高到低消耗 `contextMaxCharacters`。 - 单个超长父块按安全边界截断并标记 `truncated`。 - 不允许低排名结果挤掉已经选中的高排名证据。 ### 8.4 分块管理 文档行提供“查看分块”,打开分块管理对话框: - 显示 ordinal、角色、标题、定位、字符数、启用状态和内容预览。 - 支持分页和文档内搜索。 - 支持编辑内容。 - 支持启用或停用。 - 支持删除,并说明来源同步可能重新创建分块。 - 编辑后更新 FTS 和 CJK 索引,并使旧向量失效。 - 已配置向量模型时,编辑操作完成后为该文档重建向量。 - 删除最后一个可检索分块时,文档显示“无可检索内容”,不能显示完全就绪。 高影响删除使用具体确认文案。普通启停使用共享 Switch,并声明 `role="switch"`。 ### 8.5 单文档与全库重建 - 单文档重建重新读取来源、解析、分块、全文索引、向量和图谱。 - 全库重建按来源顺序执行,并显示文档级进度。 - 修改分块模式或关键参数后,知识库显示“设置已更新,等待重建”。 - 重建采用文档级原子替换,失败时保留上一版可用分块和向量。 - 用户可以取消全库重建;已经成功替换的文档保持可用。 - 文件不存在、网页失败或 OCR 不可用时保留可重试错误。 - 单来源允许的 2,000 个文件必须全部参与增量同步、删除检测和校验和跳过, 不受普通页面 500 项列表上限影响。 ## 9. 数据模型与兼容性 ### 9.1 KnowledgeBase 知识库增加版本化设置: ```ts type KnowledgeRetrievalSettings = { version: 1 topK: number minimumVectorSimilarity: number ftsWeight: number vectorWeight: number graphWeight: number candidateMultiplier: number contextMaxCharacters: number adjacentChunkCount: number localRerankEnabled: boolean } type KnowledgeChunkingSettings = { version: 1 mode: 'fixed' | 'structure' | 'parent-child' targetCharacters: number overlapCharacters: number parentCharacters: number childCharacters: number } ``` SQLite 使用 JSON 列保存设置,读写均经过共享 Zod Schema。迁移后的旧知识库使用 与当前行为接近的兼容默认值,不自动重建已有分块。 ### 9.2 Chunk 分块增加以下语义: ```ts type KnowledgeChunkRole = 'standalone' | 'parent' | 'child' type KnowledgeChunkState = { enabled: boolean role: KnowledgeChunkRole parentChunkId?: string manuallyEdited: boolean updatedAt?: string } ``` 实现可以使用显式列或受校验 metadata,但查询必须为旧数据提供默认值: - 缺少 `enabled` 时视为 `true`。 - 缺少 `role` 时视为 `standalone`。 - 父块不参与召回索引。 ### 9.3 检索响应 ```ts type KnowledgeRetrievalResponse = { query: string durationMs: number settings: KnowledgeRetrievalSettings diagnostics: { requestedChannels: KnowledgeRetrievalChannel[] usedChannels: KnowledgeRetrievalChannel[] degradedChannels: Array<{ channel: KnowledgeRetrievalChannel reason: string }> candidateCounts: Partial> } results: KnowledgeRetrievalResult[] context: { characterCount: number truncated: boolean groups: KnowledgeContextGroup[] } } ``` 错误、诊断和引用不得包含 API Key、Authorization Header、完整私人文档或未经 限制的 Provider 响应。 ## 10. IPC 与安全边界 新增或扩展的 IPC: - `knowledge:retrieve` - `knowledge:settings:update` - `knowledge:document:rebuild` - `knowledge:library:rebuild` - `knowledge:chunks:list` - `knowledge:chunk:update` - `knowledge:chunk:delete` - `knowledge:reference:context` - `knowledge:reference:open` 要求: - 所有输入由共享 Zod Schema 校验。 - 所有处理器校验可信 Renderer sender。 - ID 必须重新检查知识库、来源、文档和分块归属。 - 列表使用有界分页,单次最多返回 200 个分块。 - 内容编辑限制单块最大字符数。 - 外部打开只接受数据库已保存的本地普通文件或 HTTP(S) URL。 - 不向 Preload 暴露原始数据库、Electron `shell` 或文件系统 API。 - 更新与重建遵守取消、超时、应用关闭和有界错误规则。 ## 11. 交互与无障碍 - 复用 `PageTabs`、`SegmentedControl`、共享 Switch 和应用通知。 - 检索方式是互斥选项,使用 `SegmentedControl` 或语义化单选组。 - 分块启停是持久二元状态,使用 `role="switch"`。 - 检索结果列表使用可访问名称,得分不得只用颜色表达。 - 检索工作台打开后焦点进入问题输入框,关闭后返回触发按钮。 - 分块编辑和删除对话框遵守焦点陷阱、Escape 和焦点恢复。 - 异步成功使用应用通知;字段错误、检索进度和可就地恢复错误保留在工作台。 - 窄窗口下检索结果改为单列,配置摘要保持可读,不隐藏降级状态。 ## 12. 失败与恢复 | 场景 | 行为 | | --- | --- | | 向量查询失败 | 继续已配置的全文、中文和图谱通道,显示降级原因,不切换向量 Provider 或模型 | | 部分文档无向量 | 使用可用文档,显示完成数和失败数 | | CJK 索引迁移失败 | 回滚迁移,不损坏旧 FTS | | 重排失败 | 回退 RRF 排序并显示诊断 | | 分块编辑后向量失败 | 保留编辑和全文索引,标记向量失败 | | 单文档重建失败 | 保留上一版可用索引 | | 同名模型端点变化 | 旧 Fingerprint 索引标记不兼容,等待重建 | | 新向量重建失败 | 保留上一版就绪向量继续服务,单独记录失败尝试 | | 原文件已移动 | 显示来源不可用,提供重试或移除 | | 引用对象已删除 | 显示引用已失效,不打开任意替代路径 | | 上下文超预算 | 按排名截断并明确标记 | | 请求取消或应用关闭 | 停止新批次,释放句柄,不留下半替换索引 | ## 13. 埋点与评测 GoodBuddy 不上传私人检索查询或文档内容。本地诊断至少记录有界统计: - 检索模式。 - 启用知识库数量。 - 各通道候选数和耗时。 - 是否发生降级。 - 最终结果数和上下文字符数。 - 重建文档数、成功数、失败数和取消状态。 手动验收使用仓库内不含私人内容的固定样例集,覆盖: - 中文自然语言改写和同义词。 - 中英文混合产品名。 - 精确编号、路径和代码标识。 - 多文档冲突信息。 - 无答案问题。 - 10,000 个以上分块。 - 向量服务断开和模型维度变化。 ## 14. 实施顺序 ### 14.1 第一阶段 1. 共享设置、请求和检索响应契约。 2. SQLite 迁移和 CJK 索引。 3. 可扩展向量扫描、检索诊断和状态模型。 4. 检索设置与工作台。 5. 对话“每次先检索”。 6. 引用上下文和打开来源。 7. 第一阶段单元、IPC 和 Renderer 测试。 ### 14.2 第二阶段 1. 结构分块和父子分块。 2. 本地重排与相关度。 3. 相邻块合并和上下文预算。 4. 分块预览、编辑、启停和删除。 5. 单文档与全库重建。 6. 第二阶段回归、性能和生产构建验证。 ## 15. 验收标准 ### 15.1 第一阶段 - 用户可在对话中选择“模型按需检索”或“每次先检索”。 - “每次先检索”在 Runtime 启动前产生检索诊断和引用,即使模型未调用工具。 - 未配置向量模型时,中文改写问题仍能通过 CJK 索引召回相关分块。 - 向量查询失败时回答可继续,界面明确显示已降级。 - 应用托管模型、Ollama 和云端向量连接之间不会自动切换;实际数据路径持续可见。 - 10,000 个分块的向量测试能够返回正确 Top K,不出现固定上限空结果。 - 同名模型切换端点后,不会读取 Fingerprint 不匹配的旧向量。 - 重建失败时,上一版已就绪向量仍能继续召回。 - 包含 2,000 个文件的目录同步能够处理第 501 至 2,000 个文档的修改与删除。 - 检索测试展示通道、候选数、排名、相关度、上下文和降级原因。 - 引用可以查看完整上下文并打开 Main 校验后的来源。 - 查询长度在共享契约、IPC、MCP 和数据库层保持一致。 ### 15.2 第二阶段 - 用户可选择固定、结构或父子分块并显式重建。 - 父块不参与召回,子块命中后可提供父块上下文。 - 本地重排可以开启或关闭,并显示重排前后排名。 - 上下文严格遵守字符预算,重复和相邻片段按规则合并。 - 用户可预览、编辑、启停和删除分块。 - 分块修改后 FTS、CJK 和向量状态保持一致。 - 单文档重建失败不会破坏上一版可用索引。 - 所有新增操作可用键盘完成,并在浅色、深色和窄窗口下可用。 ### 15.3 工程验证 所有源代码变更完成后必须通过: ```text npm test npm run typecheck npm run lint npm run build ``` 外部或付费模型调用不属于自动验证,只有获得明确授权后才运行。