- Complete knowledge base list and detail pages - Complete document upload component - Fix CORS config (add PUT/DELETE method support) - Fix file upload issues (disabled state and beforeUpload return value) - Add detailed debug logs (cleaned up) - Create Day 21-22 completion summary document
496 lines
11 KiB
Markdown
496 lines
11 KiB
Markdown
# Day 19 - Dify客户端封装完成总结
|
||
|
||
**日期**: 2025-10-11
|
||
**状态**: ✅ 已完成
|
||
|
||
---
|
||
|
||
## 🎯 本次任务目标
|
||
|
||
封装Dify知识库API,实现完整的知识库管理功能。
|
||
|
||
---
|
||
|
||
## ✅ 完成的工作
|
||
|
||
### 1. 创建类型定义 (`backend/src/clients/types.ts`) ✅
|
||
|
||
**定义的类型**:
|
||
```typescript
|
||
// 知识库相关
|
||
- Dataset // 知识库信息
|
||
- CreateDatasetRequest // 创建知识库请求
|
||
- CreateDatasetResponse // 创建知识库响应
|
||
- DatasetListResponse // 知识库列表响应
|
||
|
||
// 文档相关
|
||
- Document // 文档信息
|
||
- DocumentListResponse // 文档列表响应
|
||
- CreateDocumentByFileRequest // 创建文档请求
|
||
- CreateDocumentResponse // 创建文档响应
|
||
|
||
// 检索相关
|
||
- RetrievalRequest // 检索请求
|
||
- RetrievalRecord // 检索结果项
|
||
- RetrievalResponse // 检索响应
|
||
|
||
// 错误处理
|
||
- DifyErrorResponse // 错误响应
|
||
- DifyError // 自定义错误类
|
||
```
|
||
|
||
**特点**:
|
||
- 完整的TypeScript类型定义
|
||
- 包含所有必需和可选字段
|
||
- 支持文档处理状态追踪
|
||
|
||
---
|
||
|
||
### 2. 实现DifyClient核心类 (`backend/src/clients/DifyClient.ts`) ✅
|
||
|
||
#### 2.1 基础功能
|
||
|
||
**构造函数**:
|
||
```typescript
|
||
constructor(apiKey?: string, apiUrl?: string)
|
||
- 支持自定义API Key和URL
|
||
- 从环境变量读取配置
|
||
- 自动配置请求头和超时
|
||
```
|
||
|
||
**错误处理**:
|
||
- axios拦截器统一处理错误
|
||
- 自定义DifyError类
|
||
- 包含错误代码和HTTP状态码
|
||
|
||
---
|
||
|
||
#### 2.2 知识库管理API
|
||
|
||
**已实现的方法**:
|
||
|
||
1. **createDataset** - 创建知识库
|
||
```typescript
|
||
async createDataset(params: CreateDatasetRequest): Promise<CreateDatasetResponse>
|
||
```
|
||
- 支持设置索引技术(high_quality/economy)
|
||
- 支持配置检索模型
|
||
- 自动设置默认参数
|
||
|
||
2. **getDatasets** - 获取知识库列表
|
||
```typescript
|
||
async getDatasets(page: number, limit: number): Promise<DatasetListResponse>
|
||
```
|
||
- 支持分页
|
||
- 返回总数、是否有更多等信息
|
||
|
||
3. **getDataset** - 获取知识库详情
|
||
```typescript
|
||
async getDataset(datasetId: string): Promise<Dataset>
|
||
```
|
||
- 获取单个知识库的完整信息
|
||
- 包括文档数量、字符数等统计
|
||
|
||
4. **deleteDataset** - 删除知识库
|
||
```typescript
|
||
async deleteDataset(datasetId: string): Promise<void>
|
||
```
|
||
- 永久删除知识库及其所有文档
|
||
|
||
---
|
||
|
||
#### 2.3 文档管理API
|
||
|
||
**已实现的方法**:
|
||
|
||
1. **uploadDocumentDirectly** - 直接上传文档
|
||
```typescript
|
||
async uploadDocumentDirectly(
|
||
datasetId: string,
|
||
file: Buffer,
|
||
filename: string
|
||
): Promise<CreateDocumentResponse>
|
||
```
|
||
- 使用FormData上传文件
|
||
- 自动配置处理规则
|
||
- 支持自定义分词策略
|
||
|
||
2. **getDocuments** - 获取文档列表
|
||
```typescript
|
||
async getDocuments(
|
||
datasetId: string,
|
||
page: number,
|
||
limit: number
|
||
): Promise<DocumentListResponse>
|
||
```
|
||
- 支持分页查询
|
||
- 返回文档状态、Token数等信息
|
||
|
||
3. **getDocument** - 获取文档详情
|
||
```typescript
|
||
async getDocument(datasetId: string, documentId: string): Promise<Document>
|
||
```
|
||
- 查询单个文档的完整信息
|
||
- 包括索引状态、字符数、点击次数等
|
||
|
||
4. **deleteDocument** - 删除文档
|
||
```typescript
|
||
async deleteDocument(datasetId: string, documentId: string): Promise<void>
|
||
```
|
||
- 从知识库中删除指定文档
|
||
|
||
5. **updateDocument** - 更新文档(重新索引)
|
||
```typescript
|
||
async updateDocument(datasetId: string, documentId: string): Promise<void>
|
||
```
|
||
- 触发文档重新处理和索引
|
||
|
||
---
|
||
|
||
#### 2.4 知识库检索API
|
||
|
||
**已实现的方法**:
|
||
|
||
1. **retrieveKnowledge** - 检索知识库
|
||
```typescript
|
||
async retrieveKnowledge(
|
||
datasetId: string,
|
||
query: string,
|
||
params?: Partial<RetrievalRequest>
|
||
): Promise<RetrievalResponse>
|
||
```
|
||
- 支持语义搜索、全文搜索、混合搜索
|
||
- 支持重排序(reranking)
|
||
- 支持设置top_k和相似度阈值
|
||
- 返回相关文档片段和相似度得分
|
||
|
||
---
|
||
|
||
#### 2.5 辅助方法
|
||
|
||
**已实现的方法**:
|
||
|
||
1. **waitForDocumentProcessing** - 轮询等待文档处理完成
|
||
```typescript
|
||
async waitForDocumentProcessing(
|
||
datasetId: string,
|
||
documentId: string,
|
||
maxAttempts: number,
|
||
interval: number
|
||
): Promise<Document>
|
||
```
|
||
- 自动轮询检查处理状态
|
||
- 支持超时控制
|
||
- 处理失败时抛出错误
|
||
|
||
2. **uploadAndProcessDocument** - 一键上传并等待处理
|
||
```typescript
|
||
async uploadAndProcessDocument(
|
||
datasetId: string,
|
||
file: Buffer,
|
||
filename: string
|
||
): Promise<Document>
|
||
```
|
||
- 上传文档 + 等待处理完成
|
||
- 返回完全处理好的文档
|
||
- 简化了常见使用场景
|
||
|
||
---
|
||
|
||
### 3. 测试脚本 (`backend/src/scripts/test-dify-client.ts`) ✅
|
||
|
||
**测试内容**:
|
||
|
||
| 测试项 | 功能 | 状态 |
|
||
|--------|------|------|
|
||
| 测试1 | 创建知识库 | ✅ 通过 |
|
||
| 测试2 | 获取知识库列表 | ✅ 通过 |
|
||
| 测试3 | 获取知识库详情 | ✅ 通过 |
|
||
| 测试4 | 上传文档 | ✅ 通过 |
|
||
| 测试5 | 获取文档列表 | ✅ 通过 |
|
||
| 测试6 | 知识库检索 | ✅ 通过 |
|
||
| 测试7 | 删除文档 | ✅ 通过 |
|
||
| 测试8 | 删除知识库 | ✅ 通过 |
|
||
|
||
**测试结果**:
|
||
```
|
||
✅ 所有测试通过!
|
||
测试耗时:约15秒
|
||
```
|
||
|
||
**测试数据**:
|
||
- 创建知识库ID: `a2e844c8-6296-42eb-8f1e-18c6c919420b`
|
||
- 上传文档: `test-document.txt` (247 tokens, 148字符)
|
||
- 检索结果: 找到1条,相似度0.4420
|
||
|
||
---
|
||
|
||
## 🔧 技术亮点
|
||
|
||
### 1. 完善的错误处理
|
||
```typescript
|
||
// 自定义错误类
|
||
export class DifyError extends Error {
|
||
code: string;
|
||
status: number;
|
||
}
|
||
|
||
// axios拦截器自动转换错误
|
||
this.client.interceptors.response.use(
|
||
(response) => response,
|
||
(error: AxiosError) => {
|
||
if (error.response?.data) {
|
||
throw new DifyError(error.response.data);
|
||
}
|
||
throw error;
|
||
}
|
||
);
|
||
```
|
||
|
||
### 2. 智能轮询机制
|
||
```typescript
|
||
// 等待文档处理完成,自动轮询
|
||
async waitForDocumentProcessing(
|
||
datasetId: string,
|
||
documentId: string,
|
||
maxAttempts: number = 30,
|
||
interval: number = 2000
|
||
): Promise<Document>
|
||
```
|
||
- 最多轮询30次
|
||
- 每次间隔2秒
|
||
- 自动检测完成或失败状态
|
||
|
||
### 3. 单例模式
|
||
```typescript
|
||
// 导出全局单例,方便使用
|
||
export const difyClient = new DifyClient();
|
||
```
|
||
|
||
### 4. FormData文件上传
|
||
```typescript
|
||
// 正确处理文件上传
|
||
const formData = new FormData();
|
||
formData.append('file', file, filename);
|
||
formData.append('data', JSON.stringify(params));
|
||
```
|
||
|
||
---
|
||
|
||
## 📦 依赖安装
|
||
|
||
**新增依赖**:
|
||
```json
|
||
{
|
||
"form-data": "^4.0.0",
|
||
"@types/form-data": "^2.5.0"
|
||
}
|
||
```
|
||
|
||
**用途**:
|
||
- `form-data`: Node.js环境的FormData实现
|
||
- `@types/form-data`: TypeScript类型定义
|
||
|
||
---
|
||
|
||
## 🐛 遇到的问题与解决
|
||
|
||
### 问题1:API Key认证失败(401)
|
||
|
||
**症状**:
|
||
```
|
||
Access token is invalid
|
||
HTTP状态码: 401
|
||
```
|
||
|
||
**原因**:
|
||
- 使用了应用API Key(`app-xxx`)
|
||
- 知识库管理需要服务API Key(`dataset-xxx`)
|
||
|
||
**解决**:
|
||
- 在Dify控制台创建服务API密钥
|
||
- 更新`.env`配置:`DIFY_API_KEY=dataset-mfvdiKvQ2l3NvxWm7RoYMN3c`
|
||
|
||
---
|
||
|
||
### 问题2:文本嵌入模型未配置(400)
|
||
|
||
**症状**:
|
||
```
|
||
Default model not found for text-embedding
|
||
HTTP状态码: 400
|
||
```
|
||
|
||
**原因**:
|
||
- Dify需要配置文本嵌入模型才能创建知识库
|
||
|
||
**解决**:
|
||
- 在Dify控制台配置默认的embedding模型
|
||
- 用户已成功配置
|
||
|
||
---
|
||
|
||
### 问题3:文件上传API路径错误
|
||
|
||
**原因**:
|
||
- 最初使用了`/files/upload`分两步上传
|
||
- Dify实际支持直接上传到知识库
|
||
|
||
**解决**:
|
||
- 改为直接调用`/datasets/{id}/document/create_by_file`
|
||
- 使用FormData直接上传文件和参数
|
||
- 简化了流程,只需一次API调用
|
||
|
||
---
|
||
|
||
## 📊 API完整性检查
|
||
|
||
### 知识库管理 API
|
||
- [x] 创建知识库
|
||
- [x] 获取知识库列表
|
||
- [x] 获取知识库详情
|
||
- [x] 删除知识库
|
||
- [ ] 更新知识库(暂未实现,Dify API不支持)
|
||
|
||
### 文档管理 API
|
||
- [x] 上传文档
|
||
- [x] 获取文档列表
|
||
- [x] 获取文档详情
|
||
- [x] 删除文档
|
||
- [x] 更新文档(重新索引)
|
||
|
||
### 知识库检索 API
|
||
- [x] 语义检索
|
||
- [x] 支持top_k配置
|
||
- [x] 支持相似度阈值
|
||
- [x] 返回相似度得分和内容
|
||
|
||
### 辅助功能
|
||
- [x] 轮询等待处理完成
|
||
- [x] 一键上传并处理
|
||
- [x] 统一错误处理
|
||
- [x] 单例模式导出
|
||
|
||
**完成度**: 100%
|
||
|
||
---
|
||
|
||
## 🚀 下一步工作计划
|
||
|
||
### Day 20-22:知识库管理功能开发
|
||
|
||
**后端API**:
|
||
1. 创建知识库管理Service层
|
||
2. 创建知识库管理Controller
|
||
3. 定义RESTful API路由
|
||
4. 实现知识库CRUD功能
|
||
5. 实现文档上传和管理功能
|
||
|
||
**数据库设计**:
|
||
```sql
|
||
-- 知识库表
|
||
CREATE TABLE knowledge_bases (
|
||
id VARCHAR PRIMARY KEY,
|
||
name VARCHAR NOT NULL,
|
||
description TEXT,
|
||
user_id VARCHAR NOT NULL,
|
||
dify_dataset_id VARCHAR NOT NULL,
|
||
created_at TIMESTAMP,
|
||
updated_at TIMESTAMP
|
||
);
|
||
|
||
-- 文档表
|
||
CREATE TABLE documents (
|
||
id VARCHAR PRIMARY KEY,
|
||
knowledge_base_id VARCHAR NOT NULL,
|
||
name VARCHAR NOT NULL,
|
||
dify_document_id VARCHAR NOT NULL,
|
||
file_url VARCHAR,
|
||
status VARCHAR,
|
||
tokens INTEGER,
|
||
word_count INTEGER,
|
||
created_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
**API设计**:
|
||
```
|
||
POST /api/v1/knowledge-bases 创建知识库
|
||
GET /api/v1/knowledge-bases 获取知识库列表
|
||
GET /api/v1/knowledge-bases/:id 获取知识库详情
|
||
DELETE /api/v1/knowledge-bases/:id 删除知识库
|
||
|
||
POST /api/v1/knowledge-bases/:id/documents 上传文档
|
||
GET /api/v1/knowledge-bases/:id/documents 获取文档列表
|
||
DELETE /api/v1/documents/:id 删除文档
|
||
```
|
||
|
||
**前端开发**:
|
||
1. 更新KnowledgePage布局
|
||
2. 实现知识库列表组件
|
||
3. 实现创建知识库对话框
|
||
4. 实现文档上传组件
|
||
5. 实现文档列表展示
|
||
6. 添加loading状态和错误处理
|
||
|
||
---
|
||
|
||
## 📝 相关文档
|
||
|
||
- **DifyClient源码**:`backend/src/clients/DifyClient.ts`
|
||
- **类型定义**:`backend/src/clients/types.ts`
|
||
- **测试脚本**:`backend/src/scripts/test-dify-client.ts`
|
||
- **Dify官方文档**:https://docs.dify.ai
|
||
|
||
---
|
||
|
||
## 🎓 技术收获
|
||
|
||
### 1. Dify API使用经验
|
||
- 理解了服务API Key和应用API Key的区别
|
||
- 掌握了知识库的创建和管理流程
|
||
- 学习了文档上传和索引的机制
|
||
- 了解了RAG检索的实现方式
|
||
|
||
### 2. TypeScript类型设计
|
||
- 完整定义了复杂的API类型
|
||
- 使用Partial类型支持可选参数
|
||
- 自定义错误类增强错误处理
|
||
|
||
### 3. Node.js文件上传
|
||
- 使用form-data处理文件上传
|
||
- 正确设置Content-Type和Authorization
|
||
- 处理Buffer类型的文件数据
|
||
|
||
### 4. 异步流程控制
|
||
- 实现轮询机制等待异步任务完成
|
||
- 使用Promise和async/await优雅处理异步
|
||
- 设置超时和重试机制
|
||
|
||
---
|
||
|
||
## 📈 项目进度
|
||
|
||
**里程碑1(MVP)**: **87%** 完成
|
||
|
||
```
|
||
✅ Day 4-5: 环境搭建
|
||
✅ Day 6: 前端基础架构
|
||
✅ Day 7: 前端完整布局
|
||
✅ Day 8-9: 项目管理API
|
||
✅ Day 10-11: 智能体配置系统
|
||
✅ Day 12-13: LLM适配器与对话系统
|
||
✅ Day 14-17: 前端对话界面
|
||
✅ Day 18: Dify平台部署
|
||
✅ Day 19: Dify客户端封装 ← 今天完成
|
||
|
||
🔄 Day 20-22: 知识库管理功能 ← 即将开始
|
||
⏳ Day 23-24: @知识库集成与RAG验证
|
||
```
|
||
|
||
---
|
||
|
||
**总结**: Day 19的Dify客户端封装工作圆满完成!实现了完整的知识库管理API,所有功能测试通过。为接下来的知识库管理功能开发提供了坚实的基础!💪
|
||
|
||
|