# 数据模型

## 文档维护规范

0. **先改文档，再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后，再进行代码实现；除非改动较小、不被文档涵盖
1. **文档分层，链接代码** - 重要或复杂设计可以另有详细文档；关键实现需标注代码文件路径；格式：`module/file.py:function_name`
2. **简洁快照，日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息，避免推测、建议、决策历史、修改日志、大量代码；决策依据或修改日志若有必要，可在 `knowhub/docs/decisions.md` 另行记录

---

## 存储架构

PostgreSQL (阿里云 AnalyticDB for PostgreSQL)。所有向量字段为 float4[]（1536维），使用余弦距离（`<=>`）检索。

Embedding 模型：`google/gemini-2.5-flash-lite`（通过 OpenRouter）。实现：`knowhub/embeddings.py`。

数据库名：`knowhub`

## 多租户版本字段（version）

6 张实体表中除 tool 外（tool.version 早已存在，指工具自身发布版本），另外 5 张都有 `version VARCHAR(32) NOT NULL DEFAULT 'v0'` 列：`knowledge`, `resource`, `requirement`, `capability`, `strategy`。

- 用途：隔离算法测试数据（tao_dev_1 等）与生产数据（v0），共用一套入库/查询/可视化管道
- 规则：独立 ID 跨版本唯一（`CAP-v0-001` 和 `CAP-tao_dev_1-00-01` 是两个不同实体）
- junction 表**不带 version**——自动继承两端实体的 version（通过 JOIN 实现过滤）
- 批量清除某版本：`cascade.purge_version(cursor, 'tao_dev_1')` 一次清 5 张实体表 + 它们所有 junction 行
- 默认查询不过滤版本（返回所有数据）；过滤时显式传 `version` 参数

---

## 设计原则

- **knowledge 是基础层**，其余实体是组织/提炼知识的维度
- 每个维度的目标是**收敛到最优知识**，不是关联尽可能多的知识
- 实体字段（description、criterion、match_result）是提炼结果，知识链是提炼来源——两者都需要
- 所有实体间关系通过**关联表**存储，不使用 JSONB 数组软关联
- 工具库和知识库共用同一套工具 ID，不做 ID 映射
- Provider（运行环境）不作为知识库实体，由执行 Agent（Craftsman）内部管理；`tool_provider` 仅提供工具可用性索引

---

## 表间关系

```
              requirement ──── requirement_strategy ──── strategy
            ╱     ╲   ╲                                 ╱  │  ╲
  capability_ids  knowledge_ids  resource_ids   capability │  knowledge / resource
           ╱              ╲         ╲                      compose
     capability          knowledge ← knowledge_resource → resource
         │  ╲              ╱  ╲                            ↑
         │  tool_ids  knowledge_ids  knowledge_relation    │
         │     ╲         ╱            (知识间关系)          │
         │      tool    ...          ← capability_resource ┤
    capability_resource                ← requirement_resource
                                       ← strategy_resource
                     tool_provider (执行层索引)
```

所有 `*_knowledge` / `knowledge_relation` / `strategy_capability` / `strategy_knowledge` 边带 `relation_type` 语义标签：
- `source` — 知识/资料是该实体的构建来源
- `case`   — 知识是该实体的应用实例
- `compose` — 组合关系（strategy → capability）
- `related` — 默认/未分类

---

## 实体表（6）

### knowledge — 知识表

基础层。用例、方法、经验、评论都是 knowledge。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | VARCHAR PK | `"knowledge-{timestamp}-{random}"` |
| `task_embedding` | float4[] | task 的向量 |
| `content_embedding` | float4[] | content 的向量 |
| `message_id` | VARCHAR | 来源 Agent 消息 ID |
| `task` | VARCHAR | 任务场景描述 |
| `content` | TEXT | 知识正文 |
| `types` | TEXT[] | 知识类型：tool / strategy / case / experience / definition |
| `tags` | JSONB | 标签键值对 |
| `tag_keys` | TEXT[] | tags 中的键列表（用于过滤） |
| `scopes` | TEXT[] | 作用域，如 `["org:cybertogether"]` |
| `owner` | VARCHAR | 所有者 |
| `source` | JSONB | 来源信息（agent_id, category, urls, submitted_by, timestamp） |
| `eval` | JSONB | 评估（score, helpful, harmful, confidence） |
| `created_at` | BIGINT | 创建时间戳（秒） |
| `updated_at` | BIGINT | 更新时间戳（秒） |
| `status` | VARCHAR | pending → approved / rejected / checked |

关联（通过关联表，API 返回时聚合为 `{entity}_ids` 扁平列表 + `{entity}_links` 带 relation_type）：
- `requirement_ids` / `requirement_links` ← requirement_knowledge
- `capability_ids` / `capability_links` ← capability_knowledge
- `tool_ids` / `tool_links` ← tool_knowledge
- `resource_ids` ← knowledge_resource
- `relations` ← knowledge_relation

### resource — 资源表

知识的原始来源。文档、代码、凭证等。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | TEXT PK | 路径格式，如 `"tools/selenium/login"` |
| `title` | TEXT | 标题 |
| `body` | TEXT | 公开内容 |
| `secure_body` | TEXT | 敏感内容（AES-256-GCM 加密） |
| `content_type` | TEXT | text / code / credential / cookie |
| `metadata` | JSONB | 附加元数据 |
| `images` | JSONB | 图片 URL 列表 `[url1, url2, ...]`，用于 dashboard 缩略图展示（v5 新增）|
| `sort_order` | INTEGER | 同级排序 |
| `submitted_by` | TEXT | 提交者 |
| `created_at` | BIGINT | 创建时间戳 |
| `updated_at` | BIGINT | 更新时间戳 |
| `version` | VARCHAR(32) | 多租户版本标签，DEFAULT `'v0'` |

### requirement — 需求表

业务目标。分解为能力的组合，以保持稳定性。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | VARCHAR PK | `"REQ_XXX"` |
| `description` | TEXT | 需求描述 |
| `source_nodes` | JSONB | 来源节点 `[{node_name, posts}]` |
| `status` | VARCHAR | 已满足 / 未满足 |
| `match_result` | TEXT | 满足方案描述（提炼结果） |
| `embedding` | float4[] | description 的向量 |

关联：
- `capability_ids` ← requirement_capability
- `knowledge_ids` / `knowledge_links` ← requirement_knowledge
- `resource_ids` ← requirement_resource
- `strategy_ids` ← requirement_strategy（满足该需求的 strategy）
- `node_refs` ← requirement_node（外部内容树节点引用，带 execution_id）
- `pattern_refs` ← requirement_pattern（外部 itemset 引用，带 execution_id）

注：`source_nodes` JSONB 列保留为快照字段，正规化后权威来源是 `requirement_node`；新数据应同步写入 junction 表。

### capability — 原子能力表

需求的稳定分解锚点。从知识中提炼，连接需求与工具。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | VARCHAR PK | `"CAP-XXX"` |
| `name` | VARCHAR | 能力名称 |
| `criterion` | TEXT | 评估标准（提炼结果） |
| `description` | TEXT | 能力描述（提炼结果） |
| `embedding` | float4[] | name + description 的向量 |

关联：
- `requirement_ids` ← requirement_capability
- `tool_ids` ← capability_tool
- `knowledge_ids` / `knowledge_links` ← capability_knowledge
- `resource_ids` ← capability_resource

### tool — 工具表

具体的技术/模型/软件。工具库和知识库共用同一套 ID。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | VARCHAR PK | 路径格式，如 `"tools/image_gen/controlnet_openpose"` |
| `name` | VARCHAR | 工具名称 |
| `version` | VARCHAR | 版本号 |
| `introduction` | TEXT | 功能介绍 |
| `tutorial` | TEXT | 使用指南 |
| `input` | JSONB | 输入规格 |
| `output` | JSONB | 输出规格 |
| `updated_time` | BIGINT | 更新时间戳 |
| `status` | VARCHAR | 未接入 / 可用 / 异常 |
| `embedding` | float4[] | name + introduction 的向量 |

关联：
- `capability_ids` ← capability_tool
- `knowledge_ids` / `knowledge_links` ← tool_knowledge
- `provider_ids` ← tool_provider

### strategy — 制作策略表

一组原子 capability 的组合，附带自身的可执行 `body`（如工作流脚本、流程描述）与 source 知识。strategy 设计用来满足 requirement。

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | VARCHAR PK | `"strategy-{...}"` |
| `name` | VARCHAR | 策略名称 |
| `description` | TEXT | 策略描述 |
| `body` | TEXT | 可执行正文（工作流/脚本/流程步骤） |
| `status` | VARCHAR | draft / approved / deprecated 等 |
| `created_at` | BIGINT | 创建时间戳（秒） |
| `updated_at` | BIGINT | 更新时间戳（秒） |
| `embedding` | float4[] | name + description 的向量 |

关联：
- `requirement_ids` ← requirement_strategy（这个 strategy 被设计用来满足哪些 requirement）
- `capability_ids` / `capability_links` ← strategy_capability（compose 组合）
- `knowledge_ids` / `knowledge_links` ← strategy_knowledge（source / case 等）
- `resource_ids` ← strategy_resource（直接原始素材）

---

## 关联表（16）

### 实体链（3）

**requirement_capability** — 需求分解为能力

| 字段 | 类型 | 说明 |
|------|------|------|
| `requirement_id` | VARCHAR | → requirement.id |
| `capability_id` | VARCHAR | → capability.id |

PK: (requirement_id, capability_id)

**capability_tool** — 能力由工具实现

| 字段 | 类型 | 说明 |
|------|------|------|
| `capability_id` | VARCHAR | → capability.id |
| `tool_id` | VARCHAR | → tool.id |
| `description` | TEXT | 该工具如何实现此能力 |

PK: (capability_id, tool_id)

**requirement_strategy** — 需求由 strategy 满足

| 字段 | 类型 | 说明 |
|------|------|------|
| `requirement_id` | VARCHAR | → requirement.id |
| `strategy_id` | VARCHAR | → strategy.id |

PK: (requirement_id, strategy_id)

### 知识链（4）

所有 `*_knowledge` 表及 `strategy_knowledge` 都带 `relation_type VARCHAR(32)` 列，值 ∈ {`source`, `case`, `related`}。DEFAULT `'related'`（历史数据）。

**requirement_knowledge** — 需求的方案策略、完成方法

| 字段 | 类型 | 说明 |
|------|------|------|
| `requirement_id` | VARCHAR | → requirement.id |
| `knowledge_id` | VARCHAR | → knowledge.id |
| `relation_type` | VARCHAR(32) | source / case / related（默认） |

PK: (requirement_id, knowledge_id)

**capability_knowledge** — 能力的原理依据、评判来源

| 字段 | 类型 | 说明 |
|------|------|------|
| `capability_id` | VARCHAR | → capability.id |
| `knowledge_id` | VARCHAR | → knowledge.id |
| `relation_type` | VARCHAR(32) | source / case / related（默认） |

PK: (capability_id, knowledge_id)

**tool_knowledge** — 工具的用法、案例、经验

| 字段 | 类型 | 说明 |
|------|------|------|
| `tool_id` | VARCHAR | → tool.id |
| `knowledge_id` | VARCHAR | → knowledge.id |
| `relation_type` | VARCHAR(32) | source / case / related（默认） |

PK: (tool_id, knowledge_id)

**strategy_knowledge** — strategy 的知识来源

| 字段 | 类型 | 说明 |
|------|------|------|
| `strategy_id` | VARCHAR | → strategy.id |
| `knowledge_id` | VARCHAR | → knowledge.id |
| `relation_type` | VARCHAR(32) | 默认 `source`；可为 `case` 等 |

PK: (strategy_id, knowledge_id)

### 组合关系（1）

**strategy_capability** — strategy 组合哪些原子能力

| 字段 | 类型 | 说明 |
|------|------|------|
| `strategy_id` | VARCHAR | → strategy.id |
| `capability_id` | VARCHAR | → capability.id |
| `relation_type` | VARCHAR(32) | 默认 `compose` |

PK: (strategy_id, capability_id)

### 来源链（5）

**knowledge_resource** — 知识的原始来源

| 字段 | 类型 | 说明 |
|------|------|------|
| `knowledge_id` | VARCHAR | → knowledge.id |
| `resource_id` | VARCHAR | → resource.id |

PK: (knowledge_id, resource_id)

**requirement_resource** — 需求直接来自的原始素材（绕过 knowledge 整理层）

PK: (requirement_id, resource_id)

**capability_resource** — capability 直接来自的原始素材

PK: (capability_id, resource_id)

**strategy_resource** — strategy 直接来自的原始素材

PK: (strategy_id, resource_id)

`*_resource` 边**无 relation_type**——存在本身即"source"语义，不需额外标签。

### 知识间关系（1）

**knowledge_relation** — 知识之间的关系（替代、扩展、矛盾等）

| 字段 | 类型 | 说明 |
|------|------|------|
| `source_id` | VARCHAR | → knowledge.id |
| `target_id` | VARCHAR | → knowledge.id |
| `relation_type` | VARCHAR | supersedes / extends / contradicts / ... |

PK: (source_id, target_id, relation_type)

### 执行层索引（1）

**tool_provider** — 工具在哪些运行环境可用（供 Craftsman 查询）

| 字段 | 类型 | 说明 |
|------|------|------|
| `tool_id` | VARCHAR | → tool.id |
| `provider_id` | VARCHAR | 运行环境标识（如 "comfyui"、"liblib"） |

PK: (tool_id, provider_id)

### 外部引用（2）

外部系统（pattern.aiddit.com）持有的实体，我们不建实体表、不持权威副本，只在 junction 里保存外部 ID + `execution_id`（外部数据快照版本）。外部 ID 无 FK 约束；`execution_id` 必须显式记录，因为外部 ID 在不同 execution 之间语义会漂移。

**这两张表都带自己的 `version` 列，与"实体链"/"来源链"等其它 junction 不同**。原因：本类 junction 不是由实体状态确定性推出，而是**标注/算法产出**——同一 (requirement, node, execution) 可能被不同算法/标注批次映射成不同结果，需要多版本共存对比。`version` 必须进 PK。

三种版本维度在本库并存、正交，不可混淆：

| 维度 | 载体 | 语义 |
|------|------|------|
| 实体多租户版本 | `requirement.version` 等实体表 | 我方数据隔离（`v0` / `tao_dev_1`），junction 一般通过 JOIN 继承 |
| 外部快照版本 | `*.execution_id`（本节两张表） | 外部系统的树/pattern 版本，当前 `56` |
| 关系标注版本 | `*.version`（本节两张表） | 本次映射由哪个算法/人员产出（`v0` / `ruotian` 等） |

**requirement_node** — 需求来源的内容树节点（外部）

| 字段 | 类型 | 说明 |
|------|------|------|
| `requirement_id` | VARCHAR | → requirement.id |
| `node_id` | INTEGER | 外部 `category.id`（pattern.aiddit.com/category_tree） |
| `execution_id` | INTEGER | 外部数据快照版本，当前使用 `56` |
| `version` | VARCHAR(32) | 关系标注版本，DEFAULT `'v0'` |
| `node_path` | TEXT | 节点路径快照（排查用，不保证与外部同步；权威数据需现场调 API） |

PK: (requirement_id, node_id, execution_id, version)
INDEX: (node_id, execution_id) — 反查"某节点产生了哪些需求"

**requirement_pattern** — 需求来源的频繁项集（外部）

| 字段 | 类型 | 说明 |
|------|------|------|
| `requirement_id` | VARCHAR | → requirement.id |
| `itemset_id` | INTEGER | 外部 `itemset.id`（pattern.aiddit.com/get_library_frequent_itemsets） |
| `execution_id` | INTEGER | 外部数据快照版本，当前使用 `56` |
| `version` | VARCHAR(32) | 关系标注版本，DEFAULT `'v0'` |

PK: (requirement_id, itemset_id, execution_id, version)
INDEX: (itemset_id, execution_id) — 反查"某 pattern 产生了哪些需求"

---

## Embedding 策略

| 表 | 向量字段 | Embedding 内容 |
|---|---|---|
| knowledge | `task_embedding` | task |
| knowledge | `content_embedding` | content |
| tool | `embedding` | name + introduction |
| capability | `embedding` | name + description |
| requirement | `embedding` | description |
| strategy | `embedding` | name + description |

