news 2026/9/29 17:26:32

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于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 设置为 4,Score 阈值设置为 0.3。如果你们的知识库质量参差不齐,把 Score 阈值调高一些,宁缺毋滥。

然后是“生成初稿”节点。这一步的输入主要是用户问题和知识库检索片段。我在这里专门用了一个 LLM 节点,模型选择 Claude 3.5 Sonnet,system prompt 写着“你是资深行业分析师”,user prompt 包含用户问题与检索到的上下文。

接下来是“事实抽取”节点。这个节点是我在第二版才加的。它的作用是把生成初稿中涉及的事实性断言标记出来,比如“今年第一季度销售额达到 2.3 亿元”这样的句子会被提取成独立行。这一步是为审视节点减轻比对负担。

然后是“独立审视”节点。模型用 GPT-4o,temperature 设为 0.1。提示词里明确要求它只看事实断言和源材料,忽略文字风格问题。输出格式用 JSON,禁止输出自然语言。

再往下是“条件判断”节点。判断审视意见中的issue_type是否包含factual_error或logic_gap。如果都没有,直接走输出节点返回初稿;如果有,进入“修正”节点。

“修正”节点是最後一棒,模型用回 Claude,temperature 设定为 0.2。输入结构包含三部分:用户原始问题、初稿内容、审视意见 JSON。提示词中强调“基于审视意见修正初稿,不改变原有行文风格”。

最后接入“直接回复”节点,输出修正版结果。

这条链路看起来有六个节点,实际上在 Dify 里配置起来大约一小时就能搭完。时间主要花在打磨提示词和调整参数上,而不是写代码。

3.2 参数选择背后的计算思路

我专门把参数计算这部分单独拎出来说,因为这地方最容易凭感觉走了弯路。

审视节点的 Score 阈值,我一开始设置得很低,只有 0.1,导致召回了很多无关片段。后来计算了一下,知识库一共 680 篇文档,TopK=4 每轮召回 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 消耗暴涨、响应时间变长,而且规则太多时模型反而记不住。后来我就坚持“少数关键规则 + 结构化输出 + 外部检索验证”的三层设计。如果你也打算做类似的工具,这条经验可以少走很多弯路。

最后一个实用的技巧:上线前一定要做“故意加错”的测试。我往知识库测试文档里塞了几处明显的数据矛盾和逻辑跳跃,确认审视节点能全部捕获,才放心把应用开放给团队。这种测试看起来笨,却是验证整个反思链路是否真正有效最直接的手段。做过的都知道,反思功能不怕模型没看住,怕的是表面在做、实际没有任何校验能力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 17:24:44

Windows软件强力卸载:注册表残留定位与彻底删除指南

简介:面向 Windows 平台使用者与维护人员,这份工具包针对顽固软件无法卸载、注册表残留清理困难等场景,提供了专业的卸载与清理解决方案。压缩包共 11 个文件,以 UninstallTool 主程序(exe)为核心&#xff…

作者头像 李华
网站建设 2026/9/29 17:23:58

用SquareLine Studio让ESP32-LVGL界面开发效率翻倍

做嵌入式带屏设备这几年,我最大的感受是:如果UI逻辑复杂一点,手写LVGL代码就是灾难。坐标算半天,一个控件挪三次编译,改个样式得翻好几处结构体赋值,遇到需求变更整个人都能麻掉。后来在ESP32项目里引入了S…

作者头像 李华
网站建设 2026/9/29 17:23:58

用示波器抓RS232串口波形,手把手教你反推波特率与解析帧结构

做嵌入式这几年,要说哪个问题把人折磨得最没脾气,串口乱码绝对排得上号。代码逻辑看着没问题,收发双方的波特率也都对上了,可串口助手打印出来的就是一团乱码。后来我养成了一个习惯:遇到这种问题,先不急着…

作者头像 李华
网站建设 2026/9/29 17:23:17

从Keil迁移到VSCode+Embedded IDE:STM32开发环境搭建全攻略

1. 为什么我从 Keil 彻底搬到了 VSCodeEmbedded IDE1.1 Keil 用久了,总有几件事让人难受我接触 STM32 开发的时间不算短,从 F103 到 H743 一路做过来,Keil MDK 用了得有七八年。老实说,Keil 并不是不能用,工程模板、芯…

作者头像 李华
网站建设 2026/9/29 17:22:42

《TCP/IP Guide》实战指南:Wireshark抓包与内核参数协同调试

简介:这是一本面向网络工程师、协议学习者与高校计算机专业学生的权威TCP/IP协议参考书,完整覆盖IPv4/IPv6、路由、传输层、应用层等核心协议体系,以图文并茂方式系统解析底层原理与实际交互机制。资源为原版PDF转化的高质量电子书包&#xf…

作者头像 李华
网站建设 2026/9/29 17:19:12

在无用时光里找回自己:高效时代的精神留白与创造力滋养

“让生命在无用时光里丰盈”——这句话是我在某个周末下午写下专栏计划时,脑子里突然蹦出来的。当时我刚泡完一壶茶,窗外的阳光正好落在书桌一角,而桌上那本翻了一半的诗集,已经搁置了三周。我记得很清楚,那时心里冒出…

作者头像 李华