Files
AIclinicalresearch/docs/05-每日进度/Day19-Dify客户端封装完成.md
AI Clinical Dev Team 239c7ea85e feat: Day 21-22 - knowledge base frontend completed, fix CORS and file upload issues
- 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
2025-10-11 15:40:12 +08:00

11 KiB
Raw Blame History

Day 19 - Dify客户端封装完成总结

日期: 2025-10-11
状态: 已完成


🎯 本次任务目标

封装Dify知识库API实现完整的知识库管理功能。


完成的工作

1. 创建类型定义 (backend/src/clients/types.ts)

定义的类型

// 知识库相关
- Dataset                    // 知识库信息
- CreateDatasetRequest       // 创建知识库请求
- CreateDatasetResponse      // 创建知识库响应
- DatasetListResponse        // 知识库列表响应

// 文档相关
- Document                   // 文档信息
- DocumentListResponse       // 文档列表响应
- CreateDocumentByFileRequest // 创建文档请求
- CreateDocumentResponse     // 创建文档响应

// 检索相关
- RetrievalRequest           // 检索请求
- RetrievalRecord            // 检索结果项
- RetrievalResponse          // 检索响应

// 错误处理
- DifyErrorResponse          // 错误响应
- DifyError                  // 自定义错误类

特点

  • 完整的TypeScript类型定义
  • 包含所有必需和可选字段
  • 支持文档处理状态追踪

2. 实现DifyClient核心类 (backend/src/clients/DifyClient.ts)

2.1 基础功能

构造函数

constructor(apiKey?: string, apiUrl?: string)
- 支持自定义API Key和URL
- 从环境变量读取配置
- 自动配置请求头和超时

错误处理

  • axios拦截器统一处理错误
  • 自定义DifyError类
  • 包含错误代码和HTTP状态码

2.2 知识库管理API

已实现的方法

  1. createDataset - 创建知识库

    async createDataset(params: CreateDatasetRequest): Promise<CreateDatasetResponse>
    
    • 支持设置索引技术high_quality/economy
    • 支持配置检索模型
    • 自动设置默认参数
  2. getDatasets - 获取知识库列表

    async getDatasets(page: number, limit: number): Promise<DatasetListResponse>
    
    • 支持分页
    • 返回总数、是否有更多等信息
  3. getDataset - 获取知识库详情

    async getDataset(datasetId: string): Promise<Dataset>
    
    • 获取单个知识库的完整信息
    • 包括文档数量、字符数等统计
  4. deleteDataset - 删除知识库

    async deleteDataset(datasetId: string): Promise<void>
    
    • 永久删除知识库及其所有文档

2.3 文档管理API

已实现的方法

  1. uploadDocumentDirectly - 直接上传文档

    async uploadDocumentDirectly(
      datasetId: string, 
      file: Buffer, 
      filename: string
    ): Promise<CreateDocumentResponse>
    
    • 使用FormData上传文件
    • 自动配置处理规则
    • 支持自定义分词策略
  2. getDocuments - 获取文档列表

    async getDocuments(
      datasetId: string, 
      page: number, 
      limit: number
    ): Promise<DocumentListResponse>
    
    • 支持分页查询
    • 返回文档状态、Token数等信息
  3. getDocument - 获取文档详情

    async getDocument(datasetId: string, documentId: string): Promise<Document>
    
    • 查询单个文档的完整信息
    • 包括索引状态、字符数、点击次数等
  4. deleteDocument - 删除文档

    async deleteDocument(datasetId: string, documentId: string): Promise<void>
    
    • 从知识库中删除指定文档
  5. updateDocument - 更新文档(重新索引)

    async updateDocument(datasetId: string, documentId: string): Promise<void>
    
    • 触发文档重新处理和索引

2.4 知识库检索API

已实现的方法

  1. retrieveKnowledge - 检索知识库
    async retrieveKnowledge(
      datasetId: string, 
      query: string, 
      params?: Partial<RetrievalRequest>
    ): Promise<RetrievalResponse>
    
    • 支持语义搜索、全文搜索、混合搜索
    • 支持重排序reranking
    • 支持设置top_k和相似度阈值
    • 返回相关文档片段和相似度得分

2.5 辅助方法

已实现的方法

  1. waitForDocumentProcessing - 轮询等待文档处理完成

    async waitForDocumentProcessing(
      datasetId: string, 
      documentId: string, 
      maxAttempts: number, 
      interval: number
    ): Promise<Document>
    
    • 自动轮询检查处理状态
    • 支持超时控制
    • 处理失败时抛出错误
  2. uploadAndProcessDocument - 一键上传并等待处理

    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. 完善的错误处理

// 自定义错误类
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. 智能轮询机制

// 等待文档处理完成,自动轮询
async waitForDocumentProcessing(
  datasetId: string,
  documentId: string,
  maxAttempts: number = 30,
  interval: number = 2000
): Promise<Document>
  • 最多轮询30次
  • 每次间隔2秒
  • 自动检测完成或失败状态

3. 单例模式

// 导出全局单例,方便使用
export const difyClient = new DifyClient();

4. FormData文件上传

// 正确处理文件上传
const formData = new FormData();
formData.append('file', file, filename);
formData.append('data', JSON.stringify(params));

📦 依赖安装

新增依赖

{
  "form-data": "^4.0.0",
  "@types/form-data": "^2.5.0"
}

用途

  • form-data: Node.js环境的FormData实现
  • @types/form-data: TypeScript类型定义

🐛 遇到的问题与解决

问题1API Key认证失败401

症状

Access token is invalid
HTTP状态码: 401

原因

  • 使用了应用API Keyapp-xxx
  • 知识库管理需要服务API Keydataset-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

  • 创建知识库
  • 获取知识库列表
  • 获取知识库详情
  • 删除知识库
  • 更新知识库暂未实现Dify API不支持

文档管理 API

  • 上传文档
  • 获取文档列表
  • 获取文档详情
  • 删除文档
  • 更新文档(重新索引)

知识库检索 API

  • 语义检索
  • 支持top_k配置
  • 支持相似度阈值
  • 返回相似度得分和内容

辅助功能

  • 轮询等待处理完成
  • 一键上传并处理
  • 统一错误处理
  • 单例模式导出

完成度: 100%


🚀 下一步工作计划

Day 20-22知识库管理功能开发

后端API

  1. 创建知识库管理Service层
  2. 创建知识库管理Controller
  3. 定义RESTful API路由
  4. 实现知识库CRUD功能
  5. 实现文档上传和管理功能

数据库设计

-- 知识库表
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优雅处理异步
  • 设置超时和重试机制

📈 项目进度

里程碑1MVP: 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所有功能测试通过。为接下来的知识库管理功能开发提供了坚实的基础💪