Files

463 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 │
│ URLhttps://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. 文档更新功能