ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

deer-flow实战指南:用可视化工作流编排搞定复杂LLM应用

deer-flow实战指南:用可视化工作流编排搞定复杂LLM应用 开头聊到deer-flow之前先说说我最近一年做 LLM 应用的真实感受光靠写 Prompt 已经撑不起稍微复杂一点的业务了。你让大模型干一件事它干得漂漂亮亮你让它按条件做判断、调接口、查知识库、再把结果拼成一段回复纯靠提示词堆砌很快就会被上下文污染、输出不稳定、分支逻辑混乱这些问题折磨到崩溃。工作流编排引擎就是在这个背景下被推上前台的而deer-flow正是这一类工具里相当有代表性的开源项目把大模型调用、工具调用、条件分支、循环处理这些能力全部变成可视化画布上的节点和连线让流程编排像搭积木一样直观。这篇文章我就围绕deer-flow的核心玩法从设计思路、节点概念到完整落地案例把我实际踩过的坑和验证过的配置方法一次讲清楚。如果你正在做 AI Agent、RAG 问答、自动化客服、内容生成这类项目或者你团队里有非开发角色也想参与流程设计这篇文章应该能帮你省下不少摸索时间。坦白说工作流编排这件事本身不算新概念但一旦和 LLM 结合起来很多原来的经验就不太适用了。deer-flow这类项目解决的恰恰是新旧经验交替地带的一系列真问题。下面我从设计思路开始一步步拆。1. 项目整体设计与思路拆解1.1 为什么纯 Prompt 工程解决不了复杂 LLM 应用先说一个我观察到的普遍现象。很多团队刚开始做 AI 应用时第一反应是“把 Prompt 写好就行”于是一个客服机器人的 Prompt 越写越长从 500 字写到 2000 字把判断规则、回复风格、知识库引用格式、兜底话术全塞进去。结果呢模型开始“忘事”用户随口说一句无关话它就开始自由发挥或者明明规则里写了“售后问题转接人工”它偏要自己硬答。这里面的核心矛盾在于大模型本质上是概率推理不是确定性计算。你希望它同时完成“意图识别、数据检索、内容生成、规则判断”四件事它往往会在执行中模糊掉某些边界。而传统代码逻辑是确定性的if 就是 ifelse 就是 else它适合做规则判断但不擅长理解语义。工作流引擎的思路是把两件事分开语义理解交给 LLM 节点规则流程交给编排引擎。比如“客户说快递一直没到”先用 LLM 节点识别出意图是“物流查询”然后引擎根据识别结果走“查询物流”分支调物流接口拿数据再让 LLM 节点基于真实数据生成回复。每一步职责单一每一步的输出都可观测、可调试。这就是deer-flow这类工具存在的根本原因让不确定性尽量收敛在单个节点里让确定性流程回到引擎手里。1.2 deer-flow 的核心设计理念我实际体验下来deer-flow的几个设计取舍很有代表性。第一是可视化优先。它把工作流定义成一张有向图节点是执行单元连线是数据流向。你不需要写繁琐的流程代码拖拽配置就能完成一版可运行的流程。这对团队协作的价值非常大——业务人员也能看懂流程图开发者和业务之间终于有了共同语言。第二是面向 LLM 场景原生化。它不是单纯的“接口编排工具”而是把大模型当作一等公民来对待。在节点配置里可以直接选择模型、写 Prompt、定义输出解析规则还支持把前序节点的结果作为变量拼进当前 Prompt。这意味着“LLM 调用”不再是某个角落里的一次 HTTP 请求而是整个流程中被统一管理、可观测的核心环节。第三是轻量可自托管。deer-flow这类开源项目通常可以本地部署数据留在自己手里。对于很多有数据合规要求的团队来说这一点比云平台更具吸引力。第四是节点化复用。一个工作流里的节点本质上是一个个独立的功能单元。今天在 A 流程里写好的“用户意图分类”节点明天可以复制到 B 流程里微调一下直接用不需要从头搭。这种积木式思维让工作流的维护成本比代码状态机低不少。1.3 同类方案横向对比与选型逻辑项目开源程度侧重点适合人群部署方式deer-flow开源可自托管LLM 工作流编排有技术团队、想深度定制的开发者本地/私有化部署Dify开源可自托管LLM 应用全栈平台偏产品化快速落地本地/Docker 部署Coze闭源 SaaS低代码 AI Agent非开发者、快速搭建云端n8n开源可自托管通用自动化集成偏传统系统集成本地/Docker 部署选型时我会重点关注三个维度是否支持私有化、节点编排是否足够灵活、是否倾向 LLM 场景。deer-flow在这些方面比较均衡尤其适合那些想深入理解工作流机制、甚至想二次开发的团队。当然如果你完全没有工程能力闭源低代码平台上手更快但后续的定制空间也小得多。2. 核心细节解析与实操要点2.1 三个必须理解的基础概念节点、连线、上下文进入配置之前先花两分钟理解工作流最底层的三个概念。这些概念在deer-flow里是基础换到任何同类工具里也八九不离十。节点是执行单元。每个节点只负责一件事调用一个大模型、发一次请求、跑一段代码、做一个判断。节点的输入来自上游节点的输出节点的输出会被下游节点消费。理解节点时把它想象成流水线上的一道工序每道工序只加工一种东西。连线是数据通路。它定义了节点之间的依赖关系和数据流向。A 节点连到 B 节点意思是 B 节点要等 A 节点执行完后才能开始并且能引用 A 节点的输出。连线本身通常还能带条件只有满足条件时数据才会往下游走这就是分支判断的底层机制。上下文是流程运行时的共享数据空间。每个节点的输出默认会写进上下文后续节点通过变量引用来读取这些数据。比如前一个 LLM 节点输出了一段 JSON下游节点就可以用类似{{节点ID.输出字段}}的语法把它拼到自己的 Prompt 里。具体语法在不同工具里略有差异但思路完全一致。注意上下文不是越大越好。我见过很多人把整段会话历史全塞进上下文结果每个节点的输入都冗长无比既浪费 token又容易让模型被无关信息干扰。正确的做法是当前节点需要什么就传什么保持上下文精简。2.2 常用节点类型与真实场景举例deer-flow这类工作流引擎通常会提供一批内置节点类型。我按实际使用频率整理如下节点类型作用典型场景开始节点定义工作流的输入参数接收用户消息、表单数据、Webhook 请求LLM 节点调用大模型执行语义理解/生成意图分类、内容生成、摘要提取知识库检索节点在向量数据库中做相似度检索RAG 问答中的文档召回HTTP 请求节点调用第三方 API查订单、查天气、调用内部系统接口条件分支节点根据条件选择后续路径按意图走不同处理流程循环节点对列表数据逐条执行子流程批量处理多条工单代码节点写一段自定义代码做逻辑处理格式化数据、做计算、拼接字符串结束节点定义工作流的输出返回最终回复给用户每个节点单独看都不复杂但组合起来就能实现很强的效果。我下面用条件分支和循环两个例子展开讲讲设计思路因为这两个节点是最容易“想当然”的地方。2.3 条件分支与循环设计不当必踩坑条件分支看起来简单实际最坑的地方在于“判断依据从哪里来”。很多人让 LLM 直接输出一段话然后想用字符串匹配去做分支判断比如 LLM 输出“该用户是投诉”然后代码里判断“如果包含‘投诉’两个字就走投诉分支”。这种做法在测试案例里可能 80% 能跑通一旦用户换个说法LLM 输出变成“用户表达了不满”分支就断了。我建议的做法是让 LLM 节点输出结构化 JSON然后用 JSON 字段做判断。比如 Prompt 里明确要求{ intent: complaint | after_sale | consultation, confidence: 0.9, summary: 一句话概括用户问题 }然后分支节点直接读intent字段命中哪种就走哪条路。这样 LLM 的自由发挥被约束在固定的枚举值里分支稳定性大幅提升。这里有一个关键技巧Prompt 里不仅要写“输出 JSON 格式”还要给出可枚举的取值列表和示例否则模型还是有可能给你来一个不在预设范围内的“创新值”。循环节点则容易栽在“跑偏和失控”上。循环本身解决的是批量处理问题比如一批工单要逐条分类、一篇文章要逐段翻译。设计时需要注意三件事设置最大循环次数。不是所有场景都能靠“循环完自然结束”兜底万一子流程里出现异常导致退出条件永远不满足流程就会卡死。我的习惯是只要有循环一定设一个上限比如 100 次宁可让它强制退出也不能让它无限跑。循环体内不要传无关上下文。循环往往要跑很多次每次如果都把整个流程上下文带上token 消耗会成倍上涨。循环结果的收集方式。很多引擎支持把循环节点每次的输出自动聚合成一个列表等循环结束后统一处理。配置时要确认聚合目标字段否则前一轮的结果会被后一轮覆盖掉。3. 实操过程与核心环节实现3.1 实战场景客户工单自动分类 回复草稿生成理论讲多了容易飘直接上一个我实际配置过的流程。场景是这样公司客服邮箱每天收到大量工单需要先判断工单类型售后 / 咨询 / 投诉再根据类型生成一封回复草稿最后把结果推送给人工复核。这个场景覆盖了 LLM 节点、条件分支节点、LLM 节点再调用的完整链路很适合当作上手练习。流程设计大概是这样的开始节点接收工单原始文本比如workorder_textLLM 分类节点读取workorder_text输出结构化分类结果条件分支节点根据intent字段进入不同分支各分支的 LLM 回复节点每个类型配置独立的回复 Prompt 策略结束节点汇总输出工单类型 紧急程度 回复草稿这一步设计的巧妙之处在于分类和回复拆成两个 LLM 节点。很多人会把它们合并成一次调用让模型直接输出分类和回复看起来省了一次模型调用但实际效果很差。因为两类任务的目标不一致——分类需要冷静判断生成回复需要贴合业务语气一旦耦合模型就容易在分类时被“写回复”的任务带偏或者写回复时被分类枚举限制住。拆开后每个节点各司其职调试时也能单独看分类准不准、回复润色得好不好。3.2 关键节点的 Prompt 配置与变量引用分类节点的 Prompt 我会这样写用系统提示词约束行为用变量引用动态数据你是一个工单分类专家。请判断以下客户工单属于哪一类别。 可选类别只能从这几个里选一个 - after_sale售后问题包括退换货、维修、物流异常 - complaint投诉包括服务态度、质量严重问题 - consultation普通咨询包括产品信息、价格、活动 请严格按照以下 JSON 格式输出不要输出其他内容 { intent: 类别枚举值, confidence: 0到1之间的数字, summary: 不超过20字的问题摘要 } 客户工单内容 --- {{begin_node.output.workorder_text}} ---这里我用了{{begin_node.output.workorder_text}}来引用开始节点的输入。这是工作流引擎最常见的变量引用方式实际字段名以你部署的版本为准但思路是一样的前序节点的输出可以通过节点 ID 字段路径来引用。回复节点的 Prompt 按分支差异配置比如投诉分支你是一名资深客服。客户刚刚提交了一条投诉请写一封回复邮件草稿。 要求 1. 先表达歉意语气真诚不敷衍 2. 明确说明我们会如何处理如果需要用户补充信息请清楚列出 3. 篇幅控制在150字以内不要用过多套话 4. 不要承诺无法确认的时间节点 客户投诉内容 {{classify_node.output.summary}} 完整工单内容 {{begin_node.output.workorder_text}}你注意我在这里没有传整个上下文只传了summary和原始工单文本。这样设计的原因前面说过上下文越精简模型发挥越稳定token 成本也越低。3.3 分支节点配置用结构化输出驱动路由分支节点本身不复杂关键是搞清楚判断字段从哪来。在我们这个流程里分支节点读的就是分类节点输出的intent字段。配置时大致会做三组条件设定如果classify_node.output.intent complaint走投诉处理分支如果classify_node.output.intent after_sale走售后处理分支否则走普通咨询分支这里有一个实战心得条件判断尽量用精确匹配不要用“包含”。用枚举值做精确匹配时分支行为完全可控用文本包含匹配时很容易因为大小写、空格、换行符之类的小问题导致路由失败。另外建议在条件判断前加一个“数据清洗节点”或者让 LLM 输出的 JSON 字段里直接带trim后的值避免不可见字符干扰判断。3.4 调试与验证从跑通到稳定工作流搭好后调试阶段往往比搭建阶段更花时间。我的调试习惯是先逐个节点验证再跑全流程。单节点验证很关键。比如先单独跑分类节点传几条不同类型的工单进去看输出 JSON 是否符合预期。如果分类结果不理想优先调整的是 Prompt 中的类别定义和示例而不是加各种限制词。类别定义越清晰、示例越具体模型分类准确率提升越快。全流程跑通后还要做一组边界测试。比如传一个空字符串进去看看会不会报错传一个超长文本看看会不会触发模型上下文限制传一个看似合规但实际无法归类的内容看看兜底分支是否接管。这些边界情况是线上故障的主要来源。我实际测试下来一个典型的工单工作流从搭建到稳定跑通大概需要 2 到 3 小时其中一半时间花在 Prompt 调优和边界测试上。这个时间成本是值得的因为这类流程一旦上线面对的输入千奇百怪前期测试越充分后期救火越少。4. 常见问题与排查技巧实录4.1 高频问题速查表现象可能原因排查思路解决建议节点一直未执行上游节点报错或连线条件不满足查看运行日志确认上游输出检查连线条件看上游节点状态变量引用报错字段名写错或节点 ID 变更查看节点输出结构在日志里先看实际输出的 JSON 结构LLM 节点输出解析失败模型返回了非 JSON 内容查看节点原始输出Prompt 里加严格 JSON 约束加解析兜底分支永远走同一侧判断字段和实际输出不匹配打印分支判断条件的实际值检查字段路径使用精确匹配流程执行超时外部 API 响应慢或循环次数过多查看耗时分布给外部请求设置超时降低循环上限上下文越长结果越差无关数据污染检查各节点输入精简上下文只传当前节点必要数据这张表里的每一个问题我都真实遇到过不是凭空总结的。尤其是“分支永远走同一侧”这个问题最容易让人抓狂因为你自己看条件写得很对但实际跑起来就是不对。后来我发现多数情况是字段引用路径错了——你以为读的是intent其实那个节点输出的字段名带了个空格或者前缀。务必先在运行日志里确认真实输出结构再配置分支条件。4.2 我在实际落地中踩过的几个坑第一个坑让 LLM 直接决定流程路径。早期版本里我尝试过让模型输出“下一步该调用什么工具”然后引擎根据模型的建议做工具调用。听起来很智能实际跑起来完全不可控——模型偶尔会选错工具一旦选错后续流程全乱。后来我改成“模型只输出结构化判断结果引擎根据结果走固定分支”稳定性一下子提升了很多。AGENT 式的自主决策确实炫酷但在生产环境里确定性的流程比发散式的智能更可靠。第二个坑不设重试机制。LLM 接口偶尔会超时或者返回异常尤其是高峰期。如果一个节点失败就导致整个工作流失败用户体验会非常差。我现在的做法是对所有外部依赖的节点LLM 调用、HTTP 请求都配置重试策略通常重试 1 到 2 次重试间隔递增。同时在工作流层面加超时控制避免一个流程跑十几分钟还没结束。第三个坑日志信息不足出问题无法定位。早期我跑工作流只看最终输出对不对中间节点输出一概不存。结果线上跑的时候出了问题根本不知道是哪个节点算错了。后来我养成了一个习惯每次运行都保存完整的工作流快照包括每个节点的输入输出。虽然会占用一些存储但排查问题的效率提升了十倍都不止。很多工作流引擎自带日志功能如果没有建议在每个关键节点加一个“日志输出”步骤把需要追踪的数据打印出来。第四个坑忽略 token 成本的增长。节点一多上下文一传token 消耗很容易超预算。我见过一个团队做 RAG 流程每个用户问题都把所有检索到的文档片段全塞进 Prompt结果单次调用成本高得吓人。合理的做法是检索结果先做重排和截断只保留最相关的前 N 条上下文中只放当前步骤需要的数据优先用小模型做分类、提取这类相对简单的任务大模型只用在真正需要复杂推理的环节。4.3 工作流上线后的扩展方向如果基础流程已经稳定了deer-flow这类引擎还能支持不少扩展玩法。一个方向是加人工审批环节。不是所有内容都适合让 AI 全自动处理敏感操作可以设计成工作流先把草稿生成好然后挂起等人工审核通过后再执行后续动作。这种“人机协同”模式在生产环境里非常实用。另一个方向是封装成对外 API。把工作流发布成一个 HTTP 接口这样外部系统就可以通过标准接口触发流程比如 CRM 系统里点了某个按钮自动调用工作流生成跟进邮件。这一步能极大拓宽工作流的应用边界。还有一个比较进阶的玩法是多模型路由。在流程里判断用户问题的难易程度简单问题走便宜的小模型复杂问题才调用大模型。配合结构化输出这个判断同样可以用一个小型 LLM 节点来做。最后分享一个我在使用过程中沉淀下来的小技巧不要一上来就追求搭一个“万能大流程”。把流程拆成多个独立的小工作流每个小工作流只做一件事然后用总流程去串联它们。比如“用户意图分类”单独做一个工作流“工单紧急度判断”单独做一个工作流“回复草稿生成”单独做一个工作流。这样做的好处是单个流程易于测试和维护替换某个环节时不影响其他部分。工作流编排真正的价值不是把一切揉在一起而是把复杂系统拆成可以独立演进的可视化积木。我个人在实际操作中的体会是deer-flow这类工具适合在流程复杂度达到一定阈值时引入如果业务场景只是“调一次大模型返回结果”直接写代码反而更轻。但一旦你开始面对多步判断、工具调用、多分支处理编排引擎带来的可观测性和可维护性优势就会非常明显。希望这篇拆解能让你少走一些弯路如果你也在用工作流编排大模型应用欢迎在实践中多试、多调、多记录这些积累的调试经验最终会成为你手里最值钱的那部分资产。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进