Dify 源码深度剖析与生产应用教程

2 阅读28分钟

基于 langgenius/dify 代码仓库 v1.13.x 版本的系统性源码分析与落地实战手册 分析基线目录:d:/opencode/q/dify/


目录

  1. 项目定位与总体架构
  2. 仓库结构与顶层组织
  3. 后端 API 架构(api/)——DDD 分层剖析
  4. 后端启动链路与扩展机制
  5. Core 核心引擎深度解读
  6. 数据模型与数据库设计
  7. Celery 任务队列与异步子系统
  8. 前端 Web 架构(web/)
  9. Docker 部署拓扑与生产化配置
  10. 生产环境最佳实践与运维手册
  11. 二次开发指南:扩展节点、工具、模型
  12. 典型业务场景案例
  13. 性能调优、安全加固与排障手册
  14. 总结:Dify 的设计哲学

1. 项目定位与总体架构

1.1 定位

Dify(读作 /ˈdɪfaɪ/,取自 "Define + Modify") 是由 LangGenius 开源的 LLM 应用开发平台(LLMOps Platform)。它不是又一个 LangChain 封装,而是定位于:

  • 面向"应用生产"的 BaaS + LLMOps:把 Prompt 工程、RAG、Agent、工作流、可观测性、权限、计费、多租户等能力一次性交付
  • 低代码可视化编排:工作流画布(基于 ReactFlow)让业务人员也能搭建 AI 应用
  • 多模型统一接入:100+ 模型提供商,通过统一 Model Runtime 抽象
  • 企业级运行时:多租户、RBAC、API Key、SSO、License Gate、OTEL 观测、Sentry 告警

1.2 五层总体架构

┌──────────────────────────────────────────────────────────┐
│                    浏览器 / 第三方客户端                   │
└──────────────────────────────────────────────────────────┘
                           │
                      HTTPS / WSS
                           │
┌──────────────────────────────────────────────────────────┐
│                 Nginx (反向代理 + SSL 终止)                │
└──────────────────────────────────────────────────────────┘
         │                                      │
         │ /console/api /v1 /api                │ 静态资源
         ▼                                      ▼
┌──────────────────┐                  ┌────────────────────┐
│  dify-api (Flask)│                  │  dify-web (Next.js)│
│  ───────────────│                  │  ──────────────────│
│  Controllers    │                  │  App Router        │
│    ↓             │                  │  ReactFlow Editor  │
│  Services       │                  │  Zustand/Jotai     │
│    ↓             │                  │  ORPC + SWR        │
│  Core (Engine)  │                  └────────────────────┘
│    ↓             │
│  Models / Repos │
└──────────────────┘
      │  │  │  │
      │  │  │  └──→ Celery Worker (异步任务:RAG 索引/工作流)
      │  │  │           │
      │  │  │           ▼
      │  │  │     ┌──────────────┐
      │  │  │     │    Redis     │(Broker + Cache + Rate Limit)
      │  │  │     └──────────────┘
      │  │  ▼
      │  │  ┌────────────────────┐
      │  │  │  Plugin Daemon (Go)│(插件运行时)
      │  │  └────────────────────┘
      │  ▼
      │  ┌────────────────────┐
      │  │  Sandbox (Rust+Py) │(代码节点沙箱)
      │  └────────────────────┘
      │        │
      │        └──→ SSRF Proxy (Squid) ──→ Internet
      ▼
┌──────────────────────────────────────────────────────────┐
│  PostgreSQL   │  Weaviate/Qdrant/PGVector │ Object Store │
│  (元数据)      │  (向量数据库)              │ (S3/本地FS)  │
└──────────────────────────────────────────────────────────┘

1.3 核心能力矩阵

能力实现位置关键技术
应用编排(5 种)core/app/apps/{chat,completion,agent_chat,advanced_chat,workflow}AppRunner + QueueManager
工作流 DAGcore/workflow/ + 外部 graphonGraph + NodeFactory + VariablePool
RAG 管道core/rag/Extractor + Splitter + Embedding + VDB
Agentcore/agent/{fc,cot}_agent_runner.pyFunction Call + CoT/ReAct
模型统一接入core/model_manager.py + core/provider_manager.py策略 + 工厂 + 负载均衡
工具体系core/tools/5 类 Provider(Builtin/API/Plugin/Workflow/MCP)
插件运行时core/plugin/ + 独立 Go DaemonRPC 进程隔离
异步调度tasks/ + schedule/Celery + Redis
多租户models/account.py:Tenant所有资源 tenant_id 外键
可观测性extensions/ext_otel.py ext_sentry.pyOTEL + Sentry

2. 仓库结构与顶层组织

dify/
├── api/           # 后端 Flask 应用(DDD 分层)
├── web/           # 前端 Next.js 应用
├── docker/        # Docker Compose 部署模板
├── sdks/          # 各语言 SDK(python/node/php 等)
├── packages/      # 前端内部 workspace 包
├── e2e/           # 端到端测试
├── dev/           # 开发脚本
├── docs/          # 多语言 README
├── images/        # 宣传图
├── Makefile
├── README.md
├── CLAUDE.md      # 指向 AGENTS.md
└── AGENTS.md      # 顶层贡献守则(DDD、TDD、TypedDict 等)

顶层 AGENTS.md 直接声明了工程规范:

  • 后端遵循 DDD + Clean Architecture
  • 异步任务通过 Celery + Redis Broker
  • 测试必须 TDD(红 → 绿 → 重构)
  • 严禁 Any,优先 TypedDict
  • 前端 i18n 强制 web/i18n/en-US/

这些准则体现在整个 codebase 的每一层实现中。


3. 后端 API 架构(api/)——DDD 分层剖析

3.1 五层架构地图

api/
├── controllers/     ← Presentation(HTTP 层)
│   ├── console/     # 控制台 API(管理员/工作空间)
│   ├── service_api/ # 外部服务 API(Bearer API Key)
│   ├── web/         # Web App 嵌入 API(EndUser 上下文)
│   ├── inner_api/   # 内部服务间 RPC
│   ├── files/       # 文件上传下载
│   ├── trigger/     # Webhook 触发
│   └── mcp/         # MCP 协议
├── services/        ← Application(用例编排)
│   ├── app_service.py
│   ├── workflow_service.py
│   ├── dataset_service.py
│   ├── conversation_service.py
│   ├── account_service.py
│   └── ...50+ 服务
├── core/            ← Domain / Engine(核心业务规则)
│   ├── app/
│   ├── workflow/
│   ├── rag/
│   ├── agent/
│   ├── tools/
│   ├── plugin/
│   ├── model_manager.py
│   ├── provider_manager.py
│   └── ...
├── models/          ← Data(SQLAlchemy ORM)
│   ├── model.py
│   ├── account.py
│   ├── dataset.py
│   └── workflow.py
├── repositories/    ← Repository(ORM 抽象)
│   └── sqlalchemy_*_repository.py
├── tasks/           ← Celery 异步任务
├── schedule/        ← 定时任务
├── extensions/      ← Infrastructure(Flask 扩展)
│   ├── ext_database.py
│   ├── ext_redis.py
│   ├── ext_celery.py
│   ├── ext_login.py
│   ├── ext_storage.py
│   ├── ext_blueprints.py
│   └── ...
├── events/          ← 领域事件
├── factories/       ← 工厂(文件、对象)
├── migrations/      ← Alembic 迁移
├── contexts/        ← 请求上下文变量
├── configs/         ← Pydantic 配置分组
├── app.py           ← 入口
├── app_factory.py   ← 工厂函数 + 扩展装配
├── dify_app.pyDifyApp(Flask 子类)
└── celery_entrypoint.py

3.2 Controllers —— HTTP 表现层

api/extensions/ext_blueprints.py 负责注册 6 大 Blueprint,每个带差异化 CORS 策略:

BlueprintURL 前缀认证方式目标用户
console_app_bp/console/apiJWT(Passport)控制台管理员
service_api_bp/v1Bearer API Key第三方开发者
web_bp/apiWebApp Passport(可选)C 端访客
files_bp/files签名 URL / Token文件直传
inner_api_bp内部Inner API Key插件守护进程
mcp_bp/mcp令牌MCP 客户端

控制台 API 按领域拆分子目录: app/auth/datasets/workspace/billing/explore/

创建应用 为例(api/controllers/console/app/app.py):

@login_required                                    # Flask-Login
@account_initialization_required                   # 账号激活校验
@cloud_edition_billing_resource_check('apps')      # 计费资源校验
@is_admin_or_owner_required                        # RBAC
def post(self):
    payload = CreateAppPayload.parse_obj(request.json)
    app = AppService().create_app(payload, current_user)
    return marshal(app, app_fields), 201

关键点:

  • 装饰器堆叠实现 AOP:认证 → 激活 → 计费 → 权限
  • 使用 Flask-RESTX 构建资源类
  • Pydantic 做入参校验,Flask-RESTX fields 做出参序列化

3.3 Services —— 应用层编排

Services 层负责用例编排,协调 Core 引擎、Model、Repository、Task、Event,不包含 HTTP 细节。

典型:api/services/workflow_service.py(约 1700 行)

class WorkflowService:
    def draft_workflow_version_to_graph(self, ...) -> Graph: ...
    def execute(self, ...) -> Generator[GraphEngineEvent, None, None]: ...
    def publish_draft(self, ...) -> WorkflowVersion: ...

服务调用图:

Controller
    ↓
WorkflowService.execute()
    ├──→ core.workflow.workflow_entry.WorkflowEntry
    ├──→ core.model_manager.ModelManager
    ├──→ core.tools.tool_manager.ToolManager
    ├──→ repositories.WorkflowExecutionRepository(持久化)
    ├──→ tasks.async_workflow_tasks(异步分发)
    └──→ events.app_was_updated(领域事件)

api/services/async_workflow_service.py 是生产环境下的关键:它不执行工作流,只是创建 WorkflowTriggerLog 并根据租户计划(sandbox / team / professional)路由到不同的 Celery 队列,立刻返回 trigger_log_id。客户端轮询或接收 Webhook 拉取结果。

3.4 DDD 的落地技巧

  • 依赖注入:Service 构造函数显式接收 Repository / Manager,便于测试替换
  • 领域事件:events/ 目录发布 app_was_createddocument_was_deleted,下游(通知、埋点)订阅
  • 上下文变量:api/contexts/wrapper.pyRecyclableContextVar 承载 current_usercurrent_tenantrequest_id,请求结束自动清理
  • 多租户隔离:所有核心表均带 tenant_id,查询层默认按当前租户过滤,防止越权

4. 后端启动链路与扩展机制

4.1 入口 api/app.py

# 根据命令行参数分叉:迁移 vs 正常启动
if flask_migrate:
    flask_app = create_migrations_app()
else:
    socketio_app, flask_app = create_app()
    celery = flask_app.extensions["celery"]

入口同时绑定 WebSocket (SocketIO) 与 Flask,用 Gevent 事件循环,监听 0.0.0.0:5001

4.2 工厂函数 api/app_factory.py

关键流程(第 49–231 行):

  1. 实例化 DifyApp(Flask 子类):api/dify_app.py 仅加了 login_manager: DifyLoginManager 类型提示,提供类型安全
  2. dify_config.model_dump() 加载 Pydantic 配置:聚合 configs/deploy/feature/middleware/extra/observability/enterprise/packaging/ 各子配置
  3. before_request:初始化日志上下文 + 线程回收 + 企业证书检查(INACTIVE/EXPIRED 时除白名单端点外全部拦截)
  4. after_request:注入 X-Trace-Id / X-Span-Id
  5. initialize_extensions():按严格顺序装配 28 个扩展

4.3 扩展装配顺序(关键)

ext_timezone → ext_logging → ext_warnings → ext_import_modules
→ ext_orjson → ext_forward_refs → ext_set_secretkey → ext_compress
→ ext_code_based_extension 
→ ext_database (SQLAlchemy + gevent 兼容)
→ ext_app_metrics → ext_migrate
→ ext_redis → ext_storage (依赖 redis) → ext_logstore (依赖 storage)
→ ext_celery (依赖 logstore)
→ ext_login → ext_mail → ext_hosting_provider
→ ext_sentry → ext_proxy_fix
→ ext_blueprints (最后注册,此时依赖都就绪)
→ ext_commands → ext_fastopenapi → ext_otel
→ ext_enterprise_telemetry → ext_request_logging → ext_session_factory

注意 gevent 兼容性 (api/extensions/ext_database.py):注册了 SQLAlchemy Pool reset 事件监听器,在 greenlet 切换时安全 rollback,防止连接状态泄漏。这是高并发场景稳定运行的关键。

4.4 配置系统

api/configs/app_config.pyDifyConfig 继承 BaseSettings,聚合多个配置分组。通过 Pydantic 自动从 .env 和环境变量解析,支持 Apollo / Nacos 远端配置中心。


5. Core 核心引擎深度解读

api/core/ 共 500+ Python 文件,是 Dify 的"发动机"。

5.1 应用运行器(App Runner)

5 种应用类型对应 5 套运行器:

类型运行器用途
CHATChatAppRunner多轮对话
COMPLETIONCompletionAppRunner单次生成
AGENT_CHATAgentChatAppRunnerAgent 循环决策
ADVANCED_CHATAdvancedChatAppRunner高级聊天(绑定工作流)
WORKFLOWWorkflowAppRunner纯工作流

基类 api/core/app/apps/base_app_runner.py 定义:

class AppRunner:
    def recalc_llm_max_tokens(...)  # 根据历史长度动态调整 max_tokens
    def organize_prompt_messages(...) # 系统提示 + 历史 + 上下文 + 查询
    def direct_output(...)          # 直接输出(moderation 命中时)

AppQueueManager —— 事件流核心

api/core/app/apps/base_app_queue_manager.py

class AppQueueManager:
    def publish(self, event: QueueEvent, publish_from): ...

事件体系:

事件语义
QueueLLMChunkEventLLM 流式 token
QueueMessageEndEvent消息结束
QueueAgentMessageEventAgent 思考 / 工具调用
QueueMessageFileEvent附件
QueueWorkflowStartedEvent工作流开始
QueueNodeStartedEvent / QueueNodeSucceededEvent节点生命周期

事件消费端把事件转译成 SSE(Server-Sent Events) 流回前端,驱动工作流画布节点高亮、聊天窗口流式输出。

5.2 工作流引擎(Workflow Engine)

核心哲学:把整个应用建模为一张有向图,节点是执行单元,边是数据流。这张图可序列化为 JSON DSL,可以在前端画布上可视化编辑。

关键组件

组件文件职责
WorkflowEntryapi/core/workflow/workflow_entry.py工作流入口,初始化 GraphEngine
DifyNodeFactoryapi/core/workflow/node_factory.py节点工厂(自注册)
VariablePool来自 graphon.VariablePool跨节点变量容器
GraphRuntimeState来自 graphon运行时状态机
Layersgraphon可堆栈中间件

GraphEngine 中间件堆栈

engine = GraphEngine(graph, variable_pool, state)
engine.use(DebugLoggingLayer())        # 调试日志
engine.use(ExecutionLimitsLayer(...))  # 最大步数 / 最大耗时
engine.use(LLMQuotaLayer(...))         # LLM 配额
engine.use(ObservabilityLayer(...))    # OTEL Trace

每层封装 run() 方法,实现类似 Express/Koa 的洋葱模型。

节点类型(40+)

启动类(_START_NODE_TYPES):

  • START——标准入口
  • DATASOURCE——数据源触发
  • WEBHOOK / SCHEDULE / PLUGIN——三类触发器

流控类:IF_ELSEITERATIONLOOPVARIABLE_AGGREGATOR

AI 类:LLMAGENTPARAMETER_EXTRACTORQUESTION_CLASSIFIER

集成类:HTTP_REQUESTTOOLCODETEMPLATE_TRANSFORM

知识类:KNOWLEDGE_RETRIEVALKNOWLEDGE_INDEX

输出类:ENDANSWER

节点类自动通过 Node.register() 注册到 Node.get_node_type_classes_mapping(),支持 多版本共存(v1、latest),运行时按版本匹配。

变量池与 Selector

变量池使用 列表路径 作为 key:

pool.add(["llm_1", "output"], "..."])
pool.get(["llm_1", "structured_output", "field_name"])

前端 {{#llm_1.output#}} 解析成 VariableSelector = ["llm_1", "output"],底层用同一套访问协议。

事件流

GraphEngineEvent(基类)
├── GraphNodeEventBase
│   ├── WorkflowNodeExecutionStarted
│   ├── WorkflowNodeExecutionSucceeded
│   ├── WorkflowNodeExecutionFailed
│   └── NodeStreamChunkEvent(流式输出)
├── GraphRunSucceededEvent
├── GraphRunFailedEvent
└── GraphEngineMetricsEvent

WorkflowEntry.run() 返回 Generator[GraphEngineEvent],上层订阅并持久化 WorkflowNodeExecutionModel,同时 Push 到前端 SSE。

5.3 Agent 运行时(Agent Runtime)

api/core/agent/ 提供两种 Agent 策略:

FC Agent(Function Calling)

api/core/agent/fc_agent_runner.py

while True:
    result = llm.invoke(messages, tools=tool_schemas, stream=True)
    tool_calls = parse_tool_calls(result)
    if not tool_calls:
        break
    for tc in tool_calls:
        tool = tool_manager.get(tc.name)
        obs  = tool.invoke(tc.params)
        messages.append(ToolPromptMessage(obs))

依赖 OpenAI / Anthropic 原生函数调用能力,Token 效率高、稳定性好,推荐优先使用。

CoT Agent(Chain-of-Thought / ReAct)

api/core/agent/cot_agent_runner.py

使用固定 Prompt 模板约束 LLM 输出结构:

Thought: 我需要查询天气
Action: get_weather
Action Input: {"city": "Beijing"}
Observation: 晴朗,25°C
Thought: 我已经有信息了
Final Answer: 今天北京晴朗,25°C

适合不支持原生 Function Call 的模型(LLaMA、ChatGLM 等)。

TokenBufferMemory

api/core/memory/token_buffer_memory.py

def get_history_prompt_messages(
    max_token_limit: int = 2000,
    message_limit: int = 500,
) -> Sequence[PromptMessage]:

从最新消息倒序累加,超出 token 预算则丢弃最早消息。支持多模态(图像内容也计入 Token)。

5.4 RAG 管道与向量数据库

api/core/rag/ 是 Dify 知识库能力的核心。

子目录地图

rag/
├── extractor/         # 文档提取(PDF/Excel/Notion/Markdown/HTML/Firecrawl/JinaReader)
├── splitter/          # 文本分割(递归字符/句子/ETC 中文/Token)
├── cleaner/           # 文本清洗(去 HTML、去脚注、去重复)
├── embedding/         # 嵌入
│   ├── embedding_base.py
│   ├── cached_embedding.py    # Redis 缓存层
│   └── retrieval.py
├── datasource/
│   ├── vdb/                    # 向量数据库适配器
│   │   ├── vector_factory.py
│   │   ├── vector_base.py
│   │   ├── qdrant_vector.py
│   │   ├── milvus_vector.py
│   │   ├── weaviate_vector.py
│   │   ├── pgvector/
│   │   ├── chroma_vector.py
│   │   ├── tidb_on_qdrant_vector.py
│   │   ├── oracle_vector.py
│   │   └── ...(20+ VDB)
│   ├── keyword/                # Jieba 分词 + BM25 倒排
│   └── retrieval_service.py
├── rerank/            # 重排
│   ├── rerank_model.py         # 模型重排(Cohere/Jina)
│   └── weight_rerank.py        # 权重加权
├── index_processor/   # 索引构建策略
│   └── processor/
│       ├── paragraph_index_processor.py
│       ├── qa_index_processor.py
│       └── parent_child_index_processor.py
└── retrieval/         # 检索路由
    ├── dataset_retrieval.py
    └── router/                 # 多数据集路由

支持的向量数据库

通过 api/core/rag/datasource/vdb/vector_type.py:

QDRANTMILVUSWEAVIATEPGVECTORCHROMAPGVECTO_RSTIDB_VECTORTIDB_ON_QDRANTORACLERELYTOPENSEARCHELASTICSEARCHTENCENTANALYTICDBCOUCHBASEVIKINGDBLINDORMOCEANBASEBAIDUUPSTASHMYSCALEVASTBASE 等。

统一接口 VectorBase:

class VectorBase:
    def create(self, texts, embeddings, **kwargs): ...
    def add_texts(self, documents, embeddings, **kwargs): ...
    def search_by_vector(self, query_vector, **kwargs): ...
    def search_by_full_text(self, query, **kwargs): ...
    def delete_by_ids(self, ids): ...
    def delete_by_metadata_field(self, key, value): ...

RetrievalService 检索管道

api/core/rag/datasource/retrieval_service.py

用户查询
  ↓
RetrievalService.retrieve(retrieval_method=HYBRID)
  ↓
ThreadPoolExecutor 并发:
   ├─ Vector.search_by_vector(embed(query))      # 语义召回
   └─ Vector.search_by_full_text(query)           # 全文召回
  ↓
DataPostProcessor:
   ├─ 去重(按 segment_id)
   ├─ Rerank(模型重排 或 权重加权)
   └─ score_threshold 过滤 + top_k 截断
  ↓
return list[Document]

索引策略(IndexProcessor)

  • Paragraph:段落级分块,最常用
  • QA:LLM 自动为每段生成 QA 对后索引,召回率更高
  • Parent-Child:父子分段,父段用于上下文,子段用于精确召回

嵌入缓存

api/core/rag/embedding/cached_embedding.py 将文本哈希作为 Redis key,避免重复 embedding。文档重建索引时节省 70%+ 调用费用。

5.5 Model Runtime 与 Provider 体系

ModelManager

api/core/model_manager.py 提供统一模型调用入口:

class ModelManager:
    def get_model_instance(self, tenant_id, provider, model_type, model) -> ModelInstance: ...

class ModelInstance:
    def invoke_llm(prompt_messages, tools=None, stream=True, ...) -> Union[LLMResult, Generator]: ...
    def invoke_text_embedding(texts) -> TextEmbeddingResult: ...
    def invoke_rerank(query, docs) -> RerankResult: ...
    def invoke_moderation(text) -> ModerationResult: ...
    def invoke_tts(text) -> Generator[bytes]: ...
    def invoke_speech2text(file) -> str: ...

ProviderManager

api/core/provider_manager.py 管理租户级配置:

  • Hosting Provider:Dify 云服务免费额度 (quota_type/quota_limit)
  • Custom Provider:用户自己填写 API Key
  • 负载均衡:一个模型配置多组凭证,轮询使用
  • 配额限流:按租户/模型粒度的日请求数/Token 数配额

Provider 注册机制

Provider 定义在独立的 graphon 库 或 Plugin 中,每个 Provider 包含:

<provider_name>/
├── provider.yaml         # 元数据(名称/图标/支持模型类型)
├── _common.py            # 凭证校验
├── llm.py                # LargeLanguageModel 实现
├── text_embedding.py     # TextEmbeddingModel
├── rerank.py             # RerankModel
├── moderation.py         # ModerationModel
├── tts.py / speech2text.py
└── models/               # 模型 schema(上下文长度/价格/能力标签)
    ├── gpt-4o.yaml
    └── ...

YAML 驱动 + Python 实现,易于扩展。

5.6 工具系统(Tools Subsystem)

api/core/tools/5 类 Provider:

类型目录场景
BUILTINbuiltin_tool/providers/内置(Google/Slack/GitHub 等)
APIcustom_tool/OpenAPI Spec 导入
PLUGINplugin_tool/第三方插件
WORKFLOWworkflow_as_tool/工作流作为工具被别的 App 调用
MCPmcp_tool/Model Context Protocol 工具

统一抽象 Tool 基类:

class Tool(ABC):
    @property
    def identity(self) -> ToolIdentity: ...
    @property
    def parameters(self) -> list[ToolParameter]: ...
    def invoke(self, tool_parameters: dict) -> ToolInvokeMessage: ...

ToolManager.get_tool_runtime() 根据 provider_type 返回对应子类实例,Agent / Tool Node 统一通过 tool.invoke() 调用。

特殊工具:DatasetRetrieverTool 把知识库包装成 Agent 可调用的工具,实现 RAG 与 Agent 的融合。

5.7 插件系统(Plugin System)

Dify 的插件运行在 独立 Go 进程 plugin_daemon 中,API 服务通过 RPC 调用。这种设计带来:

  • 进程隔离:插件崩溃不影响 API
  • 多语言支持:插件可用 Python/Node/Go 等实现,由 daemon 统一托管
  • 资源限制:daemon 可施加 CPU / 内存 / 超时限制
  • 安全签名:FORCE_VERIFYING_SIGNATURE=true 强制验证插件签名

核心类:

一个插件包(.difypkg) 可以同时声明:Tool + Model + Endpoint(HTTP 路由) + Agent Strategy + Datasource

5.8 记忆、Prompt 与 Moderation

Prompt Transform

Moderation

api/core/moderation/ 支持输入审核输出审核两道关:

  • InputModeration:Keyword / OpenAI Moderation API / 自定义 API
  • OutputModeration:流式 chunk 到达时实时审核,命中敏感词立即中止

ModerationAction:

  • DIRECT_OUTPUT:命中时直接返回预设 "抱歉我不能回答"
  • OVERRIDDEN:用占位符覆盖敏感输入

6. 数据模型与数据库设计

6.1 核心 ER 图(文字版)

Tenant(工作空间)
 ├ 1:N TenantAccountJoin ── N:1 Account
 │                         (role: OWNER/ADMIN/EDITOR/NORMAL/DATASET_OPERATOR)
 ├ 1:N App
 │    ├ 1:1 AppModelConfig
 │    ├ 1:N Workflow ── 1:N WorkflowNodeExecution
 │    ├ 1:N Conversation ── 1:N Message
 │    │                              ├ 1:N MessageFile
 │    │                              ├ 1:N MessageFeedback
 │    │                              └ 1:N MessageAgentThought
 │    ├ 1:1 Site(分享页配置)
 │    └ 1:N ApiToken1:N Dataset
 │    └ 1:N Document ── 1:N DocumentSegment ── 1:N ChildChunk1:N EndUser(C 端用户)
 ├ 1:N Provider ── 1:N ProviderModel1:N Tag ── N:M TagBinding

6.2 关键表

api/models/model.py:

说明
App应用,mode ∈ {chat, completion, agent_chat, advanced_chat, workflow}
AppModelConfig应用模型配置(prompt/参数/数据集引用)
Conversation会话,区分 from_source(console/api/web)
Message消息对,content 含角色和文本
MessageFeedbacklike/dislike 评分,评审意见
MessageAgentThoughtAgent 思考链(tool_name/inputs/thought)
EndUserC 端匿名访客(session_id)
ApiToken应用级 API Key
UploadFile上传文件映射到存储 key

api/models/account.py:AccountTenantTenantAccountJoin(关键的租户-用户-角色三元组)

api/models/dataset.py:DatasetDocumentDocumentSegmentChildChunkEmbeddingDatasetPermissionPipeline

api/models/workflow.py:Workflow(graph 字段为 JSON DSL)、WorkflowVersionWorkflowNodeExecutionModelWorkflowRun

6.3 多租户与 RBAC

  • TenantAccountRole 枚举:OWNER / ADMIN / EDITOR / NORMAL / DATASET_OPERATOR
  • 所有资源表通过 tenant_id FK 物理隔离
  • Service 层默认拼接 tenant_id = g.current_tenant.id
  • Dataset 额外支持 DatasetPermission(按成员授权)

6.4 迁移

api/migrations/versions/ 数百个 Alembic 脚本,命名类似 2024_01_01_xxxx_add_foo_column.py。升级命令:

uv run --project api flask db upgrade

7. Celery 任务队列与异步子系统

7.1 配置

api/extensions/ext_celery.py 要点:

  • Broker: Redis(支持 Sentinel 故障转移)
  • Backend: Redis(结果持久化)
  • 自定义 FlaskTask 包装:确保每个 Task 都运行在 Flask app 上下文 + 日志上下文中
  • 支持 SSL Broker(BROKER_USE_SSL=true)

7.2 任务分类

api/tasks/:

类别代表任务
RAG 索引document_indexing_taskadd_document_to_index_taskdeal_dataset_vector_index_task
RAG 清理batch_clean_document_taskclean_document_taskdelete_segment_from_index_task
工作流execute_workflow_professional/team/sandbox(按计划分流)
会话delete_conversation_task
邮件mail_invite_member_taskmail_email_code_login_task
企业enterprise_telemetry_task

api/schedule/:

定时任务作用
clean_messages定期清理旧消息
clean_workflow_runs_task归档工作流运行记录
queue_monitor_task健康监控
workflow_schedule_taskCron 触发工作流

7.3 队列分流(生产推荐)

# 按业务队列分工作进程,避免重任务阻塞轻任务
@celery.task(queue="dataset")
def document_indexing_task(...): ...

@celery.task(queue="workflow_professional")
def execute_workflow_professional(...): ...

启动多实例:

celery -A celery_entrypoint worker -Q dataset -c 4 --loglevel=info
celery -A celery_entrypoint worker -Q workflow_professional -c 8
celery -A celery_entrypoint beat --loglevel=info

8. 前端 Web 架构(web/)

8.1 技术栈

维度选型
框架Next.js 15(App Router + RSC)
语言TypeScript strict
状态Zustand(多 slice) + Jotai(原子)
数据获取ORPC 类型安全 + TanStack React Query + SWR
UITailwind CSS + CVA + Headless UI + Floating UI
编辑器ReactFlow(工作流) + Lexical(富文本) + Monaco(代码)
图表Mermaid + ECharts
i18ni18next(23 种语言)
构建Turbopack + standalone output

8.2 目录核心组

web/app/ 使用 Route Groups(括号目录)做布局分组:

  • (commonLayout) —— 控制台核心(应用/数据集/插件/工具/探索)
  • (shareLayout) —— 公开分享页(chat/workflow 等免登录嵌入)
  • (humanInputLayout) —— 人工表单
  • account/ —— 账户设置 + OAuth

web/app/components/ 组织:

  • base/ —— 基础组件(chat/form/icons/prompt-editor/file-uploader 等)
  • app/ —— 应用编辑器
  • workflow/ —— 工作流画布(下节重点)
  • datasets/ —— 知识库 UI
  • plugins/ —— 插件市场

8.3 工作流编辑器——Zustand 多 Slice

web/app/components/workflow/store/workflow/ 将巨大的 workflow store 拆成独立 slice:

Slice职责
workflow-slice工作流元数据
node-slice节点集合 / 坐标
form-slice节点配置表单
panel-slice左右面板开关
env-variable-slice环境变量
chat-variable-slice会话变量
version-slice版本控制
history-slice撤销重做
layout-slice缩放 / 迷你图
comment-slice协作注释(WebSocket)
debug/inspect-vars-slice调试变量检查

所有 slice 合并为单个 Zustand store,既避免 prop drilling,又保持关注点分离。

8.4 工作流运行时 UI 更新

web/app/components/workflow/hooks/use-workflow-run-event/ 订阅后端 SSE:

前端 fetch('/console/api/apps/.../workflows/draft/run', { method: POST })
    ↓ Response.body 读取流
    ↓ 解析 data: {...} 行
    ↓ 识别事件类型并分发到 store
        ├─ workflow_started    → 画布进入运行态
        ├─ node_started        → 节点高亮脉冲动画
        ├─ text_chunk          → LLM 流式追加
        ├─ node_finished       → 节点变色 + 输出面板填充
        ├─ agent_thought       → Agent 日志面板追加
        └─ workflow_finished   → 结束,写入运行记录

8.5 前端构建

web/Dockerfile 采用 多阶段构建:

base(node:22-alpine, pnpm) 
  → packages(仅装依赖,最大化缓存)
  → builder(pnpm build + build:vinext,产出 .next/standalone)
  → production(只搬 standalone,非 root 运行)

output: 'standalone' 极大减少镜像体积(700MB → 100MB)。


9. Docker 部署拓扑与生产化配置

9.1 Compose 服务矩阵

docker/docker-compose.yaml 声明的关键服务:

服务镜像端口职责
apilanggenius/dify-api:1.13.x5001Flask API
worker同上(MODE=worker)-Celery 异步
worker_beat同上(MODE=beat)-定时任务
weblanggenius/dify-web:1.13.x3000Next.js
dbpostgres:15-alpine5432元数据
redisredis:7-alpine6379Broker / Cache
sandboxlanggenius/dify-sandbox:0.2.x8194代码执行沙箱
plugin_daemonlanggenius/dify-plugin-daemon:0.5.x5002插件运行时
ssrf_proxyubuntu/squid:latest3128防 SSRF
nginxnginx:latest80/443反向代理
weaviatesemitechnologies/weaviate8080向量库(默认)
可选qdrant/milvus/pgvector/chroma/elasticsearch/opensearch/tidb/oceanbase/clickhouse/minio按需其他后端

9.2 网络与数据流

            ┌──── 用户/第三方
            ▼
       Nginx(80/443)
            │
     ┌──────┼──────┐
     ▼             ▼
   web(3000)   api(5001)
                  │
     ┌────┬──────┼────────┬───────────┐
     ▼    ▼      ▼        ▼           ▼
  postgres redis weaviate sandbox plugin_daemon
                          │
                          ▼
                     ssrf_proxy(3128)
                          │
                          ▼
                      Internet

两个独立网络:

  • default —— 主服务通信
  • ssrf_proxy_network —— 只有 sandbox / api / ssrf_proxy 能加入,确保外网请求必须过代理

9.3 Sandbox 的安全设计

docker-compose.yaml 中 sandbox 服务:

  • 容器级隔离(独立 PID/NS/FS)
  • HTTP_PROXY=http://ssrf_proxy:3128 强制代理外网
  • WORKER_TIMEOUT=15 单次执行上限
  • ENABLE_NETWORK=true/false 控制是否联网
  • /dependencies 预装常用 Python 包

9.4 SSRF Proxy(Squid)

docker/ssrf_proxy/squid.conf.template 禁止访问私网:

acl private src 10.0.0.0/8
acl private src 172.16.0.0/12
acl private src 192.168.0.0/16
acl private src 127.0.0.0/8
http_access deny private

防止攻击者利用 HTTP 节点或代码节点访问云元数据服务(如 169.254.169.254)。

9.5 Plugin Daemon 配置

SERVER_PORT=5002
PLUGIN_DAEMON_KEY=...
DIFY_INNER_API_URL=http://api:5001
PLUGIN_WORKING_PATH=/app/storage/cwd
PLUGIN_MAX_EXECUTION_TIMEOUT=600
FORCE_VERIFYING_SIGNATURE=true
PLUGIN_STORAGE_TYPE=local  # 或 s3

9.6 数据卷

./volumes/
├── app/storage          # 应用上传/导出
├── db/postgres          # PG 数据
├── sandbox/dependencies # pip 缓存
├── plugin_daemon        # 插件包
├── weaviate             # 向量库
└── certbot              # SSL 证书

10. 生产环境最佳实践与运维手册

10.1 快速启动(开发)

cd dify/docker
cp .env.example .env
# 按需修改 .env(至少:SECRET_KEY / DB_PASSWORD / REDIS_PASSWORD)
docker compose up -d
# 访问 http://localhost/install 完成首次初始化

10.2 生产硬化清单

密钥与证书

  • SECRET_KEY 生成 64 字节随机值:openssl rand -base64 42
  • DB_PASSWORD / REDIS_PASSWORD / WEAVIATE_API_KEY / PLUGIN_DAEMON_KEY 全部修改
  • INIT_PASSWORD 设为强密码或仅首次启动后置空
  • Nginx 开启 HTTPS:挂载 certbot 证书 + 配置 conf.d/ssl.conf

数据库

  • 使用 外部托管 PostgreSQL(RDS / Cloud SQL / 自建高可用主从),不用 compose 内嵌 PG
  • 配置备份:每日 pg_dump + WAL 归档
  • 连接池:SQLALCHEMY_POOL_SIZE=30SQLALCHEMY_POOL_RECYCLE=3600

Redis

  • 开启 Sentinel 或使用托管 Redis
  • maxmemory-policy allkeys-lru
  • Broker 与 Cache 使用不同 DB 编号分离

存储

  • 切换 STORAGE_TYPE=s3(或 OSS/Azure),不用本地卷
  • 启用版本化与生命周期策略

向量数据库

  • 超过 100 万向量推荐 Qdrant / Milvus,不再用 Weaviate 默认配置
  • 配置持久化卷 + 副本

扩容

  • API 服务横向扩展:SERVER_WORKER_AMOUNT=gevent worker 数,配合 Nginx upstream
  • Worker 按队列分工:
worker_dataset:
  image: dify-api
  command: celery -A app.celery worker -Q dataset -c 8
worker_workflow:
  image: dify-api
  command: celery -A app.celery worker -Q workflow -c 16
worker_mail:
  image: dify-api
  command: celery -A app.celery worker -Q mail -c 2

可观测性

  • SENTRY_DSN 配置 Sentry
  • ENABLE_OTEL=true + OTEL_EXPORTER_OTLP_ENDPOINT 对接 Jaeger/Tempo/阿里云 ARMS
  • 配置 Langfuse / Opik / Arize Phoenix 做 LLM 调用追踪(在应用设置里开启)

安全

  • 保留 ssrf_proxy 服务,不要删
  • FORCE_VERIFYING_SIGNATURE=true 防止未审核插件安装
  • /console/api 配置 IP 白名单或 VPN 访问
  • MAX_TOOLS_NUMAPP_MAX_EXECUTION_TIME 设合理上限,防止租户滥用

10.3 备份与恢复

# 数据库备份
docker exec dify-db pg_dump -U postgres dify > backup_$(date +%F).sql

# 文件卷备份
tar czf dify_volumes_$(date +%F).tgz docker/volumes/

# 向量库(Weaviate)
curl -X POST "http://localhost:8080/v1/backups/filesystem" \
  -H "Content-Type: application/json" \
  -d '{"id":"backup-$(date +%s)"}'

10.4 灰度发布

  • 前端 web 多版本通过 Nginx weight 做灰度
  • 后端 api 通过 Feature Flag(configs/feature/)按租户开关

11. 二次开发指南:扩展节点、工具、模型

11.1 新增自定义工作流节点

以新增一个"邮件发送"节点为例:

  1. api/core/workflow/nodes/mail/ 新建目录
  2. 定义 MailNodeData(Pydantic):
class MailNodeData(BaseNodeData):
    to: list[str]
    subject: str
    body_template: str
  1. 实现 MailNode:
from core.workflow.nodes.base.node import Node

@Node.register(NodeType.MAIL)
class MailNode(Node[MailNodeData]):
    version = "1"

    def run(self) -> Generator[GraphNodeEventBase, None, None]:
        yield WorkflowNodeExecutionStarted(...)
        to   = self.data.to
        body = render_template(self.data.body_template, self.variable_pool)
        send_mail(to, self.data.subject, body)
        yield WorkflowNodeExecutionSucceeded(outputs={"sent": True})
  1. 前端 web/app/components/workflow/nodes/mail/ 添加节点渲染与配置面板
  2. 注册到 BLOCK_ENUM 和 i18n 键

11.2 新增内置工具

api/core/tools/builtin_tool/providers/<name>/:

my_provider/
├── my_provider.yaml       # 提供者元数据
├── my_provider.py         # Provider 类(凭证校验)
└── tools/
    ├── my_tool.yaml       # 工具参数 schema
    └── my_tool.py         # Tool 实现(invoke 方法)
class MyTool(BuiltinTool):
    def _invoke(self, user_id: str, tool_parameters: dict) -> ToolInvokeMessage:
        result = call_external_api(tool_parameters["query"])
        return self.create_json_message(result)

11.3 接入自定义 LLM 提供商

推荐通过 Plugin 实现(官方 SDK):

dify plugin init
dify plugin bundle
# 上传到 /console/api/workspaces/current/plugins/install/pkg

Plugin 里实现 LargeLanguageModel._invoke(),按统一协议返回 LLMResult

11.4 新增向量数据库适配器

api/core/rag/datasource/vdb/my_vdb/ 继承 BaseVector:

class MyVector(BaseVector):
    def create(self, texts, embeddings, **kwargs): ...
    def search_by_vector(self, query_vector, **kwargs) -> list[Document]: ...
    # 其余必需方法

然后在 vector_type.py 加枚举、vector_factory.py 注册工厂。


12. 典型业务场景案例

12.1 企业知识库问答

架构:Dataset(Knowledge Base) + Chat App + RAG Prompt

用户问题
  ↓
Chat App
  ↓ 自动触发知识库检索
KnowledgeRetrieval(hybrid 检索 + Rerank)
  ↓ 上下文拼入 Prompt
LLM (GPT-4o / Claude)
  ↓
回答 + 引用来源

配置要点:

  • Dataset 用 Parent-Child 分段 提高召回
  • Top-K = 4,Rerank 使用 Cohere rerank-v3
  • Prompt 加入"基于提供的上下文回答,不知道时如实说明"

12.2 智能客服(Agent + 多工具)

架构:AgentChat App + FC Agent

Tools:
  ├─ search_order(查询订单)
  ├─ refund_request(发起退款)
  ├─ get_logistics(查物流)
  └─ DatasetRetrieverTool(政策知识库)

系统 Prompt:
  "你是 XX 客服,必须基于工具获取真实数据才能回答,
   涉及退款金额必须让用户二次确认..."

使用 FC Agent 而非 CoT,因为 GPT-4 的原生 FC 更稳定。 工具调用要加 confirm_required 机制(Dify 支持在工具中声明)。

12.3 复杂业务流(Workflow 编排)

场景:合同审查

Start(上传合同 PDF)
  → KnowledgeIndex(临时索引)
  → LLM(提取关键条款)
  → IF_ELSE(判断是否有违规条款)
      ├─ true → LLM(生成修订建议) → End(返回修订版)
      └─ false → LLM(生成审查报告) → End(通过)

利用 IF_ELSE + ITERATION 可以处理批量合同。

12.4 定时数据拉取 + 报告生成

ScheduleTrigger(每天 08:00)
  → HTTP_REQUEST(拉取业务指标 API)
  → Code(Pandas 分析)
  → LLM(生成自然语言报告)
  → Tool:send_mail(发给老板)

13. 性能调优、安全加固与排障手册

13.1 性能优化

瓶颈排查优化
LLM 调用慢查看 Message.provider_response_latency开启 stream、换更快模型、配负载均衡
知识库召回慢Vector DB 监控索引 HNSW 参数、增加副本、用 Qdrant 替换 Weaviate
Worker 堆积celery -A app.celery inspect active增加 worker 实例、分队列、提高并发
API 响应慢看 Gunicorn/Gevent worker 利用率增加 SERVER_WORKER_AMOUNT
DB 慢查询pg_stat_statements看缺失索引、分页改游标
Redis 压力redis-cli --stat拆 Broker/Cache 实例、调大 maxmemory

13.2 常见故障与解法

症状可能原因解决
前端白屏,控制台 401JWT 过期 / cookie 域配错检查 NEXT_PUBLIC_COOKIE_DOMAIN
应用卡在 "生成中"SSE 被 Nginx 缓冲Nginx 加 proxy_buffering off; proxy_read_timeout 300s;
工作流 Code 节点超时sandbox 超时默认 15s加大 WORKER_TIMEOUT,或 Celery 异步化
知识库索引失败嵌入模型凭证失效控制台 → 模型供应商 → 重新填写 Key
插件安装失败签名验证未通过要么关闭 FORCE_VERIFYING_SIGNATURE,要么改用官方签名插件
HTTP 节点访问内网失败SSRF Proxy 拦截按需修改 Squid ACL 允许特定内网段

13.3 安全加固

  • RCE 防护:Code 节点依赖 Sandbox 容器隔离,不要禁用
  • SSRF 防护:保留 ssrf_proxy,不直接给 API 容器外网出口
  • 凭证加密:DB 里的 Provider 凭证默认对称加密,SECRET_KEY 泄露等于凭证泄露,必须换
  • 审计日志:OperationLog 表记录所有管理操作,对接 SIEM
  • 限流:/console/api/login 前加 Nginx rate limit 防爆破

14. 总结:Dify 的设计哲学

14.1 工程原则

  1. DDD + Clean Architecture:Controller / Service / Core / Model 严格分层,依赖单向
  2. Core 是引擎,Service 是用例:换掉 Flask 不影响 Core
  3. Everything is a Graph:工作流是图,Agent 内部也是图
  4. Everything is a Provider:Model / Tool / VectorDB / Storage 都走工厂 + 策略
  5. 同构可替换:一个 LLM 节点可以调用 OpenAI、也可以调用本地 vLLM,代码路径一致
  6. 异步优先:所有耗时任务经 Celery,API 只做编排
  7. 多租户一等公民:tenant_id 无处不在,权限前置

14.2 架构亮点

  • graphon + NodeFactory 自注册:新节点只需实现 + 装饰器,零配置接入
  • Layers 中间件堆栈:配额/超时/观测通过洋葱模型组合
  • 事件流 + SSE:前后端通过生成器 + 事件,天然支持流式体验
  • Plugin Daemon 进程隔离:插件崩溃不拖死主进程,又能支持多语言
  • 5 类 Tool Provider 统一:Builtin/API/Plugin/Workflow/MCP 在 Agent 眼里没有区别
  • Sandbox + SSRF Proxy 双隔离:安全左移,代码执行和外网访问都受控

14.3 适用场景

  • 企业内 AI 应用平台:多团队共用,按 Tenant 隔离
  • RAG 知识库服务:开箱即用的全套 RAG 能力
  • Agent 工作流自动化:可视化编排 + 定时触发 + HTTP/Webhook
  • 模型能力测试床:一个画布对比多个模型

14.4 使用边界

  • 不适合极端低延迟场景(<100ms 单调用)——Flask + Celery 链路较长
  • 不适合纯离线训练或大规模数据处理——定位是推理编排而非训练
  • 对图引擎依赖重:graphon 库的行为需要深入理解,否则魔改易出问题

附录 A:核心文件速查表

功能文件
后端入口api/app.py
工厂 / 扩展装配api/app_factory.py
路由注册api/extensions/ext_blueprints.py
登录 / JWTapi/extensions/ext_login.py
Celeryapi/extensions/ext_celery.py
数据库 + Geventapi/extensions/ext_database.py
工作流执行api/services/workflow_service.py
异步工作流api/services/async_workflow_service.py
工作流入口api/core/workflow/workflow_entry.py
节点工厂api/core/workflow/node_factory.py
Agent FCapi/core/agent/fc_agent_runner.py
Agent CoTapi/core/agent/cot_agent_runner.py
Model Managerapi/core/model_manager.py
Provider Managerapi/core/provider_manager.py
Tool Managerapi/core/tools/tool_manager.py
RAG 检索api/core/rag/datasource/retrieval_service.py
Vector 工厂api/core/rag/datasource/vdb/vector_factory.py
核心 ORMapi/models/model.py
租户 / 账号api/models/account.py
知识库 ORMapi/models/dataset.py
工作流 ORMapi/models/workflow.py
前端工作流 Storeweb/app/components/workflow/store/workflow/
Docker 编排docker/docker-compose.yaml
环境模板docker/.env.example

附录 B:关键环境变量对照

# ——— 基础 ———
SECRET_KEY=<openssl rand -base64 42>
DEPLOY_ENV=PRODUCTION
APP_MAX_EXECUTION_TIME=1200

# ——— 数据库 ———
DB_TYPE=postgresql
DB_HOST=prod-pg.internal
DB_PORT=5432
DB_USERNAME=dify
DB_PASSWORD=<strong>
DB_DATABASE=dify
SQLALCHEMY_POOL_SIZE=30
SQLALCHEMY_POOL_RECYCLE=3600

# ——— Redis ———
REDIS_HOST=prod-redis.internal
REDIS_PASSWORD=<strong>
CELERY_BROKER_URL=redis://:<pw>@prod-redis.internal:6379/1

# ——— 向量库 ———
VECTOR_STORE=qdrant
QDRANT_URL=http://qdrant.internal:6333
QDRANT_API_KEY=<key>

# ——— 存储 ———
STORAGE_TYPE=s3
S3_ENDPOINT=https://s3.ap-east-1.amazonaws.com
S3_BUCKET_NAME=dify-prod
S3_ACCESS_KEY=<>
S3_SECRET_KEY=<>

# ——— 安全 ———
FORCE_VERIFYING_SIGNATURE=true
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128

# ——— 观测 ———
SENTRY_DSN=https://<dsn>
ENABLE_OTEL=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318

本文档基于 Dify v1.13.x 源码分析撰写,覆盖后端、核心引擎、前端、部署、运维、二开全链路。源码结构会随版本演进,建议配合最新 AGENTS.mdapi/AGENTS.md 一起阅读。