dsh-data-domain-knowledge 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +360 -0
  3. package/cordis.patch.yml +410 -0
  4. package/eval/README.md +76 -0
  5. package/eval/evaluate-retrieval.mjs +121 -0
  6. package/eval/queries.example.jsonl +2 -0
  7. package/lib/client.js +111415 -0
  8. package/lib/types/config-schema.d.ts +35 -0
  9. package/lib/types/config-schema.d.ts.map +1 -0
  10. package/lib/types/config-schema.js +34 -0
  11. package/lib/types/config-schema.js.map +1 -0
  12. package/lib/types/convert/core-loader.d.ts +32 -0
  13. package/lib/types/convert/core-loader.d.ts.map +1 -0
  14. package/lib/types/convert/core-loader.js +60 -0
  15. package/lib/types/convert/core-loader.js.map +1 -0
  16. package/lib/types/convert/host.d.ts +88 -0
  17. package/lib/types/convert/host.d.ts.map +1 -0
  18. package/lib/types/convert/host.js +479 -0
  19. package/lib/types/convert/host.js.map +1 -0
  20. package/lib/types/convert/ingest.d.ts +125 -0
  21. package/lib/types/convert/ingest.d.ts.map +1 -0
  22. package/lib/types/convert/ingest.js +228 -0
  23. package/lib/types/convert/ingest.js.map +1 -0
  24. package/lib/types/convert/settings-schema.d.ts +18 -0
  25. package/lib/types/convert/settings-schema.d.ts.map +1 -0
  26. package/lib/types/convert/settings-schema.js +26 -0
  27. package/lib/types/convert/settings-schema.js.map +1 -0
  28. package/lib/types/convert/types.d.ts +46 -0
  29. package/lib/types/convert/types.d.ts.map +1 -0
  30. package/lib/types/convert/types.js +41 -0
  31. package/lib/types/convert/types.js.map +1 -0
  32. package/lib/types/diagnosis/cards.d.ts +71 -0
  33. package/lib/types/diagnosis/cards.d.ts.map +1 -0
  34. package/lib/types/diagnosis/cards.js +482 -0
  35. package/lib/types/diagnosis/cards.js.map +1 -0
  36. package/lib/types/diagnosis/problem-classes.d.ts +51 -0
  37. package/lib/types/diagnosis/problem-classes.d.ts.map +1 -0
  38. package/lib/types/diagnosis/problem-classes.js +66 -0
  39. package/lib/types/diagnosis/problem-classes.js.map +1 -0
  40. package/lib/types/diagnosis/schema.d.ts +65 -0
  41. package/lib/types/diagnosis/schema.d.ts.map +1 -0
  42. package/lib/types/diagnosis/schema.js +208 -0
  43. package/lib/types/diagnosis/schema.js.map +1 -0
  44. package/lib/types/diagnosis/seed-source.d.ts +20 -0
  45. package/lib/types/diagnosis/seed-source.d.ts.map +1 -0
  46. package/lib/types/diagnosis/seed-source.js +96 -0
  47. package/lib/types/diagnosis/seed-source.js.map +1 -0
  48. package/lib/types/diagnosis/seed.d.ts +50 -0
  49. package/lib/types/diagnosis/seed.d.ts.map +1 -0
  50. package/lib/types/diagnosis/seed.js +242 -0
  51. package/lib/types/diagnosis/seed.js.map +1 -0
  52. package/lib/types/diagnosis/store.d.ts +81 -0
  53. package/lib/types/diagnosis/store.d.ts.map +1 -0
  54. package/lib/types/diagnosis/store.js +409 -0
  55. package/lib/types/diagnosis/store.js.map +1 -0
  56. package/lib/types/diagnosis/types.d.ts +124 -0
  57. package/lib/types/diagnosis/types.d.ts.map +1 -0
  58. package/lib/types/diagnosis/types.js +13 -0
  59. package/lib/types/diagnosis/types.js.map +1 -0
  60. package/lib/types/directory-picker.d.ts +94 -0
  61. package/lib/types/directory-picker.d.ts.map +1 -0
  62. package/lib/types/directory-picker.js +110 -0
  63. package/lib/types/directory-picker.js.map +1 -0
  64. package/lib/types/extract-model.d.ts +76 -0
  65. package/lib/types/extract-model.d.ts.map +1 -0
  66. package/lib/types/extract-model.js +193 -0
  67. package/lib/types/extract-model.js.map +1 -0
  68. package/lib/types/extract.d.ts +121 -0
  69. package/lib/types/extract.d.ts.map +1 -0
  70. package/lib/types/extract.js +549 -0
  71. package/lib/types/extract.js.map +1 -0
  72. package/lib/types/fts.d.ts +96 -0
  73. package/lib/types/fts.d.ts.map +1 -0
  74. package/lib/types/fts.js +184 -0
  75. package/lib/types/fts.js.map +1 -0
  76. package/lib/types/index.d.ts +39 -0
  77. package/lib/types/index.d.ts.map +1 -0
  78. package/lib/types/index.js +1112 -0
  79. package/lib/types/index.js.map +1 -0
  80. package/lib/types/intent/engine.d.ts +108 -0
  81. package/lib/types/intent/engine.d.ts.map +1 -0
  82. package/lib/types/intent/engine.js +501 -0
  83. package/lib/types/intent/engine.js.map +1 -0
  84. package/lib/types/intent/host.d.ts +88 -0
  85. package/lib/types/intent/host.d.ts.map +1 -0
  86. package/lib/types/intent/host.js +389 -0
  87. package/lib/types/intent/host.js.map +1 -0
  88. package/lib/types/intent/preset-tools.d.ts +37 -0
  89. package/lib/types/intent/preset-tools.d.ts.map +1 -0
  90. package/lib/types/intent/preset-tools.js +45 -0
  91. package/lib/types/intent/preset-tools.js.map +1 -0
  92. package/lib/types/intent/settings-schema.d.ts +59 -0
  93. package/lib/types/intent/settings-schema.d.ts.map +1 -0
  94. package/lib/types/intent/settings-schema.js +57 -0
  95. package/lib/types/intent/settings-schema.js.map +1 -0
  96. package/lib/types/intent/store.d.ts +75 -0
  97. package/lib/types/intent/store.d.ts.map +1 -0
  98. package/lib/types/intent/store.js +139 -0
  99. package/lib/types/intent/store.js.map +1 -0
  100. package/lib/types/intent/tools.d.ts +63 -0
  101. package/lib/types/intent/tools.d.ts.map +1 -0
  102. package/lib/types/intent/tools.js +108 -0
  103. package/lib/types/intent/tools.js.map +1 -0
  104. package/lib/types/intent/types.d.ts +189 -0
  105. package/lib/types/intent/types.d.ts.map +1 -0
  106. package/lib/types/intent/types.js +62 -0
  107. package/lib/types/intent/types.js.map +1 -0
  108. package/lib/types/knowledge-bases.d.ts +266 -0
  109. package/lib/types/knowledge-bases.d.ts.map +1 -0
  110. package/lib/types/knowledge-bases.js +1107 -0
  111. package/lib/types/knowledge-bases.js.map +1 -0
  112. package/lib/types/layout.d.ts +262 -0
  113. package/lib/types/layout.d.ts.map +1 -0
  114. package/lib/types/layout.js +312 -0
  115. package/lib/types/layout.js.map +1 -0
  116. package/lib/types/migrate.d.ts +110 -0
  117. package/lib/types/migrate.d.ts.map +1 -0
  118. package/lib/types/migrate.js +280 -0
  119. package/lib/types/migrate.js.map +1 -0
  120. package/lib/types/recall-rank.d.ts +158 -0
  121. package/lib/types/recall-rank.d.ts.map +1 -0
  122. package/lib/types/recall-rank.js +261 -0
  123. package/lib/types/recall-rank.js.map +1 -0
  124. package/lib/types/runtime.d.ts +568 -0
  125. package/lib/types/runtime.d.ts.map +1 -0
  126. package/lib/types/runtime.js +3045 -0
  127. package/lib/types/runtime.js.map +1 -0
  128. package/lib/types/settings-schema.d.ts +117 -0
  129. package/lib/types/settings-schema.d.ts.map +1 -0
  130. package/lib/types/settings-schema.js +92 -0
  131. package/lib/types/settings-schema.js.map +1 -0
  132. package/lib/types/settings-volatile.d.ts +102 -0
  133. package/lib/types/settings-volatile.d.ts.map +1 -0
  134. package/lib/types/settings-volatile.js +114 -0
  135. package/lib/types/settings-volatile.js.map +1 -0
  136. package/lib/types/types.d.ts +799 -0
  137. package/lib/types/types.d.ts.map +1 -0
  138. package/lib/types/types.js +387 -0
  139. package/lib/types/types.js.map +1 -0
  140. package/lib/types/wiki-types.d.ts +68 -0
  141. package/lib/types/wiki-types.d.ts.map +1 -0
  142. package/lib/types/wiki-types.js +322 -0
  143. package/lib/types/wiki-types.js.map +1 -0
  144. package/package.json +101 -0
  145. package/preset/tita-data-agent/agent.cordis.yml +376 -0
  146. package/preset/tita-data-agent/preset.yml +3 -0
  147. package/python/requirements.txt +8 -0
  148. package/scripts/doctor.mjs +70 -0
  149. package/scripts/e2e-pipeline.mjs +355 -0
  150. package/scripts/install-agent-preset.mjs +92 -0
  151. package/scripts/setup-embedding.sh +34 -0
  152. package/scripts/sync-agent-preset.mjs +188 -0
  153. package/src/client/AgentPresetCard.tsx +247 -0
  154. package/src/client/DirectoryPicker.tsx +357 -0
  155. package/src/client/InfoHint.tsx +65 -0
  156. package/src/client/IntentLogicTab.tsx +185 -0
  157. package/src/client/IntentTab.tsx +715 -0
  158. package/src/client/KnowledgeBaseTab.tsx +1454 -0
  159. package/src/client/KnowledgeGraphView.tsx +306 -0
  160. package/src/client/KnowledgePanel.tsx +381 -0
  161. package/src/client/KnowledgeStepRail.tsx +60 -0
  162. package/src/client/NodeSettings.tsx +392 -0
  163. package/src/client/PreviewSections.tsx +116 -0
  164. package/src/client/RecallPanel.tsx +399 -0
  165. package/src/client/TypeDefinitionDrawer.tsx +215 -0
  166. package/src/client/WikiFlowCard.tsx +226 -0
  167. package/src/client/WikiTypeEditor.tsx +332 -0
  168. package/src/client/agent-preset.ts +121 -0
  169. package/src/client/arch/AgentArchitectureGraph.tsx +219 -0
  170. package/src/client/arch/NodeLogicPanel.tsx +133 -0
  171. package/src/client/arch/ProblemDetailPanel.tsx +88 -0
  172. package/src/client/arch/model.ts +691 -0
  173. package/src/client/architecture.css +191 -0
  174. package/src/client/architecture.tsx +530 -0
  175. package/src/client/attribution/AttributionGraph.tsx +104 -0
  176. package/src/client/attribution/AttributionTab.tsx +332 -0
  177. package/src/client/attribution/CaseView.tsx +102 -0
  178. package/src/client/attribution/GraphStage.tsx +87 -0
  179. package/src/client/attribution/RunView.tsx +184 -0
  180. package/src/client/attribution/StageChrome.tsx +403 -0
  181. package/src/client/attribution/ViewSwitch.tsx +107 -0
  182. package/src/client/attribution/graph-options.ts +381 -0
  183. package/src/client/attribution/model.ts +462 -0
  184. package/src/client/config-scope.ts +119 -0
  185. package/src/client/convert/ConvertPanel.tsx +594 -0
  186. package/src/client/convert/styles.css +138 -0
  187. package/src/client/convert/styles.ts +49 -0
  188. package/src/client/format.ts +39 -0
  189. package/src/client/graph/layout.ts +181 -0
  190. package/src/client/graph.css +113 -0
  191. package/src/client/index.ts +98 -0
  192. package/src/client/problem-domains.ts +114 -0
  193. package/src/client/styles.css +940 -0
  194. package/src/client/styles.ts +11 -0
  195. package/src/client/useFitScale.ts +68 -0
  196. package/src/config-schema.ts +45 -0
  197. package/src/convert/core-loader.ts +68 -0
  198. package/src/convert/host.ts +579 -0
  199. package/src/convert/ingest.ts +367 -0
  200. package/src/convert/settings-schema.ts +27 -0
  201. package/src/convert/types.ts +65 -0
  202. package/src/diagnosis/cards.ts +498 -0
  203. package/src/diagnosis/problem-classes.ts +117 -0
  204. package/src/diagnosis/schema.ts +260 -0
  205. package/src/diagnosis/seed-source.ts +107 -0
  206. package/src/diagnosis/seed.ts +291 -0
  207. package/src/diagnosis/store.ts +432 -0
  208. package/src/diagnosis/types.ts +152 -0
  209. package/src/directory-picker.ts +164 -0
  210. package/src/extract-model.ts +227 -0
  211. package/src/extract.ts +632 -0
  212. package/src/fts.ts +203 -0
  213. package/src/index.ts +1091 -0
  214. package/src/intent/README.md +63 -0
  215. package/src/intent/engine.ts +527 -0
  216. package/src/intent/host.ts +462 -0
  217. package/src/intent/preset-tools.ts +48 -0
  218. package/src/intent/settings-schema.ts +63 -0
  219. package/src/intent/store.ts +143 -0
  220. package/src/intent/tools.ts +139 -0
  221. package/src/intent/types.ts +245 -0
  222. package/src/knowledge-bases.ts +1160 -0
  223. package/src/layout.ts +350 -0
  224. package/src/migrate.ts +262 -0
  225. package/src/python/embedding_worker.py +471 -0
  226. package/src/recall-rank.ts +299 -0
  227. package/src/runtime.ts +3069 -0
  228. package/src/settings-schema.ts +94 -0
  229. package/src/settings-volatile.ts +122 -0
  230. package/src/types.ts +1140 -0
  231. package/src/wiki-types.ts +357 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NoneFire
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,360 @@
1
+ # dsh-data-domain-knowledge
2
+
3
+ 本地知识库插件:`01_source_truth` 保存 **SourceRaw**(原始可追溯文档),`02_wiki` 保存
4
+ 按主题聚合、可双向链接的 wiki 卡片,`03_compiled` 输出可检索的 **wikiNotes**、wiki
5
+ 知识图谱和向量索引,`<agentRoot>/memory/<库 id>` 保存版本快照、访问审计与反馈。默认使用本地 WeMM Python backend:从 WeMM
6
+ 原生 2048 维向量按 MRL 截取 1024 维,先做 binary/Hamming 粗筛,再用 int8 点积精算余弦
7
+ (这是**向量路内部的粗排 → 精算**,与 stage 4 的 cross-encoder **重排**不是一回事);
8
+ 模型不可用时明确降级到 FTS,不会伪造向量结果。Markdown 中的
9
+ 本地图片会与正文一起交给 WeMM,因此图片不是独立知识类型。
10
+
11
+ ## 承载范围(五个视图 = 一个挂载单元)
12
+
13
+ 侧边栏 `TitaAgent` 面板声明的五个视图就是本插件的全部范围,`src/` 的目录结构按它们组织:
14
+
15
+ | 视图 | 面板标签 | 宿主实现 | 冻结契约 |
16
+ | --- | --- | --- | --- |
17
+ | `overview` | Agent 概览 | `src/index.ts` | 各设置的挂载节点 |
18
+ | `intent` | 意图 | `src/intent/`(0020 自 `data-domain-intent` 并入);配置与留痕落 `<agentRoot>/intent/` | `intent_*` 工具名、`/intent/*` 路由、`tita-data-agent-intent` 设置、`titaDataAgentIntent` 服务 |
19
+ | `knowledge` | 知识库 | `src/runtime.ts` + `src/knowledge-bases.ts` + `src/convert/`(0018 并入) | `recall_knowledge` 等工具名、`/knowledge/*` 与 `/convert` 路由、`tita-data-agent-knowledge` / `-convert` 设置 |
20
+ | `memory` | 记忆 | `src/runtime.ts` 的 `memoryPath()`(版本快照、`feedback.ndjson`、`access-audit.ndjson`),根在 `<agentRoot>/memory/<库 id>` | 磁盘目录布局 |
21
+ | `eval` | 评测 | `eval/evaluate-retrieval.mjs`(开发期能力,不注册运行时入口) | 问题集格式 |
22
+
23
+ **架构原理:插件的数量应当等于用户入口的数量,而不是概念的数量;而插件的名字应当指向主干概念,不指向子域。**
24
+ 意图/知识库/记忆/评测是四个概念,但它们共享同一条流水线(记录意图 → 录入来源 → 编译知识 →
25
+ 沉淀记忆 → 评测质量)和同一个入口(面板的五个 Tab)。0020 之前,「意图」Tab 已经长在本插件里、
26
+ 宿主实现却在第二个挂载单元里——**声明的信息架构与代码布局不一致**,这才是要修的东西。
27
+
28
+ 意图的**配置与留痕**落在 `<agentRoot>/intent/`(0033):`registry.json` 是分类 / act 词表的
29
+ 真源(面板的「意图配置」直接读写这个文件,不再写宿主的 settings 文档),`records.ndjson`
30
+ 是每轮一条记录的 append-only 留痕(按 `sessionKey#turn` 读时取最后一条,所以内存里
31
+ 「一轮一条」的语义不变)。读接口 `/intent/store` 与 `/intent/overview` 读的是**留痕**:
32
+ 引擎内存里那份有 600 秒 TTL,重启或隔一段时间回来不该让面板上的历史凭空消失。
33
+
34
+ `src/intent/` 的宿主半与 `src/client/IntentTab.tsx` 的浏览器半之间**必须保留 HTTP 边界**(`/intent/*`):
35
+ 两者分处两个 bundle,无法直接互相 import。这与 0018 删掉的 `POST /knowledge/sources` 不同——
36
+ 那次是宿主→宿主的回环,可以改成进程内调用。
37
+
38
+ ## 五段链路
39
+
40
+ | 段 | 名称 | 产物 | 关键配置 |
41
+ | --- | --- | --- | --- |
42
+ | 1 | SourceRaw | 原始可追溯文档:`01_source_truth/*.md` | `allowSourceTruth` / `rootDir` |
43
+ | 2 | 编译 Compile | wiki:`02_wiki`(按主题聚合、可双向链接);wikiNotes:`03_compiled/wiki_notes.json` | `schemaTypes` |
44
+ | 3 | 构建 Build | wikiNotes → 向量索引;wiki → `03_compiled/knowledge_graph.json` | `embeddingProvider` / `embeddingModel` / `python` |
45
+ | 4 | 召回 Recall | 多路(关键词 + 向量 + 知识图谱)召回 wikiNotes,取 `recallTopK`(默认 10),再解析父级 wiki 与该 wiki 的 1 跳知识图谱 | `recallTopK` / `recallMode` |
46
+ | 5 | 重排 Rerank | BERT cross-encoder 对候选 wikiNotes 精排,取 `contextTopN`(默认 5)组成 `context` | `contextTopN` / `rerankProvider` / `rerankModel` |
47
+
48
+ > 0033:第 4、5 段在**界面上是同一栏**(知识库 → 召回重排)。它们在流水线上仍是两步
49
+ > ——架构图里也仍是两个节点——但「跑一次真实召回长什么样」是一个问题,分两栏会让用户
50
+ > 先跑召回、再切到重排才能看到同一次运行的全貌,而且两栏各有一个测试按钮。
51
+
52
+ > 术语迁移:SourceRaw 曾叫 SourceRow / SourceTruth。磁盘目录 `01_source_truth`、工具名
53
+ > `add_source` / `query_source_truth`、HTTP `/knowledge/sources`、设置键 `allowSourceTruth`
54
+ > 与错误码 `SOURCE_TRUTH_DISABLED` 作为兼容名保留,语义等同 SourceRaw。
55
+ > 本轮的「编译 / 构建」仍是同一次 `rebuild()`:编译的**按主题聚合**由 Agent 完成,
56
+ > **wiki↔wiki 双向链接**与**分阶段重建**是设计目标,图谱当前只有 `supported_by` 溯源边。
57
+
58
+ - 设置项**不再有独立入口**:它们挂在 Agent 概览架构图的对应节点上(SourceRaw → 收录开关与
59
+ 知识库根目录;编译 → Schema;构建 → Embedding / Python;召回 → topK / 默认路线;
60
+ 重排 → topN / reranker;意图与上下文 → 意图路由),每个节点只保存本节点字段。
61
+ - 编译期一条 wiki 至少产出一条 note;正文按 `##`/`###` 分节且超过 800 字符时按节切分,
62
+ 首条 note 的 `unitId` 保持 `<entityType>:<entityId>`,后续为 `<entityType>:<entityId>#<n>`,
63
+ 每条 note 都带 `wikiId` 指回父级 wiki。`03_compiled/knowledge_units.json` 作为旧版兼容镜像保留。
64
+ - `recall_knowledge` 返回 `hits`(重排后的 wikiNotes)、`context`(`{ note, wiki, graph }[]`)、
65
+ `wiki`、`graph`、`routes`、`recallMode`、`rerank`、`recallTopK`、`contextTopN`;入参 `top_k`
66
+ 控制召回条数(`limit` 为兼容别名),`top_n` 控制进入上下文的条数,`mode` 覆盖默认召回路线,
67
+ `rerank: false` 可单次关闭重排。
68
+ - `rerankProvider` 默认 `bert-python`,模型默认 `BAAI/bge-reranker-base`
69
+ (存在 `~/.tita-data-agent/models/bge-reranker-base` 时优先用本地目录)。重排在独立
70
+ Python worker 进程中进行,模型缺失或超时时按融合分数返回并在 `warnings` 说明,
71
+ 不会反复重试;`rerankProvider: 'none'` 完全跳过重排。
72
+
73
+ ## 本地启用 WeMM
74
+
75
+ 在 Apple Silicon 上执行一次:
76
+
77
+ ```bash
78
+ ./plugins/dsh-data-domain-knowledge/scripts/setup-embedding.sh
79
+ ```
80
+
81
+ 脚本会把 Python 环境放到 `~/.tita-data-agent/embedding-venv`,把量化模型放到
82
+ `~/.tita-data-agent/models/WeMM-Embedding-2B-Quantized`,不会把 1.8GB 权重提交
83
+ 进仓库。新配置会自动发现这两个路径;如果 DSH 中已经保存过旧配置,则在
84
+ Tita Data Agent → Agent 概览 →「构建」节点的设置中确认:
85
+
86
+ - Provider:`WeMM Python(本地)`
87
+ - Python:`~/.tita-data-agent/embedding-venv/bin/python`
88
+ - Model:`~/.tita-data-agent/models/WeMM-Embedding-2B-Quantized`
89
+ - 维度:`1024`
90
+ - 设备:`自动(优先 MPS)`
91
+
92
+ 知识库默认保存在 `~/.tita-data-agent/knowledge`;设置了 `DSH_KNOWLEDGE_ROOT`
93
+ 或已有旧的仓库内 `domain_knowledge` 时会优先沿用。点击「编译」后,
94
+ `03_compiled` 会生成 `wiki_notes.json`、`knowledge_graph.json`、
95
+ `vector-manifest.json`、`vectors.binary` 和 `vectors.int8`。未修改的 wikiNote
96
+ 会复用已有向量,只有新增或变更的 note 重新编码;编码与重排各自使用常驻 Python
97
+ worker(同一份 `src/python/embedding_worker.py`),避免每个请求重复加载模型。
98
+
99
+ BERT 重排默认使用 `BAAI/bge-reranker-base`;如需完全离线,可把模型放到
100
+ `~/.tita-data-agent/models/bge-reranker-base`(会被自动发现),或设置
101
+ `DSH_RERANK_MODEL` / 在设置里填写本地路径。未安装时召回会降级到融合分数并给出警告。
102
+ **目录必须含分词器**(`tokenizer.json` 或 `sentencepiece.bpe.model`)——只有权重时模型会
103
+ 加载成功但给所有输入同一个分(`RERANK_TOKENIZER_DEGENERATE`),见
104
+ `docs/0024-本地模型运行时.md`。
105
+
106
+ 知识写入、编译、SourceRaw 读取和召回支持统一的
107
+ `sessionId/turnId/intentId/taskId/subtaskId/runId/traceId/domain` lineage。卡片把
108
+ 创建和状态变更写入 `provenance`,编译报告返回 `compileRunId`,召回返回
109
+ `recallId`;这些事件也会进入 `memory/<库 id>/access-audit.ndjson`,便于从最终产物
110
+ 反查到原始任务。
111
+
112
+ 可以通过工具 `check_knowledge_embeddings` 或 `GET /knowledge/embedding/health`
113
+ 查看 provider、模型、设备、索引条数和最后一次错误。
114
+
115
+ ## 格式转换(convert seam,0018)
116
+
117
+ 多格式转换的 **DSH 宿主层**自 0018 起就在本插件里:不再是第二个挂载插件,而是本插件的一个
118
+ 子模块(`src/convert/`),共用同一次挂载、同一个侧边栏 Tab、同一套 runtime。
119
+
120
+ ```
121
+ plugins/dsh-data-domain-knowledge/src/convert/
122
+ ├─ host.ts 工具 /convert_*、路由 /convert/**、设置、面板
123
+ ├─ ingest.ts 唯一写入口:ingestDelivery() → runtime.addSource()
124
+ ├─ core-loader.ts 可选内核的懒加载与降级
125
+ └─ types.ts
126
+ packages/dsh-convert-core 内核(不挂载,可独立运行:node bin/tita-convert.mjs)
127
+ └─ @firecrawl/anydoc MIT / Rust / 预编译绑定:doc docx ppt pptx xls xlsx odt ods odp rtf epub csv 文本层 PDF
128
+ ```
129
+
130
+ | 项 | 值 |
131
+ | --- | --- |
132
+ | 工具 | `convert_capabilities` / `convert_source` / `convert_task` / `convert_ingest`(后两个写操作需本轮审批) |
133
+ | 路由 | `/convert/**`(含内核 Vue3 控制台) |
134
+ | 设置命名空间 | `tita-data-agent-convert`(冻结契约,由本插件安装) |
135
+ | 交付目录 | `~/.tita-data-agent/convert-out/<taskId>/`(`index.md` / `assets/` / `manifest.json`) |
136
+
137
+ **依赖是可选的。** `dsh-convert-core` 声明在 `optionalDependencies`,由
138
+ `core-loader.ts` 在首次调用时 `import()`。平台没有 anydoc 预编译绑定、或用户显式不装时,
139
+ `convert_*` 与 `/convert` 面板返回 `DEPENDENCY_MISSING` 并给出安装建议,**knowledge 本体
140
+ (`add_source` / 编译 / 召回)照常可用**。不要把它改成静态 import:有一条测试守着这件事。
141
+
142
+ **入库是进程内调用。** `ingestDelivery()` 直接调 `runtime.addSource()`,不再走
143
+ `POST /knowledge/sources` 回环。少了一次 JSON 序列化,也因此没有旧的 ~1.2 MB body 上限。
144
+ 单条 SourceRaw **没有字符数上限**:`maxSourceBytes` 在 0029 撤掉了(先撤面板上的字段,
145
+ 后来连运行层那道闸门一起撤 —— 只撤面板等于留一个用户改不了、也找不到的硬上限)。
146
+ 真正的边界是转换内核的 `maxInputBytes`(管入口大小)与嵌入分批(管模型输入)。
147
+
148
+ 三条红线(改这一块前先读):
149
+
150
+ 1. 内核不 import knowledge,产物只写 `convert-out/`;
151
+ 2. 转换代码写知识库只能经 `ingest.ts` 的 `IngestTarget.addSource`,别处不许直接落 `01_source_truth`;
152
+ 3. 0017 的网页 / 视频 / OCR 应做成**可选适配器包**注册进内核,不要继续往本插件里塞 ffmpeg / whisper。
153
+
154
+ ## 多知识库与文档(0021)
155
+
156
+ 一个**知识库 = 独立配置 + 独立内容**(产品参照 WeKnora)。注册表持久化在
157
+ `<dataHome>/knowledge-bases.json`,`dataHome = process.env.TITA_DATA_AGENT_HOME || ~/.tita-data-agent`。
158
+ 默认库 id 固定为 `default`,其 `rootDir` 始终来自插件设置 `rootDir`(缺省
159
+ `defaultKnowledgeRoot()`);**不传 `kb` 的旧接口与旧工具一律作用于默认库,行为不变**。
160
+
161
+ ```ts
162
+ interface KnowledgeBase { id; name; description; rootDir; isDefault; sourceTypes; wikiTypes; wikiSchemaMode; createdAt; updatedAt; sourceCount; cardCount; noteCount; buildVersion }
163
+ ```
164
+
165
+ `sourceCount` / `cardCount` / `noteCount` / `buildVersion` 和每条分类/类型的计数都是
166
+ **计算字段**,由 `KnowledgeBases.refresh()` 从真实 runtime 重新统计并缓存进同一个 JSON,
167
+ 所以 `list()` / `get()` 保持同步签名,HTTP `GET /knowledge/bases` 在返回前先
168
+ `await refresh()`。
169
+
170
+ 0029 / 0032:**根路径下是六段**:
171
+
172
+ | 段 | 装什么 | 删掉的后果 |
173
+ | --- | --- | --- |
174
+ | `domain_knowledge/` | 知识树,按知识库 id 分叉 | 丢数据 |
175
+ | `memory/<知识库 id>/` | 版本快照、反馈、访问审计(append-only) | 丢历史,不可重建 |
176
+ | `intent/` | `registry.json`(分类 / act 词表)+ `records.ndjson`(每轮一条留痕) | 丢配置与审计流 |
177
+ | `output/` | 交付物,二级按日期分桶 | 什么都不损失 |
178
+ | `tmp/` | 运行期临时文件,二级按日期分桶 | 只影响未完成的任务 |
179
+ | `resource/` | 模型、Python 环境、`knowledge-bases.json` | 失去语义检索(嵌入/重排不可用) |
180
+
181
+ **记忆与意图为什么与知识树平级**(0032 的架构调整):记忆装的是版本快照与审计流水 ——
182
+ 那是**关于这个 Agent 的动作留痕**,不是关于知识的断言;留在知识树里会让「备份知识树」
183
+ 被迫连审计一起备份,也让「知识树有哪几段」这个问题混进一个横切层。意图则是**会话级**的
184
+ (同一句话在哪个知识库下说,理解方式不该变),所以它不分库;它的两份东西原来一个住在
185
+ 宿主的 settings 文档里、一个只在内存里,都不是「这个 Agent 自己的文件」。搬出来之后,
186
+ 知识、记忆、意图三段都是可以直接备份、直接 diff 的用户文件。
187
+
188
+ 知识树内部(`domain_knowledge/<知识库 id>/`)0032 起是**四段**:`00_schema`(0030 撤,
189
+ 它从建出来起就是空目录)与 `04_memory`(0032 搬去 `memory/`)都已不在。
190
+
191
+ | 段 | 装什么 | 删掉的后果 |
192
+ | --- | --- | --- |
193
+ | `01_source_truth/<source_type>/` | SourceRaw,一级是**来源分类**,二级是文档 | 丢数据 |
194
+ | `02_wiki/<entity_type>/` | Wiki 卡片,一级是卡片类型 | 丢结论 |
195
+ | `03_compiled/` | wikiNotes / 向量 / 知识图谱 | 可重建 |
196
+ | `05_diagnosis/` | 智能归因图谱 | 可重建 |
197
+
198
+ `00_schema` 撤掉的依据:它从建出来那天起就是一个**空目录**。分类注册表与 Wiki 类型
199
+ 注册表一直住在 `<agentRoot>/resource/knowledge-bases.json`(那是配置,跟着根路径走);
200
+ `00_schema` 里没有一行代码写过东西。「磁盘上有一个文件夹」本身是一种承诺,空着就是
201
+ 误导。`ensureLayout` 会在启动时把空的 `00_schema` 删掉 —— **非空则保留**:那就不属于
202
+ 「没用的空文件夹」了,删掉别人的文件比留一个空目录危险得多。
203
+
204
+ `01_source_truth` 按分类分目录(而不是平铺)的理由与 `02_wiki` 一致:分类是每份来源的
205
+ 必备元数据(frontmatter 的 `source_type`),提到目录名上之后「按分类找东西」在文件系统
206
+ 层面直接成立,不依赖界面。平铺在真实使用里会先变成垃圾场 —— 几十份来源混在一层,`ls`
207
+ 读不出「我的指标口径在哪」。启动时一次性把平铺的文档搬进分类目录;读路径不依赖这个层级
208
+ (`sourceIndex` 递归扫全段建 slug → path 索引),所以旧布局、新布局与两者并存的中间态
209
+ 都能读。**改分类 = 换目录**:`add_source` 用同一 `sourceId` 配新 `sourceType` 时,旧目录
210
+ 里那份会被删掉,不会留下孤儿。
211
+
212
+ `resource/` 是 0029 新增的:模型与虚拟环境原来住在 `~/.tita-data-agent`,现在搬进
213
+ 根路径 —— 「这个 Agent 的全部磁盘足迹」因此是一个目录,备份 / 迁移 / 整个删掉都只
214
+ 需要认一个路径。启动时一次性搬迁(先 `rename`,跨卷**不自动复制**,因为可能有几个
215
+ GB);旧的 `TITA_DATA_AGENT_HOME` 留在解析链上作为兜底,所以搬与没搬都能跑。
216
+ 搬迁**按条目合并**:`resource/models/` 里已经有用户自己放的模型时,仍会把旧的嵌入模型
217
+ 搬进来,只跳过同名的那个 —— 否则「目标目录存在」会让另一样东西永远搬不过来。
218
+
219
+ 配置里 `python` / `embeddingModel` / `rerankModel` 三个字段的**默认值改成了空串 =
220
+ 自动**:按 `<agentRoot>/resource/…` → 旧家当目录 → 兜底名(`python3` / HF 模型名)
221
+ 的顺序解析。设置面板用占位符显示解析后的真实路径,并在**家当不在 `resource/` 下时
222
+ 逐条告警**(「还在旧位置、重启会搬」和「根本不是路径、迁移搬不了」要做的事不同)。
223
+
224
+ > ⚠️ 这三个字段的 schema **不能写 `.min(1)`**。schemastery 与 zod 不同,它会**校验默认值
225
+ > 本身**,`z.string().min(1).default('')` 会让 `settings.installSection()` 在登记命名空间
226
+ > 时直接抛 —— 后果是整个设置分区注册不上(面板「设置服务不可用」)、家当迁移不执行、
227
+ > `settings.yaml` 里的值一个都不生效,而界面上没有任何原因。见
228
+ > `src/settings-schema.ts` 的模块注释与 `tests/settings-schema.test.mjs`。
229
+
230
+ 向量清单里记的模型名也从绝对路径改成了 `local:<模型目录名>` —— **身份与位置解耦**,
231
+ 否则把模型搬一次就让整个索引判成「配置不匹配」而作废。
232
+
233
+ 0029:**「文件类型 → 解析引擎」那张规则表已撤。** 它唯一被读的地方是浏览器决定
234
+ 「这份文件直读还是送转换内核」,而那个判断现在只看扩展名本身(`DIRECT_READ_EXT`);
235
+ 真正决定用哪个适配器的是**转换内核自己的格式表**(`ANYDOC/SCANNED/IDDOC/TEXT_EXTENSIONS`),
236
+ 它从来不读这张表 —— 也就是说「把 .docx 设成直读文本」这类配置**改了不生效**。撤掉
237
+ 之后:上传选择框的 `accept` 问内核要(`/convert/api/capabilities`),文件类型筛选项
238
+ 和计数从**这一库真实的文档**推导。两边都不可能再与内核漂移。
239
+
240
+ **文档扩展名 `ext` 的推导是有损的**(`deriveSourceExt`,代码注释同):优先取
241
+ `metadata.source_path` 的 basename 扩展名;否则 `source_format === 'markdown'` → `.md`,
242
+ `'office'` → `.docx`,其余 → `.` + `source_format`;都没有 → `.md`。只有上游
243
+ `convert/ingest.ts` 写了 `source_path` 时才精确。
244
+
245
+ 文档的 `parser` 字段说的是**谁解析了这份文档**:经转换内核进来的由
246
+ `convert/ingest.ts` 写 `metadata.parser`(如 `anydoc@1/pdf`),直接写进来的
247
+ (`add_source`、浏览器直读文本)是 `direct` —— 没有解析器。0029 之前这里会按扩展名
248
+ 猜一个引擎名(`.pdf` → `anydoc`),那是在陈述一件没有发生过的事。
249
+
250
+ ### HTTP API
251
+
252
+ ```text
253
+ GET /knowledge/bases → { bases, defaultBaseId }
254
+ POST /knowledge/bases { name, description?, rootDir? } → { base }
255
+ PATCH /knowledge/bases/:id { name?, description?, sourceTypes?, wikiTypes?, wikiSchemaMode? } → { base }
256
+ DELETE /knowledge/bases/:id → { deleted: true }
257
+ GET /knowledge/documents?kb=&query=&source_type=&limit=&offset= → { documents, total }
258
+ GET /knowledge/documents/:docId?kb= → { document }
259
+ GET /knowledge/documents/:docId/versions?kb= → { versions }
260
+ POST /knowledge/documents/:docId/revert?kb= { versionId } → { document }
261
+ DELETE /knowledge/documents/:docId?kb= → { deleted: true }
262
+ GET /knowledge/assets/:kb/* → 知识库根目录下的文件流
263
+ ```
264
+
265
+ `/knowledge/stats`、`/knowledge/search`、`/knowledge/rebuild`、`/knowledge/cards`、
266
+ `/knowledge/sources`、`/knowledge/graph`、`/knowledge/embedding/health` 与全部
267
+ `*_knowledge*` 工具都接受**可选** `kb`(query 或 body 字段)。`docId` 含 `:`
268
+ (如 `document:ab12…`),必须 URL 编码。
269
+
270
+ ### 删除守卫(409)
271
+
272
+ | 操作 | 条件 | 错误码 | HTTP |
273
+ | --- | --- | --- | --- |
274
+ | `DELETE /knowledge/bases/:id/source-types/:typeId` | 内置分类 | `SOURCE_TYPE_BUILTIN_LOCKED` | 409 |
275
+ | `DELETE /knowledge/bases/:id/source-types/:typeId` | 该分类下还有来源 | `SOURCE_TYPE_IN_USE` | 409 |
276
+ | `PATCH /knowledge/bases/:id`(`sourceTypes` 丢掉在用分类) | 该分类下还有来源 | `SOURCE_TYPE_IN_USE` | 409 |
277
+ | `DELETE /knowledge/bases/:id` | 目标库是默认库 | `BASE_IS_DEFAULT` | 409 |
278
+ | `DELETE /knowledge/bases/:id` | 库里还有文档 | `BASE_IN_USE` | 409 |
279
+
280
+ 守卫失败时**整体不写入**(PATCH 不会出现「名称改了、规则没删」的半成品状态),响应
281
+ 同时给出 envelope 的 `error.code` 与顶层 `code`/`message`。删除知识库只删注册表条目,
282
+ **不删磁盘内容**(删文档用 `DELETE /knowledge/documents/:docId`)。
283
+
284
+ ### 版本存储与回滚语义
285
+
286
+ 在 `addSource` 覆盖写入之前,如果目标文件**正文**与新的正文不同,就把**旧文件字节**
287
+ 原样快照到 `memory/<库 id>/source-versions/<docSlug>/<versionId>.md`,
288
+ `versionId = <紧凑ISO时间>-<contentHash 前 8 位>`(如 `20260102T030405123Z-9f3c1a2b`)。
289
+ 内容完全相同的重复写入不产生版本。快照本身也是 markdown(含 frontmatter),
290
+ `listVersions` 返回新→旧,并把当前 head 作为 `isCurrent: true` 的第一条一并列出
291
+ (head 的 `versionId` 形如 `current-<hash8>`)。
292
+
293
+ **回滚 = 用快照内容重新调用 `addSource`**:因此回滚前会把当时的 head 再快照一次,
294
+ 历史只增不减,**回滚本身也可回滚**。回滚 `current-*` 是 no-op。
295
+
296
+ ### 召回链路(0031 起:两路 + 图谱 boost)
297
+
298
+ ```text
299
+ query → R0 分词 → R1 两路各自超采并过阈值(候选池 50)
300
+ → R2 RRF 名次级融合 + 图谱 boost
301
+ → R3 对**候选池**重排,过重排阈值
302
+ → R4 组装:片段 → 卡片 → SourceRaw 证据(每卡封顶 + MMR)
303
+ → R5 弃答(insufficientEvidence)
304
+ ```
305
+
306
+ - **R0 分词**(`fts.ts`):中文按**单字 + 相邻双字**切分(不用词典),ASCII 按 `unicode61`
307
+ 的口径切开。0030 的 `tokens()` 只按非字母数字切,整句中文会变成一个 token ——
308
+ 实测 `排查`→6 命中、`怎么排查指标异常`→**0**。
309
+ - **R1 关键词路**:SQLite FTS5 + **BM25**(`node:sqlite`,零新依赖;不可用时如实降级)。
310
+ 中文之所以不用内置 tokenizer:`unicode61` 不切中文,`trigram` 要求查询 ≥3 字符且会把
311
+ 整句变成互相 AND 的三字窗口。分数按本次最高分归一到 0..1,再过 `keywordThreshold`;
312
+ 另有**多字词覆盖率**门槛(只数双字词与 ASCII 词,单字在中文里不是证据)。
313
+ - **R1 向量路**:**编码器健康门**(两段无关文本必须余弦 < 0.99,否则整路停用)→
314
+ 查询编码一次 → binary/Hamming 预筛 → int8 精算**原始余弦**(`dot / 127²`,0030 多除了
315
+ 一个 dimension,把余弦压进 ±0.001、排序完全没有区分度)→ `vectorThreshold`。
316
+ - **R2 融合**:**RRF**(`k=60`,关键词 0.3 / 向量 0.7)——只吃**名次**,所以三路分数
317
+ 量纲不同这件事不再影响排序(0030 的加权和让向量输出常数时所有命中同分)。
318
+ - **R2 图谱**:**boost,不是第三路**。它给已经在候选池里的条目加一个 RRF 项,**不能自己
319
+ 制造候选**。代价是「只提到某份来源、没提到任何卡片正文」的查询没有第二条路 ——
320
+ 由关键词索引收录 **note 的溯源身份**(sourceRefs + 来源标题)来补偿。
321
+ - **R3 重排**:作用在**候选池**上(不再是已截断的 topK,0014 点名的「分层只做了一半」),
322
+ 低于 `rerankThreshold` 的一律丢弃并报出丢了几条。阈值与 WeKnora 同刻度(**原始 logit**)。
323
+ worker 用 `predict_raw()`(`activation_fn=Identity`)返回 logit —— `CrossEncoder.predict`
324
+ 对 `num_labels == 1` 默认套 sigmoid,直接拿返回值比 0.2 会让阈值永远不生效;展示用的
325
+ `rerankScore` 由 `applyRerank()` 只 sigmoid 一次(`0.5` 这种「刚好在门槛上」的假分数
326
+ 是二次 sigmoid 的产物)。
327
+ - **R4 组装**:`context` 条目带**证据片段**(`sourceRefs` 解析到 SourceRaw 正文里覆盖查询词
328
+ 的那几段),所以「片段 → 卡片 → 原文」三层自包含;选择时**每张 wiki 封顶 2 条 + MMR**
329
+ (λ=0.7),否则 5 条上下文可能全是同一张卡的不同小节。
330
+ - **R5 弃答**:一路都没过阈值 → `insufficientEvidence: true` + `diagnostics.reason`,
331
+ 并标注判据强度(`rerank-threshold` / `vector-threshold` / `relative-only` / `not-needed`)。
332
+ 宁可说「没有」,也不凑满 topN 让模型编。
333
+ - **降级不谎报**:`routes` 只列**通过健康门且真的跑起来**的路;每一路的状态、候选数、
334
+ 最高分、阈值与降级原因都在 `diagnostics.routes` 里。0030 的向量路坏掉时照样上报
335
+ `routes: ["fts","vector","graph"]`,是这次要修的核心问题之一。
336
+ - `mode: 'graph'` 与 `hybrid` **同义**(图谱不能制造候选,「只靠图谱」不成立)。
337
+ - 阈值初值:`keywordThreshold 0.3` / `rerankThreshold 0.2` 沿用 WeKnora 的出厂值;
338
+ **`vectorThreshold` 是 0.5,不是它的 0.15** —— 那个数是它自己 embedding 模型的刻度,
339
+ 搬到 WeMM 上会让无关查询照样召回 43/44 条(实测无关查询最高余弦 0.42、相关查询 0.60–0.83,
340
+ 两簇之间有 0.42–0.59 的空带)。`recallCandidatePool` 50(对齐 `EmbeddingTopK`)。
341
+ **阈值必须按模型与语料校准**,依据是每次召回的 `diagnostics.routes[vector].topScore`
342
+ 与 `rerank.topLogit`。
343
+ - **模型健康门**:两个本地模型各有一个会失败的探针 —— 编码器比自相似度(≈1 且不同文本
344
+ 余弦 < 0.99),重排器查分词器词表(`vocab_size ≥ 1000` 且探针句有非 `<unk>` 条目,否则
345
+ `RERANK_TOKENIZER_DEGENERATE`)。原因是「能加载」不等于「可用」:本地快照缺分词器文件时,
346
+ 重排器照样加载、照样出分(实测三条无关文本 `0.999 / 0.998 / 0.9994`),只有探针能发现。
347
+ 修法与运维见 `docs/0024-本地模型运行时.md`。
348
+ - **编码器指纹** `ENCODER_FINGERPRINT` 写在向量清单里:同一个模型换了「怎么调它」也必须让
349
+ 已有向量作废,否则 `rebuild all` 会按 contentHash 把旧向量原样复用(0031 实测过:
350
+ 修好编码器后构建仍报 `reused: 44`,修复等于没发生)。
351
+
352
+ `listDocuments()` / `readDocument(docId)` / `listVersions(docId)` /
353
+ `revertDocument(docId, versionId)` / `deleteDocument(docId)` 是 `KnowledgeRuntime` 上
354
+ 新增的文档接口;详情页的 `assets[].url` 即 `/knowledge/assets/<kbId>/<rel>`。
355
+
356
+ ## 评测
357
+
358
+ 公开数据集与 Tita qrels 格式、运行命令和 FTS / WeMM / hybrid 对比矩阵见
359
+ [`eval/README.md`](eval/README.md)。本地 runner 是只读的,不会自动修改 Knowledge
360
+ Store。