diff --git a/AGENTS.md b/AGENTS.md index 3094c4f..22cb5fc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,7 +29,7 @@ Keep Electron security boundaries intact: ## Runtime Behavior -- Ask and Plan modes must remain read-only at the runtime boundary. +- Ask mode must remain read-only at the runtime boundary. - Execute mode may use tools only through the existing approval controls. - Preserve cancellation, timeout, bounded-output, and shutdown behavior. - Treat OpenCode and Continue as untrusted child runtimes. Preserve environment diff --git a/FEATURES.md b/FEATURES.md index 5924277..9073618 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -37,6 +37,11 @@ - [x] **知识图谱**:支持规则、模型和混合抽取,以及实体、关系、别名和证据维护。 - [x] **向量模型配置与检索**:可配置兼容 Embeddings 接口并用于语义检索。 - [x] **向量诊断与索引任务**:提供真实向量生成诊断、按文档重建进度、取消、失败状态与重启后结果恢复;每篇成功文档立即可用于检索。 +- [x] **混合检索测试台**:支持全文、中文词组、向量和图谱通道诊断,可调 Top K、阈值、权重、本地或学习型重排及上下文预算。 +- [x] **上下文分块与离线评估**:保留标题、页码、标题层级和块类型用于上下文索引,并提供双语 Recall、MRR、nDCG、上下文精度/召回和无答案误报评估。 +- [x] **高级分块与维护**:支持固定、结构化和父子分块,以及分块搜索、编辑、停用、删除、文档重建和可取消的全库重建。 +- [x] **受控知识本体**:每个知识库可定义实体、关系、别名和端点约束,保留证据偏移、置信度和抽取来源,并显式提示图谱重建。 +- [x] **强制检索与引用上下文**:对话可按需或每次先检索,显示零结果、降级、失败与取消状态,并可查看引用上下文或安全打开来源。 - [x] **魔法笔记 / Magic Notes**:提供本地优先的笔记与待办工作台、范围管理、编辑、筛选和受控 AI 评论;创建、保存和评论结果使用统一应用通知。 - [ ] **MCP Server Control Plane**(规划中):扩展 MCP Agent Runtime Broker,统一生命周期、健康检查、重连、Schema 缓存、按项目或任务隔离、审批和审计,并受控接入 OpenCode、Continue。 diff --git a/README.md b/README.md index b1dd493..8f144be 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,10 @@ GoodBuddy 不绑定特定模型厂商。用户可以通过 OpenAI Responses、Op ![GoodBuddy 知识工作区](docs/screenshots/knowledge-workspace.png) -- SQLite FTS5 全文检索与有界上下文召回。 +- SQLite FTS5、中文词组、向量和图谱混合检索,并提供可调权重、本地重排与有界上下文。 +- 检索测试工作台展示候选数量、通道降级、耗时、排名、分数和实际送入模型的上下文。 +- 支持固定长度、结构化和父子分块,以及分块搜索、编辑、停用、删除和可取消重建。 +- 对话可选择由模型按需检索或每次先检索,并展示检索状态与可打开上下文的来源引用。 - 支持规则、模型和混合图谱抽取。 - 支持实体、关系、别名、证据与来源位置追溯。 - 图谱可搜索、筛选、缩放和拖动节点。 diff --git a/docs/features/knowledge-rag-enhancement-prd.md b/docs/features/knowledge-rag-enhancement-prd.md new file mode 100644 index 0000000..bbfc762 --- /dev/null +++ b/docs/features/knowledge-rag-enhancement-prd.md @@ -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-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 +知识库 +├─ 文档与来源 +│ ├─ 来源管理 +│ ├─ 检索测试入口 +│ ├─ 文档状态 +│ └─ 分块查看与维护 +├─ 知识图谱 +├─ 任务中心 +└─ 设置 + ├─ 检索设置 + ├─ 分块设置 + └─ 图谱设置 +``` + +“检索测试”是当前知识库的高频诊断操作,通过知识库标题区次操作打开独立 +工作台,不新增第五个一级页签。 + +对话输入区的知识范围弹层包含: + +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. 失败与恢复 + +| 场景 | 行为 | +| --- | --- | +| 向量查询失败 | 继续全文和图谱检索,显示降级原因 | +| 部分文档无向量 | 使用可用文档,显示完成数和失败数 | +| 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 +``` + +外部或付费模型调用不属于自动验证,只有获得明确授权后才运行。 diff --git a/docs/features/knowledge-rag-enhancement-user-stories.md b/docs/features/knowledge-rag-enhancement-user-stories.md new file mode 100644 index 0000000..9cbd637 --- /dev/null +++ b/docs/features/knowledge-rag-enhancement-user-stories.md @@ -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` + 全部通过。 diff --git a/docs/features/knowledge-retrieval-evaluation.md b/docs/features/knowledge-retrieval-evaluation.md new file mode 100644 index 0000000..474110d --- /dev/null +++ b/docs/features/knowledge-retrieval-evaluation.md @@ -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. diff --git a/docs/长期助手功能规划.md b/docs/长期助手功能规划.md index f988dcd..de40db0 100644 --- a/docs/长期助手功能规划.md +++ b/docs/长期助手功能规划.md @@ -95,12 +95,6 @@ GoodBuddy 应能够: - 允许读取明确授权的上下文。 - 禁止文件写入、命令执行和外部副作用。 -#### Plan - -- Runtime 可读取上下文并生成结构化计划。 -- 用户确认计划后才能进入 Execute。 -- 计划变更需要重新确认。 - #### Execute - 允许按现有逐工具审批机制执行。