尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于Dify构建LLM自我反思工作流:AI行为复盘实践指南

基于Dify构建LLM自我反思工作流:AI行为复盘实践指南 我们团队最近在用 Dify 搭一个内部工具本来只是想做个简单的知识库问答结果越玩越深。最近趁着手头项目告一段落我把其中一个小应用“hindsight”单独拎出来重构了一遍。名字叫 hindsight其实就是后见之明——专门用来做 AI 行为复盘的工具让大模型生成完代码、写完答案、做完推理之后再回过头来对自己的产出做一轮“批判性审视”。你可能觉得这不就是让 AI 自己挑自己的毛病吗对就是这个思路但这里面门道不少。我写这篇东西就是想把这半个多月折腾出来的实操经验整理一遍。适合谁看两类人一是在 Dify 里搭过工作流但想做得更深的应用开发者二是想给现有 LLM 应用加一层“自我反思、二次校验”能力却不知道从哪位入手的同学。我会从 Dify 的编排思路讲起再到具体节点怎么配、提示词怎么写、参数怎么调最后把我在真实调试中踩过的坑一并交代清楚。内容偏实践不搞纯理论。1. 为什么我把“自我反思”做成了核心流程1.1 不是所有模型错误都能靠换模型解决先把事情说透我们最初给这个工具定的目标很朴素就是让应用在输出结果前多做一步检查。起因是团队内部用大模型生成周报摘要有时候模型会一本正经地把错误数字写进去比如把上季度的 KPI 当成这季度的或者把两个项目的里程碑合并成一个。这类错误不是模型“不聪明”而是信息抽取阶段就出了偏差。换成更强的模型也不总能解决因为强模型会更有自信地把错误观点输出得更流畅。我们试过 GPT-4 级别的模型坦白讲错误率确实降低了但偶尔翻起车来更隐蔽。后来我们想明白一个道理模型是单次前向推理它生成第一遍的时候不会自己回头看。人写文章还知道改两稿凭什么要求 AI 一次写对这就是 hindsight 的核心出发点——把“事后审视”变成工作流里一个显式的执行阶段而不是寄希望于模型在单次生成中“自动变严谨”。用 Dify 的好处是你不用自己写一大套状态机去协调多轮调用、判断何时终止、如何合并结果这些都能用可视化节点拼出来。提示当初不是没考虑过用 LangChain 之类的框架写这个流程但 Dify 在工作流可视化、调试和团队协作上更顺手。说白了低代码不是上限低而是让你把精力放在“逻辑设计”而不是“工程骨架”上。1.2 Dify 工作流怎么承载“检查—反馈—修正”的闭环做反思类应用最难的不是让 AI 挑错而是挑完错之后怎么把修正结果交回给用户。如果只是简单地把第一遍结果和第二遍结果拼接在一起用户看到的是一堆互相矛盾的输出体验非常差。所以我设计了三个核心阶段生成阶段让大模型按主任务产出初版结果。审视阶段用独立的“审视者”角色去分析初版结果对标源材料找出事实性错误、逻辑跳跃和遗漏项。修正阶段把审视意见连同初版结果一起交给一个新的生成回合产出最终版。Dify 的工作流编辑器天然支持这种链式结构。你可以在一个节点里配置“如果审视意见为空则直接输出初版结果”的分支条件而不需要额外写胶水代码。更关键的是Dify 的节点之间传递数据的逻辑非常直观。前一个节点的输出会自动变成下一个节点的变量你在提示词里用{{#审视节点.output#}}这种方式引用即可。手写代码当然也能干这事但调接口、管上下文、处理 token 超限、做幂等控制……每一样都会消耗大量时间。Dify 把这些工程细节都抹平了让你能专注于打磨审视提示词本身。有人可能会问为什么不直接在同一个提示词里写“请先生成再自我检查”这本质上就是单次推理内的“假装反思”模型并不会真的重新审视自己的输出因为它没有条件去对比“原事实”和“自己刚写的内容”它在生成第二段时依然是在同一个上下文窗口里顺着写下去缺乏真正的外部校验信号。所以在 hindsight 里“审视”不是对同一个模型的自我追问而是加载了不同角色设定、不同提示词策略的独立检查步骤。我们甚至让审视节点的 temperature 设置得比生成节点更低目的就是让检查过程更保守、更挑刺。2. 核心细节解析与实操要点2.1 节点配置拆解生成、审视、修正该用什么模型这个环节我单独拿出来讲因为模型选型对结果影响非常大而且不同阶段对模型的诉求并不一致。生成阶段我用的是默认主力模型比如 Claude 或 GPT-4 级别的模型。这个阶段的核心诉求是“产出质量要高、表达要自然”所以温度可以设置在 0.3 到 0.5 之间太高会让输出信马由缰太低又会让文字很死板。审视阶段我起初也用了同一个强模型但跑下来发现一个关键问题主力模型太容易“顺着”初版结果走。你让它找错它倾向于认为初版“整体还行小问题如下”然后列一些无关痛痒的措辞建议。这不是模型能力不够而是默认指令遵循模式下模型有迎合用户的倾向。后来我把审视节点换成了不同厂商或不同系列的模型。比如生成节点用 Claude审视节点用 GPT-4o修正节点再用回 Claude。混用有两个好处不同模型的训练分布不同挑毛病的角度会有差异同时也能避免“同一个模型自圆其说”的路径依赖。修正阶段比较特殊——它接收初版结果和审视意见要做的是“综合考量后输出最终版本”。这里我仍然用回生成阶段的强模型配合系统提示词中“你是最终审稿人参考审视意见保留初版优点”的设定。修正阶段的温度建议设置为 0.2 左右偏保守因为修改幅度不该太大主要是打补丁式修订。如果你不想混用模型也可以用同一个模型跑完三个阶段但务必在系统提示词中把角色区分清楚。角色模糊是反思链路最常见的设计错误——用户看到的是三个一模一样的“助手”在自问自答效果自然大打折扣。2.2 提示词设计的几个反直觉要点提示词是这个项目里最容易出效果也最容易翻车的部分。分享几个我们反复调整后总结出的要点。第一审视节点的输入不要只给“初版结果”必须连同“原始源材料”一起给。如果审视者只看到模型写出来的内容它只能做文字润色层面的挑刺根本无从判断内容是否与源材料冲突。所以我在审视节点前加了一个“查询结果”节点从知识库中检索相关文档片段把原文作为审视节点的附加输入。第二修正节点要明确告诉模型“保留什么”。如果你只说“请根据审视意见进行修正”模型很容易把一份挺完整的内容改得面目全非。我们最终把提示词写成“保留初版结果中所有正确且有用的部分仅针对审视意见中指出的具体问题做最小幅度的修改。不要引入初版中没有的新观点。”第三输出格式要用很强的结构化约束。我让审视节点必须以 JSON 格式输出包含三个固定字段issue_type、quote、suggestion。这样修正阶段的提示词里就可以清清楚楚地引用每一条意见模型不会被一大段口语化的批评带偏。{ review_issues: [ { issue_type: factual_error, quote: 去年同期收入增长 23%, suggestion: 根据源材料去年同期收入增长为 18%需核实数据来源 } ] }用这种格式还有一个好处——Dify 的输出解析节点可以直接从 JSON 里提取字段后续如果你想加“自动屏蔽严重错误”的逻辑不需要写字符串匹配的脏代码。2.3 知识库检索与上下文窗口的博弈反思类应用对上下文的需求比普通问答要高得多。生成阶段只需要给模型必要的背景信息但审视阶段需要同时看到“源材料”和“初版结果”两者可能都很长。上下文窗口不够用是常态。我用的解决思路是在知识库检索阶段用 Dify 的检索节点把召回结果切分成较短的片段每段控制在 500 字以内只保留与用户问题最相关的几个段落。同时审视节点不直接处理全部源材料而是先用一个“摘要抽取”节点把关键事实抽成列表再交给审视者去比对。这个做法牺牲了一部分上下文完整性但换来了非常可观的成本下降。毕竟审视节点的输入 token 是双份的——源材料和初版结果都各算一份。我们的实测数据是加了摘要抽取后审视节点的平均 token 消耗降低了 42%而找错能力几乎没下降。注意上下文窗口不是越大越好。更大的窗口意味着更长的推理时间和更多的 token 成本同时也意味着模型可能被无关信息干扰。做反思应用精简输入比堆窗口更有效。2.4 迭代机制一轮审视不够怎么办如果审视阶段挑出了多条问题修正模型一次性修改时往往会顾此失彼——改好了数据错误却把原本通顺的表述改拧了。我后来给 hindsight 加了一个循环机制修正后的结果会被再次送进审视节点直到审视意见为空或者达到最大迭代次数。在 Dify 中实现循环有两种方式一种是用“迭代”节点适合对已结构化列表的逐项处理另一种是节点之间用条件分支回连适合整体循环。两种我们都试过。迭代节点更高效但它约束你每次处理的是独立条目每轮循环之间没有状态依赖。如果是“审视意见逐条处理”用迭代节点没有问题。但如果是“修正后的整体结果需要二次审视”那必须走节点回连。Dify 支持通过“直接回复”和“条件分支”的组合实现这一逻辑你只需要在分支条件里判断审视意见是否为空。迭代次数上限我设为 3。超过 3 次意味着这个输出基本没救再迭代下去只会越来越离谱而且 token 开销是肉眼可见地暴涨。循环是个好武器但要有退出机制。3. 实操过程与核心环节实现3.1 从零到一我在 Dify 中搭建 hindsight 的完整路径我在 Dify 中的完整搭建路径大概是这样的先在工作流里建“知识库检索”节点。这一步要选定你已经准备好知识库把查询方式设为“语义检索”TopK 设置为 4Score 阈值设置为 0.3。如果你们的知识库质量参差不齐把 Score 阈值调高一些宁缺毋滥。然后是“生成初稿”节点。这一步的输入主要是用户问题和知识库检索片段。我在这里专门用了一个 LLM 节点模型选择 Claude 3.5 Sonnetsystem prompt 写着“你是资深行业分析师”user prompt 包含用户问题与检索到的上下文。接下来是“事实抽取”节点。这个节点是我在第二版才加的。它的作用是把生成初稿中涉及的事实性断言标记出来比如“今年第一季度销售额达到 2.3 亿元”这样的句子会被提取成独立行。这一步是为审视节点减轻比对负担。然后是“独立审视”节点。模型用 GPT-4otemperature 设为 0.1。提示词里明确要求它只看事实断言和源材料忽略文字风格问题。输出格式用 JSON禁止输出自然语言。再往下是“条件判断”节点。判断审视意见中的issue_type是否包含factual_error或logic_gap。如果都没有直接走输出节点返回初稿如果有进入“修正”节点。“修正”节点是最後一棒模型用回 Claudetemperature 设定为 0.2。输入结构包含三部分用户原始问题、初稿内容、审视意见 JSON。提示词中强调“基于审视意见修正初稿不改变原有行文风格”。最后接入“直接回复”节点输出修正版结果。这条链路看起来有六个节点实际上在 Dify 里配置起来大约一小时就能搭完。时间主要花在打磨提示词和调整参数上而不是写代码。3.2 参数选择背后的计算思路我专门把参数计算这部分单独拎出来说因为这地方最容易凭感觉走了弯路。审视节点的 Score 阈值我一开始设置得很低只有 0.1导致召回了很多无关片段。后来计算了一下知识库一共 680 篇文档TopK4 每轮召回 4 段Score 阈值低意味着召回段落平均相关度只有 0.4 左右审视节点要在这些无关信息里找出事实错误等于没有源材料约束。真正跑起来之后审视意见几乎全是“建议补充更多数据”这类废话。把 Score 阈值调到 0.35 之后召回段落的相关度中位数从 0.42 提升到了 0.71审视意见的质量有了质的飞跃。这个值的设置跟你们的语料清洗程度强相关——如果语料里大量重复或近似内容阈值要更高如果语料本身稀疏阈值就要放低一些否则什么都召不回。关于迭代次数上限和 token 成本的关系我用一个简单算式帮大家建立直觉假设每轮审视输入约 1800 token输出约 300 token修正阶段输入约 2200 token输出约 1500 token。一轮循环的成本大约就是输入 4000 输出 1800 token。3 次迭代大约是 6000 3000 token。按照 Claude 的价格模型单次调用成本其实很低但如果你的应用日调用量达到几万次这就是一笔不可忽略的开支。如果预算敏感建议把最大迭代次数设为 2并要求审视节点在初版已经比较干净时输出issue_type: none这样可以省掉修正节点的开销。在实际运行中我们统计过大约有 35% 的生成内容在首轮审视后就通过了不会进入修正阶段。3.3 调试过程实录一次真实的数据错误捕获我举一个我们调试时遇到的真实案例。用户的问题是“公司第一季度现金流表现如何”。生成节点输出的初稿中有这样一句话“第一季度经营性现金流为 -1.2 亿元环比下降 300%。”审视节点在审查时从知识库中召回了相关财报片段其中包括“第一季度经营性现金流为 -1.2 亿元上一季度为 -0.4 亿元”。审视节点给出了如下判定{ issue_type: factual_error, quote: 环比下降 300%, suggestion: 环比下降幅度应基于 -0.4 到 -1.2 计算降幅为 200%并非 300%。需要修正表述。 }修正节点读取这条意见后将句子改为“第一季度经营性现金流为 -1.2 亿元相较上季度的 -0.4 亿元扩大了亏损降幅为 200%”。这个案例很有代表性——生成模型本来数值计算能力就弱单靠它自己想很难发现这个问题。而审视节点给了它一个“重新面对算术”的机会。这轮调试还暴露了一个问题最初的审视提示词没有明确要求“对数值变化进行重新计算核查”所以很多算术错误会漏掉。后来我们在审视节点的 prompt 里附加了一条规则“凡涉及百分比、同比、环比变化必须基于源材料中的原始数值自行计算一次不要轻信初稿计算结果。”加了这条之后数值类错误的检出率提升了一截。4. 常见问题与排查技巧实录4.1 审视节点经常输出空意见怎么办这是一个很让人头疼的问题。模型在审视阶段的输出如果为空条件分支就会把它当成“没有发现问题”直接把初稿输出了。这等于整个反思流程白跑了。排查思路先从提示词找原因。我试过把输出模板改成“必须列出至少一条可执行的改进建议如果没有也要明确输出issue_type: none”。这招能强制模型产生结构化输出但代价是它可能为了凑数而写一些无关痛痒的建议。后来我在审视节点前加了一个变量#polarity#根据知识库召回片段的相关度得分动态调整。相关度低于阈值时审视节点会强制走“无法验证”分支而不是硬找问题。Dify 里对空输出还有一种兜底方式条件分支的判断条件改一下把“output 是否包含特定关键词”改成“如果审视节点的 JSON 解析失败则自动走修正节点”。这是最笨但最有用的办法确保空输出不会静默通过。4.2 修正结果比初版还差这种情况在模型混用时尤其常见。不同模型对同一内容的写作风格有差异修正节点可能把初稿的好句子改得平淡无奇。后来我们的处理办法是修正节点只负责“局部重写”不负责“整体重写”。我们在提示词里增加了一个硬性约束“如果审视意见中未提及某一段落则修正结果中该段落必须保持原样。不得大篇幅重写未涉及的内容。”除此之外还可以在修正节点前加一个“差异对比”子节点用编辑距离计算审视意见引用片段的文本范围。如果审视意见只引用了初稿中的一句话修正节点只允许改动这一句话及其前后一个句子的范围。这个做法我们把误改率从 30% 压到了 7% 左右。4.3 知识库更新后审视结果变差我迭代到第三版时遇到了这个问题知识库新增了一批文档结果审视节点反而开始输出大量与用户问题无关的意见。查了半天原因是新增文档中包含了较多表格形式的数据语义检索召回这些表格后模型把它们视作了额外的“事实来源”。解决方法是给 Dify 知识库的文档配置增加了 metadata 过滤比如在检索节点中只召回doc_type: policy或doc_type: report的类型。你也可以在文档上传时写明其内容领域和用途确保审视节点的输入来源始终是被验证过的。4.4 成本监控反思链路的隐性消耗要心里有数前面提到了 token 的计算但实际跑起来还有一个隐性消耗——每次审视节点和修正节点的调用都伴随着 prompt 组合。如果提示词写得冗长很多固定句式每次都会重复计费。我把系统提示词里的说明性文字尽量精简把规则从 500 字压到不到 200 字效果还挺明显。Dify 的控制台里可以直接查看每个节点的 token 消耗建议你们上线前统计一下不同节点之间的成本分布。我们实测下来审视节点占了整个应用约 50% 的 token 成本。知道成本在哪你才有优化的靶点。5. 从单点工具到通用能力hindsight 的扩展思路5.1 把它打包成工作流的“反思插件”现在 hindsight 已经不只是我们内部的一个小工具而是被包装成了 Dify 里的一个可复用工作流。任何需要严格事实核查的内容生成任务都可以在工作流里直接调用 hindsight 作为下游节点。比如我们的周报生成现在流程是周报草稿节点生成内容后调用 hindsight 审视节点如果发现问题再调用修正节点重写。整个过程对最终用户是透明的他们只看到更高质量的周报而感知不到后台有反思环节。Dify 的编排方式决定了你可以把一个复杂流程拆成多个可复用的子流程这才是这个平台真正值钱的地方。你不需要每天重新发明轮子把验证过的逻辑固化成模板团队其他成员也能直接拖过去用。5.2 未来迭代的几个方向第一针对不同任务类型的专门审视规则。现在审视节点是一套通用规则但技术问答、数据分析、文案写作所需的检查点完全不同。准备将审视规则拆成多个子节点分别检查数值、逻辑、引用、合规性。第二建立审视意见的反馈闭环。目前审视意见只用于修正结果没有沉淀下来。计划把审视意见写入 Dify 的标注系统定期分析哪些类型的错误出现频率高反过来优化知识库和生成提示词。第三引入多轮对话中的持续反思。目前 hindsight 只处理单轮问答但很多真实场景是多轮对话。用户后续的澄清和补充完全可能推翻初版的结论但应用无法感知。后续在多轮上下文中嵌入持续审视机制这会对对话应用的体验有很大提升。这几条路径都不算特别难但需要大量迭代。好在外有 Dify 的灵活性兜底内有不依赖特定模型的设计框架整个方向我还是比较有信心的。6. 个人经验与踩坑记录写到最后分享几个这半个多月折腾中建立的判断。当时反复调整后最深的感受是反思类应用真正的复杂度不在模型而在流程设计。模型的单点能力再强心虚之处在于它无法自己发现自己哪里错了。而 hindsight 的实践经验告诉我只要你能搭建好“独立审视”的流程模型之间的互相纠错远比单个模型的自省可靠。还有个值得记录的坑一开始我试图在提示词里塞进去所有规则结果就是每轮生成的 token 消耗暴涨、响应时间变长而且规则太多时模型反而记不住。后来我就坚持“少数关键规则 结构化输出 外部检索验证”的三层设计。如果你也打算做类似的工具这条经验可以少走很多弯路。最后一个实用的技巧上线前一定要做“故意加错”的测试。我往知识库测试文档里塞了几处明显的数据矛盾和逻辑跳跃确认审视节点能全部捕获才放心把应用开放给团队。这种测试看起来笨却是验证整个反思链路是否真正有效最直接的手段。做过的都知道反思功能不怕模型没看住怕的是表面在做、实际没有任何校验能力。
返回列表