> Dify工作流从0到1:可视化AI应用搭建完全指南

Dify工作流从0到1:可视化AI应用搭建完全指南

📅 2026-05-23 ⏱️ 阅读约25分钟 🏷️ AI工作流 · Dify · 教程

📋 目录

1. Dify是什么

Dify(DIY + Verify,意为"自己动手,验证想法")是一个开源的 LLM应用开发平台,其核心理念是让任何人都能通过可视化拖拽的方式搭建AI工作流,而无需编写大量胶水代码。它于2023年开源,支持接入 OpenAI、Anthropic Claude、国内通义千问/DeepSeek 等主流大模型。

官方定义:Dify是一个开源的LLM应用开发平台,提供可视化的工作流编排、知识库管理、模型接入、多端发布等能力。

对比传统开发方式,Dify 的核心价值在于:

Dify 与 LangChain 不同:LangChain 是一个 Python/SQL 编写的 开发者框架,灵活但需要写代码;Dify 是可视化平台,面向产品经理、独立开发者、甚至业务人员,非程序员也能上手。

2. 与同类工具横向对比

市场上主流的可视化AI工作流工具主要有四个:Dify、n8n、AutoGen 和 LangFlow。以下从多个维度做详细对比。

维度Difyn8nAutoGenLangFlow
定位LLM应用平台通用工作流自动化多智能体协作框架LangChain可视化
编程要求零代码/低代码低代码需写Python需写Python
工作流界面拖拽画布(类Node-RED)拖拽画布+表达式代码配置为主图形节点图
LLM接入内置(直接填API Key)通过HTTP节点调用灵活原生调用通过LangChain接入
RAG/知识库内置,开箱即用需自建或插件需自行实现通过LangChain组件
API发布一键生成,REST API自带Webhook需自行封装需自行封装
社区活跃度活跃(GitHub 40k+⭐)非常活跃一般较小
部署难度Docker一键Docker一键需Python环境需Python环境
适合人群全栈/非程序员自动化爱好者AI研究员LangChain用户

2.1 各工具适用场景

Dify — 首选推荐

  • 快速搭建AI客服机器人
  • 内容创作工作流(选题→写作→发布)
  • 私有知识库问答系统
  • 需要对外提供AI API的服务

n8n — 通用自动化

  • 连接各种第三方SaaS(Slack/Gmail/Notion)
  • 将AI能力嵌入到现有自动化流程中
  • 定时任务+条件分支的复合流程

AutoGen — 多智能体

  • 需要多个AI Agent互相协作完成复杂任务
  • 学术研究/原型验证多Agent场景
  • 需要精确控制Agent通信协议

LangFlow — LangChain用户

  • 已在使用LangChain,想可视化调试Chain
  • 需要灵活组合LangChain各种组件
  • 作为LangChain的原型设计工具
选型建议:如果你需要快速上线一个AI应用(不是研究框架),Dify 是最优解。如果你需要连接大量SaaS工具做通用自动化,用n8n。如果你在研究多智能体,用AutoGen

3. Docker安装详解(逐行命令解释)

3.1 环境要求

项目最低要求推荐配置
CPU2核4核+
内存4GB8GB+
磁盘20GB50GB+ SSD
系统Ubuntu 20.04+ / Debian 11+同上
Dockerv20.10+v24+
Docker Composev2.0+v2.20+
可用 docker --versiondocker compose version 检查已安装版本。

3.2 安装步骤(Step by Step)

第一步:安装 Docker(如果未安装)

# 01 下载 Docker 官方安装脚本(适合 Ubuntu/Debian)
curl -fsSL https://get.docker.com -o get-docker.sh

# 02 以 root 权限执行安装脚本
#    -s 支持台:让安装脚本输出安装过程
#    --with-docker-compose-v2:同时安装 Docker Compose V2
sudo sh get-docker.sh --with-docker-compose-v2

# 03 将当前用户加入 docker 组(避免每次用 sudo)
#    $USER 自动替换为当前用户名
sudo usermod -aG docker $USER

# 04 验证 Docker 是否安装成功
#    正常运行会输出 "Hello from Docker!"
docker run --rm hello-world
为什么要加 docker 组?加入 docker 组后,当前用户可以运行 Docker 容器而无需 sudo。但要注意:这相当于给用户授予了主机 root 权限,服务器环境需谨慎操作。

第二步:安装 Docker Compose V2

# 01 查看当前 Docker Compose 版本(如果是 V2 则已内置)
docker compose version
# 输出示例:Docker Compose version v2.24.0

# 02 如果是 V1 版本(docker-compose --version),升级到 V2
#    V2 集成在 docker 主命令中,语法为 `docker compose`(空格)
#    V1 语法为 `docker-compose`(横杠),新版已废弃

# 03 手动安装 Docker Compose V2(Ubuntu/Debian)
#    下载二进制文件到 /usr/local/bin/
sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" \
  -o /usr/local/bin/docker-compose

# 04 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 05 创建符号链接,使 `docker compose` 全局可用
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

# 06 验证
docker compose version

第三步:下载 Dify

# 01 创建 Dify 工作目录(可自定义路径)
mkdir -p ~/dify && cd ~/dify

# 02 下载 Dify 官方 docker-compose 文件集合
#    -O:保存为指定文件名(不覆盖本地已存在的 .env 文件)
#    官方提供三种版本:单机版 / 带宽优化版 / 社区开发版
wget https://q尊云.com/docker-compose.env.example -O .env 2>/dev/null \
  || wget https://raw.githubusercontent.com/langgenius/dify/main/docker/docker-compose.yaml \
  -O docker-compose.yaml

# 03 下载 .env 配置文件模板
wget https://raw.githubusercontent.com/langgenius/dify/main/docker/.env.example \
  -O .env

# 04 查看下载的文件
ls -la
关于 .env 文件:这个文件包含了 Dify 所有服务(API/Web/DB/Redis 等)的环境变量配置。下载后根据服务器情况修改,通常只需改 SECRET_KEYCONSOLE_WEB_URL 两项。

第四步:配置 .env 文件

# 01 编辑 .env 配置文件
nano .env  # 或 vi .env / code .env

# 02 关键配置项说明(按需修改)

# ===== 必改项 =====

# 01 Dify 控制台初始管理员账号(请务必修改为强密码!)
CONSOLE_WEB_URL=http://localhost:80
#    ^ 控制台访问地址,如果是远程服务器访问,改成本机IP或域名

CONSOLE_API_URL=http://localhost:80/api
#    ^ API服务地址,通常与 WEB_URL 保持一致

SERVICE_API_URL=http://localhost:80/api/v1
#    ^ 对外API地址,外部系统调用时使用

# 02 安全密钥(生产环境务必改掉!)
SECRET_KEY=尊云-请生成随机字符串-不要用这个默认值
#    ^ 生成方法:openssl rand --base64 42

# 03 数据库配置(生产环境建议使用外部 PostgreSQL)
DB_USERNAME=dify
DB_PASSWORD=dify_password_change_me
DB_HOST=db
DB_PORT=5432
DB_DATABASE=dify

# 04 Redis 配置
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=dify_redis_change_me

# 05 模型接入(留空则使用 Dify 内置的模型配置页面)
#    如果你计划使用第三方模型(如 OpenAI),在此配置 API Key
#OPENAI_API_KEY=sk-your-key-here
#ANTHROPIC_API_KEY=sk-ant-your-key-here

第五步:启动 Dify(逐命令解释)

# 01 进入 Dify docker-compose 所在目录
cd ~/dify

# 02 拉取所有镜像(首次运行需要下载约 2-3GB)
#    -p dify-net:创建名为 dify-net 的 Docker 网络
#    --env-file .env:加载 .env 中的环境变量
docker network create dify-net 2>/dev/null || true
#    ^ 创建网络(如果已存在则跳过)

# 03 使用 docker-compose 启动所有服务(后台运行)
#    -f:指定使用的 docker-compose 文件
#    --env-file:指定环境变量文件
#    -d:detached mode,后台运行(不加 -d 会阻塞终端)
docker compose -f docker-compose.yaml --env-file .env up -d

# 04 等待服务启动(容器内部初始化需要约 30-60 秒)
#    grep -E "Up|healthy" 检查各容器状态
docker compose -f docker-compose.yaml ps

# 05 查看日志(确认没有 Error)
#    -f:follow,实时跟踪日志
#    --tail=50:显示最近50行
docker compose -f docker-compose.yaml logs --tail=50 -f

# 06 检查容器健康状态
#    正常情况:api/web/db/redis/sandbox 状态均为 "Up"
docker compose -f docker-compose.yaml ps
启动后访问:浏览器打开 http://服务器IP:80,首次访问会引导创建管理员账号。Dify Web 界面用于管理应用和工作流;http://服务器IP:80/api/v1 是对外 API 端点。

第六步:关闭与重启命令

# 关闭 Dify(保留数据卷,重启后数据不丢失)
docker compose -f docker-compose.yaml --env-file .env down

# 关闭并删除数据卷(⚠️ 彻底删除所有数据,无法恢复!)
docker compose -f docker-compose.yaml --env-file .env down -v

# 重启所有服务
docker compose -f docker-compose.yaml --env-file .env restart

# 更新 Dify 到最新版本
git -C ~/dify pull  # 或重新下载 docker-compose.yaml
docker compose -f docker-compose.yaml --env-file .env pull
docker compose -f docker-compose.yaml --env-file .env up -d

4. 第一个工作流创建步骤

以下以"文章摘要提取"为例,完整走一遍工作流创建过程。这个工作流的逻辑是:输入一篇长文章 → 调用 LLM 提取摘要 → 输出结果。

4.1 操作序列(图解文字版)

1
登录 Dify 控制台

浏览器打开 http://服务器IP:80,使用管理员账号登录。登录后在左侧导航栏找到 「工作流」 选项卡。

2
创建空白工作流

点击「创建工作流」→ 选择「空白工作流」→ 输入名称「文章摘要提取」→ 确认。此时进入工作流画布(Canvas)页面。

3
添加「开始」节点

在左侧节点列表,找到「开始(Start)」节点,点击或拖拽到画布中央。配置内容:

4
添加「LLM」节点

从节点列表拖拽「LLM」节点到画布,放置在「开始」节点右侧。用鼠标拖动连线(蓝色箭头),从「开始」的输出端口连接到「LLM」的输入端口。

LLM 节点配置:

5
添加「直接回复」结束节点

拖拽「直接回复(Direct Output)」节点到画布最右侧,连接「LLM」节点的输出端口到这个节点。这个节点代表工作流的最终输出。

6
保存并发布

点击画布右上角「发布」按钮。第一次发布会提示设置「发布描述」,填写如"v1.0 文章摘要提取"即可。

7
在「应用」中创建可调用的实例

返回「应用」页面,创建「空白应用」→ 类型选择「工作流」→ 关联刚才的工作流。创建后会生成一个 API 访问地址。

画布操作技巧:按住 Space + 鼠标拖拽 可以平移画布;滚轮缩放;双击节点名称可编辑;右键节点可复制/删除。

4.2 截图位置说明(文字描述)

步骤对应截图位置
工作流列表左侧导航「工作流」→ 右上「创建工作流」按钮
画布界面顶部工具栏(保存/发布/设置)+ 左侧节点面板 + 中央画布 + 右侧属性面板
节点连线节点右下角圆点(输出)拖拽到目标节点左下角圆点(输入)
LLM配置右侧属性面板 → 模型选择下拉 → 系统提示词文本框 → 变量映射区
发布确认右上角「发布」按钮 → 弹出「发布描述」输入框 → 确认按钮

5. 常用节点详解

5.1 LLM 节点(大型语言模型)

功能说明

LLM 节点是 Dify 工作流的核心,用于调用大语言模型(GPT/Claude/通义千问等)进行文本生成。是工作流中处理自然语言的主力节点。

核心配置参数

配置示例:文章风格改写

# 系统提示词配置
你是一位资深的科技专栏作家,擅长将复杂的技术概念用通俗易懂的语言解释。
请根据用户提供的原始文章,用生动的语言进行改写,保持核心信息不变。
输出格式:先写一段引导语,然后分3点展开,每点不超过50字。

# 用户提示词配置(引用变量)
请将以下文章改写成适合公众号发布的风格:

{{article_text}}

# 参数设置
温度(Temperature):0.7
最大令牌数:800
停止序列:不填
变量引用语法:在提示词中用 {{变量名}} 引用上游节点的输出变量。注意变量名必须与上游节点输出的变量名完全一致。

5.2 条件分支节点(If / Switch)

功能说明

条件分支节点用于在工作流中引入逻辑判断,根据变量的值或表达式的结果,将流程路由到不同的分支路径。类似编程语言中的 if/switch 语句。

配置参数

配置示例:情绪分类路由

# 场景:用户输入一段文字,情绪分类后走不同处理流程

# 分支一:积极情绪
条件:sentiment(来自上游LLM的情绪分类结果)
运算符:等于
比较值:"positive"

# 分支二:消极情绪
条件:sentiment
运算符:等于
比较值:"negative"

# 分支三:中性/其他(兜底)
# 无需配置,作为 else 默认分支

# 后续各分支可挂载不同的处理 LLM 节点
# 分支一 → 鼓励回复 LLM
# 分支二 → 安慰回复 LLM
# 分支三 → 常规回复 LLM
变量类型注意:条件判断时,"1"(字符串)和 1(整数)是不同的值。如果比较结果与预期不符,检查上游节点输出的变量类型,必要时使用代码执行节点做类型转换。

5.3 代码执行节点(Code)

功能说明

代码执行节点运行一段 JavaScript / Python 代码(节点运行环境的 sandbox),用于数据转换、计算、格式处理等无法用可视化节点完成的任务。代码在隔离的沙箱环境中执行,无法访问网络和文件系统。

输入输出

配置示例:JSON 解析与字段提取

# 场景:上游节点返回了 JSON 格式的天气数据,需提取温度和天气状况

# 输入变量(来自上游节点):
# - weather_json_string: 类型「文本」,值为 '{"temp":22,"condition":"多云","humidity":65}'

# JavaScript 代码:
def main(weather_json_string):
    # 将 JSON 字符串解析为对象
    data = JSON.parse(weather_json_string)

    # 提取所需字段
    temperature = data.temp         # 提取温度:22
    condition   = data.condition   # 提取天气状况:多云
    humidity    = data.humidity    # 提取湿度:65

    # 组合成自然语言描述
    description = f"今天天气{condition},气温{temperature}°C,湿度{humidity}%"

    # 返回输出变量(必须在 outputs 中声明)
    return {
        "temperature": temperature,
        "condition": condition,
        "description": description
    }

# 输出变量定义:
# - temperature: 类型「数字」
# - condition:   类型「文本」
# - description: 类型「文本」
沙箱限制:代码执行节点运行在受限的 JavaScript 环境中,无法使用 require() 加载外部模块,无法访问网络,无法读写文件。只能做纯数据计算。如果需要复杂能力,考虑用「HTTP 请求」节点调用外部服务。

5.4 模板转换节点(Template)

功能说明

模板转换节点使用类似 Jinja2 的语法,将多个变量拼接/格式化为一段文本。适合生成格式化输出(如邮件模板、报告模板、消息模板等),无需写代码。

Jinja2 语法速查

配置示例:生成邮件报告模板

# 输入变量:
# - user_name:   "张总"
# - date:        "2026-05-23"
# - summary:     "本季度收入增长20%,用户活跃度提升35%"
# - next_action: "下季度重点拓展海外市场"

# 模板内容:
尊敬的 {{ user_name }}:

您好!以下是 {{ date }} 的周报摘要:

📊 本期总结:
{{ summary }}

🎯 下期计划:
{{ next_action }}

如有任何问题,请随时联系。

此致
敬礼

# 输出:
# 尊敬的 张总:
#
# 您好!以下是 2026-05-23 的周报摘要:
#
# 📊 本期总结:
# 本季度收入增长20%,用户活跃度提升35%
#
# 🎯 下期计划:
# 下季度重点拓展海外市场
#
# 如有任何问题,请随时联系。
# ...
# (渲染后的结果会被传递到下游 LLM 节点做进一步处理)

5.5 HTTP 请求节点

功能说明

HTTP 请求节点用于向外部 API 发起 HTTP 调用,是 Dify 接入第三方服务的主要方式。支持的 method:GET / POST / PUT / DELETE / PATCH。

配置参数

配置示例:调用高德天气API

# URL(变量插值):
https://restapi.amap.com/v3/weather/weatherInfo

# Method:GET

# URL Params:
key     → your_amap_api_key
city    → {{ city_code }}        # 来自上游输入的城市编码
extensions → base               # base=实时天气,all=完整天气

# Headers:
Content-Type → application/x-www-form-urlencoded

# 超时时间:10秒

# 输出变量映射:
response_body → $.weather[0]     # JSONPath 提取第一个天气对象

6. API调用示例

Dify 的每个已发布应用都暴露了 REST API。以下以「文章摘要提取」工作流为例,分别用 curl 和 Python 两种方式演示完整调用。

6.1 API 基本信息

# 应用端点基础信息(来自 Dify 控制台 → 应用 → API访问)
BASE_URL=http://服务器IP:80/api/v1
APP_ID=your_app_id_here          # 应用 ID
API_KEY=your_api_key_here        # API 密钥(控制台 → API 密钥 获取)

# 调用地址(workflow inference endpoint)
INFER_URL=${BASE_URL}/workflows/run

6.2 curl 调用示例

# 01 调用文章摘要提取工作流
# -X POST:使用 HTTP POST 方法
# -H:添加 HTTP 请求头
#    Authorization:Bearer Token 认证,API Key 填在这里
#    Content-Type:application/json,声明请求体为 JSON
# -d:指定请求体(JSON 格式)
#    inputs:工作流的输入变量,与「开始」节点定义的变量名对应
#    response_mode:响应模式
#        blocking:同步阻塞,等待工作流执行完成返回结果
#        blocking_no_output:同上,但不返回中间节点输出
#        streaming:流式响应(SSE),适合大模型输出场景
#    conversation_id:会话ID(可选,用于多轮对话上下文)

curl -X POST '${INFER_URL}' \
  -H 'Authorization: Bearer YOUR_API_KEY_HERE' \
  -H 'Content-Type: application/json' \
  -d '{
    "inputs": {
      "article_text": "人工智能技术的发展正在深刻改变各行各业的生产方式。从生成式AI到自动驾驶,从医疗诊断到金融风控,AI的应用场景越来越广泛。本文深入分析了当前AI技术的最新进展,探讨了大语言模型在自然语言处理领域的突破性应用,并展望了未来三到五年内AI技术的发展趋势。研究表明,融合多模态能力的AI系统将成为下一代人工智能的主流方向。"
    },
    "response_mode": "blocking",
    "conversation_id": ""
  }'

# 02 解释返回的 JSON 字段
# {
#   "workflow_run_id": "run_xxxxx",    # 本次运行的唯一ID,用于查询状态
#   "task_id": "task_xxxxx",           # 任务ID
#   "status": "succeeded",            # 运行状态:running/succeeded/failed
#   "outputs": {                       # 工作流输出内容
#     "summary": "AI技术正深刻改变各行业...融合多模态能力的AI系统将成为下一代主流方向。"
#   },
#   "latency": 2.345                   # 耗时(秒)
# }

# 03 如果状态为 failed,查询错误详情
#    用 workflow_run_id 查询详细状态和错误日志
curl -X GET '${BASE_URL}/workflow-runs/{workflow_run_id}' \
  -H 'Authorization: Bearer YOUR_API_KEY_HERE'

6.3 Python 调用示例(requests 库)

# Python 版本(建议 3.8+,使用 requests 库)
# 安装:pip install requests

import requests
import json

# ========== 配置区 ==========
# Dify 服务地址
BASE_URL = "http://服务器IP:80/api/v1"
# API 密钥(来自 Dify 控制台 → API 密钥)
API_KEY = "app-xxxxxxxxxxxxxxxx"
# 工作流调用地址
INFER_URL = f"{BASE_URL}/workflows/run"

# ========== 函数定义 ==========
def run_workflow(article_text: str, timeout: int = 60) -> dict:
    """
    调用 Dify 工作流,提取文章摘要。

    Args:
        article_text: 要摘要的文章原文
        timeout: 请求超时时间(秒),默认60秒

    Returns:
        dict: 工作流执行结果,包含 status 和 outputs

    Raises:
        requests.HTTPError: HTTP 请求失败时抛出
    """

    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    }

    payload = {
        # inputs:工作流的输入变量,必须与「开始」节点定义的变量名一致
        "inputs": {
            "article_text": article_text
        },
        # response_mode: blocking 同步等待,适合脚本调用
        "response_mode": "blocking",
        # conversation_id: 空字符串表示新建会话
        "conversation_id": ""
    }

    # 发起 POST 请求
    response = requests.post(
        INFER_URL,
        headers=headers,
        json=payload,
        timeout=timeout          # 请求超时,防止 Dify 响应慢时程序卡死
    )

    # 4xx/5xx 响应码会抛出 HTTPError,做异常处理
    response.raise_for_status()

    result = response.json()

    # 检查工作流执行状态
    if result.get("status") == "succeeded":
        return result
    elif result.get("status") == "failed":
        # 打印详细错误,供调试用
        print(f"❌ 工作流执行失败:{result.get('error')}")
        raise RuntimeError(f"Workflow failed: {result.get('error')}")
    else:
        print(f"⚠️ 工作流状态:{result.get('status')}")
        return result


# ========== 调用示例 ==========
if __name__ == "__main__":
    article = (
        "人工智能技术的发展正在深刻改变各行各业的生产方式。"
        "从生成式AI到自动驾驶,从医疗诊断到金融风控,AI的应用场景越来越广泛。"
        "本文深入分析了当前AI技术的最新进展,探讨了大语言模型在自然语言处理领域的突破性应用,"
        "并展望了未来三到五年内AI技术的发展趋势。研究表明,融合多模态能力的AI系统将成为下一代人工智能的主流方向。"
    )

    print("📤 正在调用 Dify 工作流...")
    result = run_workflow(article, timeout=60)

    print(f"✅ 调用成功!耗时:{result.get('latency', 'N/A')}s")
    print(f"📋 摘要结果:{result['outputs']['summary']}")

    # ========== 进阶:流式调用 ==========
    # 适用于需要实时展示 AI 生成过程(如打字机效果)的场景
    def run_workflow_stream(article_text: str):
        """流式调用(使用 SSE 协议实时获取输出片段)"""
        payload = {
            "inputs": {"article_text": article_text},
            "response_mode": "streaming",       # 关键区别:streaming 模式
            "conversation_id": ""
        }

        headers = {
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        }

        # stream=True 使 requests 返回一个迭代器
        with requests.post(INFER_URL, headers=headers, json=payload,
                           stream=True, timeout=90) as resp:
            resp.raise_for_status()
            # SSE 流式数据,按 data: 分割行处理
            for line in resp.iter_lines():
                if line.startswith("data:"):
                    # 跳过 "data: " 前缀,解析 JSON
                    raw = line[5:].strip()
                    if raw == "[DONE]":
                        break
                    chunk = json.loads(raw)
                    # chunk 格式:{"event": "output", "data": {"text": "部分输出文字"}}
                    if chunk.get("event") == "output":
                        print(chunk["data"]["text"], end="", flush=True)
                    elif chunk.get("event") == "finished":
                        print("\n✅ 流式输出完成")
API Key 安全建议:不要将 API Key 直接写在代码里。生产环境建议使用环境变量:API_KEY = os.getenv("DIFY_API_KEY"),避免 Key 随代码提交到版本库。

7. 常见报错与解决

错误1:节点未连接(Node Not Connected)

错误信息:工作流发布时报错 "The node [LLM] is not connected" 或画布上节点之间没有蓝色连线箭头。

原因分析:工作流节点之间没有建立数据流动的连线,即一个节点的输出没有连接到下一个节点的输入。

解决步骤:

  1. 进入工作流画布,检查所有节点是否都有输入和输出连线
  2. 每个节点只能有一个输入连线,但可以有多个输出连线(对应多个下游分支)
  3. 点击节点右下角的 输出端口(小圆点),拖拽到目标节点的 输入端口
  4. 确认「开始」节点和「结束」节点都已正确连接
# 自检:工作流拓扑检查命令
# 确认至少有一个「开始」节点和一个「结束」节点
# 确认除了开始/结束节点外,每个节点都至少有一个输入连线
# 确认除了开始节点外,没有节点有多于一个输入连线(除非使用「问题归并」节点)

错误2:模型超时(Model Timeout)

错误信息:"ERROR: LLM node timeout after 60s" 或 "Request timeout exceeded"

原因分析:

解决步骤:

# 01 在 LLM 节点配置中增大超时时间(单位:秒)
#    默认超时通常为 60s,对于长文本可改为 120s 或更高
LLM节点配置 → 超时时间 → 120

# 02 检查输入文本长度,适当截断
#    建议:GPT-4o 输入不超过 12.8k tokens,Claude 3.5 支持 200k tokens
#    在 LLM 节点前加一个「模板转换」节点,提前截断文本:
{% raw %}{{"{{article_text}}"[:4000]}}{% endraw %}
#    ^ Jinja2 切片语法:保留前4000字符

# 03 检查 API Key 是否有效
curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer YOUR_API_KEY"

# 04 如果是国内服务器访问 OpenAI,需配置代理
#    在服务器环境变量中添加:
export HTTP_PROXY=http://你的代理IP:端口
export HTTPS_PROXY=http://你的代理IP:端口

#    然后在 Docker 环境中让 Dify 使用代理:
#    编辑 docker-compose.yaml 中 api 服务的 environment:
environment:
  - HTTP_PROXY=http://你的代理IP:端口
  - HTTPS_PROXY=http://你的代理IP:端口

# 05 检查模型服务商的限流状态(Rate Limit)
#    OpenAI 返回 429 Too Many Requests 时,降低并发或等待后重试

错误3:变量类型错误(Variable Type Mismatch)

错误信息:"Variable type mismatch: expected text, got array" 或 "Cannot concatenate string with number"

原因分析:上游节点输出的变量类型与下游节点期望的类型不一致。比如上游「代码执行」节点输出了一个数组,下游 LLM 节点期望的是字符串。

解决步骤:

# 01 在画布右侧属性面板查看每个节点的确切输出变量类型
#    鼠标悬停在变量名称上会显示类型(text/number/array/object)

# 02 常用类型转换方法

# 方法A:使用「模板转换」节点做隐式转换
#    Jinja2 模板中的 {{变量}} 会自动调用 str(),将数字/布尔转为字符串
{{my_number}}        # 数字 → 字符串

# 方法B:使用「代码执行」节点做显式类型转换
def main(data):
    # 数组转字符串:用 join() 连接
    str_result = ",".join(data)      # ["a","b"] → "a,b"

    # 字符串转数字
    num_result = float("3.14")      # "3.14" → 3.14(浮点数)
    int_result = int("42")           # "42" → 42(整数)

    # 数字转字符串
    text = str(123)                  # 123 → "123"

    return {
        "str_result": str_result,
        "num_result": num_result,
        "int_result": int_result
    }

# 方法C:检查上游节点是否正确声明了输出类型
#    在代码执行节点,输出变量必须明确声明类型

错误4:Docker 容器启动失败(Container Failed to Start)

错误信息:"Error response from daemon: Conflict. Container name 'xxx' is already in use" 或 "dify-xxx exited with code 1"

原因分析:

  • 端口冲突:服务器上 80/5432/6379 端口已被其他进程占用
  • 磁盘空间不足:Docker 镜像拉取或容器运行失败
  • docker-compose 版本不兼容

解决步骤:

# 01 检查端口占用情况
#    查看 80 端口被谁占用(可能是 Nginx / Apache / 其他 Web 服务)
sudo netstat -tlnp | grep :80
#    输出示例:tcp6  0  0 :::80   :::*   LISTEN   1234/nginx
#    如果 80 端口被占用,有两个选择:
#    A. 停掉占用进程:sudo systemctl stop nginx
#    B. 修改 docker-compose.yaml 中的端口映射(如 8080:80)

# 02 检查 Docker 容器日志(定位具体错误)
docker compose -f docker-compose.yaml logs api --tail=100
#    常见错误:
#    - "Cannot connect to database":数据库连接失败,检查 .env 中 DB_HOST
#    - "Permission denied":权限问题,检查 data volumes 目录权限
#      sudo chown -R 1000:1000 ~/dify

# 03 清理残留容器和镜像(强制重建)
docker compose -f docker-compose.yaml down --remove-orphans
docker system prune -f  # 清理未使用的镜像
docker compose -f docker-compose.yaml up -d

# 04 检查磁盘空间
df -h
#    如果 /dev/vda1 使用率 > 90%,清理 Docker:
docker system df           # 查看 Docker 占用的磁盘
docker system prune -a -f  # 删除所有未使用的镜像、容器、网络

# 05 如果是 docker-compose V1/V2 语法混用问题,确保使用 V2 语法
#    用 `docker compose`(空格)而非 `docker-compose`(横杠)
docker compose version

错误5:工作流发布后 API 返回 400 Bad Request

错误信息:Postman/curl 调用时返回 {"code": "invalid_param_error", "message": "inputs validation failed: article_text is required"}

原因分析:API 调用时 inputs 中的变量名与工作流「开始」节点定义的变量名不匹配,或变量名为空。

解决步骤:

# 01 在 Dify 控制台 → 工作流 → 「开始」节点中确认精确的变量名
#    变量名严格区分大小写,"ArticleText" ≠ "article_text"

# 02 检查请求体 JSON 中的 keys 与变量名一一对应
#    正确:
{
  "inputs": {
    "article_text": "这里是文章内容"
  }
}
#    错误(变量名不匹配):
{
  "inputs": {
    "text": "这里是文章内容"      # ❌ text 不是定义的变量名
  }
}
#    错误(变量名写错):
{
  "inputs": {
    "Article_Text": "这里是文章内容"  # ❌ 大小写不匹配
  }
}

# 03 如果不想逐个检查 inputs,可在「开始」节点将所有输入设为可选
#    然后在 LLM 节点用 default 过滤器提供兜底值:
#    {{ article_text | default("请提供文章内容") }}

# 04 使用 Dify 自带的 API 测试工具检查
#    控制台 → 应用 → API → 「测试」按钮,可直接发送请求并查看详细错误

错误6:工作流中 LLM 输出为空或截断

错误信息:API 返回 "outputs": {"result": ""}(空字符串)或输出在某个位置被截断

原因分析:

  • Max Tokens(最大令牌数)设置过小,输出被截断
  • 提示词中让模型输出的格式与输出变量名不匹配
  • 模型 API 的输出长度限制

解决步骤:

# 01 在 LLM 节点配置中增大 Max Tokens
#    从默认值(如 256)增大到 512、1024 或 2048
#    注意:Max Tokens 是单次输出的上限,不是总上下文长度

# 02 修改系统提示词,明确要求模型输出完整内容
#    示例:
"请生成完整的摘要结果,直接输出,不要前缀说明,不要省略号结尾。"
"如果内容较长,请完整输出所有要点,不要截断。"

# 03 检查输出变量名是否与提示词中引用的一致
#    如果 LLM 节点输出变量名为 "summary",则工作流后续节点应引用 {{summary}}
#    而不是 {{result}} 或其他名称

8. 生产环境优化建议

8.1 并发处理

当 Dify 工作流对外提供 API 后,可能会面临多个并发请求。以下是并发优化方案:

# 01 在 Dify 前加一层反向代理(Nginx),配置连接池和限流
#    /etc/nginx/conf.d/dify.conf

upstream dify_backend {
    # 01 使用 Unix Socket 连接(比 TCP 少一次网络开销)
    server 127.0.0.1:80;

    # 02 或者配置多个 Dify 实例做负载均衡
    server 127.0.0.1:80 weight=1;
    server 127.0.0.1:8081 weight=1;  # 需要运行第二个 Dify 实例
}

server {
    listen 80;
    server_name your-domain.com;

    # 03 限流:单个 IP 每秒最多 10 个请求
    limit_req_zone $binary_remote_addr zone=dify_limit:10m rate=10r/s;

    location / {
        limit_req zone=dify_limit burst=20 nodelay;

        proxy_pass http://dify_backend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 04 超时配置(避免长请求占用连接)
        proxy_connect_timeout 60s;
        proxy_send_timeout 120s;
        proxy_read_timeout 120s;

        # 05 WebSocket 支持(流式输出需要)
        proxy_buffering off;
        proxy_set_header Connection "upgrade";
    }
}

# 06 测试 Nginx 配置语法
sudo nginx -t

# 07 重载 Nginx
sudo systemctl reload nginx

8.2 缓存策略

对于相同输入的重复请求(如 FAQ 类问答),加入缓存层可大幅降低延迟和 API 调用成本:

# 方案A:Nginx 层面缓存(适合 GET 请求)
#    适用于输入输出都相对固定的场景

server {
    location /api/v1/ {
        # 相同的 query string 缓存 10 分钟
        proxy_cache_valid 200 10m;

        # 缓存 Key:Host + 请求路径 + query string + API Key
        proxy_cache_key "$host$request_uri$http_authorization";

        # 缓存响应标记(命中 X-Cache-Key)
        add_header X-Cache-Key $proxy_cache_key;
        add_header X-Cache-Status $upstream_cache_status;

        proxy_pass http://dify_backend;
    }
}

# 方案B:Redis 缓存(应用层,更灵活)
#    在工作流中加入代码执行节点,判断缓存是否命中

# JavaScript 代码执行节点(Redis 缓存判断)
def main(input_text):
    # 注意:Dify 沙箱环境无法直接连 Redis
    # 这个方案需要通过「HTTP 请求」节点调用外部缓存服务
    # 以下是伪代码示例,实际需要配合外部 API 使用

    cache_key = "summary:" + hash(input_text)  # MD5(input_text)
    # 调用外部缓存服务的示例:
    # cached = http_get(f"http://cache-api/cache/{cache_key}")
    # if cached:
    #     return {"result": cached, "from_cache": True}

    return {
        "cache_key": cache_key,
        "need_generate": True
    }
    # 后续流程:先查缓存 → 命中则跳过 LLM → 未命中则调用 LLM 并写入缓存
缓存建议:Dify 本身不提供缓存层,建议在 Dify 前架一层 API 网关(如 APISIX、Caddy)来实现缓存。缓存 Key 建议使用请求内容的 MD5/SHA256 哈希,缓存时间根据业务场景设定(FAQ 类 10-60分钟,生成内容类 1-24小时)。

8.3 监控与可观测性

# 01 容器健康检查脚本(可配置 cronjob 定期执行)
#!/bin/bash
# /opt/scripts/check-dify.sh
# 用法:*/5 * * * * /opt/scripts/check-dify.sh
# 解释:每5分钟检查一次 Dify 各容器状态,异常时发告警

CONTAINERS=$(docker compose -f ~/dify/docker-compose.yaml ps --format json)
FAILED=""

for container in api web db redis sandbox worker; do
    STATUS=$(echo "$CONTAINERS" | jq -r ".[] | select(.Service==\"$container\") | .State")
    if [ "$STATUS" != "running" ]; then
        FAILED="$FAILED $container"
    fi
done

if [ -n "$FAILED" ]; then
    echo "$(date) Dify 容器异常:$FAILED" | tee /var/log/dify-alert.log
    # 发送告警(可接入钉钉/飞书/Webhook)
    curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"Dify容器异常:$FAILED\"}}"
fi

# 02 Nginx 访问日志分析(统计 API 调用量和响应时间)
#    分析最近 1 小时的 API 调用情况
tail -n 1000 /var/log/nginx/access.log | awk '
    BEGIN { total=0; slow=0 }
    {
        total++
        # 提取响应时间(nginx 日志格式需包含 $request_time)
        if ($NF ~ /[0-9.]+/) {
            rt = $NF + 0
            if (rt > 5) slow++   # 响应时间超过5秒的请求
        }
    }
    END {
        print "总请求数:" total, "慢请求(>5s):" slow, "慢请求比例:" (slow/total*100) "%"
    }'

# 03 Prometheus + Grafana 监控(可选进阶方案)
#    在 docker-compose.yaml 中加入 metrics 端点暴露
#    Dify API 服务默认在 /metrics 端点暴露 Prometheus 格式指标
#    可用 Prometheus 采集后接入 Grafana 可视化

8.4 数据库和存储优化

# 01 将 Dify 的 PostgreSQL 和 Redis 从 Docker 改为独立部署(生产推荐)
#    独立部署可以获得更好的性能和可管理性

# PostgreSQL 独立部署(使用 Ubuntu/Debian apt 安装)
sudo apt install postgresql-16
sudo systemctl enable postgresql
sudo systemctl start postgresql

# 创建 Dify 专用数据库和用户
sudo -u postgres psql << 'EOF'
CREATE USER dify WITH PASSWORD 'your_secure_password';
CREATE DATABASE dify OWNER dify;
ALTER USER dify CREATEDB;
\q
EOF

# 02 修改 Dify .env 文件中的数据库连接
sed -i 's/^DB_HOST=.*/DB_HOST=127.0.0.1/' ~/dify/.env
sed -i 's/^DB_PASSWORD=.*/DB_PASSWORD=your_secure_password/' ~/dify/.env

# 03 配置 PostgreSQL 连接池(pgbouncer,降低连接数)
sudo apt install pgbouncer
#    /etc/pgbouncer/pgbouncer.ini
[databases]
dify = host=127.0.0.1 port=5432 dbname=dify

[pgbouncer]
listen_port = 6432
listen_addr = 127.0.0.1
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
max_client_conn = 200
default_pool_size = 20   # 每个 PostgreSQL 连接池大小

sudo systemctl restart pgbouncer
安全提醒:生产环境中请务必修改所有默认密码,使用强密码策略;将 SECRET_KEY 替换为随机字符串;数据库端口不要暴露到公网;启用防火墙,只允许必要的端口(如 80/443)入站。

总结

Dify 是一个功能完善、社区活跃的开源 LLM 应用开发平台,适合快速搭建 AI 工作流并对外提供 API 服务。本文从工具选型、Docker 安装、工作流创建、节点配置、API 调用、错误排查到生产优化,完整覆盖了 Dify 从入门到上线的全流程。

核心要点回顾:

  • 选型:快速 AI 应用选 Dify,通用自动化选 n8n,多智能体研究选 AutoGen
  • 安装:Docker 一键部署,.env 文件是关键,注意端口占用
  • 工作流:开始节点定义输入 → 中间节点处理 → 结束节点输出,连线即逻辑
  • 节点:LLM 是核心,条件分支做路由,代码节点补灵活性,模板节点做输出格式化
  • API:Bearer Token 认证,blocking 同步调用,streaming 流式调用
  • 错误:大多数问题来自未连接、变量类型不匹配、超时、配置错误
  • 生产:Nginx 限流 + Redis 缓存 + 监控告警 + 独立数据库

遇到问题善用 GitHub Issues(github.com/langgenius/dify/issues)搜索,社区文档也比较完善。