# 知识库后端当前实现说明 本文档只记录当前分支中 `src/main/services/knowledge` 已经落地的后端分层、调用边界和 workflow 行为。 `v2-refactor-temp` 下的文档是临时工作笔记。当前 canonical 文档是: - [Knowledge Service](../../../docs/references/knowledge/knowledge-service.md) - [Knowledge Workflow Architecture](../../../docs/references/knowledge/workflow-architecture.md) - [Knowledge Operation Guards](../../../docs/references/knowledge/operation-guards.md) 本文不覆盖旧的 `src/main/knowledge` / `knowledge-base:*` 通道。 ## 1. 当前架构图 ```text UI / preload IPC / main-side workflow -> KnowledgeService -> KnowledgeWorkflowService -> JobManager -> knowledge.prepare-root -> knowledge.index-documents -> knowledge.delete-subtree -> knowledge.reindex-subtree -> KnowledgeLockManager -> KnowledgeBaseService / KnowledgeItemService -> KnowledgeVectorStoreService / FileManager UI Data API reads / patch -> Data API knowledge handlers -> KnowledgeBaseService / KnowledgeItemService ``` 当前没有 `KnowledgeRuntimeService`,也没有 Knowledge 自己维护的 in-memory queue。持久化调度、retry、timeout、cancel 和 startup recovery 由 `JobManager` 负责。 ## 2. 当前职责边界 `KnowledgeBaseService` / `KnowledgeItemService`: 1. 负责 SQLite 业务表读写。 2. 负责 `knowledge_item.status` / `error` 的持久化更新。 3. 负责 `knowledge_item.data` 与 `type` 的一致性校验。 4. 负责 container item 的子项状态向上聚合。 5. 不负责 reader、embedding、向量库写入、JobManager 调度或 caller-facing IPC。 Data API knowledge handlers: 1. 只暴露数据库可直接满足的读和 base metadata/config 更新。 2. 不负责 runtime mutation,不创建或删除 vector store artifacts。 `KnowledgeService`: 1. 负责 caller-facing `knowledge-runtime:*` IPC。 2. 负责 create/delete/restore base workflow。 3. 注册 Knowledge JobManager handlers。 4. 持有 `KnowledgeWorkflowService` 和 `KnowledgeLockManager`。 5. 对 delete / reindex / chunk 操作做入口 guard。 6. 不直接执行 reader / chunk / embed / vector write。 `KnowledgeWorkflowService`: 1. 负责 `addItems` / `deleteItems` / `reindexItems` 的 workflow 分支。 2. 负责 `scheduleItem(baseId, itemId)`。 3. 将 `directory` 分派为 `knowledge.prepare-root`。 4. 将 `file` / `note` / `url` 分派为 `knowledge.index-documents`。 5. 负责 add/reindex 调度失败后的状态补偿。 `KnowledgeLockManager`: 1. 负责同一 base 下的进程内 mutation 串行化。 2. 保护 vector replace/delete、FileRef cleanup、item status writes 和 destructive cleanup/reset。 3. 不能替代 `DbService.withWriteTx`;主 SQLite 写事务仍必须走 `DbService.withWriteTx`。 ## 3. 当前调用边界与调用方契约 UI / preload 当前调用模型: ```text UI | +--> Data API | -> list/get knowledge bases | -> patch base metadata/config | -> list/get knowledge items | \--> preload knowledgeRuntime IPC -> create/delete/restore base -> add/delete/reindex items -> search -> list/delete chunks ``` 添加 file / url / note / directory 时,调用方直接走: ```text caller -> preload IPC add-items(item payloads) ``` 调用方不应先通过 Data API 创建 item,再把 created item ids 传给 runtime `addItems`。 Leaf item 当前链路: ```text add-items(leaf payloads) -> create leaf item rows -> status = processing -> enqueue knowledge.index-documents ``` Container item 当前链路: ```text add-items(directory payloads) -> create root item rows -> status = preparing -> enqueue knowledge.prepare-root -> prepare-root expands owner -> prepare-root creates child rows -> workflowService.scheduleItem(child) ``` `prepare-root` 创建出的 child 可以继续是 `directory`,由 workflow service 再次分派为 `knowledge.prepare-root`。递归展开不由 reader 或 leaf indexing 分支处理。 ## 4. JobManager 模型 当前 Knowledge job types: 1. `knowledge.prepare-root` 2. `knowledge.index-documents` 3. `knowledge.delete-subtree` 4. `knowledge.reindex-subtree` 每个 base 使用独立队列: ```text base.${baseId} ``` JobManager 负责: 1. job 持久化。 2. dispatch。 3. retry / timeout。 4. cancel。 5. startup recovery。 Knowledge 不再维护 `entries` map、`controller`、`runPromise`、`interruptError` 或其他 in-memory queue 状态。 ## 5. 当前索引执行链路 `knowledge.index-documents` 当前流程: ```text handler.execute -> load base and item -> skip missing / deleting / already completed item -> under base mutation lock: rebuild source file refs status = reading -> read documents -> chunk documents -> under base mutation lock: status = embedding -> embed chunks -> under base mutation lock: re-read item skip vector write if item is deleting vectorStore.replaceByExternalId(itemId, nodes) status = completed ``` 如果 reader 返回空 documents,或 chunk 后没有可索引 chunks,`index-documents` 仍视为成功:写入 `replaceByExternalId(itemId, [])` 清空该 item 的旧 chunks,然后把 item 标记为 `completed`。 非中断错误由 JobManager retry。Retry 耗尽或 job cancel 时,handler `onSettled` 把对应 item 标记为 `failed`,但如果 item 已经是 `deleting` 则跳过失败回写。 ## 6. Delete / Reindex 当前链路 `delete-items` 当前流程: ```text delete-items(baseId, itemIds) -> collapse to top-level roots -> under base mutation lock: mark selected root subtrees deleting -> enqueue knowledge.delete-subtree ``` `knowledge.delete-subtree`: ```text -> resolve still-deleting subtree -> cancel active jobs touching subtree -> under base mutation lock: delete vectors for leaf items clear Knowledge FileRef rows for full subtree delete knowledge_item rows ``` `file_ref.sourceId` 是 polymorphic,没有 FK 指向 `knowledge_item`。因此最终 hard delete 必须先展开完整 subtree 清理 Knowledge FileRef,再删除 rows;仅删除显式 root id 对应 refs 会留下 descendant orphan refs。 `reindex-items` 当前流程: ```text reindex-items(baseId, itemIds) -> collapse to top-level roots -> reject unless every selected subtree item is completed or failed -> enqueue knowledge.reindex-subtree ``` `knowledge.reindex-subtree`: ```text -> skip if delete already marked any subtree item deleting -> under base mutation lock: re-check deleting guard delete old vectors delete expanded descendants for selected container roots reset selected roots to preparing / processing -> workflowService.scheduleItem(root) ``` Reindex 不是 cancellation primitive。Active subtree 只能 delete,不能 reindex。 ## 7. `knowledge_item.status` 当前边界 当前 `status` 表达业务生命周期和粗粒度运行进度: 1. `idle` 2. `preparing` 3. `processing` 4. `reading` 5. `embedding` 6. `completed` 7. `failed` 8. `deleting` 当前不再保留单独 `phase` 字段。`status` 是持久业务状态,不由 JobManager progress 反推。 状态语义: 1. `preparing`:`directory` 正在 expand / create children。 2. `processing`:leaf 已接受但尚未进入 reading,或 container 仍有 active children。 3. `reading`:leaf 正在读取 source documents。 4. `embedding`:leaf 正在 embedding。 5. `completed`:leaf indexing 完成,或 container 没有 active children。 6. `failed`:index/preparation/scheduling compensation 失败。 7. `deleting`:用户不可见,等待后台 cleanup。 ## 8. Base workflow `createBase(dto)` 当前流程: ```text IPC create-base(CreateKnowledgeBaseDto) -> KnowledgeBaseService.create(dto) -> KnowledgeVectorStoreService.createStore(base) -> return created base ``` 如果 vector store 初始化失败,orchestration 会调用 `KnowledgeBaseService.delete(base.id)` 回滚刚创建的 SQLite base,然后把原始错误抛给调用方。 `deleteBase(baseId)` 当前流程: ```text IPC delete-base(baseId) -> cancel active Knowledge jobs in base queue -> under base mutation lock: KnowledgeVectorStoreService.deleteStore(baseId) KnowledgeBaseService.delete(baseId) ``` Artifact 删除失败时 SQLite 行保留,用户可从 UI 重试。SQLite 删除失败时已删除 artifacts 不会恢复,orchestration 抛出 `invalidOperation`。 `restoreBase(dto)` 当前流程: ```text IPC restore-base(sourceBaseId, embeddingModelId, dimensions) -> load source base -> load source root items -> create new base with source config and requested embedding contract -> add source root item payloads to restored base ``` Restore 允许 failed base,也允许 completed base;即使 completed source base 的 `embeddingModelId` 和 `dimensions` 未变化,也允许创建同配置 clone/rebuild。 ## 9. Search / Chunk 当前边界 `search(baseId, query)` 当前流程: 1. 拒绝 failed base。 2. 拒绝没有 searchable token 的 query。 3. 使用 base embedding model 生成 query embedding。 4. 查询 sqlite-vec vector store。 5. 过滤 missing / other-base / deleting source item 的结果。 6. 如果配置了 rerank model,执行 rerank。 7. 应用 threshold 并写入 rank。 `list-item-chunks` / `delete-item-chunk` 当前规则: 1. 拒绝 failed base。 2. 要求目标 item 自身为 `completed`。 3. 对 completed `directory` list 请求,如果 subtree 仍含 `deleting` descendant,则拒绝。 ## 10. 当前明确不做的内容 1. 不使用旧 `KnowledgeRuntimeService`。 2. 不维护 Knowledge 自己的 in-memory queue。 3. 不使用 `index-leaf` job type;当前 leaf indexing job 是 `knowledge.index-documents`。 4. 不保留单独 `phase` 字段。 5. 不把 restore same embedding config 视为 no-op 并拒绝。 6. 不主动 permanent-delete detached `FileEntry` rows。 7. Round 1 不接入 FileProcessing;`knowledge_base.fileProcessorId` 当前对 indexing inert。 ## 11. 后续更新本文档时的原则 1. 如果 canonical 文档已经覆盖事实,优先更新 canonical 文档,再在本文保留短摘要或链接。 2. 不再新增大段逐实现复制,避免 `v2-refactor-temp` 与 canonical docs 漂移。 3. 如果当前实现与 RFC 目标不同,必须明确写“当前实现”还是“目标设计”。