LangGraph、n8n、Dify这三个词放到一起的时候,很多人第一反应是“我到底该学哪个”“哪个能取代哪个”。我做了两年多AI Agent相关项目,从最早手写状态机,到后来用LangGraph做复杂编排,再到帮业务团队搭Dify知识库、用n8n拉通内部系统,可以明确告诉你:它们根本不是一个赛道的东西,硬要比个高下没有意义,真正有价值的是搞懂各自边界,再根据实际场景做选型甚至组合使用。这篇就一次性拆清楚。
1. 选型前先搞清楚:LangGraph、n8n、Dify到底是谁
1.1 三条路线的定位差异
先说结论化的定位,后面再逐个展开:
LangGraph是LangChain团队推出的Agent编排框架,本质是一个Python/JS库,不是平台。核心是状态图(StateGraph),用节点和边的形式把Agent的执行流程画出来,然后在图上跑状态流转。程序员拿它写代码,自由度极高。
n8n是far taller出品的开源自动化工作流工具,本质是iPaaS(集成平台即服务),用来打通不同系统之间的数据流。它后来加入了LangChain节点和AI Agent节点,但它最擅长的依然是系统集成、定时任务、Webhook触发这类自动化场景。
Dify是一个完整的LLM应用开发平台,开箱即用。它有知识库(RAG)、Agent、工作流、模型管理、可观测性这些功能,讲得直白一点,就是一个把AI应用从“写代码”变成“配界面”的平台。
用一个生活化类比:LangGraph是给你一堆乐高零件和图纸,自己拼;n8n是给你一个插线板,把现成的电器插上去接通;Dify是给你一台功能完整的电器,面板上按按钮就行。
这三者的核心差异是“逻辑写在哪里”:LangGraph的逻辑在代码里,n8n的逻辑在节点连线里,Dify的逻辑在可视化编排界面里。
1.2 为什么会出现三分天下的局面
AI Agent开发落到工程层面,本质只有一件事:编排。LLM调用、工具调用、循环、条件分支、记忆管理、数据检索,这些东西谁来决定执行顺序、谁来决定何时终止、谁来决定下一步调什么,这就是Agent框架的全部核心。
三条路线分别从三个不同维度切入:
- LangGraph从“代码控制”切入。适合需要精细控制、复杂分支、动态路由、子图嵌套的场景,也是目前做生产级Agent的主流选择。
- n8n从“集成自动化”切入。它解决的痛点是“AI怎么接入现有系统”,比如Webhook触发、数据库查询、发邮件、发企业微信消息、调用内部API,这些事n8n做得极其顺手,代码量几乎为零。
- Dify从“完整产品闭环”切入。它解决的是“业务怎么用上AI”的问题,不需要团队里有懂LangChain的人,把文档丢进去做知识库,配一个Agent应用,前端通过API接入,一个可用的AI产品就出来了。
所以要我说,LangGraph、n8n和Dify之间存在的是互补关系而不是替代关系。Dify做不了很复杂的条件路由,n8n不适合写高并发状态机,LangGraph则不适合让非技术同事去维护。各管一段,才是常态。
1.3 LangGraph和LangChain的关系,为什么很多初学者卡住
搜索热词里出现频率很高的是“LangGraph和LangChain的区别”,这个问题不搞清楚,LangGraph教程看十遍也容易懵。
LangChain是一个面向LLM应用的工具链,提供了模型调用封装、Prompt模板、输出解析、文档加载、向量存储封装等基础能力。LangGraph则是建立在LangChain(或独立使用)之上的执行引擎,专门处理有状态、有分支、有循环的Agent流程。
我的理解是:LangChain解决的是“模型怎么调、数据怎么取”,LangGraph解决的是“整个流程怎么走、状态怎么流转、出错了怎么回退”。
初学者的典型误区,是还在用“链式思维”写LangGraph。LangChain的链是一串顺序执行,上一轮输出给下一轮;LangGraph是图,节点之间可以有条件跳转、可以循环、可以并行。用链式思维写Graph的典型症状是:写出来的图是一条直线,完全没发挥状态机的作用,还觉得LangGraph比LangChain还难用。
2. LangGraph核心机制实战:状态、节点、条件路由与子图
2.1 State设计:整个图的“全局变量”
LangGraph里的State是贯穿全流程的数据结构,你可以理解为一个全局共享对象,每个节点函数接收当前state,处理后返回要更新的部分。官方推荐用TypedDict定义。
from typing import TypedDict, Annotated from langgraph.graph.message import add_messages class AgentState(TypedDict): messages: Annotated[list, add_messages] # 消息列表,多个节点写入时自动追加 next_step: str # 当前执行到哪个步骤 risk_level: int # 自定义标记,例如日志风险等级 logs: list # 从ES查询到的日志结果这里最关键的是Annotated[list, add_messages]这个reducer。LangGraph默认情况下,每个节点返回的state是覆盖前值;加上add_messages之后,多个节点写入的消息会追加而不是覆盖。这就是LangGraph里控制状态“合并策略”的核心语法。
注意:State设计决定了你的Agent能跑多复杂。如果State里全是覆盖字段,节点一多就容易丢数据;如果全是追加字段,内存膨胀很快。建议高频更新的状态字段(如消息列表)用追加,流程标记字段(如当前步骤)用覆盖。
2.2 节点函数如何改变State状态值
节点函数接收state,返回一个部分更新的dict。返回什么,LangGraph就按reducer规则更新什么。一个标准的日志分析Agent节点可以这样写:
from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph def fetch_logs_from_es(state: AgentState): # 模拟从Elasticsearch获取error日志 query = {"size": 20, "query": {"term": {"level": "error"}}} response = es_client.search(index="app-logs-*", body=query) log_list = [hit["_source"] for hit in response["hits"]["hits"]] risk_level = len(log_list) return { "logs": log_list, "risk_level": risk_level, "next_step": "analyze" if risk_level > 0 else "end", }节点里做一些事:查ES接口、整理数据、把结果写入State,然后通过返回值更新状态。这里有个我踩过的坑:不要在节点函数内部直接修改外部变量或全局dict,所有状态变更都通过返回值完成。原因很简单,LangGraph的state更新是有执行上下文管理的,直接改外部变量会导致状态回放、并发执行时出现脏数据。
2.3 条件路由、循环检测、子图与并行分支
LangGraph的看家本领是conditional_edge。它实现的就是“根据当前状态,走不同的边”:
def route_by_risk(state: AgentState): if state["risk_level"] > 10: return "alert" # 风险高,走告警分支 elif state["risk_level"] > 0: return "analyze" # 有日志,走分析分支 else: return "end" # 无异常,结束流程 graph.add_conditional_edges( "fetch", route_by_risk, { "alert": "send_alert", "analyze": "analyze_logs", "end": "finish", } )这里我重点说三个实战细节:
循环检测。LangGraph的图是允许存在环的,一个节点通过条件边可以绕回自身,这是做Agent多轮工具调用最核心的机制。但环不设上限就是灾难,尤其在LLM接口出错时可能进入死循环。我常用的方案是在State里加一个计数器字段,路由函数里判断如果超过最大轮数就直接走结束边。这就是实战里说的“循环检测”,不是图自动检测,而是你自己限定执行轮次。
子图(Subgraph)。当一个图的规模变大之后,把一部分逻辑抽成子图是保持可维护性的关键。LangGraph的子图用法就是把一个编译好的graph当作另一个graph里的节点。比如我可以做一个“日志分析子图”,包含查询、分类、告警三个节点,然后在主图里直接调用它。子图的好处是隔离复杂度,而且可以单独调试。
并行分支。一些节点之间没有依赖关系,可以用fan-out/fan-in结构并行执行。LangGraph里可以在一个节点返回后分裂成多个并行路径,最后汇聚到同一个节点。我自己用下来,这个功能做“多数据源同时采集”特别合适。
3. n8n实战:从零搭一个可落地的AI Agent工作流
3.1 n8n安装与初始化
n8n上手最舒服的一点是部署足够简单,有Docker环境的话直接跑容器:
docker run -it --rm \ --name n8n \ -p 5678:5678 \ -v n8n_data:/home/node/.n8n \ -e GENERIC_TIMEZONE=Asia/Shanghai \ -e TZ=Asia/Shanghai \ n8nio/n8n这里有几个配置细节:
-v n8n_data:/home/node/.n8n:持久化数据卷,工作流和Credentials都存这里,容器删了数据不能丢。-e GENERIC_TIMEZONE=Asia/Shanghai:时区必须设置,否则定时触发器(Schedule Trigger)会按UTC时间执行,早上8点变成下午4点。- 端口默认5678,浏览器访问
http://localhost:5678进入工作流界面。
如果你要部署到服务器供团队使用,建议走官方推荐的Docker Compose方案,至少考虑三件事:数据库用PostgreSQL而非默认的SQLite(并发更强)、配置N8N_ENCRYPTION_KEY防止重启后Credentials无法解密、通过反向代理加HTTPS。n8n的企业级部署方案里,分布式执行器和工作队列是另一个话题,中小团队先用Compose把SQLite换掉就够用了。
3.2 Credentials配置是新手第一道坎
n8n里把MCP、LangChain、HTTP请求需要的密钥都叫Credentials。很多新手在HTTP Request节点里直接写Header,比如直接在Authorization里填Bearer xxx,这么做虽然能跑通,但极其不优雅——工作流导出分享时密钥直接泄露。
正确的打开方式:
- 左侧菜单进入Credentials,点Add Credential。
- 选择类型。调用OpenAI是OpenAI类型,调用内部接口选HTTP Header Auth类型或Basic Auth。
- 在HTTP Header Auth里填写Header名称(比如
X-API-Key)和值。 - 保存后回到HTTP Request节点,在Credential下拉框里选择刚才创建的凭据即可。
n8n里针对LangChain相关节点还有单独的Chat Model Credential管理,规则是一样的:不要在工作流里写死密钥。我见过太多人把API Key直接放在Webhook响应体里,这个必须避免。
3.3 一个案例:日志异常检测到企业微信告警的完整链路
n8n里搭一条AI Agent工作流,典型场景是:Webhook接收系统上报的数据 -> LLM判断是否异常 -> 异常则发送企业微信通知。步骤拆开:
- Webhook节点:生成一个测试URL,用来接收外部系统的POST请求。比如让日志系统把错误日志POST到这个地址。
- Code节点:把Webhook传入的数据做预处理,提取message字段、时间戳、来源系统。
- LangChain节点(或AI Agent节点):把预处理后的日志信息交给LLM,提示词是“你是运维专家,判断以下日志是否需要告警,只返回json:{needsAlert: bool, reason: string, level: string}”。
- IF节点:判断LLM返回的
needsAlert是否为true。 - 企业微信节点:条件为真时调用企业微信机器人Webhook,发送告警内容。
这条工作流全程不用写代码(除了Code节点里的几行预处理),而且每步执行日志都可以在n8n的Executions里看到,排查问题很直观。
这里说一个n8n里的关键语法坑:表达式。n8n的节点之间传数据靠$json。上一个节点的输出如果是个数组,引用时要写成{{ $json['message'] }};如果在IF节点判断字段,字段名要参考节点输出面板里的实际结构。遇到取不到值的情况,最快的办法是在Code节点里console.log($json)打印完整结构。
3.4 n8n的常见痛点
- Webhook地址在本地无法被外网访问。n8n有tunnel转发(
n8n tunnel命令),但免费限制比较多。做开发联调时,建议用ngrok之类做临时映射,生产环境一定要有公网HTTPS地址。 - 执行历史里报401。几乎都是Credentials没配好或Header名不对。用Postman先手测一下接口,确认Header格式,再去n8n里配。
- 循环遍历数据集合速度慢。n8n的Loop Over Items节点是串行执行,数据量大时性能很差。能用Split Out + 并行执行的场景,尽量别用循环。
4. Dify本地部署与知识库流水线:业务侧搭Agent的正确姿势
4.1 本地部署与初始化
Dify社区版是目前主流的开源LLM应用平台,本地部署的好处是数据不出内网、模型Key统一管理、流程可控。部署过程不复杂,Dify官方提供了docker-compose文件。
核心步骤:
git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env # 按需修改.env中的关键项 docker compose up -d.env文件里必改的几个配置项是:
SECRET_KEY:生成一个随机字符串,用于会话加密。不更换默认值会有安全风险。APP_WEB_URL:改成你的实际访问域名,否则分享链接和部分回调不对。POSTGRES_USER、POSTGRES_PASSWORD:默认密码要改掉。- 如果你要基于容器部署多租户,Dify社区版1.10开始支持多租户能力的配置,需要检查
ENABLE_ORGANIZATION这类开关。
启动后浏览器访问http://localhost/install,创建管理员账号,就能进入工作台。
注意:Dify的在线升级在Windows环境偶尔会遇到容器卷权限问题。我的做法是升级前先
docker compose down再拉新镜像,同时备份docker目录下的volumes,避免升级失败导致知识库索引丢失。
4.2 知识库流水线搭建:从文档到可检索的五个环节
Dify被用得最多的功能就是知识库RAG。很多人以为建知识库就是上传文档,点一下“完成”,其实一个完整知识库流水线包含五个环节:
- 文档加载:Dify支持PDF、Word、Markdown、TXT、HTML等格式,也支持从Notion同步。
- 分段:把长文档切分为小块。切分粒度直接影响检索效果,Dify里可以设置分段长度(Token数)和重叠长度。我的经验是:默认500-800 Token一段够用,但如果文档结构强(如产品手册的章节),建议用“自定义分段标识符”切分,避免把一个操作步骤从中间截断。
- Embedding:把文本段转化为向量。在Dify的模型供应商里配置Embedding模型,推荐用
text-embedding-3-small或BGE系列。Embedding模型的选择要和检索效果一起评估,不同模型对中文的语义理解差异很大。 - 索引构建:Dify会为每个分段生成向量索引,同时支持关键词索引。
- 检索与重排:应用侧可以选择检索模式。默认的“向量检索”只算相似度;“全文检索”基于关键词;“混合检索”两者结合。我最推荐的是混合检索 + Rerank重排。Rerank模型会对初筛结果做二次排序,明显提升准确率,代价是增加一点延迟。
我实际经验里最大的坑是“分段不合理”。之前把一份企业制度文档按固定长度硬切,结果上下文被切碎,检索到的片段语义完全不对。改成按“标题层级+段落”切分后,效果立刻改善。
4.3 Agent模式与工作流模式怎么选
Dify里有两类核心应用:Agent模式和Workflow(工作流)模式。
Agent模式更适合开放式对话和工具调用。你把一堆工具(自定义API、知识库检索、模型能力)挂给Agent,然后让LLM自己决定调用顺序。比如“日志分析Assistant”,就是把ES的REST API封装成自定义工具,然后让Agent在对话中按需查询。
Workflow模式更适合固定流程。比如“日报生成”,流程是固定的:获取数据 -> 总结 -> 发送。用工作流编排,每一步清晰可见,非技术同事也能改。
这里有个实用建议:Dify的Agent里可以嵌套调用工作流,工作流节点里也可以调用Agent。我做复杂问答系统的时候,通常外层是Workflow来控制顺序(先查知识库,再做情绪判断),内层用Agent处理开放问题,这样兼顾稳定性和灵活度。
4.4 Dify通过ES REST API做日志分析的实践
结合热词里那条“AI Agent通过ES REST API智能分析日志”,说一个我在Dify里比较成功的方案。
Dify的自定义工具本质上就是OpenAPI Schema描述的一组HTTP请求。做法是在插件/工具里创建一个OpenAPI工具,把ES的_search接口包进来:
paths: /es_log_search: get: operationId: searchLogs summary: 查询ES日志 parameters: - name: index in: query required: true schema: type: string - name: q in: query required: true schema: type: string responses: "200": content: application/json: schema: type: object然后在Agent提示词里写清楚:“当用户询问错误日志时,调用searchLogs工具,索引填app-logs-*,关键词从用户问题提取”。这样Agent就能自主完成ES日志查询和分析。
我踩过的坑:ES返回的JSON结构比较深(hits.hits._source),LLM有时解析不准。解决办法是在工具的输出描述里显式注明“返回结构为hits.hits下每个元素的_source字段包含message、timestamp、level字段”,并且把返回结果用Code节点(Dify内置代码工具)做一层扁平化,再交给LLM。一次性查询准确率从七成提升到九成以上。
5. 三套方案核心对比与选型建议
| 维度 | LangGraph | n8n | Dify |
|---|---|---|---|
| 产品定位 | 代码级Agent编排框架 | 自动化工作流平台 | LLM应用开发平台 |
| 目标用户 | 程序员、算法工程师 | 运维、业务开发、自动化爱好者 | 产品、业务、算法团队 |
| 状态管理 | 原生State,灵活但需代码维护 | JSON字段传递,靠节点连线管理 | 上下文变量,可视化维护 |
| 条件分支 | 最强,支持任意图结构 | 用IF/Switch节点实现,够用 | 有分支节点但复杂逻辑有限 |
| 循环与递归 | 原生支持,可自循环、子图 | 支持Loop,串行性能一般 | 有限支持,复杂循环不推荐 |
| RAG/知识库 | 需要自己组装检索链路 | 有向量存储节点但工程能力弱 | 开箱即用,体验最完善 |
| 可观测性 | 需要自己接日志和追踪 | 有Execution历史和调试面板 | 完整日志、标注、复盘面板 |
| 部署方式 | 作为代码库集成到现有项目 | Docker/云版,可私有化 | Docker/云版(社区版可私有化) |
| 上手门槛 | 高,需要Python/图论思维 | 中,可视化拖拽 | 低,业务人员也能上手 |
| 典型场景 | 复杂对话Agent、多工具编排 | 系统间数据同步、定时任务、告警 | 知识问答、RAG应用、内部AI助手 |
选型建议很直接:
- 如果你是个写代码的人,核心诉求是自由度和可控性,选LangGraph。它不会限制你任何结构,代价是所有可视化能力都需要自己搭。
- 如果你的核心诉求是把现有系统串起来,比如CRM、数据库、邮件、IM机器人之间的自动化,选n8n。它做的是事件驱动集成,不是AI编排。
- 如果你的核心诉求是快速交付一个AI应用给业务用,比如内部知识库问答、文档摘要、客服机器人,选Dify。
- 如果你的团队都想要,那也不用纠结:Dify做前端应用和知识库,LangGraph做底层复杂Agent服务,n8n做周边自动化连接,三者各司其职,是目前大型项目里很常见的技术组合。
6. 常见问题与排查技巧实录
| 问题现象 | 根本原因 | 排查思路与解决方案 |
|---|---|---|
| LangGraph图执行不终止 | 图里存在循环但没有上限 | 在State中增加计数器,路由函数判断最大值后走END |
| LangGraph节点返回值不是预期值 | 多个节点写同一字段被覆盖 | 用Annotated[list, add_messages]合并策略,或改用不同字段名 |
| LangGraph子图内状态不共享 | 子图State和父图State未合并 | 子图构造时需要显式声明StateSchema与父图字段兼容 |
| n8n HTTP请求报401 | Credential未配置或Header名错误 | 先用Postman测通接口,再创建Credential并在节点关联 |
| n8n表达式取到undefined | 节点输出结构不是预期对象 | 在Code节点里打印$json,逐层确认字段路径 |
| n8n定时任务时间不对 | 容器时区未设置 | 设置TZ=Asia/Shanghai环境变量后重建容器 |
| Dify知识库检索结果不准 | 分段粒度不合理或未加Rerank | 按文档结构自定义分段,检索方式改为混合检索+Rerank |
| Dify升级后登录异常 | SECRET_KEY或数据库不匹配 | 升级前备份volumes,确认.env的SECRET_KEY不变 |
| Agent调用ES工具返回解析失败 | 返回结构嵌套过深 | 在Dify里用代码节点做数据扁平化,再交给LLM |
| Dify多租户相关选项不生效 | 版本旧或环境变量未开启 | 升级到社区版1.10+,检查对应环境变量与安装文档 |
这里特别提醒一点:任何Agent框架,日志和追踪都极其重要。LangGraph里我习惯给每个节点做输入输出日志;n8n已经内置了Execution历史;Dify自带完整日志。排查问题的时候,先看数据在哪一步断了,再去看Prompt对不对,最后才是看代码逻辑。
7. 从选型思维到Agent开发进阶路径
如果你是一个想入行AI Agent开发的人,我建议的进阶路线是:先学会LangChain的基本概念(模型调用、工具定义、记忆),再学LangGraph的状态图和条件路由,然后掌握RAG知识库的基本方法,最后选一个业务场景从头到尾做一个完整Agent。这些基础打牢之后,再来用Dify或n8n会觉得它们只是“把繁琐的部分封装成了界面”。
实际开发中一个经常被忽略的点:Agent的质量上限取决于工具定义和数据质量。模型再强,如果ES返回的数据是脏的、字段含义不清晰,Agent也分析不出什么有价值的结果。所以我在日志分析类项目里,花了大量精力在写工具的OpenAPI描述和返回字段注释,Prompt反而只用了几行。这一点很值得后来者借鉴。
另外,“AI Agent 2026发展趋势”这类话题在社群一直很热,但作为工程师,我觉得与其追概念,不如把已经成熟的能力吃透:条件路由、循环控制、子图复用、RAG检索优化、多工具协同。这些技术点不会因为框架更新而过时。
这三套工具里,LangGraph、n8n、Dify各解决一块问题。我自己实际项目里的体会是:它们不是对手,而是不同工种之间的协作工具——Dify让业务侧能自助搭AI应用,n8n把AI和现有系统之间的数据管道拉通,LangGraph在底层支撑着真正复杂的Agent大脑。搞清楚“谁在执行、谁在维护、谁在改逻辑”这三个问题,选型自然就清晰了。希望这篇对你有用。