第 2 章

核心概念全景:应用类型、工作流、知识库、Agent 关系图

第2章:核心概念全景——应用类型、工作流、知识库、Agent 关系图

在动手配置之前,先在脑中建立 Dify 的概念地图——理解这四个核心模块的边界和关系,是用好 Dify 的前提。

本章导读

很多人上手 Dify 的方式是:点开界面,看到什么点什么,遇到问题搜文档。这种方式能解决眼前的问题,但容易陷入"为什么这个功能要放在这里"的困惑,或者在复杂场景下不知道该用哪个模块。

本章的目标是给你一张 Dify 的概念地图。我们会系统梳理 Dify 中的四大核心模块:应用类型(Applications)、工作流(Workflow)、知识库(Knowledge Base)、Agent,以及它们之间的关系和适用边界。

读完本章,你将能够:


Level 1:基础认知(1-3 年经验)

Dify 的四大核心模块

Dify 的所有功能可以归纳为四个核心模块,它们之间既独立又相互依赖:

┌─────────────────────────────────────────────────────────┐
│                     应用(Application)                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────┐  │
│  │ 聊天助手  │  │ 文本生成  │  │  工作流   │  │ Agent  │  │
│  └──────────┘  └──────────┘  └──────────┘  └────────┘  │
└─────────────────────────────────────────────────────────┘
              ↕ 调用                    ↕ 调用
┌─────────────────────────┐  ┌─────────────────────────────┐
│     知识库(Knowledge)  │  │       模型(Model)          │
│  文档存储 + 向量索引      │  │  LLM + Embedding + Rerank   │
└─────────────────────────┘  └─────────────────────────────┘

这个结构说明了一个关键事实:知识库和模型是基础设施,应用是使用这些基础设施的上层。不管是聊天助手、工作流还是 Agent,都可以调用同一个知识库,使用不同的模型。

五种应用类型详解

1. 聊天助手(Chat Assistant)

最常用的类型。用户和 AI 进行多轮对话,AI 能记住对话历史。

核心特征

典型场景:客服机器人、个人助理、专业咨询(法律、医疗等领域问答)

一个实际配置示例

应用类型:聊天助手
系统提示:你是一个专业的法律咨询助手,专注于中国劳动法领域...
关联知识库:劳动法条文库(包含《劳动合同法》《劳动争议调解仲裁法》等)
模型:GPT-4o
上下文历史轮数:10(保留最近 10 轮对话)

2. 文本生成(Text Generator)

单次输入,单次输出。没有对话历史,每次都是一个独立的请求。

核心特征

典型场景:SEO 文章批量生成、产品描述自动写作、代码注释生成、邮件模板生成

对比聊天助手的关键差异

3. 工作流(Workflow)

多个处理节点串联执行,每个节点可以是 LLM 调用、代码执行、HTTP 请求、条件判断等。

核心特征

典型场景

工作流 vs 聊天助手的选择原则

4. 聊天流(Chatflow)

工作流和聊天助手的结合体。有固定的处理流程,但又支持多轮对话。

核心特征

典型场景:医疗问诊助手(需要按固定流程收集症状信息,同时支持对话式交互)

5. Agent(智能体)

给 AI 提供工具集,让 AI 自主决定调用哪些工具、以什么顺序调用,来完成用户的任务。

核心特征

典型场景:数据分析 Agent(让 AI 自己决定查哪个数据库、做什么计算)、旅游规划 Agent

知识库(Knowledge Base)是什么

知识库是 Dify 中存储和检索文档的模块。本质上,它做了以下事情:

  1. 文档处理:将上传的文档(PDF、Word、Markdown 等)切分成小块(chunks)
  2. 向量化:调用 Embedding 模型将每个文本块转化为向量
  3. 存储:将向量和原始文本存入向量数据库
  4. 检索:当应用需要时,将用户问题也向量化,找最相似的文本块

知识库本身不是应用,它是被应用调用的资源。一个知识库可以被多个应用共享

用一个场景理解这四者的关系

假设你要为一家律所构建一套 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 代码,但有严格限制:

# 代码节点示例:从文本中提取金额
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)
    }

知识库的检索配置详解

知识库的检索有三种模式,理解它们的区别至关重要:

将查询转化为向量,通过余弦相似度找最接近的文档块。

优点:语义理解能力强,"苹果手机"和"iPhone"能匹配 缺点:精确词匹配能力弱,对特定编号、专有名词效果差 适合:语义模糊的问题,如"我的合同什么时候到期"

基于关键词的 BM25 算法检索。

优点:精确词匹配,对编号、代码、专有名词效果好 缺点:无法理解语义,"手机"匹配不到"iPhone" 适合:精确查询,如"合同编号 SH-2024-001 的条款"

同时进行向量检索和全文检索,用加权算法(如 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())
                }
            })

关键性能数字

多知识库检索的合并策略

当一个应用关联了多个知识库时,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}}

原因通常是:

  1. 节点 ID 写错:Dify 自动生成的节点 ID 如 llm-12345,手动输入时容易拼错
  2. 字段名不存在:LLM 节点的输出是 text,不是 contentoutput
  3. 条件分支导致变量不可达:在 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 但没有有用的输出。

生产建议

  1. 设置工具调用的超时时间(HTTP 工具可设置)
  2. 在工具的描述中明确说明何时不应该调用该工具
  3. 对 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 用对话方式分析。问题:

正确方案:工作流(文件输入 → 分块处理 → 并行分析 → 结果汇总)

误判 2:用 Agent 做本该用工作流的事

某团队用 Agent 实现"销售报告生成"。结果:

正确方案:工作流(流程固定,结果可预测)

选型口诀

模块关系最终总结图

┌─────────────────────────────────────────────────────────────────┐
│                         Dify 应用层                              │
│                                                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌───────────┐  ┌─────────┐  │
│  │  聊天助手   │  │   工作流    │  │  聊天流   │  │  Agent  │  │
│  │  多轮对话   │  │  固定流程   │  │  两者兼顾 │  │  自主决策│  │
│  └──────┬──────┘  └──────┬──────┘  └─────┬─────┘  └────┬────┘  │
└─────────┼────────────────┼───────────────┼─────────────┼───────┘
          │                │               │             │
          └────────────────┴───────────────┴─────────────┘
                                    │
              ┌─────────────────────┼─────────────────────┐
              ↓                     ↓                     ↓
    ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐
    │    知识库(RAG)  │  │   模型(LLM)    │  │    工具(Tools)  │
    │  文档 + 向量索引  │  │  生成 + Embedding│  │  搜索/计算/API   │
    └──────────────────┘  └──────────────────┘  └──────────────────┘

本章小结

Dify 的四大核心模块构成了一个完整的 AI 应用开发生态:应用层(聊天助手/工作流/Agent)、知识层(知识库)、模型层(LLM + Embedding)、工具层(外部服务)。

核心要点

  1. 应用类型选对是关键:流程固定用工作流,交互自由用聊天助手,自主决策用 Agent
  2. 知识库是共享资源:一个知识库可以被多个应用同时使用,更新知识库会影响所有使用它的应用
  3. 变量系统是数据流的骨架:理解变量作用域,是调试工作流问题的关键
  4. Agent 的不确定性:Agent 的执行路径不可预测,生产场景下要做好兜底处理
  5. 混合检索是最佳实践:对于大多数知识问答场景,混合检索 + 重排序的效果显著优于单一检索方式

下一章将进入实操环节:从零开始,完整构建你的第一个 AI 应用,涵盖从需求分析到上线的全流程。

本章评分
4.6  / 5  (91 评分)

💬 留言讨论