第一章:Dify 整体架构总览
本章目标
通过本章的阅读,你将能够:
- 理解 Dify 项目的整体架构设计,从前端到后端的完整技术栈
- 了解 Dify 前端采用的 React + Next.js + Zustand + TailwindCSS 技术组合
- 建立 Vue2 开发者到 React/Next.js 技术栈的核心概念映射
- 对 Dify 的目录结构、模块划分、请求流程有全局认识
- 为后续各章节的深入源码分析打下基础
必须阅读的源码文件或目录
| 优先级 | 文件/目录 | 说明 |
|---|---|---|
| ★★★ | dify-main/ |
项目根目录,了解 Monorepo 整体布局 |
| ★★★ | dify-main/web/ |
前端主工程 |
| ★★★ | dify-main/api/ |
后端 Flask 工程 |
| ★★☆ | dify-main/pnpm-workspace.yaml |
Monorepo 工作空间配置 |
| ★★☆ | dify-main/web/package.json |
前端依赖与脚本定义 |
| ★★☆ | dify-main/web/next.config.ts |
Next.js 配置 |
| ★☆☆ | dify-main/docker/ |
Docker 部署配置 |
| ★☆☆ | dify-main/packages/ |
共享包(UI 组件库、合同定义等) |
1. Dify 是什么
Dify 是一个开源的 LLM 应用开发平台,提供了可视化的 Prompt 编排、RAG(检索增强生成)管道、Agent 智能体、工作流引擎等能力。它融合了后端即服务(BaaS)和 LLMOps 的理念,让开发者能够快速构建和部署 AI 原生应用。
从技术角度看,Dify 是一个典型的前后端分离 的 Web 应用,前端使用 React + Next.js ,后端使用 Python Flask,通过 RESTful API 和 SSE(Server-Sent Events)进行通信。
Vue2 开发者视角的对照
| 概念 | Vue2 生态 | Dify 前端(React 生态) |
|---|---|---|
| UI 框架 | Vue 2.x | React 19 |
| 脚手架 | Vue CLI / Vite | Next.js (App Router) |
| 路由 | vue-router | Next.js 文件系统路由 |
| 状态管理 | Vuex / Pinia | Zustand + Jotai + React Query |
| 样式方案 | scoped CSS / Less/Sass | TailwindCSS (原子化 CSS) |
| HTTP 请求 | axios | ky + @orpc/client |
| 实时通信 | socket.io-client | socket.io-client (相同) |
| 类型系统 | --- (可选) | TypeScript (强类型) |
| 国际化 | vue-i18n | i18next + react-i18next |
| 组件库 | Element UI / Ant Design Vue | @langgenius/dify-ui (自研) |
| 构建工具 | Webpack / Vite | Turbopack (Next.js 内置) |
| 包管理 | npm / yarn | pnpm (workspace monorepo) |
2. 整体架构图
3. Monorepo 仓库结构
Dify 采用 pnpm workspace 进行 Monorepo 管理。整个仓库源码位于 dify-main/ 目录下:
ruby
dify-main/
├── web/ # ★ 前端应用:Next.js + React + TypeScript
│ ├── app/ # Next.js App Router 页面与路由
│ ├── components/ # 业务组件
│ ├── service/ # API 请求封装层
│ ├── models/ # 数据模型定义
│ ├── context/ # React Context 状态提供者
│ ├── hooks/ # 自定义 React Hooks
│ ├── config/ # 前端配置
│ ├── i18n/ # 国际化翻译文件
│ ├── types/ # TypeScript 类型声明
│ ├── themes/ # 主题配置
│ ├── constants/ # 常量定义
│ ├── utils/ # 工具函数
│ ├── features/ # 功能模块
│ └── public/ # 静态资源
│
├── api/ # ★ 后端应用:Python Flask
│ ├── controllers/ # 路由控制器
│ │ ├── console/ # 管理后台 API
│ │ ├── web/ # Web 应用 API
│ │ ├── service_api/ # 对外服务 API
│ │ └── files/ # 文件上传 API
│ ├── services/ # 业务逻辑层
│ ├── models/ # 数据模型 (SQLAlchemy)
│ ├── core/ # 核心框架工具
│ ├── extensions/ # Flask 扩展
│ ├── migrations/ # 数据库迁移脚本
│ └── tasks/ # Celery 异步任务
│
├── packages/ # 共享包
│ ├── dify-ui/ # UI 组件库 (@langgenius/dify-ui)
│ ├── contracts/ # 前后端接口合同定义
│ ├── tsconfig/ # 共享 TypeScript 配置
│ └── iconify-collections/ # 图标集合
│
├── docker/ # Docker 部署配置
│ ├── nginx/ # Nginx 反向代理
│ ├── pgvector/ # PostgreSQL + pgvector
│ └── ... # 其他服务
│
├── sdks/ # SDK
│ └── nodejs-client/ # Node.js SDK
│
├── e2e/ # 端到端测试
├── docs/ # 文档站
└── scripts/ # 构建和工具脚本
关键配置文件
| 文件 | 作用 |
|---|---|
pnpm-workspace.yaml |
定义 Monorepo 包含哪些子包(web, e2e, sdks/, packages/) |
web/package.json |
前端项目依赖与 npm scripts |
web/next.config.ts |
Next.js 核心配置(basePath, 页面扩展名, 跨域等) |
web/vite.config.ts |
Vite 配置(用于测试和 Storybook) |
Makefile |
项目级构建脚本(构建、测试、lint 等) |
4. 前端技术栈深度解析
4.1 React 19 + Next.js (App Router)
Dify 使用 Next.js 的 App Router 模式(而非旧的 Pages Router),这是 Next.js 13+ 引入的新路由系统。
与 Vue2 + vue-router 的核心差异:
| 特性 | Vue2 + vue-router | Next.js App Router |
|---|---|---|
| 路由定义 | 手动配置 routes.js |
文件系统即路由 :app/xxx/page.tsx 自动成为路由 |
| 布局 | 通过 <router-view> 嵌套 |
layout.tsx 文件自动包裹子页面 |
| 数据获取 | mounted 钩子中调用 API |
支持 Server Component 直接在服务端获取数据 |
| 渲染模式 | 纯客户端渲染 (CSR) | SSR / SSG / ISR / CSR 混合 |
| 路由分组 | 命名视图 | 括号文件夹 (groupName) 不影响 URL |
示例:Dify 的路由分组
bash
app/
├── (commonLayout)/ ← URL 不变,共享管理后台布局
│ ├── apps/ → /apps
│ ├── datasets/ → /datasets
│ ├── explore/ → /explore
│ ├── plugins/ → /plugins
│ └── tools/ → /tools
├── (shareLayout)/ ← URL 不变,共享分享页布局
├── signin/ → /signin
└── signup/ → /signup
4.2 状态管理:Zustand + Jotai + React Query
Dify 的前端采用了三层状态管理策略,而非单一状态树:
@tanstack/react-query] A1[缓存 API 响应] A2[自动重新请求] A3[乐观更新] end subgraph "全局客户端状态" B[Zustand] B1[应用列表状态] B2[数据集详情] B3[调试配置] end subgraph "局部/原子状态" C[Jotai] C1[UI 临时状态] C2[跨组件共享变量] end A -->|API 数据| B B -->|派生状态| C
Vue2 对照:Vuex 把所有状态(服务端数据 + 客户端 UI 状态)都放在一个 Store 里,而 Dify 将"服务端缓存"(React Query)和"客户端状态"(Zustand)分离,各司其职。
4.3 请求层:ky + @orpc/client
Dify 不使用 axios,而是:
- ky:基于 Fetch API 的轻量 HTTP 客户端,用于普通 REST 请求
- @orpc/client:类型安全的 RPC 客户端,与后端共享接口合同
HTTP 请求的封装集中在 web/service/ 目录下,每个业务域有独立的 service 文件:
csharp
service/
├── apps.ts # 应用相关 API
├── datasets.ts # 数据集相关 API
├── workflow.ts # 工作流相关 API
├── plugins.ts # 插件相关 API
├── share.ts # 分享相关 API
├── base.ts # 基础请求封装
├── fetch.ts # Fetch 底层封装
└── ...
4.4 TailwindCSS:原子化 CSS
Dify 使用 TailwindCSS 4(通过 @tailwindcss/vite 插件)进行样式管理。与 Vue2 中常见的 scoped CSS 或组件库样式覆盖不同,TailwindCSS 通过原子类直接在 JSX 中书写样式:
tsx
// TailwindCSS(Dify 实际方式)
<div className="flex items-center gap-2 px-4 py-2 bg-blue-500 rounded-lg">
<span className="text-white text-sm font-medium">提交</span>
</div>
// Vue2 等价写法
// <div class="submit-btn">
// <span>提交</span>
// </div>
// <style scoped>
// .submit-btn { display: flex; align-items: center; gap: 8px;
// padding: 8px 16px; background: #3B82F6; border-radius: 8px; }
// .submit-btn span { color: white; font-size: 14px; font-weight: 500; }
// </style>
后面的第六章将详细讲解 TailwindCSS 的实战用法。
5. 后端技术栈概览
| 层级 | 技术 | 说明 |
|---|---|---|
| Web 框架 | Flask | 轻量 Python Web 框架 |
| ORM | SQLAlchemy | 数据库 ORM |
| 数据库 | PostgreSQL + pgvector | 关系数据 + 向量存储 |
| 缓存 | Redis | 会话、缓存、消息队列 |
| 任务队列 | Celery | 异步任务处理 |
| 迁移 | Alembic (Flask-Migrate) | 数据库版本管理 |
| 实时通信 | SSE | 流式返回 LLM 生成结果 |
| 向量数据库 | 支持多种(Weaviate/Qdrant/Milvus 等) | 向量检索 |
API 路由分组
bash
api/controllers/
├── console/ # 管理后台 API(/console/api/*)
│ ├── app/ # 应用管理
│ ├── datasets/ # 数据集管理
│ ├── explore/ # 探索页
│ └── ... #
├── web/ # Web 应用 API(/api/*)
│ ├── app.py # 用户端应用调用
│ └── ... #
├── service_api/ # 对外 Service API(/v1/*)
├── files/ # 文件上传
├── inner_api/ # 内部 API(Worker 调用)
└── mcp/ # MCP 协议接口
6. 请求全链路示例
以"用户创建一个应用"为例,完整调用链路如下:
7. 二次开发切入点总览
作为前端二次开发者,你的主要关注区域集中在 dify-main/web/ 目录。以下是一个快速索引:
| 想要做什么 | 从哪里下手 |
|---|---|
| 新增一个页面 | web/app/(commonLayout)/ 下新建目录 + page.tsx |
| 修改 API 请求 | web/service/ 下对应的 service 文件 |
| 修改/新增组件 | web/app/components/ 下的业务组件 |
| 调整全局状态 | web/context/ 或新建 Zustand store |
| 修改样式/主题 | web/themes/ 和 TailwindCSS 类名 |
| 添加翻译 | web/i18n/ 下的语言文件 |
| 添加常量/配置 | web/constants/ 或 web/config/ |
| 使用新的 UI 组件 | @langgenius/dify-ui 包(位于 packages/dify-ui/) |
8. 注意事项与坑点提示
-
Monorepo 依赖管理 :Dify 强制使用 pnpm,
npm install或yarn会报错(preinstall脚本有检查)。安装依赖请用pnpm install。 -
TypeScript 强类型 :整个前端项目使用 TypeScript,没有
.js文件。Vue2 开发者需要适应类型注解、泛型、接口等概念。建议从第三章开始逐步适应。 -
Server Component vs Client Component :Next.js App Router 区分服务端组件(默认)和客户端组件(
'use client'指令)。服务端组件不能使用useState、useEffect、浏览器 API。这是 Vue2 中完全没有的概念,需要在开发中时刻注意。 -
文件系统路由 :路由由文件夹和文件决定,不是由配置文件决定。新增页面只需创建
page.tsx,无需修改 router 配置。 -
CSS 方案不同:TailwindCSS 是原子化 CSS,类名很长但很灵活。不要试图用传统的 BEM 或 CSS Module 方式覆盖,应遵循项目现有模式。
-
pnpm-workspace 的包引用 :
packages/dify-ui/作为内部包,通过workspace:*协议引用。修改 UI 组件库后需要在根目录重新pnpm install。 -
环境变量 :前端环境变量以
NEXT_PUBLIC_为前缀的会被暴露到浏览器端。.env.local用于本地开发。
下一章预告 :第二章将带你深入了解 Dify 前端的运行流程------从
pnpm dev到页面渲染,完整追踪启动过程、中间件、请求拦截、登录态管理等核心机制。