2544 lines
89 KiB
Markdown
2544 lines
89 KiB
Markdown
# 技能归纳、WeKnora 普通知识库与助手知识库:实现设计
|
||
|
||
本文档用于指导大模型或开发者实现知识库体系改造。整体包含两条线:一条是“将一个或多个技能归纳到一个 WeKnora Wiki 普通知识库”;另一条是新增自研助手知识库体系。助手知识库像普通知识库一样可以创建多个库,同时系统内置一个全局大库,用于统计全库数据、承接所有 WeKnora 导入沉淀、做全局实体对齐、Wiki 展示和导入审计。
|
||
|
||
本文档中,技能归纳目标只能是 WeKnora Wiki 普通知识库;助手知识库不接收技能直接归纳,也不接收任意本地文件。普通知识库负责向量化、检索、Wiki 和图谱;助手知识库负责自研存储、WeKnora 导入、实体对齐、Wiki 展示、搜索和导入审计。无论 WeKnora 数据导入到哪个助手知识库,最终都必须沉淀一份到系统全局大库。
|
||
|
||
> 最终约束:如果本文历史章节与本节冲突,以本节和“2. 当前边界”中的约束为准。
|
||
|
||
## 1. 背景与目标
|
||
|
||
当前系统已有:
|
||
|
||
- 技能管理:后台可管理运行中的技能,技能文件位于 `skills/public`、`skills/custom`。
|
||
- 技能地址管理:已经在管理员技能管理页中以标签页形式接入,支持扫描技能内 `.md`、`.py` 中的地址并批量替换。
|
||
- WeKnora / LLM Wiki 接入:前后端已有知识库、文档、Wiki 页面、Wiki 图谱等 API。
|
||
|
||
本次要新增一条管理员工作流:
|
||
|
||
管理员在“技能管理”页面选择多个技能,再选择一个目标 WeKnora Wiki 普通知识库,点击归纳。系统将每个技能作为独立来源读取、解析、抽取和归纳,把结果写入对应 WeKnora 知识库,并在技能列表和技能详情中展示“该技能已被哪些知识库归纳”。如果需要归纳到多个普通知识库,通过多次操作完成。
|
||
|
||
用户已确认的业务约束:
|
||
|
||
- 一次操作可以选择多个技能,但只能选择一个目标 WeKnora Wiki 普通知识库。
|
||
- 同一个技能可以在不同时间归纳到多个知识库,所以最终关系是技能与知识库多对多。
|
||
- 多知识库归纳通过多次操作完成;每次操作形成一批 `技能 x 单目标知识库` 任务。
|
||
- V1 只支持归纳到可写 WeKnora Wiki 普通知识库;不支持非 Wiki、FAQ、系统会话存档、只读知识库作为技能归纳目标。
|
||
- 技能归纳时只抽取数据、业务说明、实体、概念、对象、事件、关系等知识;Python、TypeScript、Shell 等代码和脚本类文件完全排除,不读取注释、不抽取函数、不上传、不进入 prompt。
|
||
- 技能里的 Markdown、业务数据文件、表格、PDF、Office、图片等要纳入处理范围。
|
||
- 需要同步三类内容:原始资料、归纳后的 Wiki、实体与关系。
|
||
- 关系来源包括 Markdown 自然语言描述、目录和文件引用、模型自动推断。
|
||
- 允许模型推断关系,但前端不提供逐条实体/关系预览审核。
|
||
- 支持管理员手动点击“重新归纳”;不新增自动文件监听、定时后台同步或技能变更自动远程写入。
|
||
- 解除关联时弹窗让用户选择:保留知识库内容,或删除该技能贡献的内容。
|
||
- 权限仅管理员。
|
||
- 总技能数约 200 个,需要支持批量进度、后台执行、失败重试。
|
||
- 同一目标知识库内,不同技能抽取出的同一实体需要合并。
|
||
- 重归纳时先生成新版本,成功后再替换旧版本;失败时旧版本继续可用。
|
||
- 新增知识库类型区分:普通知识库是 WeKnora,助手知识库是自研存储。
|
||
- 助手知识库支持创建多个库;其中有且只有一个系统全局大库,建议命名为“知识梳理总库”,所有用户可见。
|
||
- 助手知识库只提供 Wiki 页面展示、搜索和数据导入;不落到 WeKnora。
|
||
- 助手知识库数据来源只能是 WeKnora 导出包或从某个 WeKnora 知识库触发导入。
|
||
- WeKnora 已向量化和处理完成的 Wiki、文档、实体、关系、图谱数据默认沉淀到助手知识库;如果导入的是某个自建助手库,也必须同步沉淀到全局大库。
|
||
- 普通知识库需要提供导出或“导入到助手知识库”的功能,把 WeKnora 里已经处理好的数据导入指定助手知识库;导出数据需要包含 Wiki、文档、chunk、实体、关系、图谱。
|
||
- 即使没有配置 WeKnora 地址,也要默认展示助手知识库列表和创建入口,而不是展示空的普通知识库页面。
|
||
- 管理员可切换知识库产品版本:`v1` / `v2`,默认 `v1`。
|
||
- 助手知识库普通用户只读,管理员可导入、编辑、删除、查看版本和回滚 Wiki 页面。
|
||
|
||
## 2. 当前边界
|
||
|
||
以下能力明确不做,开发实现和验收必须按这些边界收敛:
|
||
|
||
- 不支持一次选择多个目标知识库。多知识库归纳通过多次操作完成。
|
||
- 不支持非 Wiki 知识库、FAQ 知识库、系统会话存档知识库、只读知识库作为技能归纳目标。
|
||
- 不直接写 WeKnora 的 Neo4j 或底层图数据库。
|
||
- 不新增自动文件监听、定时后台同步或技能变更自动远程写入。
|
||
- 不在前端提供逐条实体/关系预览审核。
|
||
- 不把远端 WeKnora 内部 ID 暴露为前端业务主键。
|
||
- 不支持技能直接归纳到助手知识库。技能先进入 WeKnora 普通知识库,再由 WeKnora 导出沉淀到助手知识库。
|
||
- 不支持管理员向助手知识库导入任意本地文件;手动导入也必须是 WeKnora 导出包或从某个 WeKnora 知识库触发。
|
||
- 助手知识库 V1 不做页面版本管理,只保留当前合并后的 Wiki 状态和导入审计记录。
|
||
|
||
## 3. 术语
|
||
|
||
| 术语 | 含义 |
|
||
| --- | --- |
|
||
| 技能 | DeerFlow 技能目录,通常包含 `SKILL.md`、代码、配置、示例、文档、数据文件等。 |
|
||
| 目标知识库 | 管理员选择的一个 WeKnora Wiki 普通知识库。助手知识库不是技能归纳目标。 |
|
||
| 普通知识库 | WeKnora 知识库,负责向量化、Wiki、文档检索和图谱能力。 |
|
||
| 助手知识库 | DeerFlow 自研知识库类型,支持创建多个库,用于 Wiki 展示、搜索、WeKnora 导入和实体对齐。 |
|
||
| 知识梳理总库 | 助手知识库体系中的系统全局大库,有且只有一个,自动统计和沉淀所有助手库与普通知识库导入数据,做全局实体对齐。 |
|
||
| 自建助手库 | 管理员创建的普通助手知识库,类似普通知识库列表中的一个库,可导入 WeKnora 普通知识库导出数据。 |
|
||
| 产品版本 | 知识库产品形态开关。`v1` 默认为普通知识库体验,`v2` 默认为助手知识库体验。 |
|
||
| WeKnora 导出包 | 从普通知识库导出的已处理知识集合,包含 Wiki 页面、文档、chunk、实体、关系、图谱等。 |
|
||
| 绑定 | 一个技能与一个目标知识库之间的持久关联。`skill_name + target_type + target_id` 唯一。 |
|
||
| 快照 | 某次扫描技能目录得到的内容版本,包含文件清单、摘要、抽取结果和源 digest。 |
|
||
| 贡献 | 某个技能快照对目标知识库内实体、关系、Wiki 页面、原始资料的增量内容。 |
|
||
| 规范实体 | 在同一个目标知识库内合并后的实体。多个技能可以贡献到同一个实体。 |
|
||
| 规范关系 | 在同一个目标知识库内合并后的关系。多个技能可以给同一关系提供证据。 |
|
||
| 归纳任务 | 一次管理员发起的批量操作,可包含多个目标知识库和多个技能 item。 |
|
||
| item | 归纳任务中的单个技能处理单元。 |
|
||
|
||
## 4. 总体方案
|
||
|
||
整体采用“双知识库形态 + 本地持久绑定 + 后台任务 + WeKnora 投影 + 助手底库实体对齐”的架构。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A[管理员选择多个技能] --> B[选择一个 WeKnora Wiki 目标知识库]
|
||
B --> C[创建归纳任务]
|
||
C --> D[逐技能扫描与解析]
|
||
D --> E[生成技能快照]
|
||
E --> F[LLM 归纳 Wiki 与关系抽取]
|
||
F --> G[按目标 WeKnora Wiki 合并实体/关系]
|
||
G --> H[写入 WeKnora 原始资料与 Wiki]
|
||
G --> I[写入关系投影文档]
|
||
H --> K[校验远端写入]
|
||
I --> K
|
||
K --> L[本地原子激活新版本]
|
||
L --> M[技能页展示已归纳知识库]
|
||
K --> N[WeKnora 导出已处理数据]
|
||
N --> O[导入指定助手知识库]
|
||
O --> P[同步沉淀到知识梳理总库]
|
||
P --> Q[全局实体对齐]
|
||
Q --> S[总库 Wiki 展示与搜索]
|
||
```
|
||
|
||
关键原则:
|
||
|
||
- DeerFlow 本地数据库保存权威绑定关系、版本状态、来源贡献和远端 artifact 映射。
|
||
- WeKnora 保存可检索知识内容,包括原文、Wiki 页面、FAQ、会话存档、关系投影文档和图谱。
|
||
- 不直接写 WeKnora 底层图数据库;关系以 WeKnora API 能力和关系投影文档承接。
|
||
- 重归纳使用 staged artifact,远端写入和校验成功后,本地才激活新版本。
|
||
- 删除或解除关联只影响该技能在目标知识库中的贡献,不误删其他技能共享的实体和关系。
|
||
- 助手知识库可以创建多个库;系统全局大库只有一个,负责汇总全库数据和做跨库实体对齐。
|
||
- WeKnora 的已处理结果可以导入指定助手知识库;无论是否指定自建助手库,都必须同步沉淀到知识梳理总库。
|
||
- 未配置 WeKnora 地址时,默认进入助手知识库页面,展示助手知识库列表、创建入口和知识梳理总库;与 WeKnora 相关的导出导入动作置灰或隐藏。
|
||
|
||
## 5. 现有代码落点
|
||
|
||
实现前必须先读仓库说明:
|
||
|
||
- `D:/cmzs-clean/deerflow-code/AGENTS.md`
|
||
- `D:/cmzs-clean/deerflow-code/offline-backend-20260512/backend/AGENTS.md`
|
||
- `D:/cmzs-clean/deerflow-code/offline-backend-20260512/backend/CLAUDE.md`
|
||
|
||
建议改动位置:
|
||
|
||
| 模块 | 建议文件 |
|
||
| --- | --- |
|
||
| 后端 router | `offline-backend-20260512/backend/app/gateway/routers/skill_knowledge.py` |
|
||
| 后台任务调度 | `offline-backend-20260512/backend/app/gateway/skill_knowledge_job_dispatcher.py` |
|
||
| 后台任务执行 | `offline-backend-20260512/backend/app/gateway/skill_knowledge_job_executor.py` |
|
||
| 技能归纳核心逻辑 | `offline-backend-20260512/backend/packages/harness/deerflow/skill_knowledge/` |
|
||
| 持久化模型 | `offline-backend-20260512/backend/packages/harness/deerflow/persistence/skill_knowledge/` |
|
||
| WeKnora 客户端扩展 | `offline-backend-20260512/backend/packages/harness/deerflow/integrations/weknora/client.py` |
|
||
| 助手知识库核心逻辑 | `offline-backend-20260512/backend/packages/harness/deerflow/assistant_knowledge/` |
|
||
| 助手知识库持久化 | `offline-backend-20260512/backend/packages/harness/deerflow/persistence/assistant_knowledge/` |
|
||
| 助手知识库 Gateway | `offline-backend-20260512/backend/app/gateway/routers/assistant_knowledge.py` |
|
||
| WeKnora 导出到助手库任务 | `offline-backend-20260512/backend/app/gateway/assistant_knowledge_import_executor.py` |
|
||
| 前端 API | `frontend-web/src/strategy-components/api/skill-knowledge.ts` |
|
||
| 助手知识库前端 API | `frontend-web/src/strategy-components/api/assistant-knowledge.ts` |
|
||
| 管理员技能页 | `frontend-web/src/pages/AdminSkillsPage.tsx` |
|
||
| 技能行组件 | `frontend-web/src/components/workspace/settings/skill-settings-page.tsx` |
|
||
| WeKnora API hooks | `frontend-web/src/strategy-components/api/llmwiki.ts` |
|
||
| 知识库产品版本设置 | `frontend-web/src/core/system-settings/api.ts` |
|
||
|
||
注意边界:
|
||
|
||
- `packages/harness/deerflow/*` 不能 import `app.*`。
|
||
- 路由、鉴权、FastAPI app state 等放在 `app/gateway/*`。
|
||
- 纯扫描、解析、抽取、合并、投影计划生成放在 `deerflow.*`。
|
||
- 文件 IO、Office/PDF 转换、CPU 密集处理必须通过 `asyncio.to_thread`,避免阻塞事件循环。
|
||
|
||
## 6. WeKnora 能力使用策略
|
||
|
||
现有 WeKnora 客户端已支持:
|
||
|
||
- 创建知识库。
|
||
- 上传文件。
|
||
- 导入 URL。
|
||
- 创建手动文档。
|
||
- 创建、更新、删除、查询 Wiki 页面。
|
||
- 获取 Wiki 图谱。
|
||
|
||
V1 需要新增或补齐:
|
||
|
||
- 目标知识库能力探测:是否启用 Wiki,是否可写,是否支持 GraphRAG / extract_config。
|
||
- 目标知识库分类和能力标识:Wiki、非 Wiki、FAQ、会话存档、只读、图谱可写。
|
||
- 导出已处理数据的能力:Wiki 页面、文档、chunk、实体、关系、图谱。
|
||
- WeKnora 处理完成后的自动沉淀触发点:在文件向量化、Wiki 生成和图谱抽取完成后,创建“导入助手知识库”的后台任务。
|
||
- 如果 WeKnora 当前实例 Swagger 暴露了图谱相关配置更新接口,则在目标知识库启用 `graph_enabled` 与 `extract_config`。
|
||
- 如果未暴露稳定的实体/关系写入 API,优先使用“关系投影文档 + Wiki 关系页 + Wiki 链接”让 WeKnora 自己抽取图谱;在配置显式开启时,可通过受控 Neo4j direct writer 写入底层图数据库。
|
||
|
||
参考官方资料:
|
||
|
||
- [WeKnora Knowledge Graph 文档](https://github.com/Tencent/WeKnora/blob/main/docs/KnowledgeGraph.md)
|
||
- [WeKnora knowledge-base API 文档](https://github.com/Tencent/WeKnora/blob/main/docs/api/knowledge-base.md)
|
||
- [WeKnora QA 文档](https://github.com/Tencent/WeKnora/blob/main/docs/QA.md)
|
||
- [WeKnora API 文档入口](https://github.com/Tencent/WeKnora/blob/main/docs/api/README.md)
|
||
|
||
实现要求:
|
||
|
||
- 以部署实例的 Swagger 为准,不要硬编码未确认的远端 API。
|
||
- 可以封装 `probe_capabilities()`,返回 `wiki_enabled`、`graph_enabled_supported`、`extract_config_supported`、`wiki_page_upsert_supported`、`file_upload_supported` 等能力。
|
||
- GraphRAG 失败不能导致 Wiki 归纳整体回滚。Wiki 与原始资料成功、GraphRAG 写入失败时,绑定状态为 `partial_failed`,错误信息明确写“图谱投影失败,可重新归纳重试”。
|
||
- 如果 WeKnora 不支持直接导出向量、chunk 或图谱原始结构,导出层应退化为读取 Wiki 页面、文档状态、Wiki graph 和可查询的图谱摘要;助手知识库不强依赖复用 WeKnora embedding 向量。
|
||
|
||
### 6.1 目标知识库适配策略
|
||
|
||
一次归纳任务允许选择多个技能和多个目标知识库。后端不要把它当成一个大事务,而是展开为矩阵:
|
||
|
||
```text
|
||
items = selected_skills x selected_targets
|
||
```
|
||
|
||
每个 item 对应一个 `binding`,一个技能归纳到三个目标知识库,就生成三个 binding。父 job 负责展示整体进度,item 独立成功、失败、取消和重试。
|
||
|
||
当目标是自建助手库时,item 写入顺序是:
|
||
|
||
```text
|
||
写入目标助手库 -> 生成目标库 Wiki/实体/关系 -> 创建总库沉淀任务 -> 总库实体对齐和统计
|
||
```
|
||
|
||
总库沉淀失败不能让目标助手库写入结果消失,但 item 必须标记为 `partial_failed`,并允许单独重试“沉淀到总库”。
|
||
|
||
目标知识库需要通过 adapter 写入:
|
||
|
||
| 目标类型 | 写入策略 | Wiki | 关系/图谱 |
|
||
| --- | --- | --- | --- |
|
||
| WeKnora Wiki 知识库 | 上传原始资料、upsert Wiki 页面、写 graph projection | 写 WeKnora Wiki | WeKnora GraphRAG + 可选 Neo4j direct writer |
|
||
| WeKnora 非 Wiki 知识库 | 上传原始资料和归纳文档,不强制生成 Wiki | 不写 WeKnora Wiki,可写本地 sidecar Wiki | graph projection 文档 + 可选 Neo4j direct writer |
|
||
| WeKnora FAQ 知识库 | 把归纳结果转换为 FAQ 条目、来源文档和关系摘要 | 不写或只写 sidecar Wiki | 关系作为 FAQ metadata、projection 文档和图谱边 |
|
||
| 系统会话存档知识库 | 把技能归纳结果作为系统会话归档条目写入 | sidecar Wiki 展示 | 关系作为归档 metadata 和图谱边 |
|
||
| 只读 WeKnora 知识库 | 不修改远端原库;写本地 sidecar artifact,并生成待推送状态 | sidecar Wiki 展示 | sidecar graph + 待推送 Neo4j plan |
|
||
| 助手知识库 | 写入指定助手库、实体对齐、生成 Wiki 页面版本;同时异步沉淀到知识梳理总库 | 写自研 Wiki | 写自研实体/关系表;总库做跨库实体对齐 |
|
||
|
||
只读目标说明:
|
||
|
||
- “支持只读知识库作为目标”不代表绕过远端权限强行写入。
|
||
- 对只读 WeKnora,系统创建本地 sidecar 投影:归纳结果与该远端知识库绑定展示,但远端写入状态为 `pending_remote_write`。
|
||
- 当管理员后续授予可写权限时,可执行“推送到远端”,把 sidecar staged artifact 写入 WeKnora。
|
||
- 前端必须清楚展示“只读目标:已本地归纳,未写入远端”。
|
||
|
||
### 6.2 Neo4j 直接写入设计
|
||
|
||
需求确认需要支持直接写 WeKnora 的 Neo4j 或底层图数据库。该能力风险较高,必须作为受控能力实现。
|
||
|
||
必须满足:
|
||
|
||
- 通过配置显式开启,例如 `weknora.graph.direct_write_enabled = true`。
|
||
- 只允许管理员触发。
|
||
- Neo4j 连接串、账号、库名只允许后端配置,不允许前端传入。
|
||
- LLM 不得生成任意 Cypher 并直接执行。
|
||
- graph writer 只能执行代码中预定义的参数化模板。
|
||
- 所有写入使用事务。
|
||
- 每个节点和边都带稳定业务 key、来源 binding、snapshot、job、confidence 和 evidence。
|
||
- 支持 dry-run plan、写入审计、失败重试、回滚计划。
|
||
|
||
节点 key 建议:
|
||
|
||
```text
|
||
provider = deerflow
|
||
scope = target_type + target_id
|
||
entity_key = entity_type + normalized_name 或 external_id
|
||
```
|
||
|
||
边 key 建议:
|
||
|
||
```text
|
||
source_entity_key + predicate + target_entity_key + contribution_scope
|
||
```
|
||
|
||
Neo4j 写入只作为图谱层加速和展示,不替代本地 contribution 表。本地 contribution 表仍是删除、回滚、重建、审计的权威来源。
|
||
|
||
### 6.3 实体/关系预览审核
|
||
|
||
前端必须提供逐条实体/关系预览审核能力。审核发生在“抽取完成、写入目标前”。
|
||
|
||
审核对象:
|
||
|
||
- 实体。
|
||
- 关系。
|
||
- 实体对齐候选。
|
||
- 关系合并候选。
|
||
- Wiki 页面草稿。
|
||
|
||
管理员操作:
|
||
|
||
- 批准。
|
||
- 拒绝。
|
||
- 编辑名称、类型、谓词、别名、摘要、confidence。
|
||
- 批量批准高置信结果。
|
||
- 批量拒绝低置信结果。
|
||
|
||
审核模式建议:
|
||
|
||
| 模式 | 说明 |
|
||
| --- | --- |
|
||
| `required` | 所有实体/关系必须审核后才能写入。 |
|
||
| `auto_high_confidence` | 高置信自动通过,低置信进入审核队列。 |
|
||
| `off` | 不阻塞写入,但仍保留预览页面和事后审计。 |
|
||
|
||
默认建议 `auto_high_confidence`。如果用户希望“必须逐条审核”,可在系统设置中改为 `required`。
|
||
|
||
审核记录必须入库:
|
||
|
||
- 操作人。
|
||
- 操作时间。
|
||
- 原始抽取值。
|
||
- 修改后值。
|
||
- 通过或拒绝原因。
|
||
- 对应 job/item/binding/snapshot。
|
||
|
||
### 6.4 自动同步设计
|
||
|
||
需要支持三类自动同步:
|
||
|
||
- 文件监听:技能知识文件变化后自动创建归纳任务。
|
||
- 定时同步:按管理员配置的周期重新扫描并归纳。
|
||
- 技能变更自动远程写入:技能保存、启停、导入后触发相关 binding 同步。
|
||
|
||
自动同步仍需遵守:
|
||
|
||
- 只处理非代码知识文件。
|
||
- 代码文件变化不触发归纳。
|
||
- 自动任务必须 debounced,避免保存过程中连续触发。
|
||
- 自动任务必须走 staged 版本,成功后激活,失败保留旧版本。
|
||
- 同一 binding 同一时间只能有一个 active item。
|
||
- 审核模式为 `required` 时,自动任务停在 `awaiting_review`,不写远端。
|
||
|
||
建议新增配置:
|
||
|
||
```json
|
||
{
|
||
"skill_knowledge_auto_sync": {
|
||
"watch_enabled": true,
|
||
"schedule_enabled": true,
|
||
"schedule_cron": "0 */6 * * *",
|
||
"debounce_seconds": 120,
|
||
"write_remote_enabled": true
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.5 远端 ID 暴露与业务 key
|
||
|
||
需求确认前端需要暴露 WeKnora 远端 ID,并可作为跨系统业务 key 使用。
|
||
|
||
实现要求:
|
||
|
||
- API 返回 `remote_refs`,包含 provider、remote kind、remote id、slug、url。
|
||
- 前端可以展示、复制、筛选远端 ID。
|
||
- 与外部系统交互时,可使用 `provider + remote_id` 作为业务 key。
|
||
- 本地数据库仍保留 `id` 作为 surrogate primary key,避免远端 ID 变更导致本地关系断裂。
|
||
|
||
建议响应结构:
|
||
|
||
```json
|
||
{
|
||
"id": "local-artifact-id",
|
||
"business_key": "weknora:wiki_page:remote-page-id",
|
||
"remote_refs": [
|
||
{
|
||
"provider": "weknora",
|
||
"remote_kind": "wiki_page",
|
||
"remote_id": "remote-page-id",
|
||
"slug": "skills/example/overview",
|
||
"url": "/llmwiki/kb/xxx/wiki/skills/example/overview"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
不要把远端 ID 当作唯一存储来源;本地仍需要维护 mapping、审计和状态。
|
||
|
||
## 7. 数据处理范围
|
||
|
||
归纳一个技能时,扫描技能根目录下所有有效的非代码知识文件。代码类文件不作为知识源,也不影响知识 digest。
|
||
|
||
必须处理:
|
||
|
||
| 类型 | 策略 |
|
||
| --- | --- |
|
||
| `.md` / `.mdx` / `.txt` | 直接读取,保留标题、段落、链接、表格和自然语言说明;代码块内容默认跳过,只保留“此处存在示例代码”的弱提示。 |
|
||
| `.json` / `.yaml` / `.yml` / `.toml` / `.ini` | 仅当它们承载业务数据、数据字典、枚举、模板或知识配置时处理;运行配置、依赖配置、工具入口、工程配置不入库。 |
|
||
| `.csv` / `.tsv` | 结构化读取,抽样概要 + 全量原始资料上传。 |
|
||
| `.xlsx` / `.xls` | 使用已有文件转换或表格解析能力,保留 sheet、列名、样例和统计。 |
|
||
| `.pdf` / `.docx` / `.pptx` | 复用现有 `deerflow.utils.file_conversion` 或 MarkItDown 路径转文本,同时上传原始文件。 |
|
||
| 图片 | 上传原始文件;如果已有 VLM/OCR 能力则抽取图片描述,否则记录为二进制附件。 |
|
||
| 压缩包 | 安全解压到临时目录后递归处理,必须限制大小、文件数、路径穿越、符号链接。 |
|
||
| 其他二进制 | 记录 manifest 并尝试作为原始附件上传;无法解析时不生成文本摘要。 |
|
||
|
||
必须排除:
|
||
|
||
- `.py`
|
||
- `.ts`
|
||
- `.tsx`
|
||
- `.js`
|
||
- `.jsx`
|
||
- `.sh`
|
||
- `.bat`
|
||
- `.ps1`
|
||
- 其他脚本、源码、构建脚本、依赖锁文件
|
||
- `.git`
|
||
- `node_modules`
|
||
- `__pycache__`
|
||
- `.pytest_cache`
|
||
- `dist`
|
||
- `build`
|
||
- 临时缓存目录
|
||
- 明确生成物和大体积模型文件
|
||
|
||
必须阻断:
|
||
|
||
- `.env`
|
||
- 私钥、公钥私钥对、证书私钥
|
||
- token、password、secret、access key 等高置信密钥文件
|
||
|
||
阻断规则是安全底线:发现疑似密钥时,该文件不能上传到 WeKnora,也不能进入 LLM prompt。任务 item 标记为 `partial_failed` 或 `failed`,前端展示“因安全策略跳过敏感文件”,并给出文件路径,不输出密钥内容。
|
||
|
||
代码排除规则:
|
||
|
||
- 不读取源码内容。
|
||
- 不抽取源码注释。
|
||
- 不抽取函数、类、import、依赖、入口、调用链。
|
||
- 不上传源码文件。
|
||
- 不把源码路径作为 Wiki 知识展示;最多在管理员任务详情中显示“已跳过代码类文件数量”。
|
||
- 计算 `source_digest` 时只包含知识文件;纯代码变更不应导致技能归纳状态变为 stale。
|
||
|
||
## 8. 中间表示 IR
|
||
|
||
扫描和抽取后生成统一 IR,后续 Wiki 生成、实体合并、远端投影都基于 IR,而不是直接从文件内容临时拼装。
|
||
|
||
建议结构:
|
||
|
||
```json
|
||
{
|
||
"skill": {
|
||
"name": "example-skill",
|
||
"display_name": "示例技能",
|
||
"description": "从 SKILL.md 和元数据提取",
|
||
"source_root": "skills/public/example-skill",
|
||
"source_digest": "sha256:..."
|
||
},
|
||
"files": [
|
||
{
|
||
"path": "SKILL.md",
|
||
"kind": "markdown",
|
||
"sha256": "...",
|
||
"size": 12345,
|
||
"text_digest": "sha256:...",
|
||
"title": "Example Skill",
|
||
"summary": "文件摘要",
|
||
"anchors": [
|
||
{
|
||
"id": "heading-install",
|
||
"line_start": 12,
|
||
"line_end": 36,
|
||
"text_digest": "sha256:..."
|
||
}
|
||
],
|
||
"references": [
|
||
{
|
||
"target_path": "data/schema.yaml",
|
||
"evidence": "Markdown link or import",
|
||
"confidence": 1.0
|
||
}
|
||
],
|
||
"safety": {
|
||
"status": "allowed",
|
||
"warnings": []
|
||
}
|
||
}
|
||
],
|
||
"entities": [
|
||
{
|
||
"local_id": "ent_001",
|
||
"type": "tool",
|
||
"name": "web_search",
|
||
"aliases": ["网络搜索"],
|
||
"description": "用于检索外部信息的工具",
|
||
"attributes": {
|
||
"entrypoint": "config.yaml tools.web_search"
|
||
},
|
||
"evidence": [
|
||
{
|
||
"file_path": "config.yaml",
|
||
"line_start": 10,
|
||
"line_end": 20,
|
||
"quote": "短证据,不包含敏感信息"
|
||
}
|
||
],
|
||
"confidence": 0.94
|
||
}
|
||
],
|
||
"relations": [
|
||
{
|
||
"local_id": "rel_001",
|
||
"source_local_id": "ent_001",
|
||
"predicate": "used_by",
|
||
"target_local_id": "ent_002",
|
||
"description": "web_search 被示例技能用于首步检索",
|
||
"relation_source": "llm_inferred",
|
||
"evidence": [
|
||
{
|
||
"file_path": "SKILL.md",
|
||
"line_start": 22,
|
||
"line_end": 28,
|
||
"quote": "短证据"
|
||
}
|
||
],
|
||
"confidence": 0.88
|
||
}
|
||
],
|
||
"wiki": {
|
||
"skill_page": {
|
||
"slug": "skills/example-skill/overview",
|
||
"title": "示例技能",
|
||
"content": "Markdown Wiki 内容"
|
||
},
|
||
"pages": []
|
||
}
|
||
}
|
||
```
|
||
|
||
IR 需要版本化:
|
||
|
||
- `extractor_version`:扫描、解析、提示词和抽取 schema 的整体版本。
|
||
- `prompt_hash`:LLM 抽取提示词 hash。
|
||
- `model_name`:抽取模型名。
|
||
- `source_digest`:技能目录内容 digest。
|
||
|
||
只要 `source_digest + extractor_version + prompt_hash + model_name` 相同,就可以复用已有 snapshot,避免 200 个技能批量时反复抽取。
|
||
|
||
## 9. 关系抽取规则
|
||
|
||
关系来源分三类:
|
||
|
||
| 来源 | 示例 | 置信度策略 |
|
||
| --- | --- | --- |
|
||
| 确定性结构关系 | 目录包含文件、Markdown 链接、数据文件引用、业务配置引用 | `confidence = 1.0` |
|
||
| 显式文本关系 | Markdown 中写明“本技能依赖 A”、“输出 B”、“调用接口 C” | LLM 抽取,但要求证据;通常 `0.75` 以上 |
|
||
| 模型推断关系 | 从上下文推断某工具服务于某步骤、某配置控制某行为 | 必须有证据片段和解释;无证据不得入库 |
|
||
|
||
无人工审核的前提下,必须设置阈值:
|
||
|
||
- `confidence >= 0.75`:写入 Wiki 关系页和图谱投影文档。
|
||
- `0.50 <= confidence < 0.75`:只写入技能 Wiki 的“可能关系”小节,不进入规范关系。
|
||
- `confidence < 0.50`:丢弃。
|
||
|
||
每条关系都必须包含:
|
||
|
||
- `source`
|
||
- `predicate`
|
||
- `target`
|
||
- `confidence`
|
||
- `relation_source`
|
||
- `evidence`
|
||
|
||
如果没有证据路径和证据文本,不允许写入规范关系。
|
||
|
||
建议谓词归一化:
|
||
|
||
| 原始表达 | 规范 predicate |
|
||
| --- | --- |
|
||
| 依赖、需要、requires | `depends_on` |
|
||
| 调用、使用、uses | `uses` |
|
||
| 生成、输出、produces | `produces` |
|
||
| 读取、输入、consumes | `consumes` |
|
||
| 配置、控制 | `configures` |
|
||
| 包含、目录下有 | `contains` |
|
||
| 引用、链接到 | `references` |
|
||
| 替换、迁移到 | `replaces` |
|
||
| 属于 | `belongs_to` |
|
||
|
||
实现可以先内置有限谓词表,再允许保留 `custom_predicate`,但 UI 与关系页要展示规范谓词。
|
||
|
||
## 10. 同一知识库内的实体合并
|
||
|
||
实体合并范围只在一个目标知识库内生效,不跨知识库合并。
|
||
|
||
规范实体 key:
|
||
|
||
```text
|
||
kb_mapping_id + entity_type + normalized_name
|
||
```
|
||
|
||
`normalized_name` 规则:
|
||
|
||
- Unicode NFKC 归一化。
|
||
- trim。
|
||
- 多空白折叠成单空格。
|
||
- ASCII 字母转小写。
|
||
- 中英文标点归一化。
|
||
- 去除无意义包裹符号,例如反引号、引号。
|
||
|
||
如果实体带有明确外部 ID,可优先使用:
|
||
|
||
```text
|
||
kb_mapping_id + entity_type + external_id_type + external_id
|
||
```
|
||
|
||
合并规则:
|
||
|
||
- `normalized_name` 相同且 `entity_type` 兼容:合并。
|
||
- 名称相同但类型不兼容:不合并,例如 `config:web_search` 和 `tool:web_search` 可保持两个实体,必要时用 `configures` 关系连接。
|
||
- LLM 判断别名合并:只有 `confidence >= 0.90` 且有明确证据时允许。
|
||
- 属性冲突不做最后写入覆盖,必须按来源保留 provenance。
|
||
|
||
实体贡献示例:
|
||
|
||
```json
|
||
{
|
||
"canonical_entity_id": "ce_123",
|
||
"binding_id": "bind_001",
|
||
"snapshot_id": "snap_001",
|
||
"local_entity_id": "ent_001",
|
||
"attributes": {
|
||
"entrypoint": {
|
||
"value": "config.yaml tools.web_search",
|
||
"evidence": "config.yaml:10"
|
||
}
|
||
},
|
||
"confidence": 0.94
|
||
}
|
||
```
|
||
|
||
删除贡献时:
|
||
|
||
- 只删除该 binding 的贡献。
|
||
- 如果规范实体仍有其他贡献,保留实体页并重新生成聚合内容。
|
||
- 如果规范实体贡献数为 0,删除或标记归档该规范实体及其 Wiki 页面。
|
||
|
||
## 11. 关系合并
|
||
|
||
规范关系 key:
|
||
|
||
```text
|
||
kb_mapping_id + source_canonical_entity_id + normalized_predicate + target_canonical_entity_id
|
||
```
|
||
|
||
合并规则:
|
||
|
||
- 同一 key 的关系合并为一条规范关系。
|
||
- 每个技能的证据作为 relation contribution 追加。
|
||
- `confidence` 可存储最大值、平均值和证据数,但展示优先显示最高置信证据。
|
||
- 如果来源实体或目标实体被删除到无贡献,相关关系也需要重新计算。
|
||
|
||
关系 Wiki 页面内容必须保留:
|
||
|
||
- 关系三元组。
|
||
- 关系说明。
|
||
- 贡献技能列表。
|
||
- 证据路径。
|
||
- 置信度。
|
||
- 最近更新时间。
|
||
|
||
## 12. WeKnora 内容投影
|
||
|
||
每个技能归纳到一个目标知识库后,按目标 adapter 写入三类内容。目标是 WeKnora 时写入 WeKnora;目标是助手知识库或只读 sidecar 时写入 DeerFlow 自研存储。
|
||
|
||
### 12.1 原始资料
|
||
|
||
原始资料分两种:
|
||
|
||
- 可直接上传的文件:走 WeKnora 文件上传。
|
||
- 纯文本或需要展开的内容:创建手动文档,保留路径和 fenced code。
|
||
|
||
原始资料命名建议:
|
||
|
||
```text
|
||
skills/{skill_name}/source/{relative_path}
|
||
```
|
||
|
||
文档 metadata 建议:
|
||
|
||
```json
|
||
{
|
||
"source_type": "deerflow_skill",
|
||
"skill_name": "example-skill",
|
||
"binding_id": "bind_001",
|
||
"snapshot_id": "snap_001",
|
||
"source_digest": "sha256:...",
|
||
"relative_path": "SKILL.md",
|
||
"artifact_kind": "raw_source"
|
||
}
|
||
```
|
||
|
||
如果 WeKnora 不支持自定义 metadata,则本地 artifact 表必须保存远端 ID、slug、digest、kind 和来源关系。
|
||
|
||
### 12.2 技能 Wiki 页面
|
||
|
||
每个技能至少生成:
|
||
|
||
```text
|
||
skills/{skill_name}/overview
|
||
skills/{skill_name}/files
|
||
skills/{skill_name}/entities
|
||
skills/{skill_name}/relations
|
||
skills/{skill_name}/evidence
|
||
```
|
||
|
||
内容要求:
|
||
|
||
- `overview`:技能用途、输入、输出、依赖、使用方式、风险提示。
|
||
- `files`:重要文件清单、每个文件摘要、关键入口。
|
||
- `entities`:该技能贡献的实体,使用 Wiki 链接指向规范实体页。
|
||
- `relations`:确定关系和高置信推断关系,使用 Wiki 链接指向规范关系页。
|
||
- `evidence`:证据目录,只包含短摘录和位置,不包含敏感内容。
|
||
|
||
### 12.3 规范实体 Wiki 页面
|
||
|
||
规范实体页 slug:
|
||
|
||
```text
|
||
entities/{entity_type}/{stable_entity_id}-{slugified_name}
|
||
```
|
||
|
||
页面内容:
|
||
|
||
- 实体名称和类型。
|
||
- 别名。
|
||
- 归并来源技能。
|
||
- 聚合描述。
|
||
- 属性表,冲突属性按来源列出。
|
||
- 相关关系列表。
|
||
- 证据索引。
|
||
|
||
### 12.4 规范关系 Wiki 页面
|
||
|
||
规范关系页 slug:
|
||
|
||
```text
|
||
relations/{predicate}/{stable_relation_id}
|
||
```
|
||
|
||
页面内容:
|
||
|
||
- `[[source_entity]] --predicate--> [[target_entity]]`
|
||
- 中文说明。
|
||
- 贡献技能。
|
||
- 证据。
|
||
- 置信度。
|
||
- 更新时间。
|
||
|
||
说明:即便 WeKnora Wiki graph 只能展示无类型链接,关系类型也不能丢。类型和证据由关系页保存,Wiki 链接负责把实体页和关系页连接起来。
|
||
|
||
### 12.5 图谱投影文档
|
||
|
||
为提高 WeKnora GraphRAG 抽取成功率,每个 binding 生成一份机器可读关系文档:
|
||
|
||
```text
|
||
skills/{skill_name}/graph-projection.jsonl
|
||
```
|
||
|
||
每行一个关系:
|
||
|
||
```json
|
||
{
|
||
"source": "web_search",
|
||
"source_type": "tool",
|
||
"predicate": "used_by",
|
||
"target": "example-skill",
|
||
"target_type": "skill",
|
||
"description": "web_search 被 example-skill 用于首步检索",
|
||
"confidence": 0.88,
|
||
"evidence": "SKILL.md:22-28"
|
||
}
|
||
```
|
||
|
||
同时生成一份人类可读 Markdown:
|
||
|
||
```text
|
||
skills/{skill_name}/graph-projection.md
|
||
```
|
||
|
||
该文档使用短句和固定模板,降低 WeKnora 抽取歧义:
|
||
|
||
```markdown
|
||
# 技能关系投影:example-skill
|
||
|
||
- 实体 `web_search`(tool)与实体 `example-skill`(skill)存在 `used_by` 关系。
|
||
- 说明:web_search 被 example-skill 用于首步检索。
|
||
- 证据:SKILL.md:22-28
|
||
- 置信度:0.88
|
||
```
|
||
|
||
GraphRAG 可用时上传这些投影文档;Neo4j direct writer 开启时,同时把通过审核的规范实体和关系写入底层图数据库;两者都不可用时仍保留 Wiki 关系页和本地关系表。
|
||
|
||
## 13. 重归纳一致性
|
||
|
||
重归纳必须满足“成功后替换,失败不影响旧版本”。
|
||
|
||
流程:
|
||
|
||
1. 读取当前 binding 和 active snapshot。
|
||
2. 重新扫描技能目录,生成新 snapshot。
|
||
3. 如果 digest 未变化且未强制重归纳,可以直接返回 `synced`。
|
||
4. 在本地创建 staged artifact 记录。
|
||
5. 写入 WeKnora 新版本原始资料、Wiki 页面、关系投影文档。
|
||
6. 校验远端可读取或状态完成。
|
||
7. 在一个数据库事务中:
|
||
- 将旧 artifact 标记为 `retired`。
|
||
- 将 staged artifact 标记为 `active`。
|
||
- 将 binding 的 `current_snapshot_id` 指向新 snapshot。
|
||
- 更新实体和关系贡献。
|
||
- 设置 binding 状态为 `synced` 或 `partial_failed`。
|
||
8. 对旧远端文件执行 best-effort 清理。
|
||
9. 清理失败只记录 warning,不回滚已经激活的新版本。
|
||
|
||
如果第 5 或第 6 步失败:
|
||
|
||
- binding 仍指向旧 snapshot。
|
||
- 旧 WeKnora 内容继续有效。
|
||
- staged artifact 标记为 `failed`。
|
||
- item 状态为 `failed` 或 `partial_failed`。
|
||
- 前端显示错误,允许 retry / 重新归纳。
|
||
|
||
Wiki 页面建议采用稳定 slug upsert。原始资料如果 WeKnora 没有 update API,则创建新远端文档,确认成功后再删除旧远端文档。
|
||
|
||
## 14. 解除关联
|
||
|
||
解除一个技能与一个知识库的绑定时,前端必须弹窗让管理员选择:
|
||
|
||
| 选项 | 行为 |
|
||
| --- | --- |
|
||
| 保留知识库内容 | 绑定标记为 `detached_keep`。WeKnora 远端内容、助手库 Wiki revision 或 sidecar 内容保留为冻结知识,不再随技能重归纳更新。技能页不再显示为“当前归纳”,但可在历史中显示“已解除,内容保留”。 |
|
||
| 删除该技能贡献的内容 | 删除该 binding 的原始资料、技能 Wiki 页、关系投影文档、助手库 Wiki revision contribution、sidecar artifact 和实体/关系贡献;共享实体/关系只减少该技能贡献,仍有其他贡献则重建聚合页,没有贡献才删除。 |
|
||
|
||
如果删除远端内容部分失败:
|
||
|
||
- 本地记录 artifact `delete_failed`。
|
||
- binding 状态为 `detached_delete_pending_cleanup`。
|
||
- 提供“重试清理”动作。
|
||
|
||
不要因为某个共享实体由该技能参与过,就删除其他技能还在使用的实体页。
|
||
|
||
## 15. 状态机
|
||
|
||
绑定状态建议:
|
||
|
||
| 状态 | 含义 |
|
||
| --- | --- |
|
||
| `pending` | 已创建绑定,但尚未开始处理。 |
|
||
| `queued` | 已进入任务队列。 |
|
||
| `running` | 正在处理。 |
|
||
| `awaiting_review` | 抽取完成,等待管理员审核实体、关系或 Wiki 草稿。 |
|
||
| `synced` | 当前版本已成功归纳到目标知识库。 |
|
||
| `pending_remote_write` | 只读目标已完成本地 sidecar 归纳,等待远端具备写权限后推送。 |
|
||
| `stale` | 技能源文件已变化,但尚未手动重新归纳。 |
|
||
| `partial_failed` | 核心 Wiki/原始资料成功,但部分文件、图谱或清理失败。 |
|
||
| `failed` | 当前归纳失败,旧版本若存在则继续有效。 |
|
||
| `detached_keep` | 已解除关联,远端内容保留。 |
|
||
| `detached_delete_pending_cleanup` | 已解除关联,但删除远端内容未完全成功。 |
|
||
| `detached_deleted` | 已解除关联,远端贡献已清理。 |
|
||
|
||
item 阶段建议:
|
||
|
||
```text
|
||
scanning
|
||
parsing
|
||
summarizing
|
||
extracting
|
||
awaiting_review
|
||
merging
|
||
uploading_sources
|
||
writing_wiki
|
||
writing_graph_projection
|
||
verifying
|
||
activating
|
||
cleanup
|
||
completed
|
||
```
|
||
|
||
前端展示时,父任务进度由 item 数量和阶段加权计算,不要只显示一个不可解释的 spinner。
|
||
|
||
## 16. 持久化设计
|
||
|
||
下面是建议表结构,字段命名可按项目现有风格调整。
|
||
|
||
### 16.1 `skill_knowledge_bindings`
|
||
|
||
保存技能与知识库的多对多关系。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `skill_name` | 技能名。 |
|
||
| `target_type` | `weknora` / `assistant`。 |
|
||
| `target_mode` | `wiki` / `document` / `faq` / `conversation_archive` / `readonly_sidecar`。 |
|
||
| `target_id` | 目标知识库 ID。WeKnora 使用本地 mapping ID,助手库使用全局 base ID。 |
|
||
| `remote_business_key` | 暴露给前端和外部系统的远端业务 key,例如 `weknora:kb:xxx`,可为空。 |
|
||
| `status` | 绑定状态。 |
|
||
| `active` | 是否当前有效绑定。 |
|
||
| `current_snapshot_id` | 当前激活的技能快照。 |
|
||
| `source_digest` | 最近扫描到的技能源 digest。 |
|
||
| `synced_digest` | 最近成功归纳的 digest。 |
|
||
| `last_job_id` | 最近一次父任务。 |
|
||
| `last_item_id` | 最近一次 item。 |
|
||
| `last_synced_at` | 最近成功归纳时间。 |
|
||
| `last_error_code` | 最近错误码。 |
|
||
| `last_error_message` | 最近错误摘要。 |
|
||
| `created_by` | 管理员用户。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
约束:
|
||
|
||
```text
|
||
unique(skill_name, target_type, target_id)
|
||
```
|
||
|
||
### 16.2 `skill_knowledge_snapshots`
|
||
|
||
保存技能扫描和抽取结果。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `skill_name` | 技能名。 |
|
||
| `source_digest` | 技能目录 digest。 |
|
||
| `extractor_version` | 抽取器版本。 |
|
||
| `prompt_hash` | 提示词 hash。 |
|
||
| `model_name` | 模型名。 |
|
||
| `manifest_json` | 文件清单、hash、安全状态。 |
|
||
| `ir_json` | 抽取后的 IR;较大时可存 blob 引用。 |
|
||
| `status` | `ready` / `failed`。 |
|
||
| `counts_json` | 文件数、实体数、关系数、跳过数。 |
|
||
| `created_at` | 创建时间。 |
|
||
|
||
约束:
|
||
|
||
```text
|
||
unique(skill_name, source_digest, extractor_version, prompt_hash, model_name)
|
||
```
|
||
|
||
### 16.3 `skill_knowledge_sync_jobs`
|
||
|
||
保存一次批量归纳任务。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `target_count` | 本次目标知识库数量。 |
|
||
| `targets_json` | 目标知识库列表,每项包含 `target_type`、`target_mode`、`target_id`、展示名和远端业务 key。 |
|
||
| `status` | `queued` / `running` / `completed` / `partial_failed` / `failed` / `canceled`。 |
|
||
| `total_count` | 技能数。 |
|
||
| `success_count` | 成功数。 |
|
||
| `partial_failed_count` | 部分失败数。 |
|
||
| `failed_count` | 失败数。 |
|
||
| `cancel_requested` | 是否请求取消。 |
|
||
| `created_by` | 管理员用户。 |
|
||
| `created_at` / `started_at` / `completed_at` | 时间戳。 |
|
||
|
||
### 16.4 `skill_knowledge_sync_items`
|
||
|
||
保存每个技能的任务项。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `job_id` | 父任务。 |
|
||
| `binding_id` | 绑定。 |
|
||
| `target_type` | 目标类型。 |
|
||
| `target_mode` | 目标模式。 |
|
||
| `target_id` | 目标 ID。 |
|
||
| `skill_name` | 技能名。 |
|
||
| `snapshot_id` | 本次输入快照。 |
|
||
| `status` | item 状态。 |
|
||
| `phase` | 当前阶段。 |
|
||
| `progress` | 0-100。 |
|
||
| `active_dedupe_key` | 活跃任务去重 key。 |
|
||
| `lease_owner` | 执行器标识。 |
|
||
| `lease_until` | 租约过期时间。 |
|
||
| `attempts` | 尝试次数。 |
|
||
| `last_error_code` | 错误码。 |
|
||
| `last_error_message` | 错误摘要。 |
|
||
| `created_at` / `updated_at` / `started_at` / `completed_at` | 时间戳。 |
|
||
|
||
活跃去重 key:
|
||
|
||
```text
|
||
skill_name + target_type + target_id
|
||
```
|
||
|
||
同一绑定同一时间只能有一个 active item。
|
||
|
||
### 16.5 `skill_knowledge_artifacts`
|
||
|
||
保存本地到 WeKnora 的远端 artifact 映射。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `target_type` | 目标类型。 |
|
||
| `target_mode` | 目标模式。 |
|
||
| `target_id` | 目标 ID。 |
|
||
| `binding_id` | 绑定,可为空;规范实体/关系聚合页可只属于知识库。 |
|
||
| `snapshot_id` | 来源快照。 |
|
||
| `scope` | `binding` / `kb_aggregate`。 |
|
||
| `kind` | `raw_source` / `skill_wiki` / `entity_wiki` / `relation_wiki` / `graph_projection`。 |
|
||
| `stable_key` | 本地稳定 key。 |
|
||
| `remote_kind` | `file` / `manual_document` / `wiki_page`。 |
|
||
| `remote_id` | 远端 ID。后端保存完整映射,前端可按权限展示和复制。 |
|
||
| `wiki_slug` | Wiki 页面 slug。 |
|
||
| `content_hash` | 写入内容 hash。 |
|
||
| `version` | 版本号。 |
|
||
| `status` | `staged` / `active` / `retired` / `failed` / `delete_failed`。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
### 16.6 `skill_knowledge_entities`
|
||
|
||
规范实体表。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `target_type` | 目标类型。 |
|
||
| `target_mode` | 目标模式。 |
|
||
| `target_id` | 目标 ID。 |
|
||
| `entity_type` | 实体类型。 |
|
||
| `normalized_name` | 归一化名称。 |
|
||
| `display_name` | 展示名称。 |
|
||
| `aliases_json` | 别名。 |
|
||
| `description` | 聚合描述。 |
|
||
| `stable_slug` | Wiki slug。 |
|
||
| `status` | `active` / `retired`。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
约束:
|
||
|
||
```text
|
||
unique(target_type, target_id, entity_type, normalized_name)
|
||
```
|
||
|
||
### 16.7 `skill_knowledge_entity_contributions`
|
||
|
||
规范实体的技能贡献。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `canonical_entity_id` | 规范实体 ID。 |
|
||
| `binding_id` | 绑定。 |
|
||
| `snapshot_id` | 快照。 |
|
||
| `local_entity_id` | IR 中的实体 ID。 |
|
||
| `attributes_json` | 该技能贡献的属性。 |
|
||
| `evidence_json` | 证据。 |
|
||
| `confidence` | 置信度。 |
|
||
| `status` | `active` / `retired`。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
### 16.8 `skill_knowledge_relations`
|
||
|
||
规范关系表。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `target_type` | 目标类型。 |
|
||
| `target_mode` | 目标模式。 |
|
||
| `target_id` | 目标 ID。 |
|
||
| `source_entity_id` | 源规范实体。 |
|
||
| `predicate` | 规范谓词。 |
|
||
| `target_entity_id` | 目标规范实体。 |
|
||
| `description` | 聚合说明。 |
|
||
| `stable_slug` | Wiki slug。 |
|
||
| `status` | `active` / `retired`。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
约束:
|
||
|
||
```text
|
||
unique(target_type, target_id, source_entity_id, predicate, target_entity_id)
|
||
```
|
||
|
||
### 16.9 `skill_knowledge_relation_contributions`
|
||
|
||
规范关系的技能贡献。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `canonical_relation_id` | 规范关系 ID。 |
|
||
| `binding_id` | 绑定。 |
|
||
| `snapshot_id` | 快照。 |
|
||
| `local_relation_id` | IR 中的关系 ID。 |
|
||
| `relation_source` | `deterministic` / `explicit_text` / `llm_inferred`。 |
|
||
| `evidence_json` | 证据。 |
|
||
| `confidence` | 置信度。 |
|
||
| `status` | `active` / `retired`。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
## 17. 后台任务设计
|
||
|
||
参考现有 deep research job 的持久化后台任务模式:
|
||
|
||
- 任务入库后返回 `202 Accepted`。
|
||
- 执行器通过 DB 原子条件 claim item。
|
||
- 每个 item 有 `lease_owner`、`lease_until`。
|
||
- 执行中定期 heartbeat。
|
||
- 服务重启后可恢复过期 lease。
|
||
- cancel 使用 `cancel_requested`,任务在阶段边界检查并安全停止。
|
||
|
||
并发建议:
|
||
|
||
- 同时处理技能数:2 到 4。
|
||
- 同时调用 WeKnora 写入:2 到 3。
|
||
- 同时 LLM 抽取:按系统现有限流,建议默认 2。
|
||
|
||
200 个技能批量时:
|
||
|
||
- 父 job 只保存聚合进度,不串行阻塞 HTTP 请求。
|
||
- 每个技能 item 独立失败、独立重试。
|
||
- 前端按 job polling,不为每个技能单独发 N 个请求。
|
||
- 获取技能列表时批量查 binding summary,避免 N+1。
|
||
- 快照缓存可复用,跨知识库只重新投影,不重复解析同一技能内容。
|
||
|
||
## 18. 后端 API 设计
|
||
|
||
新增 router:
|
||
|
||
```text
|
||
/api/skill-knowledge
|
||
```
|
||
|
||
所有写接口仅管理员可用。
|
||
|
||
### 18.1 获取技能绑定摘要
|
||
|
||
```http
|
||
GET /api/skill-knowledge/bindings?skill_names=a,b,c
|
||
```
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"skill_name": "example-skill",
|
||
"knowledge_bases": [
|
||
{
|
||
"binding_id": "bind_001",
|
||
"target_type": "weknora",
|
||
"target_mode": "wiki",
|
||
"target_id": "local-kb-id",
|
||
"knowledge_base_name": "作战知识库",
|
||
"remote_business_key": "weknora:kb:remote-kb-id",
|
||
"status": "synced",
|
||
"last_synced_at": "2026-08-31T10:00:00Z",
|
||
"source_digest": "sha256:...",
|
||
"synced_digest": "sha256:...",
|
||
"stale": false
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 18.2 创建归纳任务
|
||
|
||
```http
|
||
POST /api/skill-knowledge/sync-jobs
|
||
```
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"skill_names": ["skill-a", "skill-b"],
|
||
"targets": [
|
||
{
|
||
"target_type": "weknora",
|
||
"target_mode": "wiki",
|
||
"target_id": "local-kb-id"
|
||
},
|
||
{
|
||
"target_type": "assistant",
|
||
"target_mode": "wiki",
|
||
"target_id": "assistant-global-base"
|
||
}
|
||
],
|
||
"force": false
|
||
}
|
||
```
|
||
|
||
行为:
|
||
|
||
- 校验管理员。
|
||
- 校验技能存在。
|
||
- 校验目标知识库存在,并解析目标 adapter。
|
||
- 对只读目标创建 sidecar binding,不强行写远端。
|
||
- 对每个 `skill x target` upsert binding。
|
||
- 创建父 job 和 item。
|
||
- 如果同一 binding 已有 active item,返回当前 item,不重复创建。
|
||
- 返回 `202`。
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"job_id": "job_001",
|
||
"status": "queued",
|
||
"skill_count": 2,
|
||
"target_count": 2,
|
||
"total_count": 4,
|
||
"items": [
|
||
{
|
||
"item_id": "item_001",
|
||
"skill_name": "skill-a",
|
||
"target_type": "weknora",
|
||
"target_mode": "wiki",
|
||
"target_id": "local-kb-id",
|
||
"binding_id": "bind_001",
|
||
"status": "queued"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 18.3 查询任务
|
||
|
||
```http
|
||
GET /api/skill-knowledge/sync-jobs/{job_id}
|
||
```
|
||
|
||
返回父 job、item 列表、每个 item 当前阶段、错误摘要、绑定结果。
|
||
|
||
### 18.4 取消任务
|
||
|
||
```http
|
||
POST /api/skill-knowledge/sync-jobs/{job_id}/cancel
|
||
```
|
||
|
||
设置 `cancel_requested = true`。已激活成功的 item 不回滚;未完成 item 在阶段边界停止。
|
||
|
||
### 18.5 重试 item
|
||
|
||
```http
|
||
POST /api/skill-knowledge/sync-items/{item_id}/retry
|
||
```
|
||
|
||
只允许失败或部分失败 item。重试复用原 binding。
|
||
|
||
### 18.6 对单个绑定重新归纳
|
||
|
||
```http
|
||
POST /api/skill-knowledge/bindings/{binding_id}/resync
|
||
```
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"force": true
|
||
}
|
||
```
|
||
|
||
行为:创建一个只包含该 binding 的新 job。
|
||
|
||
### 18.7 解除关联
|
||
|
||
建议使用显式 POST,避免 DELETE body 兼容性问题:
|
||
|
||
```http
|
||
POST /api/skill-knowledge/bindings/{binding_id}/detach
|
||
```
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"remote_content_action": "keep"
|
||
}
|
||
```
|
||
|
||
或:
|
||
|
||
```json
|
||
{
|
||
"remote_content_action": "delete"
|
||
}
|
||
```
|
||
|
||
返回解除结果、清理状态和仍被共享的实体/关系数量。
|
||
|
||
### 18.8 知识库反查技能
|
||
|
||
```http
|
||
GET /api/skill-knowledge/knowledge-bases/{knowledge_base_id}/skills
|
||
```
|
||
|
||
用于知识库详情页展示“该知识库由哪些技能归纳而来”。
|
||
|
||
### 18.9 可选:源状态扫描
|
||
|
||
```http
|
||
POST /api/skill-knowledge/source-status
|
||
```
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"skill_names": ["skill-a", "skill-b"],
|
||
"knowledge_base_id": "local-kb-id"
|
||
}
|
||
```
|
||
|
||
只做本地快速 fingerprint 比对,标记是否可能 stale,不写 WeKnora。
|
||
|
||
### 18.10 审核队列
|
||
|
||
```http
|
||
GET /api/skill-knowledge/reviews?job_id=xxx
|
||
POST /api/skill-knowledge/reviews/{review_id}/approve
|
||
POST /api/skill-knowledge/reviews/{review_id}/reject
|
||
PUT /api/skill-knowledge/reviews/{review_id}
|
||
POST /api/skill-knowledge/reviews/bulk-approve
|
||
POST /api/skill-knowledge/reviews/bulk-reject
|
||
```
|
||
|
||
审核通过后 item 才能进入写入阶段。审核模式为 `off` 时,接口仍保留预览和审计能力。
|
||
|
||
### 18.11 自动同步配置
|
||
|
||
```http
|
||
GET /api/skill-knowledge/auto-sync-settings
|
||
PUT /api/skill-knowledge/auto-sync-settings
|
||
POST /api/skill-knowledge/bindings/{binding_id}/enable-auto-sync
|
||
POST /api/skill-knowledge/bindings/{binding_id}/disable-auto-sync
|
||
```
|
||
|
||
自动同步设置只允许管理员修改。
|
||
|
||
## 19. 前端交互设计
|
||
|
||
### 19.1 技能管理页
|
||
|
||
在 `AdminSkillsPage.tsx` 的“技能列表”页签增加:
|
||
|
||
- 技能行 checkbox。
|
||
- 顶部批量操作按钮:“归纳到知识库”。
|
||
- 支持全选当前页、清空选择。
|
||
- 选择状态跨前端分页保留。
|
||
- 技能较多时保持现有搜索/过滤能力。
|
||
|
||
点击“归纳到知识库”打开弹窗:
|
||
|
||
- 显示已选技能数量。
|
||
- 多选目标知识库。
|
||
- 按类型分组展示:WeKnora Wiki、WeKnora 非 Wiki、FAQ、系统会话存档、只读 sidecar、助手知识库。
|
||
- 只读目标要展示“本地归纳,暂不写远端”的状态说明。
|
||
- 助手知识库作为目标时,提示“直接写入知识梳理底库,不经过 WeKnora”。
|
||
- 二次确认文案说明:“将生成原始资料、Wiki 页面和关系内容;抽取完成后进入实体/关系预览审核。”
|
||
|
||
提交后:
|
||
|
||
- 创建后台 job。
|
||
- 跳转或打开“归纳任务”抽屉/页签。
|
||
- 展示总进度、成功、失败、部分失败。
|
||
- 任务运行中每 2-3 秒 polling。
|
||
- item 到达 `awaiting_review` 时,显示“待审核”并提供审核入口。
|
||
|
||
### 19.1.1 实体/关系审核页
|
||
|
||
审核页按 job 聚合展示:
|
||
|
||
- 左侧筛选:技能、目标知识库、类型、置信度、来源。
|
||
- 中间列表:实体、关系、实体对齐候选、关系合并候选、Wiki 草稿。
|
||
- 右侧详情:原始值、模型解释、证据、目标写入位置。
|
||
|
||
管理员可以:
|
||
|
||
- 单条批准、拒绝、编辑。
|
||
- 批量批准高置信结果。
|
||
- 批量拒绝低置信结果。
|
||
- 修改实体类型、名称、别名。
|
||
- 修改关系 predicate、说明、confidence。
|
||
- 查看远端 ID 或 sidecar ID。
|
||
|
||
审核完成后,任务继续写入目标知识库。
|
||
|
||
### 19.2 技能行提示
|
||
|
||
`SkillRow` 增加归纳状态区域:
|
||
|
||
- 未归纳:不显示或显示弱提示“未归纳”。
|
||
- 已归纳:显示 `已归纳至 N 个知识库`。
|
||
- 展开或悬浮可看到知识库 chips:
|
||
- 知识库名称
|
||
- 状态
|
||
- 最近归纳时间
|
||
- stale 标识
|
||
|
||
每个绑定提供动作:
|
||
|
||
- 查看知识库。
|
||
- 重新归纳。
|
||
- 解除关联。
|
||
- 失败时重试。
|
||
|
||
状态建议:
|
||
|
||
| 状态 | UI 文案 |
|
||
| --- | --- |
|
||
| `synced` | 已归纳 |
|
||
| `stale` | 待重新归纳 |
|
||
| `running` | 归纳中 |
|
||
| `partial_failed` | 部分完成 |
|
||
| `failed` | 失败 |
|
||
| `detached_keep` | 已解除,内容保留 |
|
||
|
||
### 19.3 解除关联弹窗
|
||
|
||
弹窗必须让管理员明确选择:
|
||
|
||
- 保留知识库内容。
|
||
- 删除该技能贡献的内容。
|
||
|
||
弹窗文案应提醒:
|
||
|
||
- 删除只删除该技能贡献,不删除其他技能共享的实体与关系。
|
||
- 若删除远端内容失败,可稍后重试清理。
|
||
|
||
### 19.4 归纳任务页签
|
||
|
||
建议在管理员技能管理页新增第三个页签:
|
||
|
||
```text
|
||
技能列表 | 技能地址管理 | 归纳任务
|
||
```
|
||
|
||
任务列表显示:
|
||
|
||
- 创建时间。
|
||
- 目标知识库。
|
||
- 操作人。
|
||
- 总技能数。
|
||
- 成功 / 部分失败 / 失败。
|
||
- 状态。
|
||
- 操作:查看详情、取消、重试失败项。
|
||
|
||
详情显示 item:
|
||
|
||
- 技能名。
|
||
- 目标知识库。
|
||
- 目标类型。
|
||
- 当前阶段。
|
||
- 进度。
|
||
- 错误摘要。
|
||
- 绑定状态。
|
||
|
||
### 19.6 自动同步设置
|
||
|
||
管理员可在技能归纳设置中配置:
|
||
|
||
- 是否开启文件监听。
|
||
- 是否开启定时同步。
|
||
- 同步周期。
|
||
- 自动写远端开关。
|
||
- 审核模式。
|
||
- 单个 binding 是否参与自动同步。
|
||
|
||
### 19.5 知识库详情反向展示
|
||
|
||
如果现有 WeKnora / LLM Wiki 页面有知识库详情入口,增加“来源技能”区域:
|
||
|
||
- 技能名。
|
||
- 归纳状态。
|
||
- 最近归纳时间。
|
||
- 查看技能。
|
||
- 重新归纳。
|
||
|
||
## 20. stale 检测与自动同步
|
||
|
||
系统既要支持手动重新归纳,也要支持自动同步。stale 检测负责判断“源知识文件是否变化”;自动同步负责在配置允许时创建后台任务并远程写入。
|
||
|
||
本地标识 stale:
|
||
|
||
- 技能编辑、启停、删除等已知写操作完成后,查找相关 binding 并标记 `stale`。
|
||
- 技能列表加载时可做轻量 fingerprint:路径、大小、mtime。
|
||
- 真正归纳时计算完整 SHA digest。
|
||
- 如果归纳过程中源文件变化,最终激活前再次校验 expected digest;不一致则失败并标记 stale,避免一个版本混入两次源内容。
|
||
- 代码文件和脚本文件不参与 fingerprint,也不触发 stale。
|
||
|
||
自动同步:
|
||
|
||
- 当 `watch_enabled` 开启时,知识文件变化后自动创建相关 binding 的归纳任务。
|
||
- 当 `schedule_enabled` 开启时,scheduler 按周期扫描并归纳 stale binding。
|
||
- 当技能保存、导入、删除或启停时,可触发相关 binding 的自动任务。
|
||
- 自动任务必须遵循审核模式;如果需要审核,任务停在 `awaiting_review`。
|
||
- 自动任务必须遵循 staged 激活;失败不覆盖旧版本。
|
||
|
||
## 21. 权限与安全
|
||
|
||
权限:
|
||
|
||
- 所有归纳、重归纳、解除关联、取消、重试接口仅管理员。
|
||
- 读接口如果包含后台任务错误或源文件路径,也建议仅管理员。
|
||
|
||
文件安全:
|
||
|
||
- 技能根必须限制在 `skills/public` 或 `skills/custom`。
|
||
- 禁止路径穿越。
|
||
- 默认不跟随 symlink;如果要支持 symlink,必须确认 resolved path 仍在技能根内。
|
||
- 压缩包解压必须限制总大小、文件数量、单文件大小、目录层级。
|
||
- 不执行技能代码。
|
||
- 不读取或上传密钥文件。
|
||
- 日志和错误信息不得包含文件全文、token、secret。
|
||
|
||
远端安全:
|
||
|
||
- 不新增外部 URL 抓取能力。
|
||
- 如果技能内容中包含 URL,只作为文本关系或知识内容处理,不主动访问。
|
||
- WeKnora 调用失败时,记录错误摘要和 request id,不记录认证头。
|
||
|
||
## 22. LLM 抽取设计
|
||
|
||
抽取可分两级:
|
||
|
||
- 小技能:一次性把文本摘要和结构信息送入模型。
|
||
- 大技能:先按文件或章节生成局部摘要与候选实体关系,再合并。
|
||
|
||
提示词需要明确:
|
||
|
||
- 只基于提供的内容抽取,不凭空编造。
|
||
- 允许推断,但推断必须有 evidence。
|
||
- 输出必须符合 JSON schema。
|
||
- 不输出敏感信息。
|
||
- 关系必须有 confidence。
|
||
- 低置信关系要标记,不进入规范关系。
|
||
|
||
建议 schema:
|
||
|
||
```json
|
||
{
|
||
"summary": {
|
||
"purpose": "技能用途",
|
||
"inputs": ["输入"],
|
||
"outputs": ["输出"],
|
||
"usage": "使用方式",
|
||
"risks": ["风险"]
|
||
},
|
||
"entities": [
|
||
{
|
||
"id": "ent_001",
|
||
"type": "skill|tool|api|file|config|dataset|concept|workflow|external_system|output",
|
||
"name": "实体名",
|
||
"aliases": [],
|
||
"description": "描述",
|
||
"attributes": {},
|
||
"evidence": [
|
||
{
|
||
"file_path": "SKILL.md",
|
||
"line_start": 1,
|
||
"line_end": 3,
|
||
"quote": "短证据"
|
||
}
|
||
],
|
||
"confidence": 0.9
|
||
}
|
||
],
|
||
"relations": [
|
||
{
|
||
"id": "rel_001",
|
||
"source_entity_id": "ent_001",
|
||
"predicate": "uses",
|
||
"target_entity_id": "ent_002",
|
||
"description": "关系描述",
|
||
"relation_source": "explicit_text|llm_inferred",
|
||
"evidence": [],
|
||
"confidence": 0.86
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
模型输出后必须做程序校验:
|
||
|
||
- JSON schema 校验。
|
||
- entity id 存在性校验。
|
||
- relation source/target 必须存在。
|
||
- evidence path 必须来自本次 manifest。
|
||
- confidence 必须在 0 到 1。
|
||
- 敏感内容二次扫描。
|
||
|
||
## 23. 后端实现步骤
|
||
|
||
建议按以下顺序实现。
|
||
|
||
### 23.1 持久化层
|
||
|
||
新增 `deerflow.persistence.skill_knowledge`:
|
||
|
||
- SQL model。
|
||
- memory store,用于测试或无 DB 环境。
|
||
- repository API。
|
||
- migration 或 `create_all` 接入。
|
||
|
||
Repository API 建议:
|
||
|
||
```python
|
||
class SkillKnowledgeStore:
|
||
async def upsert_binding(...)
|
||
async def list_bindings(...)
|
||
async def create_job(...)
|
||
async def create_items(...)
|
||
async def claim_next_item(...)
|
||
async def heartbeat_item(...)
|
||
async def complete_item(...)
|
||
async def fail_item(...)
|
||
async def create_or_get_snapshot(...)
|
||
async def stage_artifacts(...)
|
||
async def activate_snapshot(...)
|
||
async def detach_binding(...)
|
||
```
|
||
|
||
### 23.2 扫描与解析
|
||
|
||
新增:
|
||
|
||
```text
|
||
deerflow/skill_knowledge/scanner.py
|
||
deerflow/skill_knowledge/parsers.py
|
||
deerflow/skill_knowledge/safety.py
|
||
deerflow/skill_knowledge/digest.py
|
||
```
|
||
|
||
输出 manifest 和初始文本块。
|
||
|
||
### 23.3 抽取与归纳
|
||
|
||
新增:
|
||
|
||
```text
|
||
deerflow/skill_knowledge/extractor.py
|
||
deerflow/skill_knowledge/wiki_builder.py
|
||
```
|
||
|
||
职责:
|
||
|
||
- 构造 prompt。
|
||
- 调用项目已有模型封装。
|
||
- 解析 JSON。
|
||
- 校验 schema。
|
||
- 构建技能 Wiki 页面内容。
|
||
|
||
### 23.4 实体关系合并
|
||
|
||
新增:
|
||
|
||
```text
|
||
deerflow/skill_knowledge/merge.py
|
||
```
|
||
|
||
职责:
|
||
|
||
- 名称归一化。
|
||
- 实体 upsert。
|
||
- 关系 upsert。
|
||
- 贡献增删。
|
||
- 共享实体/关系重建计划。
|
||
|
||
### 23.5 WeKnora 投影
|
||
|
||
新增:
|
||
|
||
```text
|
||
deerflow/skill_knowledge/projector.py
|
||
deerflow/skill_knowledge/target_adapters.py
|
||
deerflow/skill_knowledge/graph_writer.py
|
||
```
|
||
|
||
职责:
|
||
|
||
- 根据 IR 和聚合结果生成 artifact plan。
|
||
- 按目标知识库类型选择 adapter。
|
||
- 调用 WeKnora client 上传原文、FAQ、会话归档或 Wiki 页面。
|
||
- 为只读目标写本地 sidecar artifact。
|
||
- 上传 graph projection docs。
|
||
- 在配置允许时通过受控 graph writer 写 Neo4j。
|
||
- 校验远端状态。
|
||
|
||
### 23.6 Gateway
|
||
|
||
新增:
|
||
|
||
```text
|
||
app/gateway/routers/skill_knowledge.py
|
||
app/gateway/skill_knowledge_job_dispatcher.py
|
||
app/gateway/skill_knowledge_job_executor.py
|
||
app/gateway/skill_knowledge_watcher.py
|
||
app/gateway/skill_knowledge_scheduler.py
|
||
```
|
||
|
||
在 app 初始化中注册:
|
||
|
||
- store。
|
||
- dispatcher。
|
||
- watcher。
|
||
- scheduler。
|
||
- router。
|
||
|
||
### 23.7 前端
|
||
|
||
新增:
|
||
|
||
```text
|
||
frontend-web/src/strategy-components/api/skill-knowledge.ts
|
||
frontend-web/src/components/workspace/skills/skill-knowledge-sync-dialog.tsx
|
||
frontend-web/src/components/workspace/skills/skill-knowledge-bindings.tsx
|
||
frontend-web/src/components/workspace/skills/skill-knowledge-jobs-panel.tsx
|
||
```
|
||
|
||
修改:
|
||
|
||
- `AdminSkillsPage.tsx`:技能列表批量选择、归纳弹窗、归纳任务页签。
|
||
- `skill-settings-page.tsx`:`SkillRow` 展示归纳知识库 chips 和操作。
|
||
- 知识库详情页:展示来源技能。
|
||
|
||
### 23.8 助手知识库
|
||
|
||
新增:
|
||
|
||
```text
|
||
offline-backend-20260512/backend/packages/harness/deerflow/assistant_knowledge/
|
||
offline-backend-20260512/backend/packages/harness/deerflow/persistence/assistant_knowledge/
|
||
offline-backend-20260512/backend/app/gateway/routers/assistant_knowledge.py
|
||
offline-backend-20260512/backend/app/gateway/assistant_knowledge_import_executor.py
|
||
frontend-web/src/strategy-components/api/assistant-knowledge.ts
|
||
frontend-web/src/pages/AssistantKnowledgePage.tsx
|
||
```
|
||
|
||
职责:
|
||
|
||
- 初始化唯一全局助手知识库“知识梳理”。
|
||
- 从 WeKnora 导出包导入 Wiki、文档、chunk、实体、关系、图谱。
|
||
- 做全局实体对齐和关系合并。
|
||
- 生成助手库 Wiki 页面。
|
||
- 建立搜索索引。
|
||
- 支持普通用户只读、管理员导入和维护。
|
||
- 支持知识库产品版本 `v1` / `v2` 切换。
|
||
|
||
### 23.9 审核队列
|
||
|
||
新增:
|
||
|
||
```text
|
||
offline-backend-20260512/backend/packages/harness/deerflow/persistence/skill_knowledge/review_model.py
|
||
frontend-web/src/components/workspace/skills/skill-knowledge-review-panel.tsx
|
||
```
|
||
|
||
职责:
|
||
|
||
- 保存实体、关系、对齐候选、Wiki 草稿的审核项。
|
||
- 支持批准、拒绝、编辑、批量处理。
|
||
- 审核完成后唤醒对应 item 继续写入。
|
||
- 保留完整审计。
|
||
|
||
## 24. 测试计划
|
||
|
||
后端测试:
|
||
|
||
| 测试 | 覆盖点 |
|
||
| --- | --- |
|
||
| `test_skill_knowledge_scanner.py` | 文件扫描、排除目录、敏感文件阻断、压缩包安全。 |
|
||
| `test_skill_knowledge_extractor.py` | LLM 输出 schema 校验、低置信关系过滤、证据路径校验。 |
|
||
| `test_skill_knowledge_entity_merge.py` | 同知识库实体合并、跨知识库不合并、属性冲突 provenance。 |
|
||
| `test_skill_knowledge_repository.py` | 绑定唯一、多对多、状态机、detach keep/delete。 |
|
||
| `test_skill_knowledge_jobs.py` | job/item claim、lease、重试、取消、崩溃恢复、200 item 聚合进度。 |
|
||
| `test_skill_knowledge_weknora_projection.py` | Wiki slug upsert、artifact staged/active、GraphRAG 不可用 partial_failed。 |
|
||
| `test_skill_knowledge_api.py` | 管理员鉴权、目标知识库校验、创建任务、查询任务、解除关联。 |
|
||
| `test_skill_knowledge_target_adapters.py` | Wiki、非 Wiki、FAQ、会话存档、只读 sidecar、助手库目标写入。 |
|
||
| `test_skill_knowledge_review.py` | 实体/关系逐条审核、编辑、批量批准、审核阻塞写入。 |
|
||
| `test_skill_knowledge_auto_sync.py` | 文件监听、定时同步、代码文件变化不触发、staged 自动写入。 |
|
||
| `test_skill_knowledge_graph_writer.py` | Neo4j 参数化写入、事务、审计、回滚计划、禁用任意 Cypher。 |
|
||
| `test_assistant_knowledge_repository.py` | 唯一全局底库、来源、导入任务、实体关系贡献。 |
|
||
| `test_assistant_knowledge_import.py` | WeKnora 导出包导入、实体对齐、关系合并、搜索索引。 |
|
||
| `test_assistant_knowledge_api.py` | 普通用户只读、管理员写入、未配置 WeKnora 场景。 |
|
||
|
||
前端测试:
|
||
|
||
- 管理员技能页可以多选技能并打开知识库选择弹窗。
|
||
- 知识库选择弹窗支持多选目标,包含 Wiki、非 Wiki、FAQ、会话存档、只读 sidecar 和助手知识库。
|
||
- 创建 job 后显示进度并 polling。
|
||
- 抽取后进入实体/关系审核页,审核通过后继续写入。
|
||
- 技能行展示已归纳知识库 chips。
|
||
- 重归纳按钮调用正确接口。
|
||
- 解除关联弹窗必须选择 keep/delete。
|
||
- 200 个技能绑定摘要使用批量接口,不触发 N+1。
|
||
- 未配置 WeKnora 时仍能展示助手知识库初始化入口。
|
||
- 普通知识库详情页可触发导入到助手知识库。
|
||
- 助手知识库搜索、Wiki 页面、来源列表按权限展示。
|
||
|
||
建议命令:
|
||
|
||
```bash
|
||
cd offline-backend-20260512/backend
|
||
PYTHONPATH=. uv run pytest tests/test_skill_knowledge_*.py -v
|
||
PYTHONPATH=. uv run pytest tests/test_harness_boundary.py -v
|
||
```
|
||
|
||
```bash
|
||
cd frontend-web
|
||
pnpm typecheck
|
||
pnpm test -- skill-knowledge
|
||
```
|
||
|
||
## 25. 验收场景
|
||
|
||
必须通过:
|
||
|
||
- 管理员选择 3 个技能归纳到 2 个目标知识库,生成 1 个 job、6 个 item、6 个 binding。
|
||
- 同一个技能随后归纳到另一个知识库,新增第二个 binding,技能行显示已归纳至 2 个知识库。
|
||
- 技能可以直接归纳到助手知识库,并生成实体对齐、Wiki 页面版本和搜索索引。
|
||
- 同一个技能同一个 digest 重复归纳,不产生重复 Wiki 页面或重复实体关系。
|
||
- 两个技能在同一知识库中抽取出同名同类型实体,只生成一个规范实体页,并列出两个贡献技能。
|
||
- 解除其中一个技能并选择删除内容后,共享实体仍保留另一个技能贡献。
|
||
- 关系必须带 evidence 和 confidence;低于 0.75 的推断关系不进入规范关系。
|
||
- 重归纳成功后,新版本替换旧版本;旧 artifact 进入 retired。
|
||
- 重归纳失败时,旧版本继续显示为当前版本。
|
||
- 解除关联选择保留内容后,远端 Wiki 和文档保留,但 binding 不再参与后续重归纳。
|
||
- 非管理员访问写接口返回 403。
|
||
- 非 Wiki、FAQ、系统会话存档知识库可作为目标,并通过对应 adapter 写入。
|
||
- 只读知识库可作为目标,结果写入本地 sidecar,远端状态显示 `pending_remote_write`。
|
||
- 直接 Neo4j 写入只在配置开启时执行,且只使用参数化 graph writer。
|
||
- 自动文件监听和定时同步可以创建后台任务,代码文件变化不会触发同步。
|
||
- 前端可逐条审核实体/关系,也可按策略批量处理。
|
||
- 前端展示 WeKnora 远端 ID,并可复制业务 key。
|
||
- WeKnora GraphRAG 不可用时,原始资料和 Wiki 成功,状态为 `partial_failed`,可重试图谱投影。
|
||
- 200 个技能批量归纳时,页面显示整体进度,失败技能可单独重试,后端没有 N+1 查询。
|
||
- 技能中出现 `.env` 或私钥时,该文件不上传、不进 prompt,页面显示安全跳过。
|
||
- 技能中的 `.py`、`.ts`、`.sh` 等代码文件不读取、不上传、不摘要,代码文件变化不触发知识 stale。
|
||
- 未配置 WeKnora 时,助手知识库仍可初始化和查看。
|
||
- 管理员可从普通知识库触发导入到助手知识库。
|
||
- 管理员可向助手知识库导入本地文件,安全扫描通过后生成 Wiki 页面版本。
|
||
- WeKnora 导出包中的 Wiki、文档、chunk、实体、关系、图谱都能进入助手底库。
|
||
- 助手底库把多个来源中的同一人或同一对象合并为一个实体 Wiki 页。
|
||
- 助手 Wiki 支持历史版本、对比和回滚。
|
||
- 助手知识库普通用户只读,管理员可导入、重导、删除来源。
|
||
|
||
## 26. 分阶段交付
|
||
|
||
第一阶段:数据模型与 API 骨架
|
||
|
||
- 建表和 store。
|
||
- 绑定列表、创建 job、查询 job、detach API。
|
||
- 管理员鉴权。
|
||
- 前端技能行能展示空绑定状态。
|
||
|
||
第二阶段:扫描、快照与后台任务
|
||
|
||
- 技能目录扫描。
|
||
- 文件 digest 和 manifest。
|
||
- job/item 执行器、lease、heartbeat、失败重试。
|
||
- 200 技能批量进度。
|
||
|
||
第三阶段:Wiki 归纳与原始资料上传
|
||
|
||
- LLM 摘要和 Wiki 页面生成。
|
||
- WeKnora 原文上传。
|
||
- Wiki page upsert。
|
||
- staged/active 替换。
|
||
|
||
第四阶段:实体关系合并与关系投影
|
||
|
||
- 规范实体和关系表。
|
||
- contribution 机制。
|
||
- 关系 Wiki 页面。
|
||
- graph projection docs。
|
||
- GraphRAG 能力探测和 partial_failed。
|
||
|
||
第五阶段:完整前端体验
|
||
|
||
- 多选技能归纳弹窗。
|
||
- 归纳任务页签。
|
||
- 技能行 chips、详情、重归纳、解除关联。
|
||
- 知识库详情来源技能反查。
|
||
|
||
第六阶段:安全、测试、文档收口
|
||
|
||
- 敏感文件阻断。
|
||
- 压缩包安全。
|
||
- 崩溃恢复。
|
||
- README / CLAUDE 更新。
|
||
- 后端和前端测试。
|
||
|
||
第七阶段:助手知识库与产品版本
|
||
|
||
- 新增唯一全局助手知识库“知识梳理”。
|
||
- 新增 WeKnora 导出到助手库导入任务。
|
||
- 新增技能直接导入助手知识库。
|
||
- 新增管理员本地文件导入助手知识库。
|
||
- 新增助手库实体对齐、关系合并和 Wiki 展示。
|
||
- 新增助手库搜索。
|
||
- 新增助手库 Wiki 页面版本管理、对比和回滚。
|
||
- 新增知识库产品版本 `v1` / `v2` 切换。
|
||
- 处理未配置 WeKnora 时的助手库默认展示。
|
||
|
||
第八阶段:多目标、审核、自动同步和底层图写入
|
||
|
||
- 支持一次选择多个目标知识库。
|
||
- 支持非 Wiki、FAQ、系统会话存档和只读目标 adapter。
|
||
- 支持实体/关系逐条审核。
|
||
- 支持文件监听、定时同步、技能变更自动远程写入。
|
||
- 支持受控 Neo4j direct writer。
|
||
- 支持远端 WeKnora ID 作为业务 key 暴露给前端。
|
||
|
||
## 27. 给实现大模型的硬性指令
|
||
|
||
实现时必须遵守:
|
||
|
||
- 先完整阅读根目录 `AGENTS.md`、后端 `AGENTS.md`、后端 `CLAUDE.md`。
|
||
- 不要回滚用户已有改动。
|
||
- 支持直接写 WeKnora 的 Neo4j,但必须通过受控 graph writer、显式配置、参数化模板、事务和审计。
|
||
- 支持把远端 WeKnora ID 作为前端业务 key 暴露,但本地仍保留 surrogate id。
|
||
- 不要让 `deerflow.*` import `app.*`。
|
||
- 不要执行技能里的代码。
|
||
- 不要读取、上传、摘要或展示技能里的代码文件、脚本文件和代码块内容。
|
||
- 不要上传或提示词输入密钥文件。
|
||
- 技能可以直接归纳到助手知识库,必须走同样的安全扫描、审核和实体对齐。
|
||
- 不要创建多个助手知识库;助手知识库只有一个全局“知识梳理”底库。
|
||
- 自动 watcher、定时同步和技能变更远程写入必须使用 staged 激活、去重、审核和失败保留旧版本。
|
||
- 重归纳必须 staged 写入,成功后再激活。
|
||
- 删除绑定贡献时必须按 contribution refcount 处理共享实体和关系。
|
||
- 助手知识库需要 Wiki 页面版本管理、版本对比、回滚和导入任务审计。
|
||
- 直接写 Neo4j 必须通过受控 graph writer 和参数化模板,不允许执行 LLM 生成的任意 Cypher。
|
||
- 远端 WeKnora ID 可以作为前端业务 key 暴露,但本地仍要保留 surrogate id 和 mapping。
|
||
- 后端代码变更后按仓库要求更新相关 README / CLAUDE。
|
||
- 涉及文件编辑使用 `apply_patch` 或项目正常格式化工具,不做无关重构。
|
||
|
||
## 28. 实现任务清单
|
||
|
||
- [ ] 新增 `skill_knowledge` 持久化模型和 store。
|
||
- [ ] 新增绑定、job、item、artifact、entity、relation、contribution 表。
|
||
- [ ] 新增管理员 router `/api/skill-knowledge`。
|
||
- [ ] 接入知识库能力校验,支持 Wiki、非 Wiki、FAQ、会话存档、只读 sidecar 和助手知识库。
|
||
- [ ] 支持一次选择多个目标知识库,并按 `技能 x 目标` 生成 item。
|
||
- [ ] 新增技能扫描器,支持全部非代码知识文件、安全排除和 digest。
|
||
- [ ] 技能扫描器完全排除代码文件、脚本文件和 Markdown 代码块内容。
|
||
- [ ] 新增 snapshot 缓存。
|
||
- [ ] 新增 LLM 抽取器,输出 schema 校验。
|
||
- [ ] 新增 Wiki 页面生成器。
|
||
- [ ] 新增实体归一化与合并逻辑。
|
||
- [ ] 新增关系归一化与合并逻辑。
|
||
- [ ] 新增 WeKnora artifact projector。
|
||
- [ ] 新增 target adapters。
|
||
- [ ] 新增 graph projection 文档生成和上传。
|
||
- [ ] 新增受控 Neo4j direct graph writer。
|
||
- [ ] 新增实体/关系审核队列。
|
||
- [ ] 新增后台 job dispatcher / executor。
|
||
- [ ] 新增文件 watcher、定时同步 scheduler、技能变更自动写入触发。
|
||
- [ ] 实现 resync 成功替换、失败保留旧版本。
|
||
- [ ] 实现 detach keep/delete。
|
||
- [ ] 技能变更后标记 binding stale。
|
||
- [ ] 前端新增 `skill-knowledge.ts` API。
|
||
- [ ] 技能管理页新增多选归纳入口。
|
||
- [ ] 新增选择知识库弹窗。
|
||
- [ ] 新增归纳任务页签。
|
||
- [ ] 技能行展示已归纳知识库状态。
|
||
- [ ] 实现重归纳、重试、取消、解除关联 UI。
|
||
- [ ] 知识库详情展示来源技能。
|
||
- [ ] 新增唯一全局助手知识库“知识梳理”。
|
||
- [ ] 新增助手知识库持久化模型、来源、导入任务、Wiki、实体、关系、贡献表。
|
||
- [ ] 新增 WeKnora 导出到助手知识库任务。
|
||
- [ ] 支持技能直接导入助手知识库。
|
||
- [ ] 支持管理员本地文件导入助手知识库。
|
||
- [ ] 导出范围覆盖 Wiki、文档、chunk、实体、关系、图谱。
|
||
- [ ] 助手知识库实现全局实体对齐和关系合并。
|
||
- [ ] 助手知识库生成 Wiki 页面并支持搜索。
|
||
- [ ] 助手知识库支持 Wiki 页面版本管理、对比、发布和回滚。
|
||
- [ ] 新增知识库产品版本 `v1` / `v2` 设置,默认 `v1`。
|
||
- [ ] 未配置 WeKnora 时仍展示助手知识库创建或初始化入口。
|
||
- [ ] 助手知识库普通用户只读,管理员可导入、重导、删除。
|
||
- [ ] 后端测试覆盖核心状态机和安全边界。
|
||
- [ ] 前端测试覆盖主要交互。
|
||
- [ ] 更新后端 README / CLAUDE 与必要前端文档。
|
||
|
||
## 29. 风险与处理
|
||
|
||
| 风险 | 处理 |
|
||
| --- | --- |
|
||
| WeKnora 图谱 API 在部署版本不稳定 | 以 Swagger 能力探测为准;Wiki 关系页和 graph projection 文档作为稳定方案。 |
|
||
| LLM 推断关系误判 | 强制 evidence、confidence 阈值、低置信不进入规范关系。 |
|
||
| 200 技能批量耗时长 | 后台 job、item 并发、snapshot 缓存、前端批量查询。 |
|
||
| 重归纳中断导致新旧混杂 | staged artifact + 本地事务激活 + 失败保留旧版本。 |
|
||
| 删除共享实体误删其他技能知识 | contribution refcount,删除只移除该 binding 贡献。 |
|
||
| 敏感信息进入知识库 | 文件级安全阻断、prompt 前二次扫描、日志脱敏。 |
|
||
| 技能目录处理阻塞 Gateway | 文件 IO 和转换统一 `asyncio.to_thread`。 |
|
||
| 技能源文件归纳中变化 | expected digest 校验,不一致则失败并标记 stale。 |
|
||
|
||
## 30. 新增:普通知识库与助手知识库双体系
|
||
|
||
本节是基于新需求的补充设计。后续实现以本节为准;如果本节与前文旧的 WeKnora-only 表述冲突,优先采用本节。
|
||
|
||
### 30.1 产品形态
|
||
|
||
系统需要区分两类知识库:
|
||
|
||
| 类型 | 存储 | 用途 | 可见性 | 写入来源 |
|
||
| --- | --- | --- | --- | --- |
|
||
| 普通知识库 | WeKnora | 文档向量化、Wiki、检索、图谱、技能归纳目标 | 按现有 WeKnora 逻辑 | 技能归纳、现有 WeKnora 导入 |
|
||
| 助手知识库 | DeerFlow 自研库 | 全局知识梳理、实体对齐、Wiki 展示、搜索、版本管理 | 所有人可见,普通用户只读 | WeKnora 导出、WeKnora 自动沉淀、技能直接归纳、管理员本地文件导入 |
|
||
|
||
产品版本开关:
|
||
|
||
- `v1`:默认值,优先展示现有普通知识库体验。
|
||
- `v2`:优先展示助手知识库体验。
|
||
- 管理员可在系统设置中切换版本。
|
||
- 如果未配置 WeKnora,即使当前版本默认是 `v1`,页面也应展示助手知识库创建/初始化入口;WeKnora 相关能力隐藏或置灰,并提示“未配置普通知识库服务”。
|
||
|
||
建议新增系统设置项:
|
||
|
||
```json
|
||
{
|
||
"knowledge_base_product_version": "v1"
|
||
}
|
||
```
|
||
|
||
### 30.2 助手知识库定位
|
||
|
||
助手知识库只有一个全局底库,建议默认名:
|
||
|
||
```text
|
||
知识梳理
|
||
```
|
||
|
||
它不是 WeKnora 的另一个知识库,也不向 WeKnora 写数据。它是 DeerFlow 自己维护的结构化知识底库。
|
||
|
||
助手知识库对用户展示:
|
||
|
||
- Wiki 页面列表。
|
||
- Wiki 页面详情。
|
||
- Wiki 页面版本、对比和回滚。
|
||
- 实体页。
|
||
- 关系页。
|
||
- 搜索。
|
||
- 数据导入记录。
|
||
|
||
助手知识库内部可以存实体、关系、贡献、来源、搜索索引,但前端主体验以 Wiki 为中心,不做复杂图数据库管理页。
|
||
|
||
权限:
|
||
|
||
- 普通用户:可查看、搜索。
|
||
- 管理员:可初始化助手知识库、从 WeKnora 导入、重新导入、删除导入来源、编辑或删除 Wiki 页面。
|
||
|
||
### 30.3 数据来源
|
||
|
||
助手知识库的数据来源包括 WeKnora、技能归纳和管理员本地文件。
|
||
|
||
支持四种触发方式:
|
||
|
||
| 方式 | 说明 |
|
||
| --- | --- |
|
||
| 自动沉淀 | WeKnora 普通知识库完成文档向量化、Wiki 生成和图谱抽取后,默认创建一个导入任务,把处理结果沉淀到助手知识库。 |
|
||
| 手动导入 | 管理员在普通知识库页面点击“导入到助手知识库”或“导出到知识梳理”,本质仍是导出 WeKnora 数据后导入助手库。 |
|
||
| 技能直接归纳 | 管理员在技能管理页选择助手知识库作为目标,系统直接写入自研助手底库。 |
|
||
| 本地文件导入 | 管理员在助手知识库页面上传本地文件,系统安全扫描后抽取实体、关系和 Wiki 页面。 |
|
||
|
||
限制:
|
||
|
||
- 普通用户不能写入助手知识库。
|
||
- 本地文件导入必须走敏感信息扫描、文件类型白名单、大小限制和导入审计。
|
||
- 技能直接归纳仍然完全排除代码文件、脚本文件和 Markdown 代码块内容。
|
||
|
||
### 30.4 WeKnora 导出范围
|
||
|
||
从 WeKnora 导入助手知识库时,需要尽可能导出全部已处理数据:
|
||
|
||
- 知识库元数据。
|
||
- Wiki 页面。
|
||
- Wiki 页面之间的链接。
|
||
- 已上传文档信息。
|
||
- 已向量化完成的 chunk 文本、chunk metadata、来源文档映射。
|
||
- WeKnora 可读取的实体。
|
||
- WeKnora 可读取的关系。
|
||
- WeKnora 可读取的图谱节点和边。
|
||
- 技能归纳产生的 source metadata,例如 `skill_name`、`binding_id`、`snapshot_id`。
|
||
|
||
说明:
|
||
|
||
- 助手知识库不强依赖复用 WeKnora embedding 向量。若 WeKnora 不暴露 embedding 原始向量,导入 chunk 文本和 metadata 即可。
|
||
- 如果 WeKnora 不暴露稳定的图谱导出 API,则使用现有 Wiki graph、关系投影文档、Wiki 关系页和可查询接口重建实体关系。
|
||
- 导入过程要记录能力缺失:例如“已导入 Wiki 与文档,图谱 API 不可用,关系由 Wiki 关系页重建”。
|
||
|
||
导出包建议:
|
||
|
||
```json
|
||
{
|
||
"export_id": "wk_export_001",
|
||
"source": {
|
||
"type": "weknora",
|
||
"knowledge_base_id": "local-kb-id",
|
||
"knowledge_base_name": "作战知识库",
|
||
"exported_at": "2026-09-01T10:00:00Z"
|
||
},
|
||
"wiki_pages": [],
|
||
"documents": [],
|
||
"chunks": [],
|
||
"entities": [],
|
||
"relations": [],
|
||
"graph": {
|
||
"nodes": [],
|
||
"edges": []
|
||
}
|
||
}
|
||
```
|
||
|
||
### 30.5 助手库实体对齐
|
||
|
||
助手知识库的核心价值是把来自不同 WeKnora 普通知识库、不同技能来源、不同 Wiki 页中的同一实体合并。
|
||
|
||
实体对齐范围是全局助手库:
|
||
|
||
```text
|
||
assistant_base_id + entity_type + normalized_name
|
||
```
|
||
|
||
如果存在更强 ID,则优先:
|
||
|
||
```text
|
||
assistant_base_id + entity_type + external_id_type + external_id
|
||
```
|
||
|
||
对齐规则:
|
||
|
||
- 确定性同一:证件号、统一社会信用代码、装备编号、系统唯一 ID 等完全一致,直接合并。
|
||
- 高置信名称同一:同类型实体 normalized name 一致,合并。
|
||
- 模型推断同一:允许模型判断“张三”“张三同志”“Zhang San”是否同一人,但必须给出 evidence 和 confidence。
|
||
- `confidence >= 0.90` 的模型对齐可以自动合并。
|
||
- `0.70 <= confidence < 0.90` 的模型对齐不自动合并,可记录为候选别名或候选关联。
|
||
- `confidence < 0.70` 丢弃。
|
||
|
||
合并后必须保留来源贡献:
|
||
|
||
- 来自哪个 WeKnora 知识库。
|
||
- 来自哪个 Wiki 页面或 chunk。
|
||
- 来自哪个技能 binding。
|
||
- 证据文本。
|
||
- 导入任务 ID。
|
||
|
||
属性冲突不覆盖:
|
||
|
||
- 不同来源给出不同姓名、职务、时间、地点、数值时,按来源分组展示。
|
||
- Wiki 页面中展示“多来源信息”而不是最后写入覆盖。
|
||
|
||
### 30.6 助手库关系对齐
|
||
|
||
关系 key:
|
||
|
||
```text
|
||
assistant_base_id + source_assistant_entity_id + normalized_predicate + target_assistant_entity_id
|
||
```
|
||
|
||
关系来源:
|
||
|
||
- WeKnora 图谱边。
|
||
- WeKnora Wiki graph 链接。
|
||
- 技能归纳时写入 WeKnora 的关系页。
|
||
- graph projection 文档。
|
||
- 模型从 WeKnora 导出包中推断的高置信关系。
|
||
|
||
关系合并后保留多个证据贡献。
|
||
|
||
关系 Wiki 页面建议:
|
||
|
||
```text
|
||
assistant/relations/{predicate}/{stable_relation_id}
|
||
```
|
||
|
||
关系页内容:
|
||
|
||
- 源实体。
|
||
- 关系类型。
|
||
- 目标实体。
|
||
- 关系描述。
|
||
- 来源知识库。
|
||
- 来源 Wiki 页。
|
||
- 证据和置信度。
|
||
|
||
### 30.7 助手库 Wiki 生成
|
||
|
||
助手库最终以 Wiki 页面展示。
|
||
|
||
页面类型:
|
||
|
||
| 页面 | slug 示例 | 说明 |
|
||
| --- | --- | --- |
|
||
| 首页 | `assistant/home` | 知识梳理总览、实体数量、来源数量、最近导入。 |
|
||
| 来源页 | `assistant/sources/{source_id}` | 某个 WeKnora 知识库导入结果。 |
|
||
| 实体页 | `assistant/entities/{type}/{entity_id}-{name}` | 对齐后的全局实体页面。 |
|
||
| 关系页 | `assistant/relations/{predicate}/{relation_id}` | 对齐后的全局关系页面。 |
|
||
| 主题页 | `assistant/topics/{topic}` | 从 WeKnora Wiki 分类或目录生成。 |
|
||
|
||
实体页结构:
|
||
|
||
- 标题:实体名。
|
||
- 类型:人物、组织、地点、装备、事件、概念、数据对象等。
|
||
- 摘要:模型基于多来源融合生成。
|
||
- 别名。
|
||
- 多来源属性。
|
||
- 相关实体。
|
||
- 相关关系。
|
||
- 来源 Wiki 页面。
|
||
- 证据。
|
||
|
||
助手库 Wiki 页面需要版本管理。每次 WeKnora 导入、技能直接归纳、管理员本地文件导入、实体对齐重建或人工编辑,都生成新 revision。新 revision 先处于 draft 或 staged 状态,发布成功后成为 current。
|
||
|
||
版本能力:
|
||
|
||
- 查看历史版本。
|
||
- 对比两个版本。
|
||
- 回滚到历史版本。
|
||
- 查看版本来源:导入任务、技能归纳任务、人工编辑。
|
||
- 查看版本发布人和发布时间。
|
||
|
||
### 30.8 助手库搜索
|
||
|
||
助手知识库需要支持搜索。
|
||
|
||
V1 建议实现:
|
||
|
||
- Wiki 标题搜索。
|
||
- 实体名称和别名搜索。
|
||
- Wiki 正文全文搜索。
|
||
- 来源知识库过滤。
|
||
- 实体类型过滤。
|
||
|
||
实现选择:
|
||
|
||
- SQLite 可使用 FTS5。
|
||
- PostgreSQL 可使用 tsvector 或 trigram。
|
||
- 如果现有持久化层不方便,先实现数据库 LIKE + normalized name 索引,后续再升级全文索引。
|
||
|
||
搜索结果只展示 Wiki 页面,不直接展示底层 chunk。
|
||
|
||
### 30.9 助手库持久化表
|
||
|
||
建议新增:
|
||
|
||
```text
|
||
deerflow.persistence.assistant_knowledge
|
||
```
|
||
|
||
核心表:
|
||
|
||
#### `assistant_knowledge_base`
|
||
|
||
只允许一条 active 记录。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `name` | 默认“知识梳理”。 |
|
||
| `status` | `active` / `disabled`。 |
|
||
| `created_by` | 初始化管理员。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
#### `assistant_knowledge_sources`
|
||
|
||
记录每个来源。来源可以是 WeKnora 知识库、技能归纳或管理员本地导入。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `base_id` | 助手库 ID。 |
|
||
| `source_type` | `weknora` / `skill` / `local_file`。 |
|
||
| `knowledge_base_mapping_id` | DeerFlow 本地 WeKnora 映射 ID,可为空。 |
|
||
| `skill_name` | 技能名,可为空。 |
|
||
| `upload_batch_id` | 本地文件导入批次,可为空。 |
|
||
| `source_name` | 来源名称。 |
|
||
| `last_import_job_id` | 最近导入任务。 |
|
||
| `status` | `active` / `import_failed` / `deleted`。 |
|
||
| `created_at` / `updated_at` | 时间戳。 |
|
||
|
||
#### `assistant_knowledge_import_jobs`
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `base_id` | 助手库 ID。 |
|
||
| `source_id` | 来源 ID。 |
|
||
| `trigger` | `auto_after_weknora_indexed` / `manual_from_weknora` / `skill_direct` / `manual_file_upload` / `scheduled` / `watcher`。 |
|
||
| `status` | `queued` / `running` / `completed` / `partial_failed` / `failed`。 |
|
||
| `phase` | `exporting` / `scanning` / `parsing` / `awaiting_review` / `aligning_entities` / `aligning_relations` / `writing_wiki` / `indexing_search` / `completed`。 |
|
||
| `counts_json` | 导入页面、实体、关系、chunk 数。 |
|
||
| `last_error_message` | 错误摘要。 |
|
||
| `created_by` | 操作人;自动任务可为空或 system。 |
|
||
| `created_at` / `completed_at` | 时间戳。 |
|
||
|
||
#### `assistant_knowledge_wiki_pages`
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `base_id` | 助手库 ID。 |
|
||
| `slug` | 全局唯一 slug。 |
|
||
| `title` | 标题。 |
|
||
| `page_type` | `home` / `source` / `entity` / `relation` / `topic`。 |
|
||
| `current_revision_id` | 当前发布版本。 |
|
||
| `content_markdown` | 当前版本冗余内容,便于列表和搜索。 |
|
||
| `summary` | 摘要。 |
|
||
| `status` | `active` / `deleted`。 |
|
||
| `search_text` | 搜索文本。 |
|
||
| `updated_at` | 更新时间。 |
|
||
|
||
#### `assistant_knowledge_wiki_revisions`
|
||
|
||
保存 Wiki 页面版本。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `page_id` | Wiki 页面。 |
|
||
| `revision_no` | 递增版本号。 |
|
||
| `content_markdown` | 版本内容。 |
|
||
| `summary` | 版本摘要。 |
|
||
| `source_id` | 来源,可为空。 |
|
||
| `import_job_id` | 导入任务,可为空。 |
|
||
| `change_type` | `import` / `skill_sync` / `manual_edit` / `entity_rebuild` / `rollback`。 |
|
||
| `status` | `draft` / `staged` / `published` / `superseded`。 |
|
||
| `created_by` | 创建人。 |
|
||
| `created_at` / `published_at` | 时间戳。 |
|
||
|
||
#### `assistant_knowledge_entities`
|
||
|
||
保存全局对齐后的实体。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `base_id` | 助手库 ID。 |
|
||
| `entity_type` | 实体类型。 |
|
||
| `normalized_name` | 归一化名称。 |
|
||
| `display_name` | 展示名称。 |
|
||
| `aliases_json` | 别名。 |
|
||
| `attributes_json` | 聚合属性。 |
|
||
| `wiki_page_id` | 实体 Wiki 页。 |
|
||
| `status` | `active` / `deleted`。 |
|
||
|
||
#### `assistant_knowledge_entity_contributions`
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `entity_id` | 全局实体。 |
|
||
| `source_id` | WeKnora 来源。 |
|
||
| `import_job_id` | 导入任务。 |
|
||
| `source_wiki_slug` | 来源 Wiki 页。 |
|
||
| `source_chunk_id` | 来源 chunk,可为空。 |
|
||
| `source_skill_name` | 来源技能,可为空。 |
|
||
| `evidence_json` | 证据。 |
|
||
| `confidence` | 置信度。 |
|
||
|
||
#### `assistant_knowledge_relations`
|
||
|
||
保存全局对齐后的关系。
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `base_id` | 助手库 ID。 |
|
||
| `source_entity_id` | 源实体。 |
|
||
| `predicate` | 关系类型。 |
|
||
| `target_entity_id` | 目标实体。 |
|
||
| `description` | 聚合描述。 |
|
||
| `wiki_page_id` | 关系 Wiki 页。 |
|
||
| `status` | `active` / `deleted`。 |
|
||
|
||
#### `assistant_knowledge_relation_contributions`
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `id` | UUID。 |
|
||
| `relation_id` | 全局关系。 |
|
||
| `source_id` | WeKnora 来源。 |
|
||
| `import_job_id` | 导入任务。 |
|
||
| `source_wiki_slug` | 来源 Wiki 页。 |
|
||
| `graph_edge_id` | WeKnora 图谱边 ID,可为空。 |
|
||
| `evidence_json` | 证据。 |
|
||
| `confidence` | 置信度。 |
|
||
|
||
### 30.10 助手库 API
|
||
|
||
新增 router:
|
||
|
||
```text
|
||
/api/assistant-knowledge
|
||
```
|
||
|
||
建议接口:
|
||
|
||
```http
|
||
GET /api/assistant-knowledge/base
|
||
POST /api/assistant-knowledge/base/initialize
|
||
GET /api/assistant-knowledge/wiki-pages
|
||
GET /api/assistant-knowledge/wiki-pages/{slug}
|
||
GET /api/assistant-knowledge/wiki-pages/{slug}/revisions
|
||
GET /api/assistant-knowledge/wiki-pages/{slug}/revisions/{revision_id}
|
||
POST /api/assistant-knowledge/wiki-pages/{slug}/revisions/{revision_id}/rollback
|
||
GET /api/assistant-knowledge/search?q=xxx&type=entity&source_id=xxx
|
||
GET /api/assistant-knowledge/entities/{id}
|
||
GET /api/assistant-knowledge/relations/{id}
|
||
GET /api/assistant-knowledge/sources
|
||
GET /api/assistant-knowledge/import-jobs
|
||
GET /api/assistant-knowledge/import-jobs/{id}
|
||
POST /api/assistant-knowledge/sources/{source_id}/reimport
|
||
POST /api/assistant-knowledge/imports/files
|
||
POST /api/assistant-knowledge/imports/skills
|
||
DELETE /api/assistant-knowledge/sources/{source_id}
|
||
```
|
||
|
||
新增 WeKnora 普通知识库导出或导入触发接口:
|
||
|
||
```http
|
||
POST /api/llmwiki/knowledge-bases/{knowledge_base_id}/export-to-assistant
|
||
```
|
||
|
||
行为:
|
||
|
||
- 校验管理员。
|
||
- 校验助手知识库已初始化;未初始化则自动创建“知识梳理”或提示管理员确认创建。
|
||
- 校验 WeKnora 知识库已完成处理。
|
||
- 创建 `assistant_knowledge_import_jobs`。
|
||
- 后台导出 WeKnora 数据并导入助手库。
|
||
|
||
本地文件导入接口:
|
||
|
||
```http
|
||
POST /api/assistant-knowledge/imports/files
|
||
```
|
||
|
||
使用 multipart 上传文件。后端必须先完成安全扫描和敏感信息阻断,再进入解析、抽取、审核、实体对齐和 Wiki 版本生成。
|
||
|
||
技能直接导入接口:
|
||
|
||
```http
|
||
POST /api/assistant-knowledge/imports/skills
|
||
```
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"skill_names": ["skill-a", "skill-b"],
|
||
"force": false
|
||
}
|
||
```
|
||
|
||
该接口也可以由 `/api/skill-knowledge/sync-jobs` 在目标类型为 `assistant` 时内部复用。
|
||
|
||
系统设置接口需要支持:
|
||
|
||
```http
|
||
GET /api/system-settings/knowledge-base-product-version
|
||
PUT /api/system-settings/knowledge-base-product-version
|
||
```
|
||
|
||
### 30.11 前端页面
|
||
|
||
知识库入口需要支持产品版本切换。
|
||
|
||
建议:
|
||
|
||
- 管理员设置页提供“知识库版本”切换:`v1 普通知识库` / `v2 助手知识库`,默认 `v1`。
|
||
- 知识库页面顶部用 Tabs 或 Segmented Control 区分“普通知识库”和“助手知识库”。
|
||
- 未配置 WeKnora 时,普通知识库 tab 隐藏或禁用;助手知识库 tab 正常显示。
|
||
- 助手知识库未初始化时,展示“创建知识梳理库”按钮。
|
||
- 创建后展示 Wiki 首页、搜索框、来源列表、最近导入和页面版本入口。
|
||
- 普通知识库详情页增加按钮:“导入到助手知识库”。
|
||
- 普通知识库列表中可显示“已沉淀到知识梳理 / 待导入 / 导入失败”状态。
|
||
- 助手知识库页面为管理员提供“导入本地文件”和“导入技能”入口。
|
||
|
||
助手知识库页面建议:
|
||
|
||
```text
|
||
知识梳理
|
||
├── 搜索
|
||
├── Wiki 首页
|
||
├── 实体
|
||
├── 关系
|
||
├── 来源知识库
|
||
├── 导入记录
|
||
└── 页面版本
|
||
```
|
||
|
||
普通用户只看到搜索、Wiki、实体、关系、来源和只读版本历史。管理员额外看到导入、重新导入、删除来源、版本对比和回滚。
|
||
|
||
### 30.12 自动沉淀时机
|
||
|
||
WeKnora 普通知识库完成以下任意流程后,应触发或排队助手库导入:
|
||
|
||
- 管理员从技能归纳到 WeKnora 成功。
|
||
- WeKnora 文档上传并完成向量化。
|
||
- WeKnora Wiki 页面生成或更新完成。
|
||
- WeKnora 图谱抽取完成。
|
||
- 管理员手动点击“导入到助手知识库”。
|
||
|
||
为了避免频繁重复导入:
|
||
|
||
- 对每个 WeKnora 知识库维护 `last_export_digest`。
|
||
- 导出前计算 Wiki 页面、文档 chunk、图谱摘要的 digest。
|
||
- digest 未变化时跳过导入。
|
||
- 同一 WeKnora 知识库同一时间只允许一个 active 导入任务。
|
||
|
||
### 30.13 与技能归纳的关系
|
||
|
||
技能归纳支持两条链路。
|
||
|
||
链路 A:先进入 WeKnora,再沉淀助手库。
|
||
|
||
```text
|
||
技能知识文件
|
||
-> WeKnora 普通知识库
|
||
-> WeKnora 向量化 / Wiki / 图谱
|
||
-> 导出已处理数据
|
||
-> 助手知识库“知识梳理”
|
||
-> 全局实体对齐
|
||
-> Wiki 展示与搜索
|
||
```
|
||
|
||
链路 B:直接进入助手知识库。
|
||
|
||
```text
|
||
技能知识文件
|
||
-> 助手知识库“知识梳理”
|
||
-> 实体/关系预览审核
|
||
-> 全局实体对齐
|
||
-> Wiki 页面版本发布
|
||
-> 搜索索引
|
||
```
|
||
|
||
代码文件在第一步就被排除,不进入后续任何知识库。
|
||
|
||
### 30.14 新增测试与验收
|
||
|
||
新增后端测试:
|
||
|
||
- 未配置 WeKnora 时,助手知识库 base 接口可用,普通知识库导入接口返回明确不可用。
|
||
- 初始化助手知识库后,只存在一个 active base。
|
||
- 普通用户可读助手 Wiki,写接口返回 403。
|
||
- 管理员可从 WeKnora 知识库触发导入任务。
|
||
- 管理员可把技能直接导入助手知识库。
|
||
- 管理员可上传本地文件导入助手知识库。
|
||
- WeKnora 导出包包含 Wiki、文档、chunk、实体、关系、图谱时,助手库全部导入。
|
||
- 同一个人或同一对象来自多个 WeKnora 来源时,在助手库合并为一个实体。
|
||
- 模型推断实体对齐 `confidence >= 0.90` 自动合并,低于阈值不合并。
|
||
- 删除某个来源时,只删除该来源贡献;其他来源贡献仍保留。
|
||
- 助手库搜索能命中 Wiki 标题、实体别名和正文。
|
||
- 助手 Wiki 页面支持 revision、对比和回滚。
|
||
- 技能归纳扫描不读取、不上传、不摘要代码文件,代码文件变化不触发 stale。
|
||
|
||
新增前端测试:
|
||
|
||
- 知识库产品版本默认 `v1`。
|
||
- 管理员可切换 `v1` / `v2`。
|
||
- 未配置 WeKnora 时仍可看到“创建知识梳理库”。
|
||
- 普通知识库详情页有“导入到助手知识库”按钮。
|
||
- 助手知识库页面展示 Wiki、搜索、来源、导入记录。
|
||
- 助手知识库页面展示页面版本、对比和回滚入口。
|
||
- 普通用户看不到导入、删除、重新导入和回滚动作。
|