Smart Reminder — 智能提醒助手
> "说过的事,AI帮你记住。"
概述
智能提醒助手是一个完全被动的后台技能。你随口说一句"明天提醒我给李总打电话",AI会记住,下次对话时自动提醒你。
核心价值:
- 被动记录:不需要打开任何App,不需要填表单,随口说就行
- 自动触发:下次打开AI对话,提醒自动出现在开场白里
- 完全无感:记录时不弹提示,不要求确认
- 纯本地存储:所有提醒数据存在本地,不上传任何地方
- 代码兜底:核心操作由reminder_engine.py强制执行,不依赖AI理解
技术架构
采用"AI策略层 + 代码执行层"双层架构:
| 层级 | 职责 | 文件 |
|---|---|---|
| AI策略层 | 判断时机、解析用户意图、决定何时提醒 | SKILL.md |
| 代码执行层 | 实际读写JSON、时间计算、异常处理 | reminder_engine.py |
AI绝不直接操作文件系统,所有文件操作必须通过reminder_engine.py执行。
reminder_engine.py 命令清单
# 检测用户输入中是否含提醒请求
python reminder_engine.py detect "用户输入文本"
→ 返回: {"has_reminder": true/false, "reminders": [{"time": "...", "action": "..."}]}
# 写入新提醒
python reminder_engine.py add "时间描述" "提醒内容"
→ 返回: {"success": true/false, "id": "..."}
# 检查是否有到期提醒(每次对话开始时调用)
python reminder_engine.py check
→ 返回: {"due": [{"id": "...", "time": "...", "action": "...", "created_at": "..."}]}
# 标记提醒已处理(提醒触发后调用)
python reminder_engine.py done "提醒ID"
→ 返回: {"success": true/false}
# 列出所有待处理提醒
python reminder_engine.py list
→ 返回: {"pending": [{...}]}
# 删除提醒
python reminder_engine.py remove "提醒ID"
→ 返回: {"success": true/false}
触发条件
被动触发(每次对话自动运行)
本技能在每次对话开始时自动激活,执行以下操作:
对话开始
↓
执行: python reminder_engine.py check
↓
如果有到期提醒(due数组非空):
在首次回复中自然带出提醒
(格式见"提醒呈现规范")
↓
用户确认已处理:
执行: python reminder_engine.py done "提醒ID"
提醒记录触发(对话进行中自动检测)
用户说话中(任何一轮)
↓
执行: python reminder_engine.py detect "用户本轮输入"
↓
如果返回 has_reminder = true:
静默提取时间和内容
执行: python reminder_engine.py add "时间" "内容"
(不向用户报告,完全无感)
主动触发(用户明确询问)
- "我有哪些提醒?"
- "提醒列表"
- "待办事项"
- "删除提醒[XXX]"
工作流程
第一步:对话开始检查(自动执行)
AI行为:
1. 对话开始后,第一时间执行 python reminder_engine.py check
2. 如果返回 {"due": []}(空数组)→ 正常开始对话,不做任何提醒操作
3. 如果返回 {"due": [...]}(非空) → 进入第二步
异常处理:
- reminder_engine.py返回错误 → 静默跳过,正常开始对话
- JSON解析失败 → 视为无到期提醒,正常开始对话
- 时间计算异常 → 跳过该条提醒,继续检查下一条
第二步:自然呈现提醒
核心原则:提醒要"自然地带出来",不能像系统通知。
格式规范(严格按此执行):
正确格式(自然融入):
"你,今天要给李总打电话,别忘了。
织金项目3.2节改得怎么样了?"
错误格式(系统通知感):
"【提醒】您有一条待办事项:给李总打电话
【时间】2026-05-25
【内容】给李总打电话"
多条提醒的处理:
- 1条 → 直接带出,1句话
- 2-3条 → 用"还有"连接,不超过2句话
- 4条以上 → 只说最紧急的2条,加一句"还有其他几件事,慢慢来"
时间表述规范:
| 原始时间 | 呈现表述 |
|---------|---------|
| 今天 | "今天" |
| 明天 | "明天" |
| 2026-05-27 | "5月27号" |
| 下周一 | "下周一" |
| 3天后 | "再过3天" |
第三步:记录新提醒(对话进行中自动检测)
检测触发条件(全部满足):
1. 用户输入含时间词(今天/明天/后天/X天后/下周X/X月X号)
2. + 动作词(提醒/记得/别忘了/通知我/到时候说一声)
3. 或含明确的待办语义("要去XXX"、"得XXX"、"需要XXX")
AI行为:
1. 执行 python reminder_engine.py detect "本轮用户输入"
2. 如果 has_reminder = true → 提取第一条reminder的time和action
3. 执行 python reminder_engine.py add "time" "action"
4. 不向用户报告"已记录提醒"(完全无感)
提取规则:
用户输入:"明天提醒我给李总打电话"
→ time: "明天"
→ action: "给李总打电话"
→ 执行: python reminder_engine.py add "明天" "给李总打电话"
→ AI回复中完全不提"已记录提醒"(装作不知道)
同一轮输入含多个提醒:
- 最多提取2个,取最明确的两个
- 分别执行add命令
第四步:提醒后处理
用户确认已处理(显式或隐式):
显式确认:
- "好的,打完了"
- "搞定了"
- "已经处理了"
隐式确认:
- 用户开始聊其他话题,且距离提醒触发已超过10分钟
AI行为:
1. 执行 python reminder_engine.py done "提醒ID"
2. 如果成功 → 不回复确认信息,直接继续对话
3. 如果失败 → 静默跳过,不影响对话
用户要求删除提醒:
1. 执行 python reminder_engine.py list 获取所有pending
2. 匹配用户描述的提醒内容
3. 执行 python reminder_engine.py remove "提醒ID"
数据存储结构
~/.workbuddy/smart-reminder/
├── pending.json ← 待触发提醒列表(reminder_engine.py管理)
└── history.json ← 已触发提醒历史(reminder_engine.py管理)
pending.json 格式:
[
{
"id": "rem_20260524_103000_001",
"time_raw": "明天",
"time_parsed": "2026-05-25",
"action": "给李总打电话",
"created_at": "2026-05-24T10:30:00",
"status": "pending"
}
]
history.json 格式:
[
{
"id": "rem_20260523_090000_001",
"time_raw": "今天",
"time_parsed": "2026-05-23",
"action": "发邮件给张总",
"created_at": "2026-05-23T09:00:00",
"triggered_at": "2026-05-23T10:15:00",
"status": "done"
}
]
时间解析规范
reminder_engine.py负责时间解析,AI不需要自己解析时间,只需要把用户原话传给引擎。
支持的时间表达:
| 用户输入 | time_raw | time_parsed(引擎计算) |
|---------|----------|----------------------|
| 今天 | 今天 | 当天日期 |
| 明天 | 明天 | 当天+1天 |
| 后天 | 后天 | 当天+2天 |
| 3天后 | 3天后 | 当天+3天 |
| 下周一本 | 下周一 | 下一个周一的日期 |
| X月X号 | X月X号 | 对应日期(当年) |
| 2026-05-27 | 2026-05-27 | 2026-05-27 |
时间解析失败的处理:
- reminder_engine.py返回 time_parsed: null
- AI在呈现提醒时,直接使用 time_raw 原文
- 例如:无法解析"下周找个时间",呈现为"你,你说下周找个时间XX,别忘了"
异常处理规范
reminder_engine.py 级异常
| 异常类型 | 处理方式 | 用户感知 |
|---|---|---|
| 文件不存在 | 自动创建空JSON文件 | 无 |
| JSON解析失败 | 返回空数组/空对象 | 无 |
| 目录权限不足 | 尝试创建目录,失败则静默跳过 | 无 |
| 时间解析失败 | time_parsed返回null,用time_raw | 无(用原文呈现) |
| 提醒ID不存在 | 返回false,不报错 | 无 |
| 编码问题 | 统一使用utf-8,失败则静默跳过 | 无 |
AI策略层异常
| 异常类型 | 处理方式 |
|---|---|
| reminder_engine.py执行失败 | 静默跳过,正常开始对话 |
| 返回的due为空或无效 | 不呈现提醒,正常对话 |
| 检测到的提醒内容模糊 | 仍然记录,用模糊内容呈现 |
| 同一天有多条提醒 | 按创建时间排序,最早创建的先提醒 |
注意事项
DO
- 每次对话开始时自动执行
python reminder_engine.py check - 使用reminder_engine.py执行所有文件操作,不直接读写JSON
- 提醒呈现要自然,融入第一句回复,不超过2句话
- 记录新提醒后不向用户报告,完全无感
- 提醒触发后,用户确认处理,执行
python reminder_engine.py done - 多条提醒时,优先呈现最紧急/最早的
- 时间表述用口语("今天"、"明天"),不用ISO日期
DON'T
- 不要直接读写pending.json或history.json(必须通过reminder_engine.py)
- 不要逐字复述提醒内容(要自然融入对话)
- 不要向用户报告"已记录提醒"、"已保存"(完全无感)
- 不要用系统通知的语气呈现提醒("【提醒】XXX")
- 不要在一次回复中呈现超过3条提醒
- 不要存储敏感信息(密码、身份证号、银行账号等)
- 不要跨用户共享提醒数据(每个用户独立存储)
快速开始示例
场景1:随口说一句,AI记住了
用户:明天提醒我给李总打电话
AI:(静默执行 detect + add,不回复"已记录")
"收到,织金项目3.2节今天继续?"
[第二天,用户打开新对话]
用户:早
AI:(执行 check,发现到期提醒)
"你,今天要给李总打电话,别忘了。
织金项目昨天改到哪了?"
场景2:查询提醒列表
用户:我有哪些提醒?
AI:(执行 list)
"目前有2条待办:
1. 今天:给李总打电话
2. 后天:提交织金项目3.2节修改版"
场景3:完成提醒后
AI:"你,今天要给李总打电话,别忘了。"
用户:"打完了"
AI:(静默执行 done)
"好嘞。织金项目3.2节改得怎么样了?"
版本说明
V1.0.0 — 基础版
- 被动检测提醒请求
- 自动记录并在下次对话触发
- 完全无感运行
- 代码兜底(reminder_engine.py)