核心概念全景:应用类型、工作流、知识库、Agent 关系图
第2章:核心概念全景——应用类型、工作流、知识库、Agent 关系图
在动手配置之前,先在脑中建立 Dify 的概念地图——理解这四个核心模块的边界和关系,是用好 Dify 的前提。
本章导读
很多人上手 Dify 的方式是:点开界面,看到什么点什么,遇到问题搜文档。这种方式能解决眼前的问题,但容易陷入"为什么这个功能要放在这里"的困惑,或者在复杂场景下不知道该用哪个模块。
本章的目标是给你一张 Dify 的概念地图。我们会系统梳理 Dify 中的四大核心模块:应用类型(Applications)、工作流(Workflow)、知识库(Knowledge Base)、Agent,以及它们之间的关系和适用边界。
读完本章,你将能够:
- 清楚区分 Dify 中五种应用类型的差异和适用场景
- 理解工作流与聊天助手的本质区别
- 知道知识库在整个系统中扮演什么角色
- 理解 Agent 的推理机制和使用限制
- 面对新需求时能快速判断该用哪个模块
Level 1:基础认知(1-3 年经验)
Dify 的四大核心模块
Dify 的所有功能可以归纳为四个核心模块,它们之间既独立又相互依赖:
┌─────────────────────────────────────────────────────────┐
│ 应用(Application) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ 聊天助手 │ │ 文本生成 │ │ 工作流 │ │ Agent │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────┘ │
└─────────────────────────────────────────────────────────┘
↕ 调用 ↕ 调用
┌─────────────────────────┐ ┌─────────────────────────────┐
│ 知识库(Knowledge) │ │ 模型(Model) │
│ 文档存储 + 向量索引 │ │ LLM + Embedding + Rerank │
└─────────────────────────┘ └─────────────────────────────┘
这个结构说明了一个关键事实:知识库和模型是基础设施,应用是使用这些基础设施的上层。不管是聊天助手、工作流还是 Agent,都可以调用同一个知识库,使用不同的模型。
五种应用类型详解
1. 聊天助手(Chat Assistant)
最常用的类型。用户和 AI 进行多轮对话,AI 能记住对话历史。
核心特征:
- 有对话历史(Memory)
- 一问一答,每次等待用户输入
- 支持关联知识库(RAG)
- 支持工具调用(Tools)
典型场景:客服机器人、个人助理、专业咨询(法律、医疗等领域问答)
一个实际配置示例:
应用类型:聊天助手
系统提示:你是一个专业的法律咨询助手,专注于中国劳动法领域...
关联知识库:劳动法条文库(包含《劳动合同法》《劳动争议调解仲裁法》等)
模型:GPT-4o
上下文历史轮数:10(保留最近 10 轮对话)
2. 文本生成(Text Generator)
单次输入,单次输出。没有对话历史,每次都是一个独立的请求。
核心特征:
- 无对话历史
- 通常有固定的输入表单(如"文章主题"、"字数要求"等变量)
- 适合批量、标准化的内容生成
典型场景:SEO 文章批量生成、产品描述自动写作、代码注释生成、邮件模板生成
对比聊天助手的关键差异:
- 聊天助手:用户主导对话方向,有来有往
- 文本生成:用户填写固定表单,AI 按模板输出
3. 工作流(Workflow)
多个处理节点串联执行,每个节点可以是 LLM 调用、代码执行、HTTP 请求、条件判断等。
核心特征:
- 固定的处理流程(DAG 图)
- 每个节点类型不同,分工明确
- 支持条件分支、循环(迭代器节点)
- 输入输出明确
典型场景:
- 内容审核流程:接收文章 → 检查违规 → 自动修改 → 人工审核 → 发布
- 客服分级处理:接收问题 → 分类(产品/技术/投诉)→ 路由到对应知识库 → 生成回答
- 数据分析报告:接收数据 → 数据清洗 → 调用 LLM 分析 → 格式化输出
工作流 vs 聊天助手的选择原则:
- 流程固定、步骤明确 → 工作流
- 交互自由、用户主导 → 聊天助手
4. 聊天流(Chatflow)
工作流和聊天助手的结合体。有固定的处理流程,但又支持多轮对话。
核心特征:
- 既有工作流的节点编排能力
- 又有聊天助手的多轮对话记忆
- 适合"有流程约束的对话"场景
典型场景:医疗问诊助手(需要按固定流程收集症状信息,同时支持对话式交互)
5. Agent(智能体)
给 AI 提供工具集,让 AI 自主决定调用哪些工具、以什么顺序调用,来完成用户的任务。
核心特征:
- 自主决策(AI 决定做什么,不是你决定)
- 工具调用(搜索、计算器、数据库查询等)
- ReAct 循环(思考 → 行动 → 观察 → 思考...)
- 不可预测性(每次执行路径可能不同)
典型场景:数据分析 Agent(让 AI 自己决定查哪个数据库、做什么计算)、旅游规划 Agent
知识库(Knowledge Base)是什么
知识库是 Dify 中存储和检索文档的模块。本质上,它做了以下事情:
- 文档处理:将上传的文档(PDF、Word、Markdown 等)切分成小块(chunks)
- 向量化:调用 Embedding 模型将每个文本块转化为向量
- 存储:将向量和原始文本存入向量数据库
- 检索:当应用需要时,将用户问题也向量化,找最相似的文本块
知识库本身不是应用,它是被应用调用的资源。一个知识库可以被多个应用共享。
用一个场景理解这四者的关系
假设你要为一家律所构建一套 AI 系统:
需求分析:
├── 律师日常咨询助手 → 聊天助手(多轮对话,关联法律知识库)
├── 合同自动审查 → 工作流(接收合同 → 条款提取 → 风险分析 → 生成报告)
├── 案情摘要生成 → 文本生成(输入案情描述,输出结构化摘要)
├── 法律检索助手 → Agent(自主搜索法律数据库、判例库,综合分析)
└── 法律知识库 → 知识库(存储所有法规、合同模板、判例文书)
同一个"法律知识库",被聊天助手、工作流、Agent 同时使用。这就是模块化的价值。
Level 2:机制深解(3-5 年经验)
应用类型背后的技术差异
从技术实现角度,五种应用类型的核心差异在于状态管理方式和执行控制流:
| 应用类型 | 状态管理 | 执行控制流 | 终止条件 |
|---|---|---|---|
| 聊天助手 | 数据库存储对话历史 | 单步 LLM 调用 | 一次响应后结束 |
| 文本生成 | 无状态 | 单步 LLM 调用 | 一次响应后结束 |
| 工作流 | 节点间变量传递 | DAG 顺序执行 | 到达终止节点 |
| 聊天流 | 对话历史 + 节点变量 | DAG + 对话状态 | 到达响应节点 |
| Agent | 工具调用结果缓存 | ReAct 循环 | 达到最大迭代次数或完成任务 |
工作流节点类型详解
工作流支持以下节点类型(Dify v0.10+):
节点类型
├── 基础节点
│ ├── 开始(Start):工作流入口,定义输入变量
│ ├── 结束(End):工作流出口,定义输出内容
│ └── 直接回复(Answer):在聊天流中直接向用户回复
├── LLM 节点
│ ├── LLM:调用大语言模型
│ └── 知识检索(Knowledge Retrieval):从知识库检索
├── 数据处理节点
│ ├── 代码(Code):执行 Python/JavaScript 代码
│ ├── 模板转换(Template Transform):Jinja2 模板渲染
│ └── 变量聚合(Variable Aggregator):合并多个变量
├── 流程控制节点
│ ├── 条件分支(IF/ELSE):根据条件选择执行路径
│ ├── 迭代(Iteration):对列表中的每个元素执行相同操作
│ └── 参数提取(Parameter Extractor):从文本中提取结构化数据
└── 外部数据节点
├── HTTP 请求(HTTP Request):调用外部 API
└── 工具(Tool):调用 Dify 内置工具或自定义工具
重要细节:代码节点的沙箱机制
代码节点执行 Python/JS 代码,但有严格限制:
- 不能访问文件系统
- 不能导入第三方库(只允许标准库)
- 执行超时:5 秒(可配置,最长 60 秒)
- 内存限制:256MB
# 代码节点示例:从文本中提取金额
def main(text: str) -> dict:
import re
# 匹配金额格式(如 ¥1,234.56 或 1234.56元)
pattern = r'[¥¥]?\d{1,3}(?:,\d{3})*(?:\.\d{2})?(?:元|美元|USD)?'
amounts = re.findall(pattern, text)
return {
"amounts": amounts,
"count": len(amounts)
}
知识库的检索配置详解
知识库的检索有三种模式,理解它们的区别至关重要:
向量检索(Vector Search)
将查询转化为向量,通过余弦相似度找最接近的文档块。
优点:语义理解能力强,"苹果手机"和"iPhone"能匹配 缺点:精确词匹配能力弱,对特定编号、专有名词效果差 适合:语义模糊的问题,如"我的合同什么时候到期"
全文检索(Full-text Search)
基于关键词的 BM25 算法检索。
优点:精确词匹配,对编号、代码、专有名词效果好 缺点:无法理解语义,"手机"匹配不到"iPhone" 适合:精确查询,如"合同编号 SH-2024-001 的条款"
混合检索(Hybrid Search)
同时进行向量检索和全文检索,用加权算法(如 RRF,Reciprocal Rank Fusion)合并结果。
优点:兼顾语义和精确匹配 缺点:需要同时运行两种检索,性能开销较大 适合:大多数实际场景(Dify 推荐的默认选项)
配置建议:
# 典型的混合检索配置
retrieval_mode: hybrid
vector_weight: 0.7 # 向量检索权重 70%
keyword_weight: 0.3 # 关键词检索权重 30%
top_k: 5 # 召回前 5 个片段
score_threshold: 0.4 # 相似度阈值(低于此值的片段丢弃)
reranking_enable: true # 启用重排序(推荐)
reranking_model: bge-reranker-v2-m3 # 重排序模型
Agent 的 ReAct 推理机制
Agent 使用的 ReAct(Reasoning + Acting)模式是理解 Agent 行为的关键:
用户问题:"帮我查一下最新的 GPT-4 价格,并计算调用 10000 次的成本"
第 1 轮推理:
思考(Thought):我需要先查询 GPT-4 的最新价格
行动(Action):调用 web_search 工具,搜索 "GPT-4 API pricing 2024"
观察(Observation):搜索结果显示 GPT-4o 输入 $5/1M tokens,输出 $15/1M tokens
第 2 轮推理:
思考(Thought):我有了价格数据,现在需要计算成本
行动(Action):调用 calculator 工具,计算 10000 次调用的成本
观察(Observation):假设每次调用平均 500 输入 + 200 输出 tokens...
第 3 轮推理:
思考(Thought):计算完成,可以给出最终答案
最终回答(Final Answer):根据最新价格,10000 次调用的成本约为...
Agent 的最大迭代次数默认是 5 次,这意味着如果任务在 5 轮工具调用内无法完成,Agent 会强制终止并给出当前已有的信息。
变量系统:连接各模块的纽带
Dify 的变量系统是理解模块间数据流的关键:
变量作用域
├── 系统变量(System Variables)
│ ├── {{sys.user_id}} — 当前用户 ID
│ ├── {{sys.app_id}} — 应用 ID
│ └── {{sys.conversation_id}} — 对话 ID
├── 应用变量(App Variables)
│ └── 在「提示词」中定义的 {{variable_name}}
├── 对话变量(Conversation Variables)
│ └── 跨轮次持久化的变量(聊天流专用)
└── 工作流变量(Workflow Variables)
└── 节点输出 {{node_id.output.field}}
一个常见的变量使用示例(工作流中):
节点 1(参数提取)→ 输出:{{extract.customer_name}}, {{extract.issue_type}}
↓
节点 2(条件分支)→ 条件:{{extract.issue_type}} == "技术问题"
↓ ↓
节点 3a(技术知识库检索) 节点 3b(售后知识库检索)
↓ ↓
节点 4(LLM 生成回答)← 合并两条路径的检索结果
Level 3:源码与原理(5 年以上)
工作流引擎的内部实现
Dify 的工作流引擎在 api/core/workflow/ 目录下,核心类是 WorkflowEngineManager。
图的存储格式(PostgreSQL 中的 JSON 结构):
{
"nodes": [
{
"id": "node_start",
"type": "start",
"data": {
"variables": [
{"variable": "user_query", "type": "string", "required": true}
]
},
"position": {"x": 100, "y": 200}
},
{
"id": "node_llm_1",
"type": "llm",
"data": {
"model": {"provider": "openai", "name": "gpt-4o", "mode": "chat"},
"prompt_template": [
{"role": "system", "text": "你是一个助手"},
{"role": "user", "text": "{{#node_start.user_query#}}"}
]
},
"position": {"x": 400, "y": 200}
}
],
"edges": [
{
"id": "edge_1",
"source": "node_start",
"target": "node_llm_1",
"sourceHandle": "source",
"targetHandle": "target"
}
]
}
注意变量引用格式:{{#node_id.output_field#}},这与 Prompt 中的 {{variable}} 格式不同——前者是工作流内部变量引用,后者是应用级变量。
工作流执行的事件驱动模型:
# 简化的工作流执行事件流
class WorkflowRunState:
def __init__(self):
self.node_run_results: dict[str, NodeRunResult] = {}
self.total_tokens: int = 0
self.start_at: datetime = datetime.utcnow()
# 每个节点执行时发出事件
class NodeRunEvent:
class NodeRunStarted(Event):
node_id: str
node_type: str
class NodeRunSucceeded(Event):
node_id: str
outputs: dict
elapsed_time: float
class NodeRunFailed(Event):
node_id: str
error: str
这种事件驱动的设计让前端可以通过 SSE(Server-Sent Events)实时接收每个节点的执行状态,实现你在 Dify 界面看到的"节点逐个亮起"的效果。
Agent 引擎的实现:从 ReAct 到 Function Calling
Dify 的 Agent 引擎支持两种策略,根据模型能力自动选择:
策略 1:Function Calling(适用于 GPT-4, Claude 3+ 等支持工具调用的模型)
# 使用 OpenAI Function Calling
response = openai.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=[
{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the web for information",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
}
}
],
tool_choice="auto" # 让模型决定是否调用工具
)
策略 2:ReAct Prompt(适用于不支持 Function Calling 的模型)
对于不支持工具调用的模型,Dify 通过精心设计的 Prompt 模拟 ReAct 行为:
你是一个可以使用工具的 AI 助手。你可以使用以下工具:
- web_search(query): 搜索网页
- calculator(expression): 计算数学表达式
当你需要使用工具时,按以下格式回复:
思考:[你的推理过程]
行动:工具名称
行动输入:{"参数名": "参数值"}
当你有了最终答案时,回复:
思考:[总结]
最终答案:[你的回答]
Dify 引擎解析 LLM 的输出,提取工具调用指令,执行工具,将结果追加到对话历史,然后继续推理。
知识库的向量化流程
文档从上传到可检索的完整流程:
# 简化的文档处理流程
class DocumentProcessor:
def process(self, file: File, config: IndexingConfig) -> Dataset:
# 1. 文档解析:将 PDF/Word/HTML 转换为纯文本
text = self.extract_text(file)
# 2. 文本清洗:去除多余空白、特殊字符
cleaned_text = self.clean_text(text)
# 3. 文本分块:按配置的策略切分
chunks = self.split_text(cleaned_text, config.chunk_size, config.chunk_overlap)
# 4. 向量化:批量调用 Embedding 模型
# 注意:批量处理以减少 API 调用次数
embeddings = []
for batch in self.batch(chunks, size=100):
batch_embeddings = embedding_model.encode(batch)
embeddings.extend(batch_embeddings)
# 5. 存储:写入向量数据库
for chunk, embedding in zip(chunks, embeddings):
vector_db.insert({
"text": chunk.text,
"embedding": embedding,
"metadata": {
"document_id": file.id,
"chunk_index": chunk.index,
"word_count": len(chunk.text.split())
}
})
关键性能数字:
- 1000 个文本块的 Embedding 处理时间:约 30-60 秒(text-embedding-3-small)
- 存储到向量数据库的吞吐量:约 500-1000 个向量/秒(Weaviate)
- 检索延迟:5-20ms(向量相似度计算)+ 50-200ms(网络 + 数据库)
多知识库检索的合并策略
当一个应用关联了多个知识库时,Dify 的检索合并流程:
def multi_dataset_retrieval(query: str, datasets: list[Dataset], config: RetrievalConfig):
all_results = []
# 对每个知识库独立检索
for dataset in datasets:
results = dataset.search(
query=query,
top_k=config.top_k,
mode=config.retrieval_mode
)
all_results.extend(results)
# 去重(同一文档的相同片段可能从多个知识库返回)
unique_results = deduplicate(all_results)
# 如果启用了重排序
if config.reranking_enable:
# 用 Reranker 模型对所有结果重新打分
reranked = reranker_model.rerank(query=query, documents=unique_results)
return reranked[:config.top_k]
else:
# 按相似度分数排序,取 top_k
return sorted(unique_results, key=lambda x: x.score, reverse=True)[:config.top_k]
Level 4:生产陷阱与决策(专家视角)
陷阱 1:工作流中的变量引用错误
最常见的工作流报错:Variable not found: {{node_x.output.field}}。
原因通常是:
- 节点 ID 写错:Dify 自动生成的节点 ID 如
llm-12345,手动输入时容易拼错 - 字段名不存在:LLM 节点的输出是
text,不是content或output - 条件分支导致变量不可达:在 IF/ELSE 分支后使用了只在某个分支中定义的变量
调试方法:启用「单步调试」模式,在 Dify 界面的调试面板中查看每个节点的实际输入和输出。
变量命名规范(减少出错):
# 好的节点命名习惯
✓ extract_customer_info → 输出:{{extract_customer_info.output.name}}
✓ search_policy_docs → 输出:{{search_policy_docs.output.results}}
✗ node1 → 输出:{{node1.output.xxx}} (容易混淆)
陷阱 2:Agent 的无限循环风险
Agent 在某些场景下会陷入循环:工具调用失败 → 重试 → 再次失败 → 再次重试...
Dify 的默认防护机制:最大迭代次数 5 次。但这 5 次都失败的代价是:消耗了大量 Token 但没有有用的输出。
生产建议:
- 设置工具调用的超时时间(HTTP 工具可设置)
- 在工具的描述中明确说明何时不应该调用该工具
- 对 Agent 应用设置更严格的速率限制
# Dify Agent 配置建议
max_iterations: 5 # 最大迭代次数(不要设太高)
tools:
- name: web_search
description: |
搜索互联网获取实时信息。
仅在以下情况调用:
1. 需要获取实时数据(价格、新闻等)
2. 用户明确要求搜索
不要在有内部知识库答案时调用此工具。
陷阱 3:知识库版本管理的缺失
企业在使用 Dify 知识库时常见的问题:法规更新了,但知识库里的文档还是旧版本。更糟糕的是,新旧文档同时存在,AI 回答时混合了两个版本的信息。
正确的知识库更新流程:
1. 不要直接修改现有文档
→ 而是:上传新版本文档,标记旧文档为"已归档"
2. 使用文档元数据记录版本
→ 在上传时添加元数据:{"version": "2024-Q1", "effective_date": "2024-01-01"}
3. 在检索时过滤过期文档
→ 配置知识库时,使用元数据过滤:version == "latest"
4. 定期清理归档文档
→ 确认旧版本不再需要后,从知识库删除
陷阱 4:模块选型的常见误判
误判 1:用聊天助手做本该用工作流的事
某公司的合同审查功能用聊天助手实现,用户需要手动粘贴合同内容,AI 用对话方式分析。问题:
- 上下文容量不足(大合同 > 128K tokens)
- 无法并行分析不同章节
- 结果格式不固定,难以后续处理
正确方案:工作流(文件输入 → 分块处理 → 并行分析 → 结果汇总)
误判 2:用 Agent 做本该用工作流的事
某团队用 Agent 实现"销售报告生成"。结果:
- 每次执行路径不同,结果格式不一致
- 有时 Agent 决定跳过某些步骤
- 调试和复现问题困难
正确方案:工作流(流程固定,结果可预测)
选型口诀:
- 流程固定、结果要可预测 → 工作流
- 交互自由、用户主导 → 聊天助手
- 自主决策、工具多样 → Agent
- 需要流程约束的对话 → 聊天流
模块关系最终总结图
┌─────────────────────────────────────────────────────────────────┐
│ Dify 应用层 │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ ┌─────────┐ │
│ │ 聊天助手 │ │ 工作流 │ │ 聊天流 │ │ Agent │ │
│ │ 多轮对话 │ │ 固定流程 │ │ 两者兼顾 │ │ 自主决策│ │
│ └──────┬──────┘ └──────┬──────┘ └─────┬─────┘ └────┬────┘ │
└─────────┼────────────────┼───────────────┼─────────────┼───────┘
│ │ │ │
└────────────────┴───────────────┴─────────────┘
│
┌─────────────────────┼─────────────────────┐
↓ ↓ ↓
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 知识库(RAG) │ │ 模型(LLM) │ │ 工具(Tools) │
│ 文档 + 向量索引 │ │ 生成 + Embedding│ │ 搜索/计算/API │
└──────────────────┘ └──────────────────┘ └──────────────────┘
本章小结
Dify 的四大核心模块构成了一个完整的 AI 应用开发生态:应用层(聊天助手/工作流/Agent)、知识层(知识库)、模型层(LLM + Embedding)、工具层(外部服务)。
核心要点:
- 应用类型选对是关键:流程固定用工作流,交互自由用聊天助手,自主决策用 Agent
- 知识库是共享资源:一个知识库可以被多个应用同时使用,更新知识库会影响所有使用它的应用
- 变量系统是数据流的骨架:理解变量作用域,是调试工作流问题的关键
- Agent 的不确定性:Agent 的执行路径不可预测,生产场景下要做好兜底处理
- 混合检索是最佳实践:对于大多数知识问答场景,混合检索 + 重排序的效果显著优于单一检索方式
下一章将进入实操环节:从零开始,完整构建你的第一个 AI 应用,涵盖从需求分析到上线的全流程。