作者:PySuper | 来源:zhengxingtao.com
Dify 是 2026 年开源 AI 应用平台的头号选手。136K GitHub Stars,Docker 一键部署,可视化工作流 + 代码双模式,RAG 内置,API 一键发布——它让你在 30 分钟内从想法到上线。这篇文章从零开始,带你走完搭建、RAG、工作流、API 发布、生产部署的全流程。
一、Dify 是什么
Dify 是一个开源的 LLMOps 平台,定位是"让不会写代码的人也能构建生产级 AI 应用"。
1.1 核心定位
plaintext
Dify = 开源 + 本地部署 + 可视化 + 企业友好
├── 完全开源(基于 Apache 2.0)
├── Docker 一键部署
├── 拖拽式工作流编排
├── RAG 全流程内置
├── 多模型统一接入
├── API 一键生成
└── 多租户原生支持
1.2 关键数据
表格
1.3 Dify vs Coze
表格
一句话:Coze 适合快速验证和 C 端场景,Dify 适合企业级深度定制和私有化部署。
二、实战1:Docker Compose 一键部署
2.1 系统要求
表格
2.2 一键部署
bash
# 1. 克隆仓库
git clone https://github.com/langgenius/dify.git
cd dify/docker
# 2. 配置环境变量
cp .env.example .env
# 3. 修改关键配置(编辑 .env 文件)
# SECRET_KEY — 安全密钥,务必修改
# DB_PASSWORD — 数据库密码
# REDIS_PASSWORD — Redis 密码
# 4. 一键启动
docker compose up -d
# 5. 验证服务
docker compose ps
# 期望输出:
# dify-api running 0.0.0.0:5001->5001/tcp
# dify-web running 0.0.0.0:3000->3000/tcp
# dify-worker running
# dify-db running 0.0.0.0:5432->5432/tcp
# dify-redis running 0.0.0.0:6379->6379/tcp
# dify-weaviate running 0.0.0.0:8080->8080/tcp
# dify-nginx running 0.0.0.0:80->80/tcp
# 6. 访问 Web 界面
# 打开浏览器 → http://localhost/install
# 设置管理员邮箱和密码
2.3 首次部署注意事项
bash
# 问题1:Docker 镜像拉取慢(国内用户)
# 解决:配置 Docker 镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://registry.docker-cn.com"
]
}
EOF
sudo systemctl restart docker
# 问题2:首次拉取约 4GB 镜像,需要 5-10 分钟
# 后续启动只需 30 秒以内
# 问题3:端口冲突(11434 等)
# 解决:修改 .env 中的端口映射
三、实战2:搭建 RAG 知识库问答应用
3.1 流程概览
plaintext
┌───────────────────────────────────────────────────────────┐
│ RAG 知识库问答全流程 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 文档上传 │──→│ 文本分块 │──→│ Embedding │ │
│ │ Upload │ │ Chunking │ │ 向量化 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 生成回答 │←──│ 检索匹配 │←──│ 向量存储 │ │
│ │ Generate │ │ Retrieve │ │ Vector DB │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ 用户获得 │ │
│ │ 精准回答 │ │
│ └──────────┘ │
└───────────────────────────────────────────────────────────┘
3.2 步骤1:接入大模型
进入 Dify 后台 → 设置 → 模型供应商,选择你要用的模型:
OpenAI:
plaintext
模型供应商 → OpenAI → 填入 API Key → 保存
支持的模型:GPT-4o、GPT-4o-mini、o3、o4-mini 等
DeepSeek(国内推荐) :
plaintext
模型供应商 → DeepSeek → 填入 API Key → 保存
优势:API 价格极低(输入 1 元/百万 token),中文能力强
Ollama(本地模型) :
plaintext
模型供应商 → Ollama → 填入服务地址 → 保存
地址:http://host.docker.internal:11434
⚠️ 注意:Docker 内的 Dify 访问宿主机 Ollama,
必须用 host.docker.internal 而不是 localhost
3.3 步骤2:创建知识库
plaintext
1. 进入「知识库」页面
2. 点击「创建知识库」
3. 上传文档(支持 PDF / Word / TXT / Markdown)
4. 配置分块策略:
├── 自动分段(推荐新手)
│ └── 自动识别段落边界
└── 自定义分段
├── 分段长度:500-1000 tokens
├── 分段重叠:50-100 tokens
└── 分段规则:按标题 / 按段落 / 按自定义分隔符
5. 选择 Embedding 模型:
├── text-embedding-3-small(OpenAI,推荐)
└── DeepSeek Embedding(国内推荐)
6. 等待向量化完成
3.4 步骤3:创建应用
plaintext
1. 进入「工作室」→「创建应用」
2. 选择「聊天助手」
3. 配置系统提示词:
你是「某某产品」的智能客服。
## 你的职责
1. 回答用户关于产品的使用问题
2. 处理简单的售后咨询
3. 引导用户找到需要的功能
## 回答规则
- 优先从知识库中查找答案
- 如果知识库没有相关内容,诚实说明并建议联系人工客服
- 回答要简洁、专业、友好
- 不要编造不存在的功能
4. 添加「上下文」→ 选择刚创建的知识库
5. 在右侧调试面板中测试
6. 点击「发布」
3.5 步骤4:测试与调优
python
# 调优维度:
# 1. 召回率调优
# 问题:知识库有答案但检索不到
# 解决:
# - 调整分段长度(更小的分段 = 更精确的匹配)
# - 增加召回数量(Top-K 从 3 调到 5)
# - 使用混合检索(向量 + 关键词)
# 2. 准确率调优
# 问题:检索到了但答案不相关
# 解决:
# - 提高分段质量(更好的分段策略)
# - 增加上下文窗口
# - 优化系统提示词(要求"仅基于检索到的内容回答")
# 3. 覆盖率调优
# 问题:很多问题知识库无法回答
# 解决:
# - 补充更多文档
# - 添加 FAQ 文档
# - 配置"未知回答"兜底策略
四、工作流编排
4.1 可视化节点编排
Dify 的工作流编辑器支持以下节点类型:
plaintext
┌─────────────────────────────────────────────────────────┐
│ Dify 工作流节点类型 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ LLM │ │ 条件分支 │ │ 代码 │ │
│ │ 节点 │ │ IF/ELSE │ │ 执行 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ HTTP请求 │ │ 工具 │ │ 变量聚合 │ │
│ │ 节点 │ │ 调用 │ │ 节点 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 知识检索 │ │ 迭代 │ │ 模板 │ │
│ │ 节点 │ │ 循环 │ │ 转换 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
4.2 实战:多步研究工作流
plaintext
用户输入主题
│
▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ LLM │────→│ 知识检索 │────→│ 条件分支 │
│ 解析主题 │ │ 相关文档 │ │ 有知识? │
└──────────┘ └──────────┘ └────┬─────┘
│
┌────────┼────────┐
│ 是 │ │ 否
▼ │ ▼
┌──────────┐ │ ┌──────────┐
│ 基于知识 │ │ │ Web搜索 │
│ 生成回答│ │ │ 补充信息│
└──────────┘ │ └──────────┘
│ │ │
└──────┼────────┘
│
▼
┌──────────┐
│ LLM │
│ 综合输出 │
└──────────┘
│
▼
┌──────────┐
│ 返回用户 │
└──────────┘
4.3 节点配置示例
LLM 节点:
yaml
节点类型: LLM
模型: GPT-4o
温度: 0.3
系统提示词: |
你是一个研究助手。基于提供的上下文和检索结果,
生成全面、准确的回答。
要求:
- 引用来源
- 区分事实和观点
- 标注不确定的信息
输入变量:
- user_query: {{start.query}}
- knowledge: {{knowledge_retrieval.result}}
输出变量:
- answer: LLM 生成的回答
条件分支节点:
yaml
节点类型: IF/ELSE
条件: {{knowledge_retrieval.count}} > 0
为真: 走"基于知识生成"路径
为假: 走"Web 搜索补充"路径
HTTP 请求节点:
yaml
节点类型: HTTP请求
方法: GET
URL: https://api.example.com/search
Headers:
Authorization: Bearer {{env.API_KEY}}
Query Params:
q: {{start.query}}
limit: 5
输出变量:
- search_results: HTTP 响应体
五、Knowledge 管理
5.1 数据集版本化
plaintext
知识库版本管理:
├── v1.0 (2026-01-15)
│ ├── 产品手册.pdf (20 chunks)
│ ├── FAQ.md (15 chunks)
│ └── API文档.md (30 chunks)
│
├── v1.1 (2026-03-01)
│ ├── 产品手册v2.pdf (25 chunks) ← 更新
│ ├── FAQ.md (18 chunks) ← 更新
│ ├── API文档.md (30 chunks) ← 不变
│ └── 新功能说明.md (10 chunks) ← 新增
│
└── v2.0 (2026-06-01)
├── 全面更新...
└── 支持增量更新(只处理变更部分)
5.2 分块策略
表格
推荐配置:
yaml
# 通用最佳实践
分块策略: 自动分段 + 按标题
分段长度: 800 tokens
分段重叠: 100 tokens
Embedding 模型: text-embedding-3-small
检索模式: 混合检索(向量 + 关键词)
Top-K: 5
Score 阈值: 0.7
5.3 召回调优
python
# 召回率优化技巧
# 1. 混合检索 > 纯向量检索
# 向量检索擅长语义匹配,关键词检索擅长精确匹配
# Dify 支持混合检索,两者取长补短
# 2. 调整 Top-K
# Top-K 太小 → 遗漏相关文档
# Top-K 太大 → 引入噪声
# 推荐:从 3 开始,逐步增加到 5-7
# 3. 分段重叠
# 重叠太少 → 跨段信息丢失
# 重叠太多 → 冗余和 Token 浪费
# 推荐:50-150 tokens 重叠
# 4. 查询改写
# 原始查询:"怎么退款"
# 改写后:"退款流程 退款政策 退货指南"
# Dify 支持 LLM 自动改写查询
六、API 发布
6.1 一键生成 REST API
Dify 中每个应用都可以一键生成 API:
bash
# 1. 在应用页面点击「发布」
# 2. 选择「API访问」
# 3. 复制 API Key 和 Endpoint
6.2 API 调用示例
python
"""
Dify API 客户端封装
"""
import httpx
import json
from typing import AsyncGenerator
class DifyClient:
"""Dify API 客户端"""
def __init__(self, api_key: str, base_url: str = "http://localhost/v1"):
self.api_key = api_key
self.base_url = base_url
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
async def chat(
self,
query: str,
conversation_id: str = None,
user: str = "user",
inputs: dict = None
) -> dict:
"""非流式对话"""
payload = {
"query": query,
"user": user,
"response_mode": "blocking",
"inputs": inputs or {}
}
if conversation_id:
payload["conversation_id"] = conversation_id
async with httpx.AsyncClient(timeout=120) as client:
response = await client.post(
f"{self.base_url}/chat-messages",
headers=self.headers,
json=payload
)
response.raise_for_status()
return response.json()
async def chat_stream(
self,
query: str,
conversation_id: str = None,
user: str = "user",
inputs: dict = None
) -> AsyncGenerator[dict, None]:
"""流式对话,逐步返回 token"""
payload = {
"query": query,
"user": user,
"response_mode": "streaming",
"inputs": inputs or {}
}
if conversation_id:
payload["conversation_id"] = conversation_id
async with httpx.AsyncClient(timeout=300) as client:
async with client.stream(
"POST",
f"{self.base_url}/chat-messages",
headers=self.headers,
json=payload
) as response:
response.raise_for_status()
async for line in response.aiter_lines():
if not line.startswith("data: "):
continue
data_str = line[6:]
if data_str == "[DONE]":
break
try:
data = json.loads(data_str)
yield data
except json.JSONDecodeError:
continue
async def upload_file(self, file_path: str, user: str = "user") -> dict:
"""上传文件用于对话"""
async with httpx.AsyncClient(timeout=120) as client:
with open(file_path, "rb") as f:
response = await client.post(
f"{self.base_url}/files/upload",
headers={"Authorization": f"Bearer {self.api_key}"},
files={"file": f},
data={"user": user}
)
response.raise_for_status()
return response.json()
async def get_conversations(self, user: str, limit: int = 20) -> list:
"""获取对话历史列表"""
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.base_url}/conversations",
headers=self.headers,
params={"user": user, "limit": limit}
)
response.raise_for_status()
return response.json()["data"]
# 使用示例
async def main():
client = DifyClient(
api_key="app-xxxxxxxxxxxx",
base_url="http://localhost/v1"
)
# 非流式对话
result = await client.chat("如何使用 RAG 功能?")
print(result["answer"])
# 流式对话
async for chunk in client.chat_stream("介绍一下你们的产品"):
if chunk.get("event") == "message":
print(chunk["answer"], end="", flush=True)
print()
if __name__ == "__main__":
import asyncio
asyncio.run(main())
6.3 FastAPI 集成
python
"""
Dify + FastAPI 集成示例
"""
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from typing import Optional
import asyncio
app = FastAPI(title="AI Assistant API")
dify_client = DifyClient(api_key="app-xxxxx", base_url="http://localhost/v1")
class ChatRequest(BaseModel):
query: str
conversation_id: Optional[str] = None
user: str = "user"
class ChatResponse(BaseModel):
answer: str
conversation_id: str
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
"""非流式对话"""
try:
result = await dify_client.chat(
query=request.query,
conversation_id=request.conversation_id,
user=request.user
)
return ChatResponse(
answer=result["answer"],
conversation_id=result["conversation_id"]
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/chat/stream")
async def chat_stream(request: ChatRequest):
"""流式对话"""
async def generate():
async for chunk in dify_client.chat_stream(
query=request.query,
conversation_id=request.conversation_id,
user=request.user
):
if chunk.get("event") == "message":
yield f"data: {json.dumps(chunk)}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream"
)
七、模型管理
7.1 多模型配置
plaintext
Dify 模型管理界面:
┌───────────────────────────────────────────────────┐
│ 模型供应商 │
│ │
│ ├── OpenAI │
│ │ ├── GPT-4o ──── 聊天/推理 │
│ │ ├── GPT-4o-mini ── 轻量聊天 │
│ │ ├── o3 ──────── 深度推理 │
│ │ └── text-embedding-3-small ── Embedding │
│ │ │
│ ├── Anthropic │
│ │ ├── Claude 4 Sonnet ── 高质量推理 │
│ │ └── Claude 4 Haiku ── 快速推理 │
│ │ │
│ ├── DeepSeek │
│ │ ├── DeepSeek V4 ── 中文推理 │
│ │ └── DeepSeek Embedding ── 中文 Embedding │
│ │ │
│ └── Ollama(本地模型) │
│ ├── Qwen3:7B ──── 中文对话 │
│ ├── Llama3.1:8B ── 英文对话 │
│ └── nomic-embed-text ── 本地 Embedding │
└───────────────────────────────────────────────────┘
7.2 模型切换策略
python
# 根据场景选择不同模型
model_strategy = {
"简单问答": {
"model": "gpt-4o-mini",
"reason": "成本低,速度快",
"cost_per_1k": "$0.00015"
},
"复杂推理": {
"model": "gpt-4o",
"reason": "推理能力强",
"cost_per_1k": "$0.005"
},
"中文场景": {
"model": "deepseek-v4",
"reason": "中文能力最强",
"cost_per_1k": "¥0.001"
},
"隐私敏感": {
"model": "ollama:qwen3-7b",
"reason": "数据不出本机",
"cost_per_1k": "免费"
}
}
八、生产部署
8.1 高可用架构
plaintext
┌─────────────────────────────────────────────────────────┐
│ 负载均衡器 (Nginx) │
│ SSL 终端 / 速率限制 │
└────────────┬────────────────────────────┬───────────────┘
│ │
┌────────▼────────┐ ┌────────▼────────┐
│ Dify API #1 │ │ Dify API #2 │
│ (Container) │ │ (Container) │
└────────┬────────┘ └────────┬────────┘
│ │
┌────────▼────────────────────────────▼───────────────┐
│ 共享存储层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │PostgreSQL│ │ Redis │ │ Weaviate │ │
│ │ (主从) │ │ (哨兵) │ │ (集群) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ │
│ │S3/MinIO │ ← 文件存储 │
│ └──────────┘ │
└──────────────────────────────────────────────────────┘
8.2 Nginx 反向代理配置
nginx
# Nginx 反向代理配置(生产环境)
upstream dify_api {
server api:5001;
keepalive 64;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/ssl/certs/your-cert.pem;
ssl_certificate_key /etc/ssl/private/your-key.pem;
# 上传文件大小限制(知识库文档)
client_max_body_size 100m;
# API 代理
location /api {
proxy_pass http://dify_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# SSE 流式输出必须的配置
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
# 关闭 gzip(SSE 不兼容 gzip)
gzip off;
}
# Web 界面
location / {
proxy_pass http://dify_web:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
8.3 监控与日志
bash
# Dify 日志查看
docker compose logs api --tail 100 -f
docker compose logs worker --tail 100 -f
# 关键指标监控
# 1. API 响应时间
# 2. Worker 队列长度
# 3. PostgreSQL 连接数
# 4. Redis 内存使用
# 5. Weaviate 索引大小
# 使用 Prometheus + Grafana 监控
# Dify 1.0+ 支持导出 Prometheus 指标
8.4 多租户配置
plaintext
Dify 多租户架构:
├── 租户隔离
│ ├── 数据隔离(每个租户独立的数据库 schema)
│ ├── 模型隔离(不同租户可用不同模型)
│ └── API Key 隔离
│
├── 权限管理
│ ├── 管理员:全局配置
│ ├── 编辑者:创建和编辑应用
│ └── 查看者:只能查看和使用
│
└── 资源配额
├── API 调用次数限制
├── 存储空间限制
└── 并发请求限制
九、插件生态
9.1 Dify Plugin 市场
plaintext
Dify 1.9+ 插件架构:
├── Plugin Manifest v3
├── Rust + WASM 双运行时
├── 高性能插件执行
└── 安全沙箱隔离
9.2 MCP Server 集成
Dify v1.9+ 支持将应用发布为 MCP Server:
plaintext
1. 应用设置 → MCP → 启用
2. 复制 MCP URL
3. 在 Claude Desktop 的配置文件中添加:
{
"mcpServers": {
"my-dify-app": {
"url": "https://your-domain.com/mcp/sse",
"headers": {
"Authorization": "Bearer app-xxxxx"
}
}
}
}
4. Claude Desktop 现在可以直接调用你的 Dify 应用
9.3 自定义插件开发
bash
# 安装 Dify 插件 CLI
pip install dify-plugin-cli
# 从模板创建插件
dify-plugin init my-plugin --template tool
# 目录结构
# my-plugin/
# ├── plugin.yaml # 插件元数据
# ├── manifest.yaml # 插件清单
# ├── provider/ # 供应商实现
# ├── tools/ # 工具实现
# └── models/ # 模型实现(如果需要)
# 构建插件
dify-plugin build --schema plugin.yaml
# 部署插件
dify-plugin deploy --app my-agent
十、踩坑记录
坑1:Docker 内访问宿主机 Ollama
plaintext
问题: Dify 无法连接本地 Ollama
原因: Docker 容器内的 localhost 指向容器自身,不是宿主机
修复: 使用 host.docker.internal 替代 localhost
Ollama 地址: http://host.docker.internal:11434
教训: Docker 网络是独立的,跨网络访问要用正确的地址
坑2:SSE 流式输出被 Nginx 缓冲
plaintext
问题: 流式对话变成了一次性返回全部内容
原因: Nginx 默认开启 proxy_buffering,缓冲 SSE 响应
修复: 在 Nginx 配置中添加:
proxy_buffering off;
proxy_cache off;
gzip off; # gzip 也不兼容 SSE
教训: SSE 和 Nginx 默认配置不兼容,必须显式关闭缓冲
坑3:知识库中文分块质量差
plaintext
问题: 中文文档分块后语义被切断
原因: 默认分块策略基于英文标点和空格
修复:
1. 使用"按标题"或"自定义分隔符"策略
2. 分段长度设为 500-800 tokens(中文更短更精确)
3. 增加重叠到 100-150 tokens
教训: 中文文档的分块策略需要专门调优,不能直接用英文默认值
坑4:Weaviate 内存溢出
plaintext
问题: 知识库文档增多后,Weaviate 占用内存持续增长
原因: 向量索引没有定期清理和优化
修复:
1. 定期运行 Weaviate 的索引优化
2. 限制单个知识库的文档数量
3. 考虑升级到更大的服务器
教训: 向量数据库也需要运维,不是"建了就不管"
坑5:API Key 泄露
plaintext
问题: 前端代码中直接硬编码 Dify API Key
原因: 开发时图方便,忘记移除
修复:
1. API Key 只存后端,前端通过后端代理
2. 使用 Dify 的 Rate Limit 功能
3. 定期轮换 API Key
教训: Dify 的 API Key 等同于应用访问权限,必须像密码一样保护
坑6:Dify 升级后数据库迁移失败
plaintext
问题: docker compose pull 后升级,数据库迁移报错
原因: 新版本的数据库 schema 与旧版本不兼容
修复:
1. 升级前备份数据库
docker compose exec db pg_dump -U postgres dify > backup.sql
2. 按版本号逐步升级(不要跨大版本)
3. 升级后检查 docker compose logs api 日志
教训: 数据库备份是升级前的必须步骤,不要偷懒
总结
Dify 的核心价值:让 AI 应用开发从"写代码"变成"搭积木" 。
表格
推荐路线:
plaintext
步骤1: 用 Dify 云版体验(cloud.dify.ai),5 分钟上手
步骤2: Docker 自部署,数据完全可控
步骤3: 搭建 RAG 知识库,验证业务价值
步骤4: API 集成到现有系统
步骤5: 生产优化(高可用、监控、多租户)
本文由 PySuper 撰写,首发于 zhengxingtao.com
参考来源:
据《用Dify搭建AI应用:零代码接入大模型,30分钟从想法到上线》(掘金, 2026-05-08)
据《How to Self-Host Dify with Docker — Complete AI Workflow Guide 2026》(Effloow, 2026-04-04)
据《Dify 1.0工程实践:开源LLM应用开发平台的生产级部署完全指南》(CSDN, 2026-05-14)
据《Dify vs Coze: 2026 年 AI 应用编排平台怎么选》(掘金, 2026-04-30)
评论区