>
Dify(DIY + Verify,意为"自己动手,验证想法")是一个开源的 LLM应用开发平台,其核心理念是让任何人都能通过可视化拖拽的方式搭建AI工作流,而无需编写大量胶水代码。它于2023年开源,支持接入 OpenAI、Anthropic Claude、国内通义千问/DeepSeek 等主流大模型。
官方定义:Dify是一个开源的LLM应用开发平台,提供可视化的工作流编排、知识库管理、模型接入、多端发布等能力。
对比传统开发方式,Dify 的核心价值在于:
市场上主流的可视化AI工作流工具主要有四个:Dify、n8n、AutoGen 和 LangFlow。以下从多个维度做详细对比。
| 维度 | Dify | n8n | AutoGen | LangFlow |
|---|---|---|---|---|
| 定位 | 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用户 |
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| CPU | 2核 | 4核+ |
| 内存 | 4GB | 8GB+ |
| 磁盘 | 20GB | 50GB+ SSD |
| 系统 | Ubuntu 20.04+ / Debian 11+ | 同上 |
| Docker | v20.10+ | v24+ |
| Docker Compose | v2.0+ | v2.20+ |
docker --version 和 docker compose version 检查已安装版本。
# 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
# 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
# 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
SECRET_KEY 和 CONSOLE_WEB_URL 两项。
# 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
# 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
以下以"文章摘要提取"为例,完整走一遍工作流创建过程。这个工作流的逻辑是:输入一篇长文章 → 调用 LLM 提取摘要 → 输出结果。
浏览器打开 http://服务器IP:80,使用管理员账号登录。登录后在左侧导航栏找到 「工作流」 选项卡。
点击「创建工作流」→ 选择「空白工作流」→ 输入名称「文章摘要提取」→ 确认。此时进入工作流画布(Canvas)页面。
在左侧节点列表,找到「开始(Start)」节点,点击或拖拽到画布中央。配置内容:
article_text从节点列表拖拽「LLM」节点到画布,放置在「开始」节点右侧。用鼠标拖动连线(蓝色箭头),从「开始」的输出端口连接到「LLM」的输入端口。
LLM 节点配置:
你是一位专业的文字编辑。请在200字内提取这篇文章的核心观点和关键信息。article_text(来自开始节点的输出)拖拽「直接回复(Direct Output)」节点到画布最右侧,连接「LLM」节点的输出端口到这个节点。这个节点代表工作流的最终输出。
点击画布右上角「发布」按钮。第一次发布会提示设置「发布描述」,填写如"v1.0 文章摘要提取"即可。
返回「应用」页面,创建「空白应用」→ 类型选择「工作流」→ 关联刚才的工作流。创建后会生成一个 API 访问地址。
Space + 鼠标拖拽 可以平移画布;滚轮缩放;双击节点名称可编辑;右键节点可复制/删除。
| 步骤 | 对应截图位置 |
|---|---|
| 工作流列表 | 左侧导航「工作流」→ 右上「创建工作流」按钮 |
| 画布界面 | 顶部工具栏(保存/发布/设置)+ 左侧节点面板 + 中央画布 + 右侧属性面板 |
| 节点连线 | 节点右下角圆点(输出)拖拽到目标节点左下角圆点(输入) |
| LLM配置 | 右侧属性面板 → 模型选择下拉 → 系统提示词文本框 → 变量映射区 |
| 发布确认 | 右上角「发布」按钮 → 弹出「发布描述」输入框 → 确认按钮 |
LLM 节点是 Dify 工作流的核心,用于调用大语言模型(GPT/Claude/通义千问等)进行文本生成。是工作流中处理自然语言的主力节点。
配置示例:文章风格改写
# 系统提示词配置
你是一位资深的科技专栏作家,擅长将复杂的技术概念用通俗易懂的语言解释。
请根据用户提供的原始文章,用生动的语言进行改写,保持核心信息不变。
输出格式:先写一段引导语,然后分3点展开,每点不超过50字。
# 用户提示词配置(引用变量)
请将以下文章改写成适合公众号发布的风格:
{{article_text}}
# 参数设置
温度(Temperature):0.7
最大令牌数:800
停止序列:不填
{{变量名}} 引用上游节点的输出变量。注意变量名必须与上游节点输出的变量名完全一致。
条件分支节点用于在工作流中引入逻辑判断,根据变量的值或表达式的结果,将流程路由到不同的分支路径。类似编程语言中的 if/switch 语句。
配置示例:情绪分类路由
# 场景:用户输入一段文字,情绪分类后走不同处理流程
# 分支一:积极情绪
条件:sentiment(来自上游LLM的情绪分类结果)
运算符:等于
比较值:"positive"
# 分支二:消极情绪
条件:sentiment
运算符:等于
比较值:"negative"
# 分支三:中性/其他(兜底)
# 无需配置,作为 else 默认分支
# 后续各分支可挂载不同的处理 LLM 节点
# 分支一 → 鼓励回复 LLM
# 分支二 → 安慰回复 LLM
# 分支三 → 常规回复 LLM
代码执行节点运行一段 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: 类型「文本」
require() 加载外部模块,无法访问网络,无法读写文件。只能做纯数据计算。如果需要复杂能力,考虑用「HTTP 请求」节点调用外部服务。
模板转换节点使用类似 Jinja2 的语法,将多个变量拼接/格式化为一段文本。适合生成格式化输出(如邮件模板、报告模板、消息模板等),无需写代码。
{{变量名}} — 插入变量值{% if 条件 %}...{% endif %} — 条件判断{% for item in 列表 %}...{% endfor %} — 循环| length / | upper / | lower / | default(值) — 过滤器配置示例:生成邮件报告模板
# 输入变量:
# - user_name: "张总"
# - date: "2026-05-23"
# - summary: "本季度收入增长20%,用户活跃度提升35%"
# - next_action: "下季度重点拓展海外市场"
# 模板内容:
尊敬的 {{ user_name }}:
您好!以下是 {{ date }} 的周报摘要:
📊 本期总结:
{{ summary }}
🎯 下期计划:
{{ next_action }}
如有任何问题,请随时联系。
此致
敬礼
# 输出:
# 尊敬的 张总:
#
# 您好!以下是 2026-05-23 的周报摘要:
#
# 📊 本期总结:
# 本季度收入增长20%,用户活跃度提升35%
#
# 🎯 下期计划:
# 下季度重点拓展海外市场
#
# 如有任何问题,请随时联系。
# ...
# (渲染后的结果会被传递到下游 LLM 节点做进一步处理)
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 提取第一个天气对象
Dify 的每个已发布应用都暴露了 REST API。以下以「文章摘要提取」工作流为例,分别用 curl 和 Python 两种方式演示完整调用。
# 应用端点基础信息(来自 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
# 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'
# 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 = os.getenv("DIFY_API_KEY"),避免 Key 随代码提交到版本库。
原因分析:工作流节点之间没有建立数据流动的连线,即一个节点的输出没有连接到下一个节点的输入。
解决步骤:
# 自检:工作流拓扑检查命令
# 确认至少有一个「开始」节点和一个「结束」节点
# 确认除了开始/结束节点外,每个节点都至少有一个输入连线
# 确认除了开始节点外,没有节点有多于一个输入连线(除非使用「问题归并」节点)
原因分析:
解决步骤:
# 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 时,降低并发或等待后重试
原因分析:上游节点输出的变量类型与下游节点期望的类型不一致。比如上游「代码执行」节点输出了一个数组,下游 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:检查上游节点是否正确声明了输出类型
# 在代码执行节点,输出变量必须明确声明类型
原因分析:
解决步骤:
# 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
{"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 → 「测试」按钮,可直接发送请求并查看详细错误
"outputs": {"result": ""}(空字符串)或输出在某个位置被截断
原因分析:
解决步骤:
# 01 在 LLM 节点配置中增大 Max Tokens
# 从默认值(如 256)增大到 512、1024 或 2048
# 注意:Max Tokens 是单次输出的上限,不是总上下文长度
# 02 修改系统提示词,明确要求模型输出完整内容
# 示例:
"请生成完整的摘要结果,直接输出,不要前缀说明,不要省略号结尾。"
"如果内容较长,请完整输出所有要点,不要截断。"
# 03 检查输出变量名是否与提示词中引用的一致
# 如果 LLM 节点输出变量名为 "summary",则工作流后续节点应引用 {{summary}}
# 而不是 {{result}} 或其他名称
当 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
对于相同输入的重复请求(如 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 并写入缓存
# 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 可视化
# 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 从入门到上线的全流程。
核心要点回顾:
遇到问题善用 GitHub Issues(github.com/langgenius/dify/issues)搜索,社区文档也比较完善。