# 工具表(Resource)与知识库对接文档 ## 文档维护规范 0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖 1. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name` 2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议、决策历史、修改日志、大量代码;决策依据或修改日志若有必要,可在 `knowhub/docs/decisions.md` 另行记录 --- ## 一、核心概念 知识库(KnowHub)中的工具表存储在 **Resource** 模块里,与 **Knowledge**(知识条目)通过双向索引关联。 | 模块 | 存储后端 | 主键格式 | |------|----------|----------| | Resource(工具表) | SQLite | `tools/{category}/{slug}` | | Knowledge(知识) | Milvus(向量库) | `knowledge-{日期}-{随机}` | --- ## 二、Resource 数据结构 ### 工具表字段 ```json { "id": "tools/plugin/ip_adapter", "title": "IP-Adapter", "body": "", "content_type": "text", "metadata": { "category": "plugin", "tool_slug": "ip_adapter", "status": "未接入", "version": "v1.0", "description": "22M参数的轻量适配器,通过CLIP ViT-H图像编码器实现图像提示", "usage": "scale=1.0用于纯图像提示,scale=0.5用于多模态(图像+文本)", "scenarios": ["人物一致性控制", "风格迁移", "图像引导生成"], "input": "参考图像 + 文本提示(可选)", "output": "生成图像", "source": "https://github.com/tencent-ailab/IP-Adapter", "knowledge_ids": ["knowledge-20260309-215835-a699"], "migrated_from": "knowhub_old" }, "submitted_by": "migrate_script" } ``` ### metadata 字段说明 | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `category` | string | ✅ | 分类:`image_gen` / `image_process` / `model` / `plugin` / `workflow` / `other` | | `tool_slug` | string | ✅ | 小写英文短名,空格换下划线,如 `controlnet`、`ip_adapter` | | `status` | string | ✅ | 接入状态:`未接入` / `已接入` / `测试中` | | `version` | string\|null | — | 版本号 | | `description` | string\|null | — | 一句话功能介绍 | | `usage` | string\|null | — | 核心用法说明 | | `scenarios` | array | — | 应用场景列表 | | `input` | string\|null | — | 输入类型描述 | | `output` | string\|null | — | 输出类型描述 | | `source` | string\|null | — | 来源/文档链接 | | `knowledge_ids` | array | — | 关联的知识 ID 列表(双向索引) | ### ID 命名规则 ``` tools/{category}/{slug} 示例: tools/plugin/ip_adapter tools/plugin/controlnet tools/image_gen/midjourney tools/model/sdxl ``` --- ## 三、双向索引机制 ``` Resource(工具) Knowledge(知识) ┌─────────────────────────┐ ┌──────────────────────────────┐ │ id: tools/plugin/ip_adapter │◄────►│ id: knowledge-20260309-xxx │ │ metadata.knowledge_ids: │ │ resource_ids: │ │ ["knowledge-xxx"] │ │ ["tools/plugin/ip_adapter"] │ └─────────────────────────┘ │ tags: {"tool": true} │ └──────────────────────────────┘ ``` - **Resource → Knowledge**:`metadata.knowledge_ids` 存储关联知识的 ID 列表 - **Knowledge → Resource**:`resource_ids` 存储关联工具的 ID 列表,同时打 `tags.tool = true` 标记 ### 重要:双向索引是手动维护的 **目前没有任何自动同步机制**,两侧的索引相互独立存储,需要调用方自己负责保持一致。 两侧的写入时机: | 方向 | 存在哪 | 写入时机 | |------|--------|----------| | Resource → Knowledge | SQLite `resources.metadata.knowledge_ids` | 创建/更新 Resource 时手动 PATCH | | Knowledge → Resource | Milvus `resource_ids` 字段 | Knowledge 创建时传入,**创建后无法通过 API 修改** | > Knowledge 的 `resource_ids` 字段目前**不在 PATCH 接口的支持范围内**,一旦 Knowledge 创建,只能通过删除重建来更改其关联的工具。 --- ## 四、API 接口 服务地址由环境变量 `KNOWHUB_API` 指定(如 `http://localhost:9999`)。 ### 4.1 工具表(Resource) #### 创建工具 ```http POST /api/resource Content-Type: application/json { "id": "tools/plugin/controlnet", "title": "ControlNet", "body": "", "content_type": "text", "metadata": { "category": "plugin", "tool_slug": "controlnet", "status": "已接入", "description": "...", "usage": "...", "scenarios": [...], "knowledge_ids": [] }, "submitted_by": "your_name" } ``` #### 更新工具(局部更新,推荐) ```http PATCH /api/resource/tools/plugin/controlnet Content-Type: application/json { "metadata": { "status": "已接入", "knowledge_ids": ["knowledge-xxx", "knowledge-yyy"] } } ``` > ⚠️ PATCH metadata 会**整体替换** metadata 字段,需带上所有已有字段。 #### 获取工具详情 ```http GET /api/resource/tools/plugin/controlnet ``` 返回额外的导航字段:`toc`(根节点)、`children`(子节点)、`prev`/`next`(同级导航)。 #### 列出所有工具 ```http GET /api/resource?limit=1000 ``` 过滤出工具(客户端过滤): ```javascript const tools = results.filter(r => r.id.startsWith("tools/")); ``` #### 删除工具 ```http DELETE /api/resource/tools/plugin/controlnet ``` --- ### 4.2 知识(Knowledge) #### 搜索工具相关知识(语义搜索) ```http GET /api/knowledge/search?q=IP-Adapter人物一致性&top_k=5&min_score=3 ``` #### 列出所有工具相关知识 ```http GET /api/knowledge?tags=tool&status=approved,checked&page_size=200 ``` #### 获取单条知识 ```http GET /api/knowledge/knowledge-20260309-215835-a699 ``` #### 批量删除知识 ```http POST /api/knowledge/batch_delete Content-Type: application/json ["knowledge-xxx", "knowledge-yyy"] ``` --- ## 五、典型操作示例(Python) ### 新增一个工具并关联知识 ```python import httpx KNOWHUB_API = "http://your-server:9999" # 1. 创建工具 tool = { "id": "tools/plugin/controlnet", "title": "ControlNet", "body": "", "content_type": "text", "metadata": { "category": "plugin", "tool_slug": "controlnet", "status": "已接入", "version": "v1.1", "description": "基于条件图像控制SD生成的插件", "usage": "提供边缘图/骨骼图/深度图等条件,精确控制生成结果", "scenarios": ["姿势控制", "边缘控制", "深度控制"], "input": "条件图像(canny/pose/depth等)+ 文本提示", "output": "生成图像", "source": "https://github.com/lllyasviel/ControlNet", "knowledge_ids": [] }, "submitted_by": "your_name" } resp = httpx.post(f"{KNOWHUB_API}/api/resource", json=tool) print(resp.json()) # {"status": "ok", "id": "tools/plugin/controlnet"} # 2. 回填知识关联(PATCH 更新 knowledge_ids) patch = { "metadata": { **tool["metadata"], # 保留所有已有字段 "knowledge_ids": ["knowledge-20260309-215835-a699"] } } resp = httpx.patch(f"{KNOWHUB_API}/api/resource/tools/plugin/controlnet", json=patch) print(resp.json()) # {"status": "ok"} ``` ### 更新工具接入状态 ```python # 先获取当前 metadata,再更新 resp = httpx.get(f"{KNOWHUB_API}/api/resource/tools/plugin/controlnet") tool = resp.json() meta = tool["metadata"] meta["status"] = "已接入" httpx.patch( f"{KNOWHUB_API}/api/resource/tools/plugin/controlnet", json={"metadata": meta} ) ``` --- ## 六、前端查看 访问 KnowHub 管理界面,点击右上角 **🔧 工具表** 按钮: - 按 `category` Tab 切换分类 - 左侧列表点击工具查看详情 - 详情页显示:基础概览 / 使用指南 / 技术规格 / 消息信源 / 关联知识(可跳转) - 知识卡片底部有工具 Tag,点击可跳回工具表对应条目 --- ## 七、注意事项 1. **PATCH metadata 是整体替换**:更新前先 GET 拿到当前值,合并后再 PATCH,避免覆盖已有字段(尤其是 `knowledge_ids`)。 2. **Resource ID 含斜杠**:URL 调用时需注意路径编码(框架已支持 `{resource_id:path}`,直接拼接即可,无需手动 encode)。 3. **双向索引需手动维护**:创建/删除工具时,需同步更新关联 Knowledge 的 `resource_ids` 字段(PATCH `/api/knowledge/{id}`)。 4. **工具筛选靠客户端**:`GET /api/resource` 返回所有 resource,需在客户端过滤 `id.startsWith("tools/")` 得到工具列表。