待办应用如何理解“明天上午 9 点”
简要游览一遍自然语言日期解析、它背后的正则技巧,以及为什么设备端 AI 正在改变什么是可能的。
在一个好的待办应用里输入“明天上午 9 点给 Sam 发邮件”,应该会发生两件事之一。要么你得到的任务是一个干净的对象,标题为“给 Sam 发邮件”,截止日期设为次日上午 9:00;要么应用什么都不做,你得去填一个日期选择器。这两种结果之间的差别,正是决定你究竟会不会真的去用这个应用的东西。
自然语言日期解析已经存在了几十年。它驱动过 Quicksilver。它驱动过 Fantastical。如今它几乎驱动着每一款值得发布的效率应用。但它在底层的工作方式,在过去这两三年里以有趣的方式发生了变化,结果是 2026 年成了头一个年份——在大多数应用里,这项技术对英语来说真正得到了解决,并开始在其他语言里运作良好。
这篇文章就来游览一遍它如何工作。
问题的基本形态
用户输入一个句子。应用需要:
- 判断这个句子里到底有没有日期。
- 如果有,找出文本中哪一段指代了日期。
- 把那一段解析为一个绝对的日期和时间。
- 从句子里移除那一段日期,好让剩下的文本就是任务标题。
这每一步都有自己的失败模式。大多数早期实现在第一步上很脆弱,产生误报。“去取那 15 份报告”不应该得到一个本月 15 号的截止日期。“买 3 个苹果”不应该被解读成某种关于三的什么东西。“在 IBM 给 Sam 发邮件”大概不是把时间钉在“在 I.B.M.”上。
经典的策略是正则表达式。它们在这件事上出奇地好。一小撮精心写就的模式就能识别出人们实际输入到待办应用里的日期短语中的 90% 以上:
\bin\s+(a|an|\d+|some|several)\s+(min|minute|minutes|hour|hours|hr|hrs|day|days|week|weeks|month|months)\b\b\d{1,2}(:\d{2})?\s*(am|pm)\b\b(tomorrow|today|tonight|noon|midnight)\b\b(monday|tuesday|wednesday|thursday|friday|saturday|sunday)\b
把十五或二十个这样的模式组合起来,你就覆盖了长尾。然后你把这些匹配拼接起来:一个表示天的词加上一个表示时间的词,就成了一个具体的时刻。一个没有限定词的星期名意味着“那个星期几的下一次出现”。一个没有天的、单独的时间词意味着今天。
正则在哪里失灵
正则在三类输入面前撞墙:
- 含糊的短语。 “下周某个时候”是一个日期,但不是一个具体的。
- 歧义。 “周五下午”可能是下午 2 点也可能是下午 4 点,取决于习惯。
- 拼写错误和俚语。 “tmrw at 9p”一个人能解析,但一个严格的正则若没有大量的变体就不行。
很长一段时间里,待办应用对这些只是耸耸肩。如果你输入“tmrw at 9p”,你什么都得不到。如果你输入“明天一早第一件事”,你什么都得不到。用户学会了去输入正式的版本。
过去这一年里有趣的进展是,设备端语言模型如今能处理这些情况,而无需通过网络发送任何东西。自 macOS 26 起可用的 Apple Foundation Models 框架,附带了一个在本地运行的模型,它快到足以在正则失手时用作后备。Google 在 Android 上有类似的产品。由此产生的模式看起来是这样的:
快速通路覆盖了 90% 的情况。模型处理其余的。两个阶段都不会通过网络发送用户的文本。隐私和速度都得到了保全。
为什么“2 小时后”比看上去更难
“2 小时后”这个短语看上去很简单。它不简单。
用户可能指的是以下任何一种:
- 从现在起 2 小时,精确到分钟。
- 从现在起 2 小时,为了干净四舍五入到最近的 15 分钟。
- 从现在起 2 小时,但如果那落在用户标记的睡眠时段里,就改到第二天早上。
- 从下一个整点起 2 小时(在下午 1:55 说的“2 小时后”可能意味着下午 4:00,而不是 3:55)。
大多数应用做一个选择并坚持它。最常见的是“从现在起 2 小时,精确到分钟”,它用优雅换取了可预测性。一个在下午 1:23 输入“2 小时后”的用户,会在下午 3:23 收到一个通知。他们学会了在想要干净时间时输入整数。
为什么“明天”默认是上午 9 点
当你输入没有时间的“明天”时,应用得挑一个时间。市面上几乎每一个应用,这个习惯都收敛到了上午 9:00。为什么?
因为猜错的代价是不对称的。如果应用挑了上午 9 点而你想要的是上午 11 点,你在注意到时能很快调整。如果应用挑了午夜或随便某个别的钟点,你会在睡着时收到通知,或者干脆错过它。对几乎每一种工作任务来说,上午 9 点都是那个安全的默认值。
少数应用默认为上午 8 点。少数应用使用你输入这个任务时的当天时间(“你在下午 2 点说的,所以你大概是指明天下午 2 点”)。后者很聪明但不可靠,因为大多数在下午 2 点输入一个任务的人,是在工作日的过程中这么做的,针对的是他们想在未来某个工作日去做的任务,而不是恰好次日下午 2 点。
这在 TodoBar 内部是什么样子
TodoBar 使用上面描述的两阶段模式。输入任何带时间短语的任务,正则层会率先开火,用时不到一毫秒。如果它找到一个日期,任务就会带着正确的截止时间出现在你的清单里。如果正则层无法解析这个短语,设备端的 Foundation Models 分类器就会上场一试,典型延迟在 50 毫秒左右。无论哪种方式,都没有文本离开你的 Mac。
正则层识别的那些模式记录在支持页面里。作为快速参考,以下这些全都管用:
- “in 30 minutes”
- “in 2 hours”
- “in a couple hours”
- “tomorrow”
- “tomorrow at 9am”
- “tonight”
- “tonight at 8”
- “next Friday”
- “Friday at 5pm”
- “May 12”
- “May 12 at 2pm”
- “the 15th”
- “in 3 days”
- “1 week from now”
- “first thing tomorrow”
如果你输入的是解析器无法处理的东西,任务仍然会被添加进来,只是没有截止日期,你可以从那一行的铃铛按钮手动附上一个。解析器的失败模式是“没有附上日期”,而不是“任务丢失”。
这一切将走向何方
下一个有趣的前沿是多语言解析。像“mañana a las 9”这样的西班牙语短语,应当和它的英语对应物运作得一样好,而在认真对待本地化的应用里,它越来越能做到了。在我们内部的测试中,Apple 的设备端模型对西班牙语处理得很好。同样的方法将适用于法语、德语、日语,并且大概会在未来一年内适用于大多数主要语言。
各个部件如今都齐了。曾经是一次昂贵的云端往返的东西,如今是一个耗时 50 毫秒的本地函数调用。一个独立的待办应用能免费、无需按用户计费的推理账单就推出那个功能,这才是真正的故事。
TodoBar 是一款贴心的 macOS 菜单栏待办清单。支持大白话截止日期、全局快捷键、iCloud 同步。一次付费,永久属于你。
在 App Store 获取 TodoBar