Files
AIclinicalresearch/第一周开发指南.md
AI Clinical Dev Team 9acbb0ae2b feat: complete Dify platform deployment (Day 18)
## Dify 閮ㄧ讲瀹屾垚 鉁?
### 瀹屾垚鐨勫伐浣?1. Docker 闀滃儚鍔犻€熷櫒閰嶇疆
   - 閰嶇疆 5 涓浗鍐呴暅鍍忔簮
   - 澶у箙鎻愬崌涓嬭浇閫熷害鍜屾垚鍔熺巼

2. Dify 闀滃儚鎷夊彇 (鍏?11 涓湇鍔?
   - langgenius/dify-api:1.9.1
   - langgenius/dify-web:1.9.1
   - postgres, redis, weaviate, nginx 绛?   - 鎬诲ぇ灏忕害 2GB锛岃€楁椂绾?15 鍒嗛挓

3. Dify 鏈嶅姟鍚姩
   - 鉁?nginx (80/443)
   - 鉁?api, worker, worker_beat
   - 鉁?web (3000)
   - 鉁?db (PostgreSQL), redis
   - 鉁?weaviate (鍚戦噺鏁版嵁搴?
   - 鉁?sandbox, plugin_daemon, ssrf_proxy

4. Dify 鍒濆鍖栭厤缃?   - 鍒涘缓绠$悊鍛樿处鍙?   - 鍒涘缓搴旂敤: AI Clinical Research
   - 鑾峰彇 API Key: app-VZRn0vMXdmltEJkvatHVGv5j

5. 鍚庣鐜閰嶇疆
   - DIFY_API_URL=http://localhost/v1
   - DIFY_API_KEY 宸查厤缃?
### 鏂囨。鏇存柊
- 鏂板: docs/05-姣忔棩杩涘害/Day18-Dify閮ㄧ讲瀹屾垚.md
- 鏇存柊: docs/04-寮€鍙戣鍒?寮€鍙戦噷绋嬬.md (Day 18 鏍囪涓哄畬鎴?

### 涓嬩竴姝?Day 19-24: 鐭ヨ瘑搴撶郴缁熷紑鍙?- Dify 瀹㈡埛绔皝瑁?- 鐭ヨ瘑搴撶鐞?CRUD
- 鏂囨。涓婁紶涓庡鐞?- @鐭ヨ瘑搴撻泦鎴?- RAG 闂瓟楠岃瘉

---
Progress: 閲岀▼纰?1 (MVP) 85% -> 鐭ヨ瘑搴撶郴缁熷紑鍙戜腑
2025-10-11 08:58:41 +08:00

18 KiB
Raw Blame History

第一周开发指南Day 1-7

目标: 搭建完整的开发环境,实现第一个功能(用户认证)
时间: 7天
状态: 🚀 准备就绪!


已完成准备工作

  • Docker Desktop 安装完毕
  • DeepSeek API Key 已申请
  • Qwen API Key 已申请

📅 本周计划

天数 任务 预计时间
Day 1 验证环境 + 创建项目结构 2小时
Day 2 启动基础服务Docker 1小时
Day 3 搭建后端框架 3小时
Day 4 搭建前端框架 3小时
Day 5 实现用户认证(后端) 4小时
Day 6 实现登录界面(前端) 4小时
Day 7 测试联调 2小时

🎯 Day 1: 验证环境 + 创建项目结构

步骤1验证 Docker 安装

打开终端Windows用PowerShell或CMDmacOS用Terminal执行

# 检查 Docker 版本
docker --version
# 应输出类似Docker version 24.0.x

# 检查 Docker Compose 版本
docker-compose --version
# 应输出类似Docker Compose version v2.x.x

# 检查 Docker 是否运行
docker ps
# 应输出表头(即使没有容器运行)

如果遇到错误:

  • Windows: 确保 Docker Desktop 已启动系统托盘有Docker图标
  • macOS: 确保 Docker Desktop 已启动

步骤2创建项目目录结构

# 选择一个工作目录(比如 D:\Projects 或 ~/Projects
cd D:\Projects  # Windows
# 或
cd ~/Projects   # macOS/Linux

# 创建项目根目录
mkdir ai-clinical-research
cd ai-clinical-research

# 创建子目录
mkdir backend frontend config docs

# 验证目录结构
tree -L 1
# 或 Windows: dir

预期结构:

ai-clinical-research/
├── backend/          # 后端代码
├── frontend/         # 前端代码
├── config/           # 配置文件
└── docs/             # 文档

步骤3创建 docker-compose.yml

在项目根目录创建 docker-compose.yml

version: '3.8'

services:
  # PostgreSQL 数据库
  postgres:
    image: postgres:15-alpine
    container_name: acr-postgres
    environment:
      POSTGRES_DB: ai_clinical_research
      POSTGRES_USER: dev_user
      POSTGRES_PASSWORD: dev_pass_2024
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dev_user -d ai_clinical_research"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: acr-redis
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

  # Dify Sandbox沙箱环境Dify依赖
  dify-sandbox:
    image: langgenius/dify-sandbox:latest
    container_name: acr-dify-sandbox
    restart: unless-stopped

  # Dify API
  dify-api:
    image: langgenius/dify-api:latest
    container_name: acr-dify-api
    environment:
      # 数据库配置
      DB_USERNAME: dify
      DB_PASSWORD: dify_pass_2024
      DB_HOST: dify-postgres
      DB_PORT: 5432
      DB_DATABASE: dify
      
      # Redis配置
      REDIS_HOST: dify-redis
      REDIS_PORT: 6379
      REDIS_DB: 0
      
      # 应用配置
      MODE: api
      SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
      CONSOLE_WEB_URL: http://localhost
      CONSOLE_API_URL: http://localhost:5001
      SERVICE_API_URL: http://localhost:5001
      APP_WEB_URL: http://localhost
      
      # 文件存储(本地)
      STORAGE_TYPE: local
      STORAGE_LOCAL_PATH: /app/storage
      
      # Vector Store向量数据库
      VECTOR_STORE: qdrant
      QDRANT_URL: http://dify-qdrant:6333
      QDRANT_API_KEY: dify-qdrant-key
      
      # Celery异步任务
      CELERY_BROKER_URL: redis://dify-redis:6379/1
      
      # 模型配置可选可在Web界面配置
      # OPENAI_API_KEY: your-key-here
    ports:
      - "5001:5001"
    volumes:
      - dify_app_storage:/app/storage
    depends_on:
      - dify-postgres
      - dify-redis
      - dify-qdrant
      - dify-sandbox
    restart: unless-stopped

  # Dify Worker后台任务处理
  dify-worker:
    image: langgenius/dify-api:latest
    container_name: acr-dify-worker
    environment:
      MODE: worker
      DB_USERNAME: dify
      DB_PASSWORD: dify_pass_2024
      DB_HOST: dify-postgres
      DB_PORT: 5432
      DB_DATABASE: dify
      REDIS_HOST: dify-redis
      REDIS_PORT: 6379
      REDIS_DB: 0
      CELERY_BROKER_URL: redis://dify-redis:6379/1
      SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
      STORAGE_TYPE: local
      STORAGE_LOCAL_PATH: /app/storage
      VECTOR_STORE: qdrant
      QDRANT_URL: http://dify-qdrant:6333
      QDRANT_API_KEY: dify-qdrant-key
    volumes:
      - dify_app_storage:/app/storage
    depends_on:
      - dify-postgres
      - dify-redis
      - dify-qdrant
    restart: unless-stopped

  # Dify PostgreSQL
  dify-postgres:
    image: postgres:15-alpine
    container_name: acr-dify-postgres
    environment:
      POSTGRES_DB: dify
      POSTGRES_USER: dify
      POSTGRES_PASSWORD: dify_pass_2024
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - dify_postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dify -d dify"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # Dify Redis
  dify-redis:
    image: redis:7-alpine
    container_name: acr-dify-redis
    volumes:
      - dify_redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    restart: unless-stopped

  # Qdrant 向量数据库
  dify-qdrant:
    image: qdrant/qdrant:latest
    container_name: acr-dify-qdrant
    environment:
      QDRANT__SERVICE__API_KEY: dify-qdrant-key
    ports:
      - "6333:6333"
    volumes:
      - dify_qdrant_data:/qdrant/storage
    restart: unless-stopped

  # Dify Web界面
  dify-web:
    image: langgenius/dify-web:latest
    container_name: acr-dify-web
    environment:
      CONSOLE_API_URL: http://localhost:5001
      APP_API_URL: http://localhost:5001
    ports:
      - "3000:3000"
    depends_on:
      - dify-api
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:
  dify_postgres_data:
  dify_redis_data:
  dify_qdrant_data:
  dify_app_storage:

networks:
  default:
    name: acr-network

保存文件: ai-clinical-research/docker-compose.yml


步骤4创建 .gitignore

在项目根目录创建 .gitignore

# Node modules
node_modules/
*/node_modules/

# Environment variables
.env
.env.local
.env.*.local
*.env

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Build outputs
dist/
build/
*.log

# Database
*.sqlite
*.db

# API Keys重要
**/config/api-keys.json
backend/config/api-keys.json

步骤5创建 README.md

在项目根目录创建 README.md

# AI科研助手

## 快速启动

### 启动所有服务
\`\`\`bash
docker-compose up -d
\`\`\`

### 查看服务状态
\`\`\`bash
docker-compose ps
\`\`\`

### 查看日志
\`\`\`bash
docker-compose logs -f
\`\`\`

### 停止所有服务
\`\`\`bash
docker-compose down
\`\`\`

## 访问地址

- 前端开发服务器: http://localhost:5173
- 后端API: http://localhost:3001
- Dify Web管理界面: http://localhost:3000
- Dify API: http://localhost:5001
- PostgreSQL: localhost:5432
- Redis: localhost:6379

## 开发文档

详见 `docs/` 目录

Day 1 完成检查清单:

  • Docker 命令验证通过
  • 项目目录创建完成
  • docker-compose.yml 创建完成
  • .gitignore 创建完成
  • README.md 创建完成

🎯 Day 2: 启动基础服务

步骤1启动 Docker 服务

# 确保在项目根目录
cd ai-clinical-research

# 启动所有服务首次启动会下载镜像需要5-10分钟
docker-compose up -d

# 查看启动日志
docker-compose logs -f

# 等待所有服务启动完成约2-3分钟
# 看到类似信息表示成功:
# acr-dify-api       | INFO: Application startup complete.
# acr-dify-web       | ready - started server on 0.0.0.0:3000

注意: 首次启动会下载Docker镜像约2GB请耐心等待。


步骤2验证服务状态

# 查看所有容器状态
docker-compose ps

# 应该看到所有服务都是 "Up" 状态
# NAME                    STATUS
# acr-postgres            Up (healthy)
# acr-redis               Up (healthy)
# acr-dify-postgres       Up (healthy)
# acr-dify-redis          Up (healthy)
# acr-dify-qdrant         Up
# acr-dify-api            Up
# acr-dify-worker         Up
# acr-dify-web            Up

步骤3访问 Dify Web 界面

  1. 打开浏览器访问:http://localhost:3000
  2. 首次访问会要求创建管理员账号
  3. 填写信息:
    • 邮箱:admin@example.com
    • 密码Admin123!(自己设置一个)
    • 确认密码Admin123!
  4. 点击"创建账号"

成功标志: 进入Dify管理后台


步骤4获取 Dify API Key

  1. 在Dify管理后台点击左侧 "设置" → "API密钥"
  2. 点击 "创建密钥"
  3. 复制生成的API Key类似app-xxx...
  4. 保存到安全的地方(后面会用到)

步骤5测试数据库连接

# 测试 PostgreSQL业务数据库
docker exec -it acr-postgres psql -U dev_user -d ai_clinical_research -c "SELECT version();"

# 应输出 PostgreSQL 版本信息

# 测试 Redis
docker exec -it acr-redis redis-cli ping
# 应输出: PONG

# 测试 Dify API
curl http://localhost:5001/health
# 应输出: {"status":"ok"}

Day 2 完成检查清单:

  • 所有Docker容器启动成功
  • Dify Web界面可访问
  • Dify管理员账号创建完成
  • Dify API Key获取完成
  • 数据库连接测试通过

🎯 Day 3: 搭建后端框架

步骤1初始化后端项目

# 进入后端目录
cd backend

# 初始化 Node.js 项目
npm init -y

# 安装依赖
npm install fastify@4.26.0 \
  @fastify/cors@9.0.0 \
  @fastify/jwt@7.2.0 \
  @prisma/client@5.10.0 \
  bcryptjs@2.4.3 \
  dotenv@16.4.0 \
  ioredis@5.3.0 \
  axios@1.6.0

# 安装开发依赖
npm install -D \
  prisma@5.10.0 \
  typescript@5.3.0 \
  @types/node@20.11.0 \
  @types/bcryptjs@2.4.6 \
  tsx@4.7.0 \
  nodemon@3.0.0

步骤2配置 TypeScript

创建 backend/tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "moduleResolution": "node"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

步骤3配置环境变量

创建 backend/.env

# 数据库配置
DATABASE_URL="postgresql://dev_user:dev_pass_2024@localhost:5432/ai_clinical_research"

# Redis配置
REDIS_URL="redis://localhost:6379"

# JWT配置
JWT_SECRET="your-super-secret-jwt-key-change-this-in-production-2024"
JWT_EXPIRES_IN="7d"

# LLM API Keys
DEEPSEEK_API_KEY="你的DeepSeek API Key"
DASHSCOPE_API_KEY="你的Qwen API Key"

# Dify配置
DIFY_API_URL="http://localhost:5001"
DIFY_API_KEY="你在Day2获取的Dify API Key"

# 应用配置
NODE_ENV="development"
PORT=3001

注意: 把"你的XXX API Key"替换成你实际申请的Key


步骤4初始化 Prisma

# 初始化 Prisma
npx prisma init

# 这会创建 prisma/schema.prisma 文件

编辑 backend/prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// 用户表
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  password  String
  name      String?
  role      String   @default("user") // user, admin
  status    String   @default("active") // active, inactive
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  // 关联
  projects  Project[]
  knowledgeBases KnowledgeBase[]

  @@map("users")
}

// 项目/课题表
model Project {
  id          String   @id @default(uuid())
  userId      String
  name        String
  description String   @db.Text
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  // 关联
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  conversations Conversation[]

  @@map("projects")
}

// 对话表
model Conversation {
  id        String   @id @default(uuid())
  projectId String?
  userId    String
  agentId   String
  title     String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  // 关联
  project   Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
  messages  Message[]

  @@map("conversations")
}

// 消息表
model Message {
  id             String   @id @default(uuid())
  conversationId String
  role           String   // user, assistant
  content        String   @db.Text
  createdAt      DateTime @default(now())

  // 关联
  conversation   Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)

  @@map("messages")
}

// 知识库表
model KnowledgeBase {
  id             String   @id @default(uuid())
  userId         String
  name           String
  description    String?
  difyDatasetId  String   // Dify中的知识库ID
  fileCount      Int      @default(0)
  totalSizeBytes BigInt   @default(0)
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt

  // 关联
  user           User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  documents      Document[]

  @@map("knowledge_bases")
}

// 文档表
model Document {
  id              String   @id @default(uuid())
  kbId            String
  userId          String
  filename        String
  fileType        String
  fileSizeBytes   BigInt
  fileUrl         String
  difyDocumentId  String
  status          String   @default("uploading") // uploading, processing, completed, failed
  progress        Int      @default(0)
  errorMessage    String?
  segmentsCount   Int?
  tokensCount     Int?
  uploadedAt      DateTime @default(now())
  processedAt     DateTime?

  // 关联
  knowledgeBase   KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)

  @@map("documents")
}

步骤5创建数据库表

# 生成 Prisma Client
npx prisma generate

# 创建数据库迁移
npx prisma migrate dev --name init

# 看到类似输出表示成功:
# ✔ Generated Prisma Client
# ✔ Your database is now in sync with your schema.

步骤6创建基础目录结构

# 在 backend 目录下创建
mkdir -p src/routes src/services src/config src/utils src/types

步骤7创建服务器入口文件

创建 backend/src/server.ts

import Fastify from 'fastify';
import cors from '@fastify/cors';
import dotenv from 'dotenv';

// 加载环境变量
dotenv.config();

const server = Fastify({
  logger: true
});

// 注册CORS
server.register(cors, {
  origin: true // 开发环境允许所有来源
});

// 健康检查端点
server.get('/health', async (request, reply) => {
  return { status: 'ok', timestamp: new Date().toISOString() };
});

// 测试端点
server.get('/api/test', async (request, reply) => {
  return { 
    message: 'AI科研助手后端服务运行正常',
    env: process.env.NODE_ENV,
    timestamp: new Date().toISOString()
  };
});

// 启动服务器
const start = async () => {
  try {
    const port = parseInt(process.env.PORT || '3001');
    await server.listen({ port, host: '0.0.0.0' });
    console.log(`🚀 服务器启动成功!`);
    console.log(`📝 API地址: http://localhost:${port}`);
    console.log(`🏥 健康检查: http://localhost:${port}/health`);
  } catch (err) {
    server.log.error(err);
    process.exit(1);
  }
};

start();

步骤8配置 package.json scripts

编辑 backend/package.json,添加 scripts

{
  "scripts": {
    "dev": "tsx watch src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js",
    "prisma:generate": "prisma generate",
    "prisma:migrate": "prisma migrate dev",
    "prisma:studio": "prisma studio"
  }
}

步骤9启动后端服务

# 启动开发服务器
npm run dev

# 看到类似输出表示成功:
# 🚀 服务器启动成功!
# 📝 API地址: http://localhost:3001
# 🏥 健康检查: http://localhost:3001/health

步骤10测试后端API

打开新的终端窗口:

# 测试健康检查
curl http://localhost:3001/health

# 测试API
curl http://localhost:3001/api/test

Day 3 完成检查清单:

  • 后端项目初始化完成
  • 依赖安装完成
  • TypeScript配置完成
  • 环境变量配置完成
  • Prisma数据库模型创建完成
  • 数据库迁移成功
  • 后端服务启动成功
  • API测试通过

🎯 Day 4-7: 继续开发...

后续天数的详细步骤将在您完成Day 1-3后提供


📊 当前进度

✅ 环境准备: 100%
⏳ Day 1: 待开始
⏳ Day 2: 待开始
⏳ Day 3: 待开始

🆘 常见问题

Q1: Docker 容器启动失败

# 查看日志
docker-compose logs [服务名]

# 重启服务
docker-compose restart [服务名]

# 完全重置
docker-compose down -v
docker-compose up -d

Q2: 端口被占用

# Windows 查找占用端口的进程
netstat -ano | findstr :3001

# macOS/Linux
lsof -i :3001

# 修改端口(在 .env 中)
PORT=3002

Q3: npm install 太慢

# 使用国内镜像
npm config set registry https://registry.npmmirror.com

🎉 准备开始!

现在就开始 Day 1 吧!

执行第一个命令:

docker --version

有任何问题随时告诉我!🚀