☰
基于Dify搭建个人AI复盘助手:从时间线抽取到报告生成
2026/9/28 7:10:52 网站建设 项目流程

1. 项目整体设计与思路拆解

1.1 先聊聊“hindsight”这个词的来历

如果你接触过强化学习,可能听说过一个概念叫 Hindsight Experience Replay(事后经验回放),这是 OpenAI 的研究者提出的一种训练技巧。核心想法很有意思:让智能体把“没有达到的目标”改写成“已经达到的目标”,从失败结果里反向学习经验。比如机器人想抓杯子却没抓住,算法会把这个过程“重新解释”成一次成功的抓取,从轨迹里找出有信号价值的动作片段。这种“把结果往回看、重新理解它”的思路,就是 hindsight 的底色。

但把 hindsight 放到普通人的日常场景里,它其实更接近一个我们天天都在做却常常做不好的动作:复盘。晚上躺在床上回想今天干了什么,经常一片空白;翻着浏览器历史找三天前看过的那篇文章,翻到手指发酸;月底回看自己的时间花销,发现计划和实际完全是两码事。这些痛点本质上是同一个问题——我们在“往回看”这件事上,没有任何趁手的工具。大脑的记忆不可靠,浏览器的历史记录只是冷冰冰的 URL 列表,笔记软件里堆了一堆没有被检索的碎片。hindsight 这个项目想解决的,就是“如何低成本地留下记录,并且在事后用 AI 帮你把记录变成有意义的回顾”。

我一开始构思这个项目时,并没有想着要做多么宏大的系统,目标非常具体:能不能在 Dify 平台上快速搭一个“回顾助手”,把零零散散的数据(浏览记录、屏幕截图、语音碎片、日程安排)丢进去,让它自动生成一条时间线和一份复盘报告。跑通之后发现,这个方向的可玩性比预想中大得多,也踩了不少坑。这篇博文就完整记录一遍我的实现过程、设计取舍和避坑经验。

1.2 为什么选择 Dify 而不是自己写代码

有人可能会问,做这种工具为什么不用 Python 脚本加 OpenAI API 一把梭?我的答案是:单人项目追求的不是“从零造轮子”,而是“尽快跑通闭环”。Dify 这种 LLM 应用开发平台最大的价值在于,它把工作流编排、上下文管理、模型调用、知识库检索这些容易写崩的部分都封装好了,你只需要关注业务逻辑本身。

我的具体需求有三个,Dify 全部都能覆盖:

  • 需要可视化的工作流编排:处理一份“今天的杂七杂八数据”,中间要经过数据清洗、时间线抽取、分段总结、汇总成文等步骤,每个环节都可能要调试提示词。在代码里调试这种多阶段流程,要写大量胶水代码;在 Dify 的工作流画布上,拖拽节点、单独测试每个节点,效率高一个量级。
  • 需要多模型切换与对比:不同总结任务适合不同的模型,有的要便宜快,有的要推理强。Dify 的模型管理界面里点几下就能切换,还能给不同节点指定不同模型,这对后期调优非常友好。
  • 需要有日志和运行记录:复盘工具的输入输出比较主观,经常需要回看某一次运行到底为什么结果不理想。Dify 自带的运行日志功能非常详细,每个节点的输入输出都有记录,省去自己埋点打日志的功夫。

当然也不是没有缺点。Dify 对流程控制的原生能力偏弱,比如循环、条件分支需要额外处理。但作为搭建“hindsight 应用”的第一版,这些缺点完全在可接受范围内。重要的是:先把完整的价值链路跑通,再考虑优化问题。

1.3 整体架构:hindsight 应用到底长什么样

我的应用架构分三层,每一层解决一个问题:

  • 数据接入层:负责把各种碎片化信息转换成统一格式的文本。浏览器导出的 HTML 书签、一条语音备忘录的转写文本、手打的当日日志、系统截图,全部先变成“时间 + 内容”的纯文本块。
  • 处理分析层:由 Dify 工作流承担。核心节点包括:文本清洗节点(去掉重复内容和噪音信息)、时间线抽取节点(从文本里识别时间点)、分类节点(把事件归入工作、学习、生活、娱乐等类别)、LLM 总结节点(生成回顾报告)。
  • 输出展示层:以 Markdown 报告为主,内容包括当日大事记、时间分配分析、异常偏差识别、明日建议四个板块。

这个架构的好处是足够松耦合。数据接入层不管后面怎么变,处理分析层只认“统一格式”的输入;后续想接新的数据源,只需要写一个转换函数。如果你不想用 Dify,也可以把处理分析层换成别的流程引擎,但 Dify 让这个应用从“想法”变成“能点的 Demo”只花了一个周末。

2. 核心功能拆解与关键细节

2.1 时间线抽取为什么是第一个要过的坎

hindsight 应用最核心的能力不是“总结”,而是“把无序信息变成有序时间线”。你想,我丢给它的是“上午开会讨论了预算的事”“下午写了三页方案”“晚上看了一篇关于注意力机制的文章”这种零散句子,它得先知道这些事情发生的先后顺序,才能生成有意义的回顾。时间线抽取就是这道工序。

这里有一个关键选择:到底靠正则表达式硬抽时间,还是让 LLM 自己识别?我的结论是——两条腿走路。正则负责“兜底”,LLM 负责“理解”。做法是这样的:

  • 先用正则匹配文本里显式的时间格式,比如“上午 9 点”“14:30”“周三下午”,把带明确时间锚点的事件先排到时间线上。
  • 再把剩余没有时间锚点的文本块喂给 LLM,让它根据语义推断一个大致的时间顺序。比如“中午吃饭时聊到……”显然是下午之前的事,“发布前检查了配置”大概率发生在一天的后半段。

这个“正则兜底 + 语义推断”的组合在实测中效果很稳。我一开始偷懒,全部抛给 LLM 去抽取,结果遇到一种尴尬情况:文本里根本没有明确时间词时,LLM 会瞎编一个时间出来,明明没依据,但它一本正经地写“下午 2 点”。加了正则前置过滤之后,这类幻觉明显减少了。

另一个细节是时间表达归一化。用户输入的数据千奇百怪,有写“上午”的,有写“am”的,有写阿拉伯数字的。归一化逻辑必须在进入 LLM 之前做好,否则后面每次调用模型都会多花 token 去理解这些变体。我在代码处理节点里维护了一张时间表达映射表,把所有常见口语化时间表达统一成“HH:mm”格式,这样 LLM 拿到的时间线数据非常干净。

2.2 分类与打标:让报告有维度可言

如果只是输出一条时间线,这个工具充其量是个“高级版记事本”。真正让它有价值的是维度的引入——同样是记录了 20 条事件,你得告诉用户“这 20 条里,工作占 10 个番茄钟,学习占 2 个番茄钟,摸鱼占了 6 个番茄钟”,这份报告才谈得上复盘价值。

分类节点的设计我考虑过两种方案。方案一是预设固定分类:工作、学习、生活、娱乐、健康、其他。方案二是让 LLM 动态生成分类。固定分类的好处是输出高度可控,后续做统计时不需要重新归类;坏处是覆盖面有限,比如“灵感记录”这种类别它可能就分到“其他”里去了。我用的是折中方案:预设一级分类固定,二级标签动态生成。一级分类保证统计稳定,二级标签保留灵活性。举个例子,“下午三点和产品经理过需求评审”会被打上一级分类“工作”,同时挂上“需求评审”“跨团队沟通”这些二级标签。

打标还有一层隐藏价值:支持后续检索。我在 Dify 里接了知识库功能,每次生成的回顾报告都自动写入文档集。用户以后提问“上周和产品相关的事儿有哪些”,RAG 检索可以顺着分类标签把相关段落捞出来。这一步让 hindsight 从“一次性总结工具”升级成了“可累积的个人记忆库”。

2.3 报告生成的三个层次:从流水账到真复盘

报告生成是用户最终看到的结果,也是整个应用价值传递的最后一步。我要求生成的报告必须分三个层次,缺一不可:

第一层是事实回顾。今天到底发生了什么,按时间顺序列出关键事件。这一层不需要任何加工,只做转述,保证信息不失真。

第二层是偏差识别。把“计划做的事”和“实际做的事”放在一起对照,找出偏差。这里需要引入用户前置输入的今日计划,没有也没关系,LLM 可以根据事件内容反推可能的意图,然后判断哪些时间是花在计划外的。比如,计划里写了“上午写周报”,但时间线里整个上午都在回 IM 消息,那“被碎片消息打断”就会被识别成一条偏差。

第三层是经验沉淀。针对偏差给出可执行的建议。这一层最容易写成空洞的鸡汤,比如“建议提高专注力”,毫无价值。我调了几版提示词之后,会强制 LLM 基于具体事件给出行动建议。比如,检测到上午有 3 个碎片时段都在回复同类问题,建议就应该是“把常见问题整理成 FAQ 文档,下次直接丢链接”,而不是“减少回复”。

三层结构还有一个好处:如果用户只想要快速浏览,直接看事实回顾就行;想要深度复盘,读完全文。不同需求的人各取所需。

3. 在 Dify 上从零实现 hindsight 应用

3.1 前期准备:模型选择和工作流模式

开始搭建前,我先确认了两个前提。

模型方面,我的主力模型选择是 Claude 3.5 Sonnet,辅助节点用 DeepSeek。原因很简单:主节点(时间线抽取、报告生成)需要较强的指令跟随能力,Claude 系模型对中文长文本的结构化输出控制得比较稳;辅助节点(分类、关键词提取)任务单一,用便宜模型可以明显压成本。Dify 支持在每一个 LLM 节点单独指定模型,这种“强模型做主,弱模型做辅”的组合非常实用。

工作流模式我选了“Chatflow”。原因是我希望用户能和这个应用对话,而不是一次性提交完就跑。Chatflow 允许我在同一个应用里既有对话入口又能编排复杂的工具调用链。如果你只是想批处理数据,选“Workflow”模式就够了。我个人的建议是:哪怕初期只需要批处理,也尽量用 Chatflow 搭,因为复盘这件事天然是迭代的——用户看完第一版报告会追问“昨天呢”“上周呢”“关于某件事的细节再展开讲讲”,这个扩展空间必须留给用户自己。

3.2 分步配置:从数据输入到报告输出的完整画布

下面按我的实际配置顺序,一步步走一遍工作流画布。

第一步是输入变量设计。我定义了两个输入变量:一个叫 daily_log,用来接收用户粘贴的当日原始文本;另一个叫 plan_todo,用来接收当天的计划清单,允许为空。变量类型都设为“paragraph”,长度不限。这里有个小坑:Dify 的输入变量不支持直接上传多个文件,所以如果你有截图之类的数据,得先在外部转成文本再粘贴进来。

第二步是代码节点做预处理。我用一个 Python 代码节点把原始文本切成事件块。切分逻辑很简单:按换行符和常见分隔符(比如“然后”“接着”“之后”)分句,每句作为一个候选事件。然后对每个事件做时间表达归一化,格式统一成“HH:mm”,没有时间词的先标记为“unknown”。这一步输出的是一串 JSON,结构大概是:

[ {"time": "09:30", "event": "和产品经理过需求评审", "has_time": true}, {"time": "unknown", "event": "傍晚跑了五公里", "has_time": false} ]

第三步是时间线整理节点。这里用 LLM,把上一步输出的 JSON 和原始文本一起喂给模型,让它推断“unknown”项的大致时间位置,并输出一个排好序的完整时间线。提示词里我加了硬性约束:只准调整时间顺序,不准改写事件内容;对无法推断时间的事件,放在时间线末尾并标注“时间不确定”。这个约束很重要,否则模型会自作主张帮你润色事件描述,导致后面报告生成时事实失真。

第四步是分类打标节点。我用了一个 LLM 节点加一个代码节点组合。LLM 节点负责给每个事件打一级分类和二级标签,输出标准化 JSON;代码节点负责统计每个分类的事件数量和预估时长占比。预估时长这部分,我用了很朴素的启发式规则:如果事件描述里带了时长(如“开会一小时”),直接读出来;没带时长的,默认按 30 分钟计,并标注“估算值”。这样用户至少能看到一个时间花销的粗略画像。

第五步是报告生成节点,这是最复杂的一个 LLM 节点。我把前三步的输出(完整时间线、分类统计、计划清单)全部塞进上下文,然后用一个大提示词要求模型按“事实回顾、偏差识别、经验沉淀”三层结构输出 Markdown 报告。为了稳定格式,我在提示词里给了非常具体的输出模板,甚至把每个章节的小标题都写死了。模型只需要按模板填空。实测下来,这种方式比让模型自由发挥稳定得多。

第六步是输出节点。把 Markdown 报告直接返回给用户,同时在后台把报告写入知识库。写入知识库这一步我踩过坑:Dify 的“知识库写入”节点要求文档格式必须先转成纯文本,如果我直接把带 Markdown 符号的报告写进去,后续检索时会把#和**这些符号也当成内容,降低检索质量。我的解法是单独接一个代码节点,先把 Markdown 语法剥掉再写入。

3.3 提示词设计的一些实测经验

提示词是整个应用效果的上限所在。我前后迭代了五版,几个关键发现值得记录下来。

第一,给足输出模板。模型对“请总结一下”这种模糊指令的响应千奇百怪,但当你给出一份精确到“章节名 + 要点格式 + 示例”的模板时,它基本会照着模板走。我的报告生成提示词里甚至放了一段“参考示例”,示例里包含了虚构的输入和对应的输出,效果立竿见影。

第二,明确禁止事项比明确要求事项更重要。我在这版提示词里明确写了“禁止使用‘总而言之’‘综上所述’这类套话”“禁止输出跟输入无关的建议”“禁止编造时间点”。这些负向约束极大地减少了幻觉输出。

第三,温度参数要调低。最后一个报告生成节点的 Temperature 我设置在 0.2 左右。温度太高,模型会在复盘建议里放飞自我;太低又显得机械。0.2 是平衡点。中间处理节点(分类、时间抽取)我用的是 0,保证确定性优先。

第四,上下文长度是隐形天花板。如果你输入的原始日志很长,时间线抽取节点可能会遇到上下文溢出。我的处理方案是把事件块分批送进同一个 LLM 节点,每批 20 条,最后再让模型合并。Dify 的节点支持循环但配置稍繁琐,批处理拆分用代码节点手动做更省心。

3.4 完整测试:从输入到输出的实际效果

为了测试,我准备了一段模拟的一天记录作为输入,内容涵盖了开会、写方案、摸鱼刷视频、健身、看书,以及若干碎片时间。下面是一段节选:

9 点 15 分到会议室参加周会,讨论了本周 OKR,确认了周四要交付的版本范围。10 点回来继续写用户画像文档,写到一半被同事叫去排查线上告警,搞了大概 40 分钟。中午跟组里的同学吃饭,讨论了新项目的技术选型。下午 2 点半把用户画像文档写完,发到群里。3 点左右刷了会儿短视频,大概 20 分钟。4 点和数据团队对了一下埋点需求。晚上去健身房跑了 40 分钟,回家看了会书。

输入计划清单是:“上午写用户画像文档,下午对埋点需求,晚上健身”。

实际生成的时间线准确捕捉了所有带时间锚点的事件,同时把“中午吃饭”推断到了 12 点前后,“刷短视频”排在了下午写文档之后。分类统计显示工作 4 项、生活 2 项、健康 1 项、娱乐 1 项,偏差识别精准指出了“上午被线上告警打断导致文档完成时间延后”和“计划外出现了 20 分钟短视频时间”。最终报告里给的建议包括“把常见告警排查步骤写成 wiki,下次直接照着走”,算是比较接地气了。

4. 常见问题与排查技巧实录

4.1 数据缺失与时间推断失真

实际使用中最常遇到的问题是输入数据本身质量太差。比如用户粘贴的日志里有一半的句子没有主语、没有时间、没有上下文,单靠 LLM 很难推断顺序。我的应对策略是:在预处理代码节点里加了一个“清洗提示”——如果一段文本字符数少于 5 个字,直接丢弃;如果一段文本里既没动词也没名词,也丢弃。这个简单的规则能过滤掉至少三成噪音。

时间推断失真也遇到过几次。典型情况是:用户输入“下午 3 点做 A 和 B”,模型不知道 A 和 B 谁先谁后,于是随机排列。我最后的解法是在代码节点里做“保持原序”处理:当多条事件共用一个时间锚点时,按原始文本出现顺序保留,不交给 LLM 排序。这个处理虽然牺牲了一点智能感,但确保了稳定性。

4.2 LLM 输出格式不稳定怎么解

这是所有 Dify 应用都会遇到的老大难。有时候模型返回的 JSON 有残缺,有时候章节标题自己改了,有时候本来应该输出 Markdown 它却输出纯文本。我的排查思路可以总结成一张速查表:

问题现象根因解决方式
模型偶尔返回残缺 JSON提示词约束不够强在每个 LLM 节点的提示词里加“必须输出合法 JSON,不能带注释,不能带 markdown 代码块标记”
章节标题不一致模型自由发挥把完整标题模板写进提示词,并要求“严格按照模板,不允许修改标题文本”
有时输出夹杂分析过程思维链泄漏在提示词里明确“直接输出结果,不要解释思考过程”
中文标点偶发变为英文标点模型语言偏好在报告生成后接一个代码节点,用字符串替换把英文标点转成全角

其中最后一条是我比较实用的发现。很多时候问题不是出在模型能力上,而是出在输出的“格式清洁度”上。加一个后处理代码节点做符号规整,成本极低,收益却非常明显。

4.3 成本与延迟控制

如果每次交互都调用全流程,成本会有点难看。我的实测数据是:如果用户输入的日志有 2000 字,整个工作流跑一次大约消耗 2 万到 3 万 token,其中报告生成节点占了一半以上。为了控成本,我做了两个优化。

第一个优化是按需执行。用户如果只在对话框里问“今天有哪些工作相关的事”,没必要跑完整的分类统计和报告生成流程。我在 Dify 的画布里加了一个条件分支节点,根据用户的输入内容动态决定走“完整报告流程”还是“快速问答流程”。这里需要在 Chatflow 模式下,把用户输入先经过一个意图识别节点,再分流。实际操作并不复杂,但成本能直接降一半。

第二个优化是把常用的中间结果缓存下来。同一个用户在同一天重复提交相似数据时,先比对输入文本的哈希值,如果一致,直接读取上一次运行的缓存结果。这个功能我用了一个外部 Redis 服务来实现,Dify 的应用内部本身不提供缓存能力,需要自己写代码扩展。如果不想引入外部服务,至少可以把之前的运行结果存在知识库里,通过相似度检索复用。

4.4 知识库检索质量不理想的修整

我把每次生成的报告写进知识库后,本来期望用户能自然语言检索历史复盘,结果发现检索命中率并不高。排查下来有三个原因:

  • 报告太长,分段切分后每段承载的信息密度参差不齐,Embedding 的结果不够聚焦。
  • 写入时没有保留足够的元信息(比如日期、分类标签)。
  • 用户提问往往是口语化的,和报告正文的书面表达在向量空间里距离较远。

前两个问题通过改写写入格式解决了。我在写入前把报告的内容调整成“标题 + 分类标签 + 摘要 + 正文”的结构,并且在知识库设置里开启了“分段标识符”,让 Dify 按我指定的分隔符切分而不是自动切分。第三个问题,我加了一个“历史记录问答”专用提示词,让模型在回答时先根据用户问题生成一组可能的关键词,再用这些关键词去检索。实测检索命中率从不到一半提升到了七成以上。

5. 从“回顾工具”到“个人记忆外挂”的扩展方向

hindsight 应用跑通基本流程后,我花了不少时间思考它能扩展到什么程度。如果你做完了基础版本,这几种扩展方向值得一试。

第一个方向是接入更多数据源。浏览器历史是最容易接的:Chrome 可以直接导出 HTML 格式的历史记录,写一个 Python 脚本把 URL、标题、访问时间抽出来,转成文本喂给 hindsight,就能自动生成“今天在网上做了什么”的时间线。语音记录也可以用类似思路,先把录音转成文字,再进流程。甚至本地的代码提交记录、飞书文档的编辑记录,只要能导出成文本,通通可以接入。

第二个方向是做周期性复盘。把日复盘报告累积一段时间后,可以再用一个汇总工作流,把过去七天的日复盘报告作为输入,生成周复盘。周复盘里可以看趋势,比如“这周的深度工作时间比上周多了两个小时”“碎片时间依然集中在下午三点以后”。这个汇总流程本质上和日复盘流程长得一模一样,只是输入数据变了,复用性极高。我甚至做了一个“月度回顾”版本,把每天的偏差和建议汇总,看哪些问题反复出现。

第三个方向是把 hindsight 嵌入到更多角色里。不只是个人复盘,团队周报、项目复盘、甚至家庭月度总结都能复用同一套“时间线 + 分类 + 报告”的架构。你只需要替换输入数据的来源和建议的输出格式。我试过把一个项目群的聊天记录导出后丢进工作流,生成的“项目进展回顾”比群里翻聊天记录高效太多了。

需要提醒的是,这种工具涉及的数据大多是个人敏感信息。如果接入了浏览器历史、录音转写、日程数据,一定要搞清楚存储位置和数据权限。我目前的做法是:默认不着陆任何数据到第三方服务,Dify 的模型调用通过自部署网关转发,知识库放在本地私有化部署的向量数据库里。个人工具一旦涉及隐私,宁可功能少一点,也要把数据控制在自己手里。

最后再分享一个最近的小技巧:我把 hindsight 生成的每日报告末尾加了一个“明日锚点”字段,让 LLM 根据今日复盘内容提出明天最该守住的三件事。这个字段并不复杂,但每天早晨打开电脑看到这三条时,确实能帮助我快速进入状态。工具能做的本来就不多,能帮你把“昨天发生过什么”和“明天该专注什么”连起来,就已经值回搭建它的时间了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询