# Dify 知识库 API 功能实现清单 ## 概述 本文档对比 Dify 官方知识库 API 与当前项目已实现的功能。 - ✅ 已实现 - ❌ 未实现 - 🚫 不开放 --- ## 系统架构 ### 完整数据流向 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 第一层:React 组件 (浏览器) │ │ 位置:app/components/dify-dataset-manager/ │ │ 调用:客户端 API 函数 │ └────────────────────────────┬────────────────────────────────────────┘ │ 使用 axios 发送 HTTP 请求 │ URL: /api/dataset/... │ 自动携带 cookies (JWT) ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 第二层:客户端 API 层 (浏览器侧) │ │ 位置:app/api/dify-dataset/api/*.ts │ │ 作用:封装 axios 请求,提供类型安全的函数接口 │ │ 请求:axios.get('/api/dataset/datasets', { withCredentials: true })│ └────────────────────────────┬────────────────────────────────────────┘ │ HTTP 请求 (浏览器 → Remix 服务器) ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 第三层:Remix 路由层 (Node.js 服务端) │ │ 位置:app/routes/api.dataset.*.tsx │ │ 作用:接收浏览器请求,验证 JWT,转发到 FastAPI │ │ 请求:fetch(`${API_BASE_URL}/dify_dataset/...`, { headers: JWT }) │ └────────────────────────────┬────────────────────────────────────────┘ │ HTTP 请求 (Remix → FastAPI) ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 第四层:FastAPI 后端代理 (Python) │ │ 位置:docauditai/routers/dify_dataset.py │ │ 作用:验证用户 JWT,添加 Dify DATASET_API_KEY,转发请求 │ └────────────────────────────┬────────────────────────────────────────┘ │ HTTP 请求 (FastAPI → Dify) ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ 第五层:Dify 官方知识库 API │ │ URL:https://api.dify.ai/v1/datasets/... │ │ 鉴权:Authorization: Bearer {DATASET_API_KEY} │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 为什么有两层 API? | 层级 | 位置 | 执行环境 | HTTP 库 | 作用 | |------|------|----------|---------|------| | **客户端 API** | `app/api/dify-dataset/api/*.ts` | 浏览器 | axios | 供 React 组件调用,类型安全 | | **Remix 路由** | `app/routes/api.dataset.*.tsx` | Node.js | fetch | 接收浏览器请求,转发到 FastAPI | **调用链路**: ``` React 组件 → 客户端 API (axios) → Remix 路由 (fetch) → FastAPI → Dify API ``` --- ## 一、知识库管理 | 功能 | API 端点 | 方法 | 状态 | 路由文件 | 客户端函数 | |------|----------|------|------|----------|-----------| | 获取知识库列表 | /datasets | GET | ✅ | `api.dataset.datasets.tsx` | `fetchDatasets()` | | 查看知识库详情 | /datasets/{dataset_id} | GET | ✅ | `api.dataset.datasets.$datasetId.tsx` | `fetchDataset()` | | 创建空知识库 | /datasets | POST | ❌ | - | - | | 修改知识库名称 | /datasets/{dataset_id} | PATCH | ✅ | `api.dataset.datasets.$datasetId.tsx` | `updateDatasetName()` | | 删除知识库 | /datasets/{dataset_id} | DELETE | 🚫 | - | - | **说明**: - 修改知识库:仅允许修改 `name` 字段,其他字段不开放 - 删除知识库:出于安全考虑不对用户开放 --- ## 二、文档管理 | 功能 | API 端点 | 方法 | 状态 | 路由文件 | 客户端函数 | |------|----------|------|------|----------|-----------| | 获取文档列表 | /datasets/{id}/documents | GET | ✅ | `api.dataset.datasets.$datasetId.documents.tsx` | `fetchDocuments()` | | 获取文档详情 | /datasets/{id}/documents/{docId} | GET | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.tsx` | `fetchDocument()` | | 通过文件创建文档 | /datasets/{id}/document/create-by-file | POST | ✅ | `api.dataset.datasets.$datasetId.documents.tsx` | `uploadDocument()` | | 通过文本创建文档 | /datasets/{id}/document/create-by-text | POST | ❌ | - | - | | 通过文件更新文档 | /datasets/{id}/documents/{docId}/update-by-file | POST | ❌ | - | - | | 通过文本更新文档 | /datasets/{id}/documents/{docId}/update-by-text | POST | ❌ | - | - | | 删除文档 | /datasets/{id}/documents/{docId} | DELETE | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.tsx` | `deleteDocument()` | | 更新文档状态 | /datasets/{id}/documents/status/{action} | PATCH | ✅ | `api.dataset.datasets.$datasetId.documents.status.$action.tsx` | `toggleDocumentStatus()` | | 获取文档嵌入状态 | /datasets/{id}/documents/{batch}/indexing-status | GET | ✅ | `api.dataset.datasets.$datasetId.documents.$batch.indexing-status.tsx` | `fetchIndexingStatus()` | | 获取上传文件信息 | /datasets/{id}/documents/{docId}/upload-file | GET | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.upload-file.tsx` | `fetchUploadFileInfo()` | | 索引预估(预览分段) | /datasets/{id}/indexing-estimate | POST | ✅ | `api.dataset.datasets.$datasetId.indexing-estimate.tsx` | `fetchIndexingEstimate()` | | 重新处理文档 | /datasets/{id}/documents/reprocess | POST | ✅ | `api.dataset.datasets.$datasetId.documents.reprocess.tsx` | `reprocessDocument()` | **说明**: - 上传文档:支持 multipart/form-data 格式 - 文档状态:action 可选值为 `enable` / `disable` / `archive` / `un_archive` - 索引预估:用于预览分段效果,不会实际修改文档 - 重新处理文档:通过 `original_document_id` 参数使用新的分段设置重新处理已有文档 --- ## 三、分段管理 | 功能 | API 端点 | 方法 | 状态 | 路由文件 | 客户端函数 | |------|----------|------|------|----------|-----------| | 获取分段列表 | /datasets/{id}/documents/{docId}/segments | GET | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.segments.tsx` | `fetchSegments()` | | 获取分段详情 | /datasets/{id}/documents/{docId}/segments/{segId} | GET | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.segments.$segmentId.tsx` | `fetchSegment()` | | 新增分段 | /datasets/{id}/documents/{docId}/segments | POST | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.segments.tsx` | `createSegments()` | | 更新分段 | /datasets/{id}/documents/{docId}/segments/{segId} | POST | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.segments.$segmentId.tsx` | `updateSegment()` | | 删除分段 | /datasets/{id}/documents/{docId}/segments/{segId} | DELETE | ✅ | `api.dataset.datasets.$datasetId.documents.$documentId.segments.$segmentId.tsx` | `deleteSegment()` | **说明**: - 新增分段:支持批量新增 `{ segments: [...] }` - 更新分段:可更新 `content`, `answer`, `keywords`, `enabled` --- ## 四、子分段管理(父子模式) | 功能 | API 端点 | 方法 | 状态 | 路由文件 | 客户端函数 | |------|----------|------|------|----------|-----------| | 查询子分段 | .../segments/{segId}/child_chunks | GET | ✅ | `...segments.$segmentId.child_chunks.tsx` | `fetchChildChunks()` | | 新增子分段 | .../segments/{segId}/child_chunks | POST | ✅ | `...segments.$segmentId.child_chunks.tsx` | `createChildChunk()` | | 更新子分段 | .../segments/{segId}/child_chunks/{chunkId} | PATCH | ✅ | `...segments.$segmentId.child_chunks.$childChunkId.tsx` | `updateChildChunk()` | | 删除子分段 | .../segments/{segId}/child_chunks/{chunkId} | DELETE | ✅ | `...segments.$segmentId.child_chunks.$childChunkId.tsx` | `deleteChildChunk()` | **说明**:子分段用于 Dify 的父子模式分段策略 --- ## 五、检索功能 | 功能 | API 端点 | 方法 | 状态 | 路由文件 | 客户端函数 | |------|----------|------|------|----------|-----------| | 检索知识库 | /datasets/{id}/retrieve | POST | ✅ | `api.dataset.datasets.$datasetId.retrieve.tsx` | `retrieveDataset()` | **检索参数详解**: ```typescript { query: string; // 检索关键词 retrieval_model: { search_method: 'keyword_search' | 'semantic_search' | 'full_text_search' | 'hybrid_search'; reranking_enable: boolean; // 是否开启 rerank reranking_model?: object; // Rerank 模型配置 top_k: number; // 返回结果数量 score_threshold_enabled: boolean; score_threshold: number; // 分数阈值 (0-1) } } ``` --- ## 六、元数据管理 **当前状态:❌ 全部未实现** | 功能 | API 端点 | 方法 | 说明 | |------|----------|------|------| | 新增元数据 | /datasets/{id}/metadata | POST | type, name | | 更新元数据 | /datasets/{id}/metadata/{metaId} | PATCH | name | | 删除元数据 | /datasets/{id}/metadata/{metaId} | DELETE | | | 查询元数据列表 | /datasets/{id}/metadata | GET | | | 启用/禁用内置元数据 | /datasets/{id}/metadata/built-in/{action} | POST | | | 更新文档元数据 | /datasets/{id}/documents/metadata | POST | 批量更新 | --- ## 七、模型查询 | 功能 | API 端点 | 方法 | 状态 | 说明 | |------|----------|------|------|------| | 获取嵌入模型列表 | /workspaces/current/models/model-types/text-embedding | GET | ❌ | 创建知识库时需要 | --- ## 八、标签管理 **当前状态:❌ 全部未实现** | 功能 | API 端点 | 方法 | 说明 | |------|----------|------|------| | 新增标签 | /datasets/tags | POST | name (最大50字符) | | 获取标签列表 | /datasets/tags | GET | | | 修改标签名称 | /datasets/tags | PATCH | name, tag_id | | 删除标签 | /datasets/tags | DELETE | tag_id | | 绑定知识库到标签 | /datasets/tags/binding | POST | tag_ids, target_id | | 解绑知识库和标签 | /datasets/tags/unbinding | POST | tag_id, target_id | | 查询知识库已绑定的标签 | /datasets/{id}/tags | POST | | --- ## 功能统计 | 类别 | 已实现 | 未实现 | 不开放 | 完成度 | |------|--------|--------|--------|--------| | 知识库管理 | 3 | 1 | 1 | 75% | | 文档管理 | 9 | 3 | 0 | 75% | | 分段管理 | 5 | 0 | 0 | 100% | | 子分段管理 | 4 | 0 | 0 | 100% | | 检索功能 | 1 | 0 | 0 | 100% | | 元数据管理 | 0 | 6 | 0 | 0% | | 模型查询 | 0 | 1 | 0 | 0% | | 标签管理 | 0 | 7 | 0 | 0% | | **总计** | **22** | **18** | **1** | **55%** | --- ## 代码文件清单 ### Remix 路由层 (服务端) 所有路由文件位于 `app/routes/` 目录: | 文件名 | HTTP 方法 | 功能 | |--------|----------|------| | `api.dataset.datasets.tsx` | GET | 获取知识库列表 | | `api.dataset.datasets.$datasetId.tsx` | GET / PATCH | 知识库详情 / 修改名称 | | `api.dataset.datasets.$datasetId.documents.tsx` | GET / POST | 文档列表 / 上传文档 | | `api.dataset.datasets.$datasetId.documents.$documentId.tsx` | GET / DELETE | 文档详情 / 删除文档 | | `api.dataset.datasets.$datasetId.documents.$documentId.upload-file.tsx` | GET | 获取上传文件信息 | | `api.dataset.datasets.$datasetId.documents.$batch.indexing-status.tsx` | GET | 获取嵌入状态 | | `api.dataset.datasets.$datasetId.documents.status.$action.tsx` | PATCH | 更新文档状态 | | `api.dataset.datasets.$datasetId.indexing-estimate.tsx` | POST | 索引预估(预览分段) | | `api.dataset.datasets.$datasetId.documents.reprocess.tsx` | POST | 重新处理文档 | | `api.dataset.datasets.$datasetId.documents.$documentId.segments.tsx` | GET / POST | 分段列表 / 新增分段 | | `api.dataset.datasets.$datasetId.documents.$documentId.segments.$segmentId.tsx` | GET / POST / DELETE | 分段详情 / 更新 / 删除 | | `api.dataset.datasets.$datasetId.documents.$documentId.segments.$segmentId.child_chunks.tsx` | GET / POST | 子分段列表 / 新增 | | `api.dataset.datasets.$datasetId.documents.$documentId.segments.$segmentId.child_chunks.$childChunkId.tsx` | PATCH / DELETE | 子分段更新 / 删除 | | `api.dataset.datasets.$datasetId.retrieve.tsx` | POST | 检索知识库 | ### 客户端 API 层 (浏览器侧) ``` app/api/dify-dataset/ ├── index.ts # 统一导出 ├── client.server.ts # 服务端基础请求函数(备用) ├── type/ # 类型定义 │ ├── index.ts # 类型统一导出 │ ├── commonTypes.ts # 通用类型 │ ├── datasetTypes.ts # 知识库类型 │ ├── documentTypes.ts # 文档类型 │ └── segmentTypes.ts # 分段/子分段/检索类型 └── api/ # API 调用函数 ├── index.ts # 函数统一导出 ├── datasetApi.ts # 知识库 API ├── documentApi.ts # 文档 API └── segmentApi.ts # 分段/子分段/检索 API ``` ### 客户端函数清单 **datasetApi.ts - 知识库管理** ```typescript fetchDatasets(page, limit) // 获取知识库列表 fetchDataset(datasetId) // 获取知识库详情 updateDatasetName(datasetId, name) // 修改知识库名称 ``` **documentApi.ts - 文档管理** ```typescript fetchDocuments(datasetId, page, limit, keyword) // 获取文档列表 fetchDocument(datasetId, documentId) // 获取文档详情 deleteDocument(datasetId, documentId) // 删除文档 toggleDocumentStatus(datasetId, documentId, enabled) // 启用/禁用文档 uploadDocument(datasetId, file, onProgress) // 上传文档 fetchIndexingStatus(datasetId, batch) // 获取嵌入状态 fetchUploadFileInfo(datasetId, documentId) // 获取上传文件信息 fetchIndexingEstimate(datasetId, fileId, processRule, docForm, docLanguage) // 索引预估(预览分段效果) reprocessDocument(datasetId, originalDocumentId, processRule, docForm, docLanguage) // 重新处理文档 ``` **segmentApi.ts - 分段/子分段/检索** ```typescript // 分段 fetchSegments(datasetId, documentId, page, limit, keyword) fetchSegment(datasetId, documentId, segmentId) createSegments(datasetId, documentId, segments) updateSegment(datasetId, documentId, segmentId, segment) deleteSegment(datasetId, documentId, segmentId) toggleSegmentStatus(datasetId, documentId, segmentId, enabled) // 子分段 fetchChildChunks(datasetId, documentId, segmentId, page, limit, keyword) createChildChunk(datasetId, documentId, segmentId, content) updateChildChunk(datasetId, documentId, segmentId, childChunkId, content) deleteChildChunk(datasetId, documentId, segmentId, childChunkId) // 检索 retrieveDataset(datasetId, query, retrievalModel) ``` ### UI 组件 ``` app/components/dify-dataset-manager/ ├── index.tsx # 主容器组件 - 状态管理、标签页切换 ├── layout.tsx # 布局组件 - 左侧菜单栏 + 右侧内容区 ├── document-list.tsx # 文档列表 - 表格、搜索、上传、删除 ├── document-detail.tsx # 文档详情 - 分段设置、预览块 ├── retrieve-test.tsx # 召回测试 - 知识库检索测试 └── dataset-settings.tsx # 知识库设置 - 名称、描述修改 ``` ### 布局结构(仿 Dify 风格) ``` ┌─────────────────────────────────────────────────────────────┐ │ dataset-layout │ ├──────────────────┬──────────────────────────────────────────┤ │ dataset-sidebar │ dataset-main │ │ │ │ │ ┌─────────────┐ │ 根据 activeTab 渲染: │ │ │ 知识库信息 │ │ - documents → DocumentList │ │ │ (名称/数量) │ │ - documents + selectedDoc → DocumentDetail│ │ └─────────────┘ │ - retrieve → RetrieveTest │ │ │ - settings → DatasetSettings │ │ ┌─────────────┐ │ │ │ │ 文档 │ │ │ │ │ 召回测试 │ │ │ │ │ 设置 │ │ │ │ └─────────────┘ │ │ └──────────────────┴──────────────────────────────────────────┘ ``` --- ## 鉴权机制 ### 三层认证流程 ``` ┌────────────────────────────────────────────────────────────────┐ │ 浏览器 → Remix 服务器 │ │ 认证方式:Cookie (会话中的 JWT) │ │ axios 配置:{ withCredentials: true } │ └────────────────────────────────────────────────────────────────┘ ↓ ┌────────────────────────────────────────────────────────────────┐ │ Remix 服务器 → FastAPI │ │ 认证方式:Authorization: Bearer {frontendJWT} │ │ JWT 来源:getUserSession(request) │ └────────────────────────────────────────────────────────────────┘ ↓ ┌────────────────────────────────────────────────────────────────┐ │ FastAPI → Dify API │ │ 认证方式:Authorization: Bearer {DATASET_API_KEY} │ │ API Key:服务端环境变量配置 │ └────────────────────────────────────────────────────────────────┘ ``` ### 关键配置 ```typescript // app/config/api-config.ts export const API_BASE_URL = apiConfig.baseUrl; // 如:http://10.79.97.17:8000 // 根据端口自动选择配置 const portConfigs = { '51703': { baseUrl: 'http://172.16.0.55:8073' }, // 梅州 '51704': { baseUrl: 'http://10.79.97.17:8001' }, // 云浮 '51707': { baseUrl: 'http://10.79.97.17:8004' }, // 省级 // ... }; ``` --- ## 常见错误码 | code | status | message | |------|--------|---------| | no_file_uploaded | 400 | Please upload your file. | | too_many_files | 400 | Only one file is allowed. | | file_too_large | 413 | File size exceeded. | | unsupported_file_type | 415 | File type not allowed. | | high_quality_dataset_only | 400 | Current operation only supports 'high-quality' datasets. | | dataset_not_initialized | 400 | The dataset is still being initialized or indexing. | | archived_document_immutable | 403 | The archived document is not editable. | | dataset_name_duplicate | 409 | The dataset name already exists. | | invalid_action | 400 | Invalid action. | | document_already_finished | 400 | The document has been processed. | | document_indexing | 400 | The document is being processed and cannot be edited. | | invalid_metadata | 400 | The metadata content is incorrect. | --- ## 九、文档分段设置(上传时配置) ### API 支持的分段参数 在上传文档时,可以通过 `process_rule` 参数配置分段设置: ```typescript { indexing_technique: 'high_quality' | 'economy', process_rule: { mode: 'automatic' | 'custom', rules: { pre_processing_rules: [ { id: 'remove_extra_spaces', enabled: boolean }, // 替换连续空格 { id: 'remove_urls_emails', enabled: boolean } // 删除URL和邮件 ], segmentation: { separator: string, // 分段标识符,如 "\\n\\n" max_tokens: number // 分段最大长度,100-4000 } } } } ``` ### 功能支持情况 | 功能 | API 支持 | 参数 | 说明 | |------|----------|------|------| | 分段标识符 | ✅ | `separator` | 如 `\\n\\n`、`###` | | 分段最大长度 | ✅ | `max_tokens` | 100-4000 | | 替换连续空格 | ✅ | `remove_extra_spaces` | 预处理规则 | | 删除URL和邮件 | ✅ | `remove_urls_emails` | 预处理规则 | | 分段重叠长度 | ❌ | - | API 不支持 | | Q&A 分段 | ⚠️ | `doc_form: "qa_model"` | 需特殊配置 | ### 重要限制 ⚠️ **已有文档无法直接修改分段设置** Dify API 不支持修改已上传文档的分段规则。如需应用新设置,必须: 1. 使用 `original_document_id` 参数重新上传文档 2. 或删除文档后重新上传 --- ## 优先级建议 ### 高优先级(核心功能) 1. ~~**检索知识库**~~ ✅ 已实现 2. ~~获取文档嵌入状态~~ ✅ 已实现 3. **创建空知识库** - 让用户能创建新的知识库 4. **获取嵌入模型列表** - 创建知识库时需要选择模型 ### 中优先级(完善功能) 5. **通过文本创建文档** - 支持直接输入文本 6. ~~**新增分段**~~ ✅ 已实现 7. ~~修改知识库详情~~ ✅ 已实现 8. ~~获取上传文件信息~~ ✅ 已实现 ### 低优先级(扩展功能) 9. ~~子分段管理系列~~ ✅ 已实现(API层) 10. 元数据管理系列 11. 标签管理系列 12. 文档更新功能