【第 3 篇:Dify——低代码开发平台,快速搭建一个智能体】
第 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检索增强,搭建 “查询改写 + 答案验证 + 自动重试” 质量闭环。
更多推荐



所有评论(0)