你有没有过这样的经历:项目上线一周后出了故障,复盘会上大家七嘴八舌——“其实当时评审就该拦住”“我早说那个接口设计有问题”“数据校验就是少了这一步”。会议室里充满了事后才显得无比正确的判断,但下一个迭代,类似的坑照样踩。
这种感觉的关键词就是 hindsight,事后才看明白。心理学里有个对应的词叫 hindsight bias(事后偏差):结果一旦确定,人就倾向于相信自己早就预料到了。这一偏差不纠正,所有复盘都只是集体表演。我最近做了一个叫 hindsight 的小项目,目标是让大模型帮我把“事后聪明”改造成“事前雷达”:记录事件、还原事实、区分“当时能知道的”和“事后才明白的”,最终输出一份不掺马后炮的分析报告。整个项目跑在 Dify 上,用它来编排工作流、管理提示词、接模型。
这篇文章会把项目的完整思路、工作流搭建过程、中间踩过的坑,以及几处我认为最关键的设计点全部写出来。想自己复刻一套复盘分析工具的人,或者对 Dify 搭建 LLM 应用感兴趣的人,都能从里面找到可直接照抄的部分。项目本身不大,但思路值得慢慢盘。
1. 复盘这件事,为什么总变成一场集体表演
先别急着上工具。我花了大半个月确认了一件事:绝大多数团队的复盘流程,失败的原因根本不在“工具不好用”或“大家不积极”,而在一个更底层的认知问题——我们都在用后见之明审视过去。
1.1 会议室里的“事后诸葛亮”
我做这个项目之前,观察过七八个团队的真实复盘场景。几乎每个会议都遵循同一个剧本:事故发生了,时间线贴出来,有人开始问“当时为什么没发现”,然后最有经验的那个人开始回忆“其实我早就觉得这里有问题”。
这句“我早就觉得”非常典型,但大多时候它是记忆重构出来的假象。心理学实验早就证明,在结果公布之后再让人复盘当初的判断,人的记忆会悄悄把自己往“猜对了”的方向修正。这不是道德问题,是认知机制本身就是这样运行的。
这也解释了为什么复盘记录容易变成两堆垃圾:一堆是情绪化的指责(“谁谁谁当时不上心”),另一堆是毫无可操作性的口号(“以后要加强测试”“要提高安全意识”)。前者制造对立,后者制造疲劳。日子久了,大家就学会了在复盘会上如何安全地附和,会议变成仪式,文档变成存档,问题原地踏步。
1.2 为什么“写总结”救不了团队
很多人以为复盘做得差是因为形式不对,于是今天用 KPT,明天换成 4L,后天又开始写 AAR。这个方法换成那个方法,最后还是没效果。
我的判断是:问题不在方法名称,而在三个结构性缺陷。
第一,记忆失真。复盘依赖人脑回忆,而人脑的记忆是会篡改的。大多数人不会提前记录决策时的信息环境,只能靠事后倒推。倒推出来的“原因”,天然带着结果的光芒。
第二,把相关当因果。事情发生后,所有在当时发生过的事实都摆在眼前,人很容易挑出几个“看起来和结果有关”的,编一条自洽的故事线。这个故事线通常不是完整因果链,只是最省力的叙事。
第三,行动建议没有约束条件。复盘常见的产出是“要增加自动化测试”“要补充监控指标”,但没有负责人、没有触发条件、没有验证方式,三个月后谁都不记得,甚至当时写下这条的人自己都忘了它是为什么而写。
1.3 复盘的真正痛点:信息不对称
我把这些现象归结成一个词:信息不对称。复盘时人心里有两套信息——一套是事件发生时真实可得的,一套是结果公布后才获得的。真正有价值的复盘,是搞清楚“当时的信息环境到底支持做什么判断”,而不是“现在回头看应该怎么做”。
我当时就跟自己说,如果一个工具能强制把这两套信息分开,让团队在复盘时只能基于“当时可得信息”下结论,这件事就成了一半。hindsight 这个名字,一开始就是冲这个念头去的。
2. hindsight 的核心思路:把“事后聪明”改造成“事前雷达”
想清楚痛点之后,我开始设计这个系统的核心逻辑。它不是一个简单的“把事件描述丢给大模型,让它总结几点教训”的工具——那种工具我试过,输出的东西跟会议室里大家喊的口号没什么区别。
2.1 一个关键的划分:事实和判断必须分离
整个项目最核心的设计决策,是把“事实”和“判断”强行分成两道工序。
事实是什么?是可以被时间戳、人名、具体操作验证的信息:“15:02 支付服务返回超时”“发布单在 18:40 通过审核”“A 同学在评审会上提出过缓存穿透风险,未形成决议”。判断是什么?是推测、情绪、归因:“因为并发太高导致超时”“早就该加熔断”“负责人不够重视”。
绝大多数复盘,问题就出在第一步——事实还没理清,所有人就开始甩判断。所以 hindsight 的第一道工序是“事实还原”,这一步只允许产出清单,不允许产出任何评价。我甚至在提示词里写死规则:这一轮你如果给出了归因或评价,整份输出作废。
2.2 三层次分析模型:事实还原、归因分析、行动生成
我参照了事后复盘领域常用的结构,把分析流程固定为三个层次,每一层有独立的模型调用,层与层之间只传递结构化数据,不传递废话。
第一层是事实还原层,输入是用户填写的原始事件描述,输出是三类清单:已确认事实、存疑信息、信息缺口。第二层是归因分析层,输入是第一层的清单,输出是多维度归因,并且每条归因必须标注“该信息在事件发生时是否可得”。第三层是行动生成层,输入是第二层的结果,输出是带有负责人、触发条件、验证方式的行动条目,并且明确忽略所有“不可预判”的归因。
这三层不是一次性扔给大模型让它一次生成,而是拆成三次调用。原因很简单:大模型一次做三件事时,中间的推理过程是不可控的,它可能在归因阶段就把事实加工歪了。拆开之后,每一层都只做一个动作,结果稳定得多。
2.3 决策日志:对抗事后偏差的入场券
如果只靠事后输入,系统再怎么设计也逃不过信息失真,因为它唯一的语料来源就是事后回忆。所以我加了第二个关键设计:决策日志。
具体做法是在 Dify 里建了一个最简单的知识库,专门存放团队或个人的“事前预判”记录。格式非常朴素:一个表单,包含时间、事件背景、你的判断、信心值(1-5)。每次开工之前、每次发版之前、每次做重要方案之前,花两分钟填一条。存进去的时候不需要任何整理,就是原话。
复盘时,hindsight 会把事件发生前的决策日志作为参考材料喂给归因分析层。模型拿“当时实际想的”来对比“事后复盘说的”,如果两者偏差太大,输出里会显式标注出来。这个设计的目的不是抓谁撒谎,而是让所有人看见:我们的记忆在多大程度上被结果扭曲了。数据一旦摆在台面上,集体表演就很难继续了。
2.4 系统整体结构
hindsight 最终跑通的形态是一个典型的 Dify 工作流,外加一个用于检索的知识库和几段固化好的提示词。用户输入入口是一个结构化的表单,而不是一个自由文本框——这一点非常关键,后面我会单独解释。表单字段包括:事件标题、发生时间、事件描述、已知影响、当时的决策日志关联 ID、参与角色。提交后,工作流自动执行三层分析,最后输出一份 Markdown 格式的复盘报告,可以直接复制进团队的文档系统。
从技术实现难度来说,这个项目没有任何炫技成分,没有微调模型,没有 RAG 之外的检索技巧,更没有什么复杂算法。它真正的价值全在流程约束和提示词设计上。而这,恰恰是大多数做“AI 复盘助手”的人忽略的部分。
3. 用 Dify 搭建 hindsight:工作流设计与关键节点实现
Dify 是这两年很火的开源 LLM 应用开发平台,你可以把它理解成一个可视化的工作流画布:把模型调用、知识检索、条件分支、变量处理串成一条流水线,不需要写太多后端代码。选它而不是直接用 Python 调 API,原因很实际:迭代提示词方便,团队里不懂代码的人也能参与调整,而且输出模板、知识库这些基础能力开箱即用。
3.1 工作流节点逐个拆解
我的工作流一共六个节点,按顺序串起来。先说清楚,这不是 Dify 官方文档式教程,我不讲每个按钮在哪,只讲每个节点在这个项目里承担什么职责、以及我踩过的坑。
第一个节点是开始节点,也就是输入表单。我在上面定义了六个输入变量:event_title、event_time、event_desc、impact、decision_log_ref、roles。如果让我重做一遍,我依然会坚持用结构化字段而不是一个巨大的 textarea。原因是我测试过:自由文本框里用户往往会写一大段情绪化叙事,模型很容易被叙事带偏。当你强制他分字段填写,他反而会稍微收敛一点,描述也更接近事实。
第二个节点是知识检索节点,在 Dify 里叫知识库。我挂了一个名为“hindsight-memory”的知识库,里面存的是历史复盘报告和历史决策日志。这里有一个很实用的配置:检索模式选“向量检索”,top_k 设为 3。不需要更多,复盘相似案例有个三五条就够参考,多了反而干扰分析。
第三个节点是第一个 LLM 节点“事实还原”。这里我绕过了一个大坑——千万不能把知识检索的结果和用户输入直接塞进同一个提示词。检索出来的历史案例属于“参考信息”,用户输入属于“待分析对象”,两者一旦混在一起,模型常常会把历史案例里的事件当成当前事件来分析。我在提示词里用分隔符强制区分,效果立刻稳定了。
第四个节点是第二个 LLM 节点“归因分析”。它的输入是第一个 LLM 节点的结构化输出,加上从知识库检索到的事件发生前的决策日志(如果有的话)。这个节点我专门配置了一个低温度,temperature 设 0.2。原因后面会细说。
第五个节点是第三个 LLM 节点“行动生成”。输入是归因分析输出,输出是行动清单。这里我设计了一个硬性过滤规则:归因中被标注为“不可预判”的条目,直接不进入行动生成环节。宁可少给建议,也不给假建议。
第六个节点是模板转换和结束节点。我让所有 LLM 节点输出 JSON 格式的数据,然后在模板节点里拼接成带标题、表格、复选框的 Markdown 报告。JSON 的好处是后续如果要接别的系统,可以直接机器读。
3.2 三层提示词的写法
这三段提示词是整个项目的心血,我直接贴出来,你可以拿去改。
事实还原层提示词:
你是一名复盘分析师。下面是一段事件描述,由当事人提交。 你的任务只有一个:把"事实"和"判断/情绪"强制分离。 事实的定义:拥有时间戳、人名、系统名、可验证的具体操作。 判断的定义:推测、情绪、指责、马后炮(包含"应该""早就""本来"等词)。 输出格式(JSON): { "confirmed_facts": ["事实1", "事实2"], "disputed_items": ["需要进一步确认的表述"], "info_gaps": ["目前缺失的关键信息"] } 硬性规则: 1. 不要解释,不要铺垫。 2. 不要把当事人的主观结论当成事实收录。 3. 对每一条事实,必须附带"(时间:xxx, 来源:xxx)"。 4. 如果你认为无法区分,请放入 disputed_items。归因分析层提示词:
你是一名风险管理专家。下面是经过事实还原的事件事实清单,以及事件发生前团队的决策日志(如果存在)。 你的任务:基于这些材料,给出多维度归因分析。 约束: 1. 禁止使用"应该""早就""本来""明显"等事后语言。 2. 对每条归因,必须标注"当时信息可得性":available(当时能获得)/ unavailable(当时无法获得)。 3. 区分"系统根因"和"流程根因"两个维度。 4. 若某归因无法获得当时证据支撑,请评估依据强度:strong / medium / weak。 输出格式(JSON): { "root_causes": [ {"dim": "system|process", "cause": "...", "evidence": "...", "info_available": true/false, "evidence_strength": "strong|medium|weak"} ], "hindsight_notes": ["指出两个明显的后见之明表述,并解释为什么它们在当时不可得"] }行动生成层提示词:
根据以下归因分析结果,生成可执行的改进行动清单。 规则: 1. 只针对 info_available=true 的归因生成行动。 2. 每条行动必须包含:action(做什么)、owner(角色而非人名)、trigger(什么情况下触发)、verification(怎么验证做完了且有效)。 3. 禁止生成"加强意识""提高警惕""加强测试"这类空话。 4. 如果一条归因有 medium/weak 的证据,必须在行动中附带一个验证性任务,而不是直接改造。 输出格式(JSON): { "actions": [ {"action": "...", "owner": "...", "trigger": "...", "verification": "..."} ], "ignored_causes": ["列出因当时不可得而忽略的归因"] }三段提示词有一条共同原则:每一层都只做一件事,并且每一层都用 JSON 把输出锁死。你问我要哪一段最重要,我会说归因层那两条规则最重要——禁止事后语言和标注信息可得性,这两条直接决定了输出不是马后炮。
3.3 参数配置与输出模板
模型选择上,我默认用 gpt-4o-mini 这一个档位,足够用,成本也低。三个 LLM 节点我用同一套模型,但温度不同:事实还原层 0.1,归因分析层 0.2,行动生成层 0.4。温度不能倒过来,理由很简单——事实还原和归因是基础,越稳定越好,最后生成行动时可以稍微放开一点,让表达更自然。
输出模板我在 Dify 的模板节点里拼了一个 Markdown 报告,结构如下:事件概览、事实还原结果(含疑点和信息缺口)、决策日志对比、归因分析表(含可得性标注)、行动清单(复选框形式)、被忽略的归因。复制到飞书或 Notion 后,复选框能直接勾选,行动项就可以当任务管理用,不用二次加工。
4. 最难的一环:让 AI 输出不带“后见之明”的分析
如果你照着上面的工作流搭完,跑几个测试案例,大概率会发现一个尴尬的问题:模型输出的分析,跟传统复盘的废话其实差不太多。这不是你配置错了,而是因为大模型同样深受“后见之明”困扰。
4.1 大模型天然倾向“事后诸葛”
大模型训练数据的特征决定了它天生就是事后视角——它看到的是已经发生了的、带答案的案例。你给它一段事故描述,问它“原因是什么”,它给出的答案天然站在上帝视角,因为它知道最终结果。最典型的体现就是输出里出现“果然”“这就解释了为什么”“显然是因为”。
我最早用单次调用写过一个版本,让模型直接读完整事件描述、直接产出归因。结果 10 个测试案例里有 7 个输出都带着一种已被剧透的视角。这个问题的本质是:你只给了它结果,没给它还原到事件发生时刻的“信息状态”。
所以对策也很清晰:要在提示词层面强制模型做“视角切换”,并明确禁止它使用结果信息来倒推过程。
4.2 用“事前预判”提示词反向约束
最有效的办法就是我在 2.3 里提到的决策日志。模型在归因分析时如果能拿到事件发生前团队写的“我当时判断是 X,信心 3 分”,它就有了参照系,能够对比“事前预期”和“事后现实”的差距。
配合决策日志,我在归因提示词里加了一个强制动作:要求模型必须输出 hindsight_notes 字段,把明显的事后判断挑出来点名。比如用户复盘写“当时就应该看到监控曲线异常”,模型会标注:该监控曲线在第 20 分钟才出现明显拐点,而系统报警延迟正是待查根因,因此这一判断在当时不可得。这个字段的效果惊人——它把模糊的“我们该早点发现”变成了一条具体的、关于信息时间线的分析。
4.3 反事实约束与置信度校准
除了视角切换,我还在归因层做了两处细节加固。
第一处叫反事实约束:提示词里明确要求模型对每条归因追问“如果把这个信息从场景里拿掉,结论还成立吗”。这一步在实际测试里能把不少虚假因果滤掉。举个例子,有一次复盘把故障归因于“代码评审不认真”,反事实问一下:评审就算认真,也会因为当时缺失一份接口文档而无法发现兼容性问题,于是归因从“人不认真”转向“接口文档缺失”,方向完全不同。
第二处叫置信度校准。我让模型在证据不足时,明说证据强度 weak,而不是硬挤一个结论出来。这一点花了我很长时间才想通。以前我总希望 AI 给出确定答案,后来发现复盘场景里,敢于说“不确定”才是价值。weak 的归因不会被删掉,但会单独进验证任务流程,而不是直接变成行动。
4.4 分析质量怎么评估
你可能会问,怎么知道这套设计真的有效?我给自己的评估定了一个很朴素的指标:抽查报告里所有行动条目,问它“这条行动在事件发生前对应的信息是否可得”。可得性为否的条目越少,说明马后炮越少。
另一个辅助指标是“归因可执行率”。知识库里沉淀了一个季度的归因记录后发现,没有决策日志的项目,归因可执行率大概在 30% 左右;有决策日志做参考的项目,能到 65% 以上。虽然样本有限,但方向很明显:给模型的参照信息越接近“事发当时”,输出越能落地。
5. 上线两个月实测:它能拦住什么,又拦不住什么
说这么多,不如看一次真实输出。项目从一个内部工具变成我们小团队每周固定使用的流程,已经跑了两个月。下面的案例我脱敏了细节,但结构完整。
5.1 一次真实的故障复盘输出
事件背景:一次线上服务超时,恢复耗时 40 分钟。传统写法很容易变成“监控不到位,报警太慢,以后要加强监控”。hindsight 跑出来的报告,有几个值得说的输出。
事实还原层先干了一件事:把“没有熔断机制”和“监控报警慢”拆开了。它敏锐地发现,“没有熔断机制”作为一条事实本身没问题,但事件发生时,架构评审记录里显示有人 30 天前提议过熔断方案,没有形成决议,这条信息在事发时是可得信息。而“监控报警慢”则被标为存疑——监控阈值在事发当天上午刚被调整过,调整时无人提交变更评审,模型把这条列入了信息缺口。
归因层的结论没有停在“缺熔断”这个表层,而是指出:更准确的流程根因是“阈值变更未走评审”,因为如果走了评审,变更影响就会被评估,报警延迟问题在事发前就有机会被发现。这条归因的证据强度是 medium,模型建议先做一次阈值变更记录审计来验证。
行动层最后给出的三条行动分别是:熔断方案在下一个发布窗口内进入技术方案评审,触发器是“任何对接口超时时间或重试策略的变更”;监控阈值变更必须绑定变更评审单,触发器是“提交监控配置修改”;对近 30 天所有监控阈值变更做一次审计,验证方式是“输出变更清单并标注审批状态”。
看完这份输出我最大的感受是:它没有给出任何石破天惊的结论,但它把“人云亦云”的复盘硬生生掰成了“可核验、可追踪”的流程记录。同一次事故,以前复盘的结论是“加强监控”,现在的结论是三件具体的事。
5.2 踩坑记录:模型顺着你说、上下文漂移、信息过载
两个月里踩的坑不少,最典型的有三个,我一个个说。
第一个坑是模型顺着用户说。用户在原描述里如果带了主观倾向(“明显是缓存策略的问题”),事实还原层的模型有时会不自觉地把这句话当成事实收录。我在 3.1 里说的分隔符方案解决了大部分,但真正关键的一招是让事实还原层输出时强制附带来源标签(“来源:当事人描述”),模型就不容易把“人说的”当成“发生过的”。
第二个坑是长流程中的上下文漂移。Dify 工作流跑下来,如果某个环节把整个聊天记录或者大段原文传给下一个节点,很容易出现中间某一步的分析结论“漂”掉。我后来定了一条铁律:节点之间只传结构化数据,原始事件描述只进第一个节点,后面环节一律不传。这样既省 token,又控制漂移。
第三个坑是信息过载。有段时间团队成员图省事,把一整段聊天记录直接贴进事件描述。结果是模型抓到一堆无关细节,输出又长又散。最后我在表单里加了字段长度限制,并且加了必填的“影响范围”字段,逼着提交人先自己把信息压缩一遍。这算是用流程设计对抗模型的注意力问题。
5.3 我加的三处“人工闸门”
纯自动化在复盘这种场景里是不可能的,我加了三处人工闸门。
第一处:事实还原结果提交前需要事件当事人确认,确认后才允许进入归因分析。第二处:归因分析里每一条 available=true 的归因,需要一位不直接相关的同事复核。第三处:行动清单生成后,由团队负责人做最后筛选,决定哪些进排期。这三处闸门让系统永远处于“人定案,AI 拟稿”的位置,而不是反过来。
在这个过程里,有一句话让我印象很深。团队里有位同事第一次看报告时说:“原来我当时不是没看到,是信息根本没有到我这里。”这句话说得很朴素,但恰恰是 hindsight 想解决的问题:大多数“早知道”,其实都是“事后才知道”。能把这两种“知道”区分开,复盘才真正有它的价值。
6. 想复刻这个项目的人,我建议你先搞定这三件事
如果你看完想自己搭一个类似的系统,我在代码和配置层面能帮的都在上面了。但还有三件不在技术范围内的事,我建议你在动手之前先想清楚。
6.1 数据习惯比模型更重要
技术方案再漂亮,也抵不过没有数据。这个项目能不能转起来,真正的前提是团队有没有记录决策日志、记录事件、使用工具的习惯。所以最开始不要追求完整流程,只做两件事:让每个人提交事件前花五分钟填字段、让负责人每周固定时间跑一次工作流。等这个习惯养成了,再逐步加知识库和决策日志,否则一上来就是空跑。
6.2 提示词要在真实案例里磨
我贴出来的三套提示词,是经过一个季度迭代才成型的。第一次版本只有两层,第二次加了“信息可得性”标注,第三次才加了 hindsight_notes 字段。如果你直接拿去用,一开始可能不稳定,这很正常。我的建议是拿最近三个月真实发生的三四个案例去测,看输出的行动清单里有没有空话、归因里有没有明显的事后语言,然后针对性地在提示词里补约束规则。提示词工程不是写出来的,是改出来的。
6.3 期望管理:它不是决策替代品
把话说清楚:hindsight 解决的是复盘过程中的信息失帧问题,它不替你做判断,不替你定责任,更不会告诉你“如果重来一次该怎么做”。它的输出永远只是草稿,需要人去认领、去复核、去决定是否执行。想拿它当自动决策工具的人,会让团队陷入另一种形式的甩锅:“AI 都提示过了你们还犯错”。
最后再分享一点个人体会。我最初做这个项目是想“让 AI 帮我们复盘”,做完之后才发现,它真正改变的不是复盘效率,而是大家对“知道”这件事的理解——知道不发生在结果之后,知道是发生在行动之前的信息积累。每次看到报告里那句“该信息在事件发生时是否可得”的标注,我都觉得,这个概念比任何一份漂亮的复盘文档都重要。如果你也想做类似的事,先从这个标注开始,哪怕没有工作流,没有 Dify,只是每场复盘会上多问一句“当时我们到底能知道什么”,就已经赢了大多数人。