ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

构建个人复盘系统:用命令行工具实现主动回顾

构建个人复盘系统:用命令行工具实现主动回顾 前阵子整理年度计划的时候我翻出去年某次项目复盘留下的十几条随手记录突然意识到一件事大部分经验和教训其实都是在事情结束之后才真正看得清的。那个当下觉得“再熬一熬就好了”的关卡回头看往往有清晰的前兆那个当时觉得“稳了”的决定事后复盘却能找到明显的漏洞。人类天生就有一种“后见之明”的能力英语里叫 hindsight可惜这种能力大多数时候只是用来产生“我早就知道”的错觉而不是用来沉淀真实可用的经验。这篇文章想聊的就是我围绕 hindsight 这个词做的一件小事把“事后的智慧”从一种被动产生的心理偏差变成一个主动运行的复盘系统。我会从概念怎么落地为需求、需求怎么转化为一个小工具的设计再到具体的表结构、脚本、使用流程和踩坑记录完整分享整套方案。如果你经常觉得“复盘很重要但坚持不下去”或者你试过用 Notion、表格、备忘录记录总结却总是中途放弃这篇文章应该对你有用。1. 从“事后诸葛亮”到主动复盘hindsight 的真实价值1.1 后见之明偏差为什么靠不住心理学里有个概念叫 hindsight bias中文通常翻译为“后见之明偏差”。最经典的表现是当一件事情的结果已经摆在眼前时人们会倾向于认为这个结果“本来就很容易预测”。比如一个项目上线后出了事故回看日志会发现所有迹象都指向某个模块于是团队里弥漫着一种“当时怎么没人发现”的懊恼。但真相是在事故发生之前那些迹象淹没在几十个正常信号里优先级排列困难关注度分散。事后觉得明显是因为我们已经站在结果上往回看大脑自动把复杂的历史拉成了一条直线。这个偏差不是因为我们笨而是大脑的省力机制。把复杂历史压缩成“早该预料到”的简单叙事能降低认知负荷让我们感觉世界更有秩序、更可控。但它带来的代价很实在如果一切都“早就知道”那复盘就只剩自责和甩锅而真正的经验、决策依据、情绪状态都会被忽略。我见过不少团队写 post-mortem 文档结果变成“谁背锅”的审判书就是因为整个复盘过程被后见之明偏差主导大家不是在还原过程而是在证明自己“早就知道”。要对抗这个偏差最直接的办法是改变信息流的方向。普通人复盘是“先有结果再往回找原因”大脑会顺着结果去找能解释它的证据其他信息全被丢弃。主动复盘应该反过来先有连续、中立、低过滤的过程记录然后再回头看结果时这些记录能帮你抵抗“事后拉直线”的本能。换句话说你需要的不是一颗更聪明的大脑而是一个更忠实的记忆外挂。1.2 把“回顾”变成一个可持续流程我在做这个小项目之前试过很多复盘方式每周日晚写一篇周记、用表格记录关键决策、在日历里标注情绪波动。它们都有一个共同问题——太依赖意志力。一旦某天加班到十一点或者连续几天节奏混乱“补记录”这件事就会被无限期推后最后复盘变成了补作业补不出真实感受干脆放弃。后来我想明白一件事复盘不是“事后集中处理”而是“平时低成本捕获固定时间低成本回看”。平时需要做的只是在事情发生的当下用十秒钟记一行字、打一个标签、选一个情绪值而不是写小作文。回看则需要一个固定的仪式感比如每周日晚上打开终端跑一条命令就能看到本周发生的事件按标签聚合成一张清单再配上简单问题引导自己深入分析。这个思路并不高深本质上就是把“记忆”和“理解”切分成两个独立环节。记忆环节追求的是低摩擦、高保真理解环节追求的是结构化、可操作。很多复盘工具死掉都是因为把两个环节混在一起要求用户在现场就想清楚“这件事说明了什么”可现场往往没有足够信息和距离感说出来的全是直觉和情绪。hindsight 这个名字就是从这个角度取的。它不是让你事后才看的而是平时建立一个“未来的你回头看得见”的数据库。每一天记录的内容都是给未来的自己留的线索。说它是日记也好、事件日志也好、agent 的记忆库也好——本质都是同一件事给时间这条河流建立标记点。2. 工具形态与设计思路一个命令行复盘系统2.1 为什么不做 Web 应用而是命令行工具市面上个人信息管理工具很多Notion、Obsidian、各种日记 App功能都很强大。但我的需求比较特殊首先希望记录动作足够快打开手机备忘录要解锁、点开应用、等界面加载这三步在忙碌时会被大脑判定为“太麻烦”然后放弃。其次希望数据完全在我自己手里不依赖某个云服务的格式和存续状态。最后希望回看动作能自动化无论是终端命令还是脚本聚合都要比打开一个网页、翻找文件夹更直接。所以我决定做成一个命令行小工具核心交互只有三条命令hindsight add用于记录hindsight week用于生成本周清单hindsight review用于进入复盘问答流程。终端交互在很多人眼里不够友好但对我来说它足够快、足够透明、足够容易自动化。数据落在一个 JSONL 文件或者 SQLite 数据库里备份就是复制一个文件迁移就是把文件拷到新电脑。没有服务端没有账号体系没有厂商锁定。当然如果你不是重度终端用户也不用照搬这个形态。相同逻辑完全可以套在微信群里的机器人打卡、一个固定格式的日历事件、或者一份每天花三十秒填的在线表单里。UI 形态不重要重要的是底层流程是否满足“低摩擦记录”和“固定节奏回看”这两条铁律。2.2 事件模型与数据格式颗粒度怎么设计才不累设计记录格式时我踩过最大的坑是“想记的太多”。最早一版我设计了一堆字段项目、任务、关联目标、预期结果、实际结果、感受分析、行动项。听起来很完整实际上用了一个星期就崩了——每次记录都要想半天“这在项目 A 还是在任务 B 下”心理负担太重高频记录根本维持不了。后来重新设计只保留五个核心字段occurred_at事件发生的真实时间默认取当前时间title一句话描述主语加动作再加结果比如“完成注册模块联调”tags逗号分隔的标签用于后续聚合比如“项目X、技术、联调”note可选的补充信息限制自己写三行以内mood1 到 5 的数字标记事件发生时的大致情绪能量字段少到极致之后记录动作就变成了一种条件反射一句话、一两个标签、一个情绪值十秒内完成。颗粒度不是越小越好而是要让记录这个动作在低能量状态也能无痛执行。很多复盘系统死在“完整地记录”而不是“持续地记录”这是设计者容易忽略的点。用 JSONL 而不是 SQLite 做存储也是这个逻辑。JSONL 每一行就是一个事件追加就是往文件里写一行天然支持流式追加坏了也能从最后一行开始修肉眼可读grep 方便。虽然多了之后查询性能不如数据库但个人使用一年也就几千行完全没压力。数据文件路径可以放在~/hindsight/events.jsonl目录下再放一个meta.json存标签别名和复盘模板。2.3 用本地模型做可选摘要保留原始记录优先既然是 2024 年之后做这种工具很多人会条件反射地问“有没有 AI 功能”。我的答案是可以有但必须是配角。使用场景是这样每周回顾时系统先把原始事件按标签和时间线整理好然后你带着这些素材去问本地跑着的大语言模型“根据这些事件总结一下这周的主要变化、拖延点、以及下周建议”。模型的作用是帮你在素材上做文本结构化而不是替代你判断。这里有一个非常关键的安全准则绝不能让模型只给我一个总结而不给我原始记录。AI 的最大风险是平滑地去掉细节把所有事情变成“总体上不错”“有一些待改进的地方”这样的复盘完全失去意义。所以我的设计顺序永远是原始事件列表优先模型摘要只是额外修饰。而且我会用本地模型而不是云端 API这样事件数据——其中包含不少私人内容——始终不出本机。如果你在意隐私这个点值得认真考虑。关于模型选择我目前用的是 llama.cpp 跑一个参数量 7B 到 13B 的小模型量化之后在 M 系列芯片或者有 16G 内存的机器上跑得动。它做摘要和提炼完全够用距离感、幻觉都能控制在可接受范围。如果你的机器跑不动或者嫌麻烦完全可以跳过这一步直接看聚合出的周度清单效果也不差。3. 核心实现细节从零搭一个能跑的 hindsight3.1 环境准备与数据目录结构这个项目不需要重型依赖我用 Python 3.10 加上标准库就完成了大部分功能唯一的外部依赖是typer命令行参数解析和rich终端输出美化。数据库方面我用了 SQLite因为虽然存储用 JSONL但聚合查询时临时导入 SQLite 会很顺手而且 Python 内置了 sqlite3。准备环境的步骤很简单mkdir -p ~/hindsight python3 -m venv ~/hindsight/venv source ~/hindsight/venv/bin/activate pip install typer rich然后把项目脚本放在~/hindsight/hindsight.py。数据文件路径我建议直接用绝对路径避免不同目录下运行产生不同行为。目录里可以预先放一个空的events.jsonl文件以及一个config.json配置里记录默认标签、简单情绪词汇映射之类的内容。我习惯把这个工具的源码放在 Git 仓库里目录做成这样~/hindsight/ ├── hindsight.py ├── events.jsonl ├── config.json ├── backup/ └── weekly_review/backup/放定时任务做的压缩备份weekly_review/放每周生成的复盘快照。这样整个系统就是“一个脚本加一个数据文件”换电脑时拷走整个目录所有历史和配置都跟着走。3.2 记录接口add 命令与数据结构add命令是整个系统使用频率最高的入口设计原则是“参数越少越好”。我最终的调用方式有三种hindsight add 完成订单模块性能优化 --tags 项目X,后端 --mood 4 hindsight add 和设计师对齐新版交互稿 --tags 项目X,协作 hindsight add 跑了5公里 --tags 运动 --mood 5 --note 配速比上周快了20秒如果--tags和--mood没填就从config.json里读默认值保证命令永远可以跑通。occurred_at默认取当前时间也可以加--at 2024-06-01 09:30回填忘记记录的事件。底层实现很简单就是读 JSONL 文件、追加一行、再回写import json from pathlib import Path from datetime import datetime EVENTS_PATH Path.home() / hindsight / events.jsonl def add_event(title, tagsNone, noteNone, moodNone, occurred_atNone): event { occurred_at: occurred_at or datetime.now().isoformat(timespecminutes), title: title.strip(), tags: tags if tags else [], note: note, mood: mood, } with open(EVENTS_PATH, a, encodingutf-8) as f: f.write(json.dumps(event, ensure_asciiFalse) \n)这里有一个容易被忽略的细节occurred_at用datetime.now().isoformat(timespecminutes)其实只精确到分钟。对于复盘用途分钟级足够如果精确到秒反而会让时间线显得杂乱。另外注意写入时用追加模式永远不要在内存里读全文件再写回那样数据量大了之后每次都会 O(n) 读加 O(n) 写早晚卡顿。还有一个细节标题里不要带标点符号或者引号。JSONL 本身对转义有要求虽然 json 库会处理好但为了肉眼可读、grep 方便标题保持纯文本最舒服。刚上手的人容易把title写得跟朋友圈文案一样长这会破坏后续聚合时的可读性所以我会在交互层面限制长度超过 30 个字符就提示精简。对于没有终端的日常用户也可以做成一个简单的快捷指令或者用 iOS 的“快捷指令”App 发 POST 请求到本机一个轻量 HTTP 端点动作更快。3.3 聚合查询weekly review 的生成逻辑光能记录不够回看才是核心。每周日晚我会跑一条hindsight week命令它做的事情是读 JSONL 文件里最近 7 天的事件按标签聚合成一个清单输出到终端。为了让输出更直观我把数据导入 SQLite用一条查询搞定聚合CREATE TABLE events ( occurred_at TEXT, title TEXT, tags TEXT, note TEXT, mood INTEGER, created_at TEXT ); SELECT date(occurred_at) as day, group_concat(tags, , ) as related_tags, count(*) as cnt, printf(%.1f, avg(mood)) as avg_mood FROM events WHERE occurred_at ? GROUP BY date(occurred_at) ORDER BY day DESC;这条查询的意图是让我一眼看到“这周哪几天发生了什么、情绪能量分布如何、哪类标签出现得最多”。注意我用了group_concat(tags, , )而不是直接 group by tags因为一个事件可能属于多个标签先按天聚合标签串在一起显示信息的可读性比严格分类高得多。真正执行时我并不会每次手动建库而是在week命令里动态创建临时数据库、导入数据、查询、展示用完即弃。因为数据量小整个过程用不了半秒。这样做的优势是“查询永远是可重复的”不会因为某个临时表没清理而影响下一次结果。生成的结果大致长这样2025-06-15 周日 [项目X] 完成模块联调 (mood: 4) [协作] 和设计师对齐新版交互稿 (mood: 3) [运动] 跑了5公里 (mood: 5) ...共 12 条事件avg_mood: 3.8这个输出其实已经能承担“周度复盘”的主要职责了你看到自己这周在哪个项目上花的时间多、情绪能量如何变化、是否保持了运动、哪些日子是空白的。空白本身就是信息很多时候周末复盘发现周一到周三以后没有记录就说明那几天忙到连十秒都没抽出来这本身就是压力信号。3.4 复盘向导带着问题看记录week给的是素材review给的是结构。我设计了一个固定五问的复盘流程一条一条在终端里展示本周最重要的三件事是什么它们的结果是否和你的预期一致本周让你情绪波动最大的一件事是什么当时的判断依赖了什么假设事情的发展和你当时的判断相比有哪些出入是否有反复出现的同类问题如果有它们共同的触发条件是什么下周准备在哪一个环节上做出一个最小改变我会把每一条问题的回答追加到weekly_review/2025-W25.md里保留每周的历史。这个五问模板不是拍脑袋想出来的它对应了复盘的四个层次事实层事件、感受层情绪、判断层预期与结果差异、行动层下一步。对一个刚开始做复盘的人来说这五个问题不要去求全能答出两条就已经赢了。复盘的产出不是“深刻的结论”而是“可观察的差异”——实际发生的事与当初想法的偏差。只要你坚持几周就能在记录里看到一些端倪某些标签反复出现但从未有后续动作某些情绪低点总是在同类型会议之后。这些才是值得改进的真实线索。4. 实操过程完整跑一遍从记录到周复盘4.1 初始化与第一次习惯养成第一次使用我的建议是不要急着把工具部署完整先用手动方式跑一周。我做的第一件事是写了一个假的示例事件跑通add、week、review三条命令确认输出正常。然后给自己设了三条规则每天至少记录 1 条事件最多 5 条不贪多每条事件必须在发生后的 30 分钟内记录否则放弃记录绝不补录每周日晚上固定 20 分钟跑week和review“绝不补录”这条规则是我从失败经验里总结出来的。补录的问题在于记忆会骗人滞后记录会加一层美化事件发生时是愤怒的晚上补记可能变成“有点不满”事件发生时只有隐约不安第二天补记可能彻底忘了。复盘系统最值钱的是真实而真实只能靠及时记录来保证。4.2 第 25 周的完整复盘实录为了让你对整个过程有直观感觉这里放一个真实跑过的周复盘简化版。那一周我同时推进两个项目加上日常琐事一共记了 17 条事件。week命令输出的摘要里我注意到两个现象一是项目B相关的标签出现频率异常高但情绪均值只有 2.8二是周一、周三完全没有记录。按照五问模板我对着明细一条一条看发现项目B高频率出现是因为那周我在反复处理同一类接口联调问题每次都记了“联调失败、定位中”。情绪均值低自然跟联调卡壳有关但更深一层是我没有在第一天联调失败时就把阻塞原因升级反馈给负责人而是自己闷头试试了两天才反馈。这就导致整个事情比预想多花了一倍的时间。这个发现不是靠聪明想到的是靠记录里的重复模式逼出来的。如果只是周末凭记忆回想我大概率只会记得“项目B挺麻烦”而不会注意到“第一天之后没有升级阻塞”这个具体判断失误。复盘的产出从来不在“总结”本身而在“看到重复模式然后改变行为”。4.3 输出归档与推进 AI 摘要复盘完毕后生成的 markdown 文件我会存到weekly_review/2025-W25.md并在文件底部追加一个“下周最小改变”区比如那一周写的是“联调阻塞超过 4 小时必须发消息升级不等下班”。下一周的复盘会先打开上一周的文件对照检查“最小改变”是否真的执行了。如果你配置了本地模型可以在review命令结束后追加一个--summarize参数它会把你本周的原始事件列表发给本地模型生成一小段结构化摘要然后追加到 markdown 文件里。注意我在实现时会把提示词写得很克制以下是我本周的事件记录请按“主要事项”“阻塞与消耗”“情绪曲线”“下周建议”四个小节输出。 不要遗漏任何原始事件不要添加事件之外的猜测。加“不要添加事件之外的猜测”这句提示词是因为我发现大多数模型默认会脑补事件的背景和动机而那些脑补对于复盘是毒药。模型的作用是整理语言不是替你分析动机。5. 常见问题与排查技巧实录5.1 记录坚持不下去怎么办这是复盘系统最大的敌人比任何技术问题都致命。我的经验是如果连续三天没有记录不要想着补也不要自责而是降低记录标准。标准降到自己都觉得“这也算事件吗”的程度比如“吃了顿好的”“午休出去走了一圈”都可以记。跑通这个低标准循环两三天手感回来了再恢复正常标准。根本原因是人的行为需要即时反馈而复盘系统的反馈周期天然是周级这太漫长了。为了缓解我在add命令后面加了一个“连击数”每次添加事件时终端会显示“本周已连续记录 N 天”类似于 GitHub 的绿格子。这个小东西看起来弱智实际对习惯养成帮助非常大我建议你也做类似机制。5.2 聚合展示时标签混乱怎么办用久了你会发现同一类事件标签写法五花八门有时写“项目X”有时写“项目x”有时写“项目X/后端”。这会让group_concat出来的清单很难看。我解决的办法是在add命令里加一个轻量级的标签提示读取config.json里的已有标签当用户输入的标签无法模糊匹配时提示“是否要新增标签”。同时每周复盘时会列出“本周新增标签”清单合并格式不统一的项。这个操作治标不治本但个人使用足够了。如果你有强迫症也可以在导入 SQLite 时做一层别名映射把“项目x”统一替换成“项目X”。5.3 时区与时间戳的坑datetime.now().isoformat()默认返回本地时间不带时区信息。这在单机使用没有问题但如果你把数据文件同步到其他设备或者导入云服务就会出现时间错乱。我用了一个保守策略所有事件都存成带时区偏移的 ISO 8601 字符串即datetime.now().astimezone().isoformat()。这样不管文件在哪里被解析时间含义都是明确的。坑在于 Python 的 SQLite 查询默认对带时区偏移的文本字符串按字典序排序效果上依然等价于时间排序所以查询逻辑不用改。但如果你需要跨时区汇总“按天聚合”要注意先把时间统一到某个时区再转日期否则某天的事件会切到错误的日期分组。这块调试起来很隐蔽我第一次写week命令时就在跨时区场景翻了车。5.4 隐私、备份与文件损坏恢复数据文件里的内容非常私人我强烈建议至少做三件基础保护目录权限设为700数据库文件不放进任何同步盘备份时使用带 gpg 对称加密的压缩包。备份频率可以靠 cron 或者 launchd 做每日一次保留最近 30 天的滚动备份。0 2 * * * cd ~/hindsight tar czf backup/hindsight-$(date \%Y\%m\%d).tgz events.jsonl config.json weekly_review/JSONL 文件如果因为断电等原因出现半行写入读的时候会报错。我的处理方式是写一个很短的修复函数逐行读取如果某一行无法解析成 JSON直接丢掉并输出一条“可能丢了一行数据”的警告。这个丢行代价可以接受毕竟只是损失一次记录总比整个文件打不开好。5.5 周复盘变成了流水账没有深度怎么办发现自己每周复盘都写成“做了A、做了B、下周做C”而且持续好几周说明这时候工具层面的问题已经解决但思考层面的深度还没打开。我的方法是在原来五问模板基础上每周加一个“挑战性对比”拿出上周写的“最小改变”问自己“当时为什么觉得这个改变有效现在的证据支持吗”另一种提高深度的办法是给每个事件打上第二层元标签除了“项目X”“运动”这些时间与内容标签再加一个“预期/实际/意外”的分类。比如事件记的是“完成联调”元标签选“实际结果”如果事件是“预估需要两天”元标签选“预期”。这样每周复盘就能看到“预期 vs 实际”的时间分布通常你会发现预估持续偏乐观或者偏悲观而这个发现本身就是深度。写在结尾的一点个人体会这个名叫 hindsight 的小工具运行了大半年给我最大的变化不是“更会写总结”了而是我更敢面对真实数据了。以前我复盘全靠记忆而记忆会自动美化、简化、扣掉那些不舒服的细节。现在打开终端跑一条命令上周的状态赤裸裸摆在眼前忙乱时标签很散乱、情绪均值低、某几天是空白——这些其实都是我“事后诸葛”时根本不想承认的部分但正视它们之后反而更容易找到真正的行动点。如果你也想做一套自己的 hindsight我不建议照抄我的代码更建议抄我的设计原则记录要快要轻、回看要定期要固定、AI 只能做整理不能做判断、隐私第一。从一套最简单的方案开始跑哪怕只有一条命令、一个文本文件先跑一年再说。技术上不值得追求复杂真正值钱的是那个每周都能稳定执行的回顾仪式。
RELATED READING

延伸阅读

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