第 3 篇:Dify——低代码开发平台,快速搭建一个智能体

系列记录:《从零搭建企业级 LLM 应用》,这是第 3 篇
上一篇:框架选型——LangChain、LangGraph、CrewAI
下一篇:RAG 知识库问答——检索只是第一步


Dify 是什么

Dify 是一个开源的 LLM 应用开发平台。你可以把它理解为"大模型时代的低代码工具"——通过拖拽节点、连线的方式,把 LLM、知识检索、代码执行、HTTP 请求等模块串成一条工作流,无需写后端代码就能搭出一个 AI 应用。

它提供的主要能力包括:

  • 可视化工作流编排:知识检索节点 → LLM 节点 → 代码节点 → 条件分支,拖拽连线即可
  • 知识库管理:上传文档自动分段、向量化、建索引,开箱即用
  • 内置 LLM 接入:支持 OpenAI、Claude、文心、通义千问等主流模型
  • API 发布:搭好的应用可以一键发布为 RESTful API

对于想快速验证 AI 应用想法的场景,Dify 确实是一个效率很高的工具。


为什么一开始选了 Dify

最初的需求:想搭建一个企业知识助手,但不确定 Agent 架构怎么设计、路由逻辑怎么写、工具调用怎么串。Dify 的可视化工作流正好能帮我跳过这些技术细节,先把想法跑起来。

而且 Dify 自带知识库管理——上传文档即可检索,不需要自己搭向量数据库。对于"先验证想法能不能行"的阶段,这个效率很关键。

所以我先在 Dify 上搭了一个原型:知识检索节点搜文档 → LLM 节点生成回答。基本跑通了最简单的问答场景。


Dify瓶颈:无法动态生成代码

对于"数据统计分析"类的业务场景,Dify 存在一定局限:LLM需要根据用户的问题,动态生成一段 Python 代码,然后执行这段代码对数据进行统计。

Dify 内置"代码节点",但它只能写静态代码。你在编辑工作流的时候就把代码写死了——比如 df.groupby('部门').sum()。问题是用户每次问的维度都不一样:今天问迟到统计、明天问加班趋势、后天问跨月对比。我不可能为每一种统计需求预写代码。

我需要的是一套"LLM 生成代码 → 代码被执行 → 结果返回"的动态链路,而 Dify 工作流做不到这一点。


一个临时的绕过方案

既然代码节点只能写死代码,那我就把代码节点换成一个 HTTP 请求节点。在本地起一个 FastAPI 后端服务,流程变成:

用户在 Dify 提问
  → LLM 节点根据问题生成 Python 代码(作为文本输出)
  → HTTP 请求节点 → 本地后端服务接收代码并执行
  → 后端返回统计结果
  → Dify 工作流继续走后续节点

这个方案能跑通,但本质上是把 Dify 当成一个"中间层",真正的执行逻辑已经跑在本地服务上了。

用了一段时间后,问题越来越多:

  • 工作流是静态的——一旦发布,执行路径就固定了,无法根据中间结果动态调整。而 Agent 需要"先看有哪些文件 → 再决定怎么处理"这种动态决策。
  • 多轮对话记不住上下文——每次请求独立,做不了"上一轮查了 A 文件,这一轮基于它继续分析"。
  • 三个 Agent 需要三套独立工作流——各自维护一套配置,没有共享的路由逻辑。
  • 出错了很难定位——只能看每个节点的输入输出日志,没有像 LangSmith 这样的全链路追踪。

Dify 工作流是一个静态图——你在编辑阶段定义好所有分支。而我的需求需要动态决策——Agent 根据当前状态自主判断下一步该干什么。这是根本性的架构差异。


转 LangGraph 框架开发

二者适用场景不同

低代码平台(如 Dify 工作流) 代码开发(如 LangGraph)
适合什么 流程固定、分支有限的场景 需要动态决策、自主路由的场景
灵活性 受限于平台提供的节点类型和编排方式 完全自由,可以定义任意复杂的状态流转
Agent 自主性 工作流定义"先做什么后做什么" Agent 自己决定"当前该调哪个工具"
多轮上下文 每次请求独立,需手动管理 框架内置 checkpoint 机制
调试体验 节点级日志 LangSmith 全链路 Trace
开发速度 初始搭建快 初始搭建慢,但复杂场景下反而更快

当需求足够简单时,Dify 工作流确实是最快的选择。


Dify 知识库

虽然放弃了 Dify 的工作流编排能力,但保留了知识库构建。

用 Dify 的知识库 API,接入成本极低,可视化操作,无需自建向量知识库。

切块策略:决定召回率的关键

Dify 上传文档后自动分段、向量化,表面上"上传即用",但默认配置远不是最优解。我在调召回率的过程中,花的精力最多的就是切块(Chunk)策略。

三种切块模式怎么选

模式 原理 适合什么
默认 通过"\n\n"区分段落边界 结构清晰的文档
自定义分段 手动设分隔符、最大长度、重叠 有固定格式的文档(制度、合同)
通用分段 按固定字符数切割 纯文本、无格式文档

对于企业制度类文档,选的是自定义分段。制度文件层级分明——“第一章 总则”“第一条 xxx”——通用分段会把一条规定拦腰切断,检索出来的片段上下文缺失。


默认分隔符是 \n或者\n\n,但制度文档里有大量编号列表:

第二条 考勤时间
1. 上午上班:09:00
2. 下午下班:18:00
3. 午休:12:00-13:30

默认切块可能把第 3 条切到下一个 chunk,"午休"脱离"第二条"的上下文,语义关联就断了。

测召回率
Dify知识库中的文档设置分段和检索规则后,可通过输入问题直接测试各分段的召回率,以此评判分段和检索规则是否需要调整。


调通 API 只是开始,踩了好几个坑

坑 1:简单问题搜不到

上传完文档,问了句"公司的核心价值观是什么"——返回空结果。

知识库里明明有这份文档。排查后发现,Dify 默认开启了检索分数阈值,短问题的语义向量匹配度天然偏低,被直接过滤掉了。调整检索参数后解决:关闭分数阈值、关闭重排序、增加返回条数。

坑 2:短问题语义匹配弱

"考勤制度"这种四个字的查询,语义向量信息量太少,匹配效果很差。

这不是 Dify 的问题,而是短文本语义搜索的固有局限。后来在 RAG Agent 里加了查询改写策略:长问题让 LLM 扩展语义,短问题直接用原文。

坑 3:改写过的问题也搜不到

有时候 LLM 把"迟到怎么算"改写成了"企业考勤管理迟到判定标准",方向是对的,但措辞与文档原文差距太大,反而搜不到。加回退逻辑解决:改写查询无结果时,自动用原始问题再搜一次。


一些思考

Dify 工作流和 LangGraph 代码开发,不是"谁更好"的对立关系,而是"什么时候用哪个"的递进关系。

我的路径是:先用 Dify 工作流快速验证想法 → 发现需求的复杂度超过了平台边界 → 切换到 LangGraph 获得完全控制权 → 但保留了 Dify 的知识库能力,因为它在这一块确实高效。


下一篇记录:RAG检索增强,搭建 “查询改写 + 答案验证 + 自动重试” 质量闭环。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐