Skip to content

ADR-028:知识库文档由人与 AI 共管(agent 可写)+ 稳定标识

English: ADR-028-knowledge-base-documents-co-managed.md

状态:Accepted 日期:2026-06-19 决策者:Yuxing Wu 关联:spec 006-knowledge-base;构建于 ADR-012 之上;与 ADR-026(memory 经 MCP) 同源;属于统一知识重设计的一部分(知识 = 记忆 + 文档,二者皆人 + AI 共管)

修订(2026-06-20,simplification 5.7)。 决策 3(逐文档锁)已撤回:KB 文档始终可写;F01 审计痕迹加 vault 备份取代了这个可退出的锁。支柱 1(ULID 标识)与 2(agent 可写)保留。

背景

最初的 006-knowledge-base 设计(ADR-012 时期)把 KB 定位为用户策展的库,对 agent 只读:agent 通过 MCP 网关读取(search / grep / read_document),永远 不能写入。文档标识是内容寻址的——doc id(也就是 <doc-id>.md 文件名)取原始 文件 source_sha256 的前 16 个十六进制字符。

统一知识重设计把 Coffer 的知识重新定位为知识 = 记忆(notes)+ 文档(documents), 二者皆人 + AI 共管。memory(007)本就 agent 可写(remember / update_memory / forget)。要让 KB 这一面成为活的、共管的知识库而非静态库,"agent 能写 memory 却永远 不能写文档"这种不对称是没有道理的——agent 也应该能贡献文档,并带上 memory 同样的护栏 (F01 审计)。

内容寻址标识还有两个具体缺陷:

  1. 重新上传同一文件的更新版本会生成一个新的 doc id——因为字节(进而 sha)变了 ——把旧版本留作一个无声的重复,而不是就地更新文档。
  2. id 不透明,且会随编辑而不稳定。 标识应当是一个稳定的逻辑句柄,与内容解耦; 内容哈希是出处与 reindex 的 no-op 闸门,不是标识。

决策

KB 文档由人与 agent 共管。 三处改动:

  1. 标识 = 稳定 ULID,在首次 ingest 时生成,而非 source_sha256[:16]

    • content_sha256(Markdown 正文哈希)继续作为 reindex no-op 闸门;原始文件的 source_sha256 继续留在 metadata 中作为出处。
    • 重新上传语义(在一个 store 内按 original_filename 匹配):字节完全相同 = 幂等 no-op;同名但内容变化的文件就地更新同一文档(复用 id;覆盖 docs/ + raw/,只保留最新一份原件——无版本历史;source_mode 重置为 converted),且需要 replace=true不同文件名则是带新 ULID 的新文档。
  2. agent 可写 KB 文档,通过新增的 MCP 网关工具 coffer__add_document / coffer__edit_document / coffer__delete_document,与现有读工具并列。每次写入都 走人类写入所用的同一套幂等 re-index 例程,并以 agent 为 actor 记入 F01 审计。

范围与排序

本 ADR 交付全局 scope 下的共管核心。统一知识重设计中另两块相关内容,随后续在统一 知识 UI 中呈现它们的切片一起落地,以保持本次改动可评审、避免堆出没有 UI 的后端状态:

  • 逐项目文档 scope(文档的 全局/项目 轴)——与统一知识的项目视图相互依赖;推迟到那 个切片。
  • 可恢复软删除(回收站/恢复)——需要自己的 UI 才有意义;目前删除是硬删除,但仍留下 F01 审计痕迹。

应用内文档查看器保持只读 + 外部编辑器入口(只读查看器的决策):人类通过外部编辑器 或 edit API 编辑正文;agent 通过 MCP 工具编辑。本 ADR 重新引入应用内文本编辑器。

后果

正面

  • KB 成为与知识模型一致的、活的共管知识库——与 agent 可写的 memory 对称。
  • 修复"重新上传更新版文件产生重复"的缺陷:更新后的源现在会在稳定 id 下就地更新其文档。
  • agent 的贡献被审计(F01)且可逆;硬删除留下审计痕迹。

负面

  • agent 获得对 KB 文档的删除能力。由完整 F01 审计加 vault 备份缓解; 这是刻意的范围——没有删除的共管是半吊子。
  • 稳定 id 意味着同一文件上传到两个 KB 现在有两个 id——KB 文档不再跨 store 去重。 接受:每个 KB 是自己的语料库,且逐 store 的 chunk-id 命名空间本就将它们隔离。

备选方案

保持 KB 对 agent 只读(现状)。 否决:与共管知识模型矛盾,且与 agent 可写的 memory 无理由地不对称。

保留内容寻址标识。 否决:它导致重新上传重复的缺陷,并把标识与内容混为一谈。把内容 哈希保留为出处、标识改用稳定逻辑 id 严格更优。

现在就做软删除。 推迟:可恢复回收站只有配上恢复 UI 才有用,而那属于统一知识切片。 硬删除 + F01 审计对本切片已是足够的保护。

每次重新上传都自动更新(无 replace 标志)。 否决:同名重新上传时无声覆盖文档令人 意外,且可能覆盖手改过的正文;对内容变化的文件要求 replace=true 让覆盖保持显式(UI 弹出"更新现有 / 新建")。