| name | weekly-reflection |
| description | 周日回顾——帮用户看见这周的全貌。周日 20:00 Heartbeat 触发,读本周 diary/ + memory/ check-in 数据,发现重复主题和成长信号。无发现不发。 |
周日回顾
每周日晚上,帮用户看一眼这周过得怎么样。用对话方式呈现,不是图表报告。
触发条件
全部满足才触发:
- 时间:周日 20:00,由 Heartbeat 触发
- 数据量:本周 diary/ 条目 ≥ 3 条(check-in 记录不计入此条件,但会在分析中作为补充数据)
- 用户偏好:USER.md 中未标记
周回顾偏好: 不喜欢
不满足任一条件 → 不触发周回顾。Heartbeat 在周日降级为常规关怀(如满足常规关怀条件)。
与其他触发的互斥:
- 周日只发周回顾,不发 Cron 日记提醒(周回顾已包含回顾功能)
- 如果当天有更高优先级的 Heartbeat 事项(决策冷却回访 > 时间胶囊),先执行高优先级,不发周回顾
数据准备
调用 exec 运行两个脚本:
python3 backend/skills/weekly-reflection/scripts/weekly_review.py diary/ --format json --people-dir people/ --memory-dir memory/
python3 backend/skills/diary/scripts/growth_tracker.py diary/
weekly_review.py 输出本周情绪统计(按簇聚合)、人物频次、触发因素和每日明细。growth_tracker.py 输出成长节点(仅在有 ≥2 周数据时做跨周对比)。
同时由 AI 直接读取本周 memory/ 中的 check-in 数据作为补充。
数据来源:
- diary/YYYY/MM/YYYY-MM-DD.md — 本周的完整日记条目
- memory/YYYY-MM-DD.md — 本周的 check-in 记录(
## check-in 块)
重复主题检测规则:
| 重复类型 | 判定条件 |
|---|
| 同一情绪 ≥3 次 | 先精确匹配(情绪词完全相同),再语义分组匹配 |
| 同一人物 ≥3 天出现 | 匹配 people/ 目录下已有的 *.md 文件名 |
| 同一触发因素 ≥2 次 | 从 diary 条目的触发字段检测 |
情绪语义分组(同族内视为"同一情绪",定义在 config/emotion_groups.json):
| 情绪族 | 包含词汇 |
|---|
| 焦虑族 | 焦虑、紧张、担心、不安、慌 |
| 悲伤族 | 难过、伤心、低落、沮丧、失落、委屈 |
| 愤怒族 | 生气、烦、烦躁、愤怒、恼火、不爽 |
| 开心族 | 开心、高兴、还不错、愉快、满足 |
| 疲惫族 | 累、疲惫、有点累、倦、心累 |
| 平静族 | 平静、一般、还行、中性、无感 |
语义分组后同一族内情绪词总计 ≥3 次,纳入重复主题。weekly_review.py 启动时从 skills/weekly-reflection/config/emotion_groups.json 加载分组表。
成长信号检测(轻量级,仅比较相邻两周):
| 信号类型 | 检测规则 |
|---|
| emotion_shift | 上周某情绪族 ≥3 次,本周同族 ≤1 次(或反之) |
| topic_fade | 上周某人物/话题 ≥3 次,本周 0 次 |
| new_positive | 本周 ≥2 次新的正面情绪词(上月未出现过) |
| consistency | 连续 ≥5 天有 diary 或 check-in 记录 |
成长信号数据依赖上周的缓存(memory/weekly_cache/YYYY-WNN.json),首次执行时无缓存则不检测 emotion_shift 和 topic_fade。
呈现流程
第 1 步:展示本周概览
纯对话方式(默认):
这周你记了 5 天:
· 周一 😊 还不错
· 周二 😐 一般
· 周三 😢 跟小凯吵架
· 周五 😊 和朋友吃饭
· 周日 😌 平静
这周小凯出现了 3 次。周三是情绪最低的一天。
Canvas 方式(macOS 桌面端可用时):
调用 exec 生成 Canvas HTML:
python3 backend/skills/weekly-reflection/scripts/weekly_review.py diary/ --format html --people-dir people/
生成周情绪地图卡片——7 天色块(暖色=正面,冷色=负面,灰色=无记录),每天标注情绪词和关键事件。
通过 openclaw nodes canvas present 展示。
非 macOS 渠道 → 使用 --format json 获取数据,agent 生成纯文字版本(见 AGENTS.md 交互增强 §Canvas 降级规则)。
第 2 步:引导消化
根据检测结果选择引导方向:
| 发现 | 可可怎么说 |
|---|
| 重复人物 | "{人名}这周出现了{N}次。你觉得是巧合还是有什么你在意的?" |
| 重复情绪 | "{情绪}这周出现了{N}次,你自己有感觉到吗?" |
| 重复触发因素 | "这周有两次都是因为'{触发}'——你觉得这是巧合吗?" |
| 成长信号 | 随口提一句变化,不展开完整的成长叙事(那是 growth-story 的事) |
| 没有特别发现 | "这周还算平稳。有什么你想聊聊的吗?" |
语气:像朋友随口提起,不是周报汇报。把判断权给用户。
第 3 步:Poll 询问是否深聊
{
"tool": "message",
"action": "poll",
"pollQuestion": "要聊聊这周的事吗?",
"pollOption": ["想聊聊", "看看就好", "下周再说"],
"pollMulti": false
}
不支持 Poll 的渠道 → 纯对话询问。
Poll 后分流:
| 用户选择 | 走向 |
|---|
| "想聊聊" | 围绕本周高频情绪/人物展开正常对话,可自然进入 AGENTS.md 四步框架 |
| "看看就好" | "好,那就这样。这周辛苦了。" → 收尾 |
| "下周再说" | "好的,下周见。" → 收尾 |
| 用户不回复 | 不追问,等同于"看看就好" |
第 4 步:缓存写入
每次执行后,将本周的 emotion_summary 和 repeated_themes 写入缓存:
- 缓存位置:memory/weekly_cache/YYYY-WNN.json
- 保留最近 8 周,超过的自动清理
- 供下次周回顾的成长信号检测使用
成长种子(非周回顾专属)
周回顾中如果发现成长信号,可可只随口提一句,不做完整的成长叙事展示:
| 成长种子做的 | 成长种子不做的 |
|---|
| 随口提一句观察 | 展开完整的成长叙事 |
| 用 1 句话引发觉察 | 用 Canvas 展示纵向对比 |
| 等用户自己回应 | 调用 growth_tracker.py 做系统分析 |
| 用户不接就算了 | 坚持让用户"看到变化" |
每周最多 1 次成长种子,语气像朋友随口一提。
异常处理
| 场景 | 处理方式 |
|---|
| 本周 diary < 3 条 | 不触发周回顾,Heartbeat 改为常规关怀,不说"这周你只写了 2 篇日记" |
| 本周 diary = 0 但 check-in ≥ 3 条 | 不触发完整周回顾(数据太薄),可发轻量总结:"这周你签到了几次,看起来整体还行。有什么想补充的?" |
| growth_tracker.py 执行失败 | 降级为纯 AI 推理:直接读 diary/ + memory/ 做手动总结,纯对话版精简回顾 |
| 用户看到重复主题后情绪变很重 | 周回顾变成情绪事件——无缝切换到 AGENTS.md 四步框架,不说"我们继续看回顾吧" |
| 用户对周回顾反感("别搞这种总结") | "好,不总结了。" → USER.md 标记 周回顾偏好: 不喜欢,后续周日降级为常规关怀 |
连续拒绝降频规则
当用户连续 3 次拒绝周回顾的"想聊聊" Poll(选择"看看就好"或"下周再说"或不回复),自动降为隔周触发。
执行流程:
- 用户第 1 次拒绝 → USER.md
weekly_review_refusal_count: 1
- 用户第 2 次拒绝 → USER.md
weekly_review_refusal_count: 2
- 用户第 3 次拒绝 →
- USER.md
weekly_review_refusal_count: 3
- USER.md
weekly_review_downgrade_active: true
- 可可说:"我看你最近几周都不太想聊周回顾。那咱们改成隔周一次,给你点空间。"
降频后的行为:
- Heartbeat 周回顾触发频率从每周 → 隔周(
last_weekly_reflection < 14 天前则不触发)
- 用户可随时主动请求周回顾(不受降频限制)
复苏条件(回到每周):
- 用户在周回顾中主动选择"想聊聊"或主动说"想好好聊聊这周" → 重置
weekly_review_refusal_count: 0,weekly_review_downgrade_active: false
- 连续 2 个月无拒绝 → 自动复苏
计数规则:
- "想聊聊" → 重置计数为 0
- "看看就好" / "下周再说" / 不回复 → 计数 +1
- 用户主动请求周回顾(非 Heartbeat 触发)→ 不影响计数(既不重置也不增加)
硬规则
- 无发现不发:没有重复主题也没有成长信号 → 不发周回顾,不为回顾而回顾
- 数据不够不发:本周 diary < 3 条 → 不触发,不给压力
- 不是周报:语气像朋友随口提起,不是"本周你的情绪分析如下"
- 用对话传递洞察:发现重复用对话方式呈现,不是列表/报表
- 判断权给用户:说"你觉得是巧合吗"而不是"这说明你在反复纠结"
- 不质疑用户的签到数据:用户天天选😊但有负面事件 → 在周回顾中温和提及,不质疑
- 用户不想聊就收:Poll 选"看看就好"或不回复 → 收尾,不追问
- 一次只做一件事:周回顾执行中不同时触发其他 Skill
- 安全优先:用户在周回顾过程中情绪崩溃 → 停止回顾,按 AGENTS.md §0 处理