docs: specify knowledge retrieval enhancements

This commit is contained in:
lofyer
2026-08-12 21:45:20 +08:00
parent 6a44335238
commit e0e5a8c1b3
7 changed files with 1236 additions and 8 deletions
@@ -0,0 +1,591 @@
# 知识库检索与分块增强 PRD
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 状态 | 实施中 |
| 版本 | 0.1 |
| 日期 | 2026-08-11 |
| 适用产品 | GoodBuddy 桌面端 |
| 实施范围 | 第一阶段:可用、可见、可诊断;第二阶段:可调、可优化、可维护 |
## 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. 向量服务不可用时保留全文检索,但必须返回明确降级状态。
6. 中文召回使用应用内可控的 CJK n-gram 索引,不新增远程服务依赖。
7. 混合检索保留 RRF 候选融合,并增加本地确定性重排、可选的
Cohere/Jina 兼容学习型重排、最低相关度和上下文预算。学习型重排失败时
安全降级,不影响全文、向量和图谱召回。
8. 向量搜索取消 5,000 分块静默失效,使用有界内存的分页扫描。在没有稳定
跨平台向量扩展前,接受本地 CPU 线性扫描,并持续显示性能诊断。
9. 向量索引兼容性同时校验 Provider、Model、维度和 Provider Fingerprint。
同名模型切换端点后,旧向量不能继续参与召回。
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-11Dify、FastGPT 和 RAGFlow 的公开文档均把检索测试、可配置
分块和可调检索参数作为知识库基础能力:
| 能力 | Dify | FastGPT | RAGFlow | GoodBuddy 本期 |
| --- | --- | --- | --- | --- |
| 检索测试 | 支持 | 支持 | 支持 | 第一阶段支持 |
| Top K / 阈值 | 支持 | 支持 | 支持 | 第一阶段支持 |
| 全文 + 向量 | 支持 | 支持 | 支持 | 已有,第一阶段增强中文 |
| Rerank | 模型 Rerank | 模型 Rerank | 模型 Rerank | 本地确定性与可选兼容模型重排 |
| 父子分块 | 支持 | 可通过索引与大分块组合 | 支持多种切分策略 | 第二阶段支持 |
| 分块维护 | 支持内容维护 | 支持数据维护 | 支持块级检查 | 第二阶段支持 |
| 深度文档理解 | 中等 | 中等 | 强 | 继续复用本地解析与 OCR |
| 本地目录监听 | 非核心 | 非核心 | 非核心 | GoodBuddy 差异化能力 |
| 本地可编辑图谱 | 非核心 | 非核心 | 部分版本支持 GraphRAG | GoodBuddy 差异化能力 |
本期不复制竞品的云端工作流平台,而是将其成熟 RAG 交互映射为桌面、本地、
受控的数据链路。
参考公开文档:
- Dify Knowledge
<https://docs.dify.ai/en/use-dify/knowledge/readme>
- Dify 检索测试:
<https://docs.dify.ai/en/use-dify/knowledge/test-retrieval>
- Dify 分块设置:
<https://docs.dify.ai/en/use-dify/knowledge/create-knowledge/chunking-and-cleaning>
- FastGPT 知识库搜索方案和参数:
<https://doc.fastgpt.io/docs/introduction/guide/knowledge_base/dataset_engine>
- RAGFlow Dataset 配置:
<https://ragflow.io/docs/configure_knowledge_base>
- RAGFlow 检索测试:
<https://ragflow.io/docs/run_retrieval_test>
## 6. 信息架构
知识工作区继续使用主从布局和现有四个页签:
```text
知识库
├─ 文档与来源
│ ├─ 来源管理
│ ├─ 检索测试入口
│ ├─ 文档状态
│ └─ 分块查看与维护
├─ 知识图谱
├─ 任务中心
└─ 设置
├─ 检索设置
├─ 分块设置
└─ 图谱设置
```
“检索测试”是当前知识库的高频诊断操作,通过知识库标题区次操作打开独立
工作台,不新增第五个一级页签。
对话输入区的知识范围弹层包含:
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<Record<KnowledgeRetrievalChannel, number>>
}
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. 失败与恢复
| 场景 | 行为 |
| --- | --- |
| 向量查询失败 | 继续全文和图谱检索,显示降级原因 |
| 部分文档无向量 | 使用可用文档,显示完成数和失败数 |
| 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 索引召回相关分块。
- 向量查询失败时回答可继续,界面明确显示已降级。
- 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
```
外部或付费模型调用不属于自动验证,只有获得明确授权后才运行。
@@ -0,0 +1,523 @@
# 知识库检索与分块增强 User Stories
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 状态 | 实施中 |
| 版本 | 0.1 |
| 日期 | 2026-08-11 |
| 关联 PRD | [知识库检索与分块增强 PRD](knowledge-rag-enhancement-prd.md) |
## 1. 角色
### 1.1 普通知识使用者
已经导入公司制度、产品手册或项目资料,希望直接提问并得到稳定、带来源的回答,
不需要理解向量、RRF 或分块算法。
### 1.2 知识库维护者
负责导入、同步和清理资料,需要知道哪些文档成功、哪些索引失败,以及如何修复
错误解析或错误分块。
### 1.3 RAG 调试者
需要用真实问题验证召回,比较不同参数和通道,定位“文档里有但没有命中”的
原因。
### 1.4 本地与内网用户
不能把资料上传到外部知识库服务,希望全文检索、分块、重排和诊断均在本机
完成,只在显式配置 Embeddings 后发送有界文本。
## 2. Epic A:明确控制是否检索
### US-A1 模型按需检索
作为普通知识使用者,我希望保留由模型判断是否需要检索的模式,以便一般闲聊
不会产生不必要的知识搜索。
验收:
- Given 当前启用了至少一个知识库并选择“模型按需检索”
- When 用户发送问题
- Then Main 只向本次请求开放已选知识库的只读搜索能力
- And 模型没有调用知识搜索时,不显示虚假的“已检索”
- And 未选中的知识库不可被工具参数扩大范围
### US-A2 每次先检索
作为普通知识使用者,我希望选择“每次先检索”,以便模型不能跳过已启用的
知识库。
验收:
- Given 当前启用了至少一个知识库并选择“每次先检索”
- When 用户发送文本问题
- Then Main 在 Runtime 启动前使用原始问题执行一次有界检索
- And 命中证据以不可信上下文进入 Runtime
- And 模型仍可通过只读工具执行后续改写检索
- And 页面明确显示“已预检索”“零结果”或“已降级”
- And 图片生成请求不执行知识预检索
### US-A3 请求级范围
作为普通知识使用者,我希望每次请求只使用我勾选的知识库,以免不相关资料
干扰回答。
验收:
- 新建知识库后只新增该知识库到当前选择,不自动重新启用已取消的知识库
- 删除知识库后从当前范围中移除对应 ID
- 同一请求最多启用 20 个知识库
- 对话输入区持续显示已选数量和检索方式
- 范围为空时检索方式不产生误导状态
## 3. Epic B:检索可见、可诊断
### US-B1 打开检索测试
作为 RAG 调试者,我希望在当前知识库直接输入问题并测试,以便不通过聊天模型
也能验证索引。
验收:
- 知识库标题区提供“测试检索”次操作
- 工作台打开后焦点进入查询输入框
- 查询最多 4,000 字符
- 测试不创建聊天消息、任务成果或模型调用
- 关闭工作台后焦点返回触发按钮
### US-B2 查看通道诊断
作为 RAG 调试者,我希望看到每种检索通道的结果和降级原因,以便判断问题来自
全文、向量还是图谱。
验收:
- 结果显示请求通道和实际使用通道
- 结果显示 FTS/CJK、向量和图谱候选数
- 结果显示总耗时和有界通道耗时
- 向量未配置、请求失败或索引不兼容时显示明确原因
- 不在错误或诊断中显示 API Key、Authorization 或完整文档
### US-B3 查看排名与上下文
作为 RAG 调试者,我希望看到候选排名、最终相关度和送入模型的上下文,以便
解释最终回答为什么使用这些资料。
验收:
- 每条结果显示文档、定位、片段和最终排名
- 可用时显示全文、向量、图谱独立排名和向量相似度
- 启用本地重排后显示重排前排名
- 展示相邻块或父块合并后的上下文
- 展示上下文字符数、预算和截断状态
### US-B4 零结果诊断
作为普通知识使用者,我希望零结果时获得具体原因,而不是只有空列表。
验收:
- 区分“知识库为空”“索引不可用”“查询无命中”“被阈值过滤”
- 提供修改关键词、检查状态或调整阈值的下一步说明
- 零结果不显示为首次使用空状态
- 检索测试保留原查询和设置,方便再次执行
## 4. Epic C:中文与混合检索
### US-C1 中文自然语言召回
作为中文用户,我希望不用输入原文中的连续短语,也能找到表达相同意思的内容。
验收:
- 中文索引生成连续二元词组
- 中文查询不会要求所有不同汉字同时出现
- 短查询具有有界单字回退
- 中英文、数字和产品标识混合查询仍能召回
- 相同查询和索引产生稳定排序
### US-C2 向量服务降级
作为本地与内网用户,我希望向量服务断开时仍可使用全文搜索,同时清楚知道
语义召回不可用。
验收:
- 查询向量失败不阻止 FTS/CJK 和图谱检索
- 检索响应包含向量降级原因
- 文档状态不把向量失败显示成全部完成
- 同名模型切换端点后,Fingerprint 不匹配的旧向量不得参与召回
- 重建失败时,上一版已就绪向量继续服务
- 修复配置并重建后,降级状态消失
- 故障信息经过脱敏
### US-C3 大知识库向量检索
作为知识库维护者,我希望超过 5,000 个分块后语义搜索仍然工作。
验收:
- 向量分批扫描没有固定 5,000 分块空结果
- 只保留所需最佳候选,内存不会随全库候选等比例增长
- 扫描支持取消和应用关闭
- 10,000 个以上分块的测试返回正确 Top K
- 诊断显示扫描数量与耗时
### US-C4 大目录完整同步
作为知识库维护者,我希望包含 2,000 个文件的目录也能完整增量同步,以免后半
部分文档长期保留旧内容。
验收:
- 第 501 至 2,000 个文档参与校验和比较
- 未变化文档不会重复解析和向量化
- 已删除文件对应文档会被移除
- 页面分页上限不影响后台同步完整性
### US-C5 调整召回参数
作为 RAG 调试者,我希望调整 Top K、最低相关度和通道权重,以便适配不同知识
类型。
验收:
- Top K、阈值、候选倍数和权重具有明确范围和默认值
- 至少一个召回通道权重大于 0
- 图谱关闭时图谱权重不可生效并说明原因
- 设置持久化到当前知识库,不影响其他知识库
- 非法输入不能跨 IPC
## 5. Epic D:真实索引状态
### US-D1 查看分阶段状态
作为知识库维护者,我希望分别看到解析、全文、向量和图谱状态,以便准确判断
文档能否使用。
验收:
- 文档不再用单个“ready”代表所有索引完成
- 全文完成但向量失败时,明确显示“全文可用、向量失败”
- 向量未启用与向量失败是不同状态
- 图谱按需、未启用和失败是不同状态
- 汇总显示全文可用数、向量完成数和失败数
### US-D2 修复失败文档
作为知识库维护者,我希望单独重建失败文档,而不是重新同步整个目录。
验收:
- 文档行提供“重建文档”
- 重建重新执行解析、分块、全文、向量和图谱
- 失败时保留上一版可用索引
- 完成后更新任务和状态
- 原文件不存在时保留可重试错误
### US-D3 修改设置后重建
作为知识库维护者,我希望分块设置修改后明确提示需要重建,以免误以为旧文档
已经使用新设置。
验收:
- 保存关键分块设置后显示“等待重建”
- 设置保存本身不删除现有索引
- 用户可选择全库重建
- 全库重建可取消
- 已成功替换的文档继续可用
## 6. Epic E:高级分块
### US-E1 固定分块
作为知识库维护者,我希望配置目标长度和重叠,以便处理日志、代码或简单文本。
验收:
- 目标长度为 400 至 8,000 字符
- 重叠不超过目标长度的 40%
- 优先在自然边界切分
- 每个块保留来源 section、定位和 ordinal
- 旧知识库迁移后不自动改变已有分块
### US-E2 结构分块
作为知识库维护者,我希望分块尽量保持标题和段落结构,以便命中片段保留语义。
验收:
- 优先保持解析 section
- Markdown 标题能够成为分块 heading
- 标题随子段落进入索引元数据
- 超长 section 仍按有界规则继续切分
- 空标题和空段落不创建分块
### US-E3 父子分块
作为 RAG 调试者,我希望小块负责准确召回、大块负责完整上下文,以便兼顾精度
和完整性。
验收:
- 父块和子块具有稳定关系
- 父块不直接进入 FTS/CJK/向量候选
- 子块命中后可返回父块上下文
- 引用突出实际命中的子块
- 父块输出仍受上下文预算和截断限制
## 7. Epic F:重排与上下文
### US-F1 本地重排
作为本地与内网用户,我希望在不调用外部模型的情况下改善候选排序。
验收:
- 本地重排默认关闭并可按知识库开启
- 使用 RRF、词覆盖、短语、标题、路径、向量和重复惩罚等确定性特征
- 结果相关度归一化到 0 至 1
- 检索测试显示重排前后排名
- 关闭时保持原 RRF 行为
- UI 不把本地算法描述为 AI Rerank 模型
### US-F1.1 学习型重排
作为需要更高排序质量的用户,我希望可选择兼容的学习型重排模型,并在服务
不可用时继续获得本地结果。
验收:
- 模式明确区分关闭、本地规则和学习型重排
- Main 最多发送 100 个候选,每个候选不超过 8,000 字符
- API Key 仅通过环境变量或 Main 加密存储使用,不进入 Renderer
- 超时、无效响应和服务错误回退本地重排,并显示脱敏诊断
- 用户取消和应用关闭必须终止请求,不得按普通降级吞掉
### US-F2 相邻分块合并
作为普通知识使用者,我希望命中片段包含必要的上下文,而不是孤立半句话。
验收:
- 可配置向前、向后相邻 0 至 2 个块
- 只合并同文档且 ordinal 连续的启用分块
- 同一块不会重复输出
- 每个原命中仍保留引用定位
- 合并结果遵守上下文预算
### US-F3 上下文预算
作为普通知识使用者,我希望低质量内容不会挤占模型上下文。
验收:
- 按最终相关度从高到低选择上下文
- 已选择的高排名证据不会被低排名证据替换
- 超预算时明确标记截断
- 预算范围为 2,000 至 48,000 字符
- IPC 和 Runtime 输入继续受总大小限制
### US-F4 上下文索引
作为知识库维护者,我希望检索可以利用文档结构,而引用仍忠于原文。
验收:
- 可按知识库启用上下文索引,并在修改后提示显式重建
- 标题、标题层级、页码和块类型使用有界确定性前缀进入 FTS、CJK 和向量文本
- 原始分块、引用、模型上下文和图谱证据不显示生成前缀
- FTS、CJK、向量和内容校验使用同一规范索引文本
## 7.1 Epic F+:受控本体与检索评估
### US-F5 每库受控本体
作为知识库维护者,我希望控制可用实体和关系类型,以便图谱保持一致。
验收:
- 每库保存实体类型、关系类型、双语名称、别名和可选端点约束
- 手工编辑使用受控选择器并拒绝未知类型或不兼容端点
- 图谱抽取按类型解析实体,保留人工锁定字段和跨类型边界
- 证据保存原文偏移、置信度、抽取来源和有界 provenance
- 本体或启用中的图谱策略变化标记需要重建
### US-F6 离线检索评估
作为 RAG 维护者,我希望用固定双语样本检测召回回归,而不读取用户数据或调用
网络服务。
验收:
- `npm run eval:retrieval` 使用临时 SQLite 和确定性内存 Provider
- 报告 Recall@5/10、MRR@10、nDCG@10、上下文精度/召回、无答案误报和延迟
- 提供词法、确定性向量、混合及本地重排消融
- 质量门槛按中英文分别检查,报告不包含原文、查询、端点、模型名或凭据
- 可选报告路径仅允许工作区内非符号链接文件
## 8. Epic G:分块维护
### US-G1 查看分块
作为知识库维护者,我希望查看某篇文档实际生成的分块,以便确认解析和切分质量。
验收:
- 文档行提供“查看分块”
- 列表显示序号、角色、标题、定位、字符数和启用状态
- 支持有界分页和文档内搜索
- 可查看完整单块内容
- 父子块关系可辨认但不只靠颜色表达
### US-G2 编辑分块
作为知识库维护者,我希望修正错误文本,以便问答使用正确内容。
验收:
- 编辑限制单块最大字符数
- 保存后同步更新全文和 CJK 索引
- 旧向量立即失效并触发当前文档重建
- 编辑块标记为人工修改
- UI 说明来源再次同步可能覆盖修改
- 保存失败保留用户草稿
### US-G3 启停分块
作为知识库维护者,我希望暂时停用有害或无关片段,而不永久删除它。
验收:
- 使用共享 Switch 和 `role="switch"`
- 停用块不参与任何召回通道
- 重新启用后恢复全文索引,并按需重建向量
- 状态更新失败时保留最后确认状态
- 引用已停用块时显示引用已失效
### US-G4 删除分块
作为知识库维护者,我希望删除确定无用的分块,以便避免错误召回。
验收:
- 删除前说明来源同步可能重新创建该块
- 删除使用具体动作和对象文案
- 删除联动清理全文、CJK、向量和图谱证据
- 删除最后一个可检索块后文档显示“无可检索内容”
- 不删除原始文件
## 9. Epic H:引用和来源
### US-H1 查看完整引用上下文
作为普通知识使用者,我希望从回答引用查看完整上下文,以便验证回答是否忠于
资料。
验收:
- 引用携带稳定 `libraryId``documentId``chunkId`
- 点击引用由 Main 重新校验对象归属
- 展示命中分块、相邻块或父块
- 展示知识库、文档、来源和定位
- 对已删除对象显示明确失效状态
### US-H2 打开原始来源
作为普通知识使用者,我希望从引用打开原文件或网页,以便继续阅读。
验收:
- 本地来源只通过数据库保存的普通文件路径打开
- 网页来源只允许数据库保存的 HTTP(S) URL
- Renderer 不能传入任意待打开路径或 URL
- 文件已移动时显示可恢复错误
- 不能跨平台精确跳页时仍显示原定位信息
### US-H3 引用与回答一致
作为普通知识使用者,我希望引用列表只显示本次实际检索到的内容。
验收:
- Main 只收集本次 capability token 产生的引用
- 预检索和模型后续检索引用去重
- 引用顺序遵循最终相关度和首次使用顺序
- 单消息引用数和序列化大小有明确上限
- 不把未检索文档显示为来源
## 10. Epic I:迁移、安全和兼容
### US-I1 无损迁移
作为现有用户,我希望升级后保留知识库、来源、分块、图谱和向量。
验收:
- SQLite 迁移在事务中执行
- 旧分块默认启用并视为 standalone
- 旧知识库获得兼容检索和分块设置
- CJK 索引回填失败时回滚迁移
- 升级不自动删除或重建原有内容
### US-I2 安全边界
作为本地用户,我希望新增功能不扩大 Renderer 和子 Runtime 权限。
验收:
- 新增 IPC 全部校验可信 sender 和共享 Schema
- Main 重新检查知识库、文档、分块和来源归属
- Renderer 不访问 SQLite、文件系统、Electron shell 或凭据
- 知识内容标记为不可信证据
- Ask 不获得写工具
- 错误和日志不包含密钥、授权头和未限制正文
### US-I3 取消和关闭
作为用户,我希望大库检索或重建可以停止,不留下损坏索引。
验收:
- 长向量扫描、单文档重建和全库重建响应 AbortSignal
- 应用关闭停止新批次并等待有界清理
- 文档级替换成功前继续使用上一版索引
- 取消状态区别于失败
- 取消不会删除原文件或用户维护的其他文档
## 11. 优先级映射
### 第一阶段
- US-A1、US-A2、US-A3
- US-B1、US-B2、US-B3、US-B4
- US-C1、US-C2、US-C3、US-C4、US-C5
- US-D1
- US-H1、US-H2、US-H3
- US-I1、US-I2
### 第二阶段
- US-D2、US-D3
- US-E1、US-E2、US-E3
- US-F1、US-F2、US-F3
- US-G1、US-G2、US-G3、US-G4
- US-I3
## 12. Definition of Done
每个 User Story 只有在以下条件全部满足时才完成:
1. Main、Preload、Renderer 和共享契约保持明确边界。
2. 行为有聚焦的单元、IPC 或组件回归测试。
3. 中英文文案同时更新。
4. 浅色、深色、键盘和窄窗口核心流程可用。
5. 失败、取消、空结果和降级状态均有独立表现。
6. 不覆盖用户现有未提交或未跟踪文件。
7. `npm test``npm run typecheck``npm run lint``npm run build`
全部通过。
@@ -0,0 +1,112 @@
# Knowledge retrieval evaluation
GoodBuddy's retrieval evaluation is an offline Vitest suite that exercises the
real `KnowledgeService` and `KnowledgeDatabase` retrieval path without changing
production data. Run it with:
```text
npm run eval:retrieval
```
By default the suite returns the report only to its tests and leaves no file.
To retain a JSON report, set `GOODBUDDY_RETRIEVAL_EVAL_OUTPUT` to a
workspace-relative file path. Absolute paths and paths escaping the workspace
are rejected.
## Corpus and labels
The committed `synthetic-bilingual-v1` fixture is wholly synthetic, bilingual
(Simplified Chinese and English), and CC0. Stable document, chunk, and query IDs
make changes reviewable. The strict Zod schema bounds every field and rejects
unknown fields, duplicate or dangling IDs, inexact annotations, and
path/endpoint/secret-like values. It also rejects degenerate label sets: each
language must contain both an answerable and a no-answer query.
Each answerable query has graded chunk judgments:
- `3`: directly answers the question.
- `2`: substantially answers it.
- `1`: useful supporting evidence.
Every judgment also contains one or more exact, verbatim answer spans from its
chunk. A no-answer query has no judgments. When adding labels, two reviewers
should independently check relevance grades and exact spans, resolve
disagreements, then update the fixture version or ID when the corpus meaning
changes.
## Evaluation design
Each run creates a temporary SQLite database and directly seeds the production
knowledge classes with stable IDs. It uses deterministic in-memory embedding
providers with stable fingerprints; it does not read API keys, environment
provider settings, user databases, or network resources. Five ablations use
the same corpus:
1. lexical retrieval only;
2. topic-agnostic deterministic token-hash vector retrieval;
3. handcrafted-alias vector retrieval;
4. lexical/vector hybrid retrieval;
5. hybrid retrieval with the local heuristic reranker.
The token-hash provider hashes normalized input tokens without topic-specific
knowledge, so it is a transparent lexical-overlap vector ablation. The
handcrafted bilingual alias provider exists only as **regression plumbing** to
exercise vector, hybrid, and rerank production paths with stable cross-language
matches. It is fixture-aware and is not an embedding-quality model or a claim
about real provider quality.
The suite runs twice and compares the deterministic projection (IDs, hashes,
rank metrics, and failures). Wall-clock latency is intentionally excluded from
that equality check.
## Metrics
- **Recall@5 / Recall@10:** fraction of all annotated relevant chunks returned
within the cutoff, macro-averaged over answerable queries.
- **MRR@10:** reciprocal rank of the first relevant chunk, with zero when none
appears in the first ten.
- **Graded nDCG@10:** discounted cumulative gain using `2^grade - 1`, divided
by the ideal graded ordering.
- **Context precision:** characters in exact annotated spans found in returned
context divided by all returned context characters.
- **Context recall:** characters in exact annotated spans found in returned
context divided by all annotated span characters.
- **No-answer false-positive rate:** no-answer queries that return any result
divided by all no-answer queries.
- **Latency:** count, minimum, median, p95, maximum, and arithmetic mean in
milliseconds for each ablation. These are diagnostic, not deterministic
gates.
Rankings are deduplicated by chunk ID before cutoffs and ranking metrics are
computed. Overlapping or nested exact evidence spans are unioned, so duplicate
rank entries and overlapping annotations cannot inflate context precision or
recall. Aggregate metrics are also emitted per language.
## Privacy
Reports contain only fixture/query/ablation IDs, a SHA-256 corpus hash, an
evaluation-definition hash, a hash of provider definitions, aggregate metrics,
latency summaries, and ID-based actionable failures. The
`evaluationDefinitionHash` covers fixture version/ID, raw queries, judgments,
retrieval settings, ablations, provider definitions, and metric version; it
changes when the evaluated contract changes without disclosing that contract.
Reports omit raw queries, document titles, corpus text, snippets/context,
source paths, endpoints, fingerprints, model names, credentials, metadata, and
vectors. The integration test checks every fixture title, chunk, query, and
private provider identifier against the serialized report.
Retained report paths must be workspace-relative. Resolution uses async
filesystem APIs, rejects absolute/traversal paths and null bytes, checks each
parent component, and refuses symlink traversal or a symlink destination. The
report is first written to a same-directory temporary file and then renamed.
## Quality gates
The integration test gates stable lexical, topic-agnostic token-hash,
regression-vector, hybrid, context-precision/context-recall, and per-language
baselines. It also requires reranked MRR@10 of at least 0.78, reranked nDCG@10
of at least 0.75, no-answer false positives no higher than 0.34, and prevents
local reranking from reducing hybrid nDCG@10 by more than 0.05. Exact nDCG
arithmetic has a focused unit test. Gates are fixture baselines rather than
universal production-SLA claims; adjust them only with a reviewed fixture or
justified retrieval behavior change.
-6
View File
@@ -95,12 +95,6 @@ GoodBuddy 应能够:
- 允许读取明确授权的上下文。
- 禁止文件写入、命令执行和外部副作用。
#### Plan
- Runtime 可读取上下文并生成结构化计划。
- 用户确认计划后才能进入 Execute。
- 计划变更需要重新确认。
#### Execute
- 允许按现有逐工具审批机制执行。