通知与摘要。
"要不要打扰这个人"是第二套策略,与干活的那套完全分离,而几乎没有人是这么建的——于是有能力的环境智能体一个接一个死于被静音,而不是死于出错。这里的代价函数不对称,而且只进不退:一条有用的通知省下几分钟,一条无用的通知则永久压低接下来五十条所能得到的注意力,而"静音"是一个吸收态,没人从那里回来。把通知策略单独设计,给它自己的预算和自己的指标,你才能在真正出事的那天还留着那条你需要的通道。
两套策略,其中只有一套关于任务。
一个无人值守的智能体每次运行都产出两样东西:它做了什么,以及它告诉了你什么。团队调的是第一样,第二样则由框架的默认行为顺手决定——通常是"完成时发消息"——然后奇怪为什么没人看这些消息。
- 任务策略问的是该做什么;通知策略问的是人现在是否需要知道。两者的输入不同:后者取决于收件人是谁、他能对什么采取行动、他那边现在几点,以及今天早上他已经被告知过什么——而这些统统不该是任务策略需要知道的事。
- 把它们分开,两者才都可测。你可以在不重跑智能体的前提下、直接在历史运行上评测通知策略:回放一周的结果,问"当时会发出什么",然后打分。这是一条便宜的评测回路,而耦合在一起的设计不允许它存在。
- "完成"不是事件。"任务已成功完成"是这个品类里发送量最大、价值最低的一条通知。成功是预期情况;如果它需要被宣告,那这次运行属于摘要,不属于推送。
- 默认必须是沉默。每一条消息都需要一个"它等不了"的理由。把默认反过来——除非被抑制否则就通知——正是一个循规蹈矩的智能体在第三个功能之后变成消防水管的原因。
定义一个智能体时有个好用的测试:先写下它会发什么,再写下它会做什么。如果你说不出三个值得推送的具体情形和一个值得传呼的情形,那这个智能体大概根本不需要推送通道——有个地方可查就够了。摘要所在的那个界面见异步与离场。
代价是不对称的、非平稳的,而且由别人承担。
精确率与召回率在每个分类器里都要权衡,而这里的兑换率残酷地一边倒——之所以容易被忽略,是因为那份损失落在你的指标之外。
- 一次误报不是一条坏消息。它是对该通道上未来每一条消息所获注意力的一次微小而永久的削减。这份损害会累积;与它交换来的那条真阳性带来的收益不会。
- 静音是终局。一个人一旦关掉某类通知,实际上就再也不会打开,你对这位收件人的召回率归零——包括整套系统赖以存在的那唯一一条告警。把静音率当作压在其余一切之上的护栏指标。
- 习惯化在你的日志里是看不见的。投递成功、消息在技术意义上被打开、然后什么都没发生。打开率会奉承一条早已停止工作的通道;只有"行动"才说明问题。
- 承担代价的人不是调阈值的人。建设者眼里只有一个智能体;收件人面对的是十一个之和。按第 5 步在收件人层面做预算,否则每个单看都合理的智能体,合起来会不可用。
- 通知不足同样有真实代价,而且更安静。一个悄悄放弃任务的智能体,或者一个在等待没人知道其存在的审批的智能体,其失效方式根本不产生任何信号。这是"守尸开关"的理由,不是"降低阈值"的理由。
按决策期限路由,不按重要性。
"这有多重要?"无法回答,而每个智能体都会乐观地回答它。"这件事到什么时候就不再可行动了?"则是一个有可核查答案的问题,而且能干净地映射到通道上。
- 立刻打断——窗口在几分钟或几小时内关闭,而人的决定会改变结果。卡在期限上的审批、仍在累积的花费异常、等待确认的不可逆动作。
- 摘要——可行动,但明早再说也行。已完成的工作、各类建议、尚未紧迫的漂移。批量化不是降级;它是智能体绝大多数产出的正确通道。
- 只记日志——不隐含任何决定。有人问起时可查,永不推送。
- 无人响应就升级,不要重复。如果窗口关闭前没人行动,下一步是换一个收件人,或者执行一个书面写明的安全默认动作——而不是把同一条消息再发一遍。重发只会教会别人第一条本来就可以不理。
- 尊重收件人的作息,并预先定义例外。免打扰时段加上一类写明的破窗条件,才是诚实的设计。一个在凌晨三点自行判定"这条够重要"的智能体,等于刚刚重新发明了静音键。
按期限路由也顺带告诉你:在等待期间智能体可以做什么。如果一项审批一小时后过期而收件人正在睡觉,设计问题就不是"该在哪条通道上喊得更大声",而是"到期时的安全默认动作是什么"——即定时与事件触发的智能体里的那个"弃权还是继续"的决定。
把通知写成决策能在它内部完成的样子。
一条需要打开看板才能读懂的通知已经失败了,因为打断的代价付了,决定却没做成。这种格式存在的全部意义,就是在通知本身之内把回路闭合。
- 开头就说变了什么、在问什么。第一行是那个决定或那个事实。不是智能体的名字,不是运行 ID,也不是"我已完成对……的分析"。
- 附上能改变答案的那份证据。那个数值、它越过的阈值,以及测量所用的窗口。一行落地信息,就能把一句主张变成一个人不必离开这条消息即可接受或否决的东西——纪律见来源归属体验。
- 写明没人回复会发生什么。"14:00 将继续执行"和"14:00 将放弃"是两条不同的消息,要求的紧迫感也不同。对默认动作只字不提,是智能体通知里最常见的缺陷。
- 把撤销放在动作旁边。批准与撤销属于同一个界面,见撤销与可逆性;一个一键批准却看不到退路的设计,会抬高每一条通知的赌注,并把所有通知都拖慢。
- 让措辞与置信度对齐。一个把六成把握的发现说得和确定事实一样的智能体,是在训练读者把两者一并打折。在这里,留有余地的措辞是特性——见为信任而设计。
- 摘要要排序,不要按时间排列。按时间排的摘要就是一份日志。把需要决定的条目放最前,已完成的工作放下面,并让第二组的数量可见而不必逐条列出。
把限流放在智能体的判断之外。
"再发一条"的每一个论据,都由那个想发的组件提出。所以预算不能住在 prompt 里,不能住在智能体的推理里,也不能住在一份各团队按自家智能体调优的按智能体配置里。
- 按收件人按周期做预算,跨所有智能体。配额共享在通知服务里,而不是每个智能体一份。用尽之后,后续消息降级为摘要——智能体没有投票权,也没有宣布例外的权力。
- 按稳定的键去重。同一条件、同一对象、同一个未关闭的事件,是一条带状态更新的通知,不是十一条。多数通知风暴其实是同一个条件被反复观察到。
- 按相关性抑制。当四十条投放线同时越界时,说明上游坏了;发一条关于上游原因的消息加一个计数即可。事故期间的扇出,正是通道在最糟的那天被静音的原因。
- 留一类破窗条件,并保持它很小。让极少数条件绕过预算——待执行的不可逆动作、安全条件、仍在累积的花费。如果有超过一小撮条件够格,那就等于一个都不够格。
- 给沉默装一个守尸开关。一个本该每日汇报却没有汇报的智能体,其失效在构造上就不会产生任何通知。要从智能体之外,对"缺席"告警。
- 给收件人细粒度的控制权,并把他们的使用当作数据。按类别而非按智能体静音,能保住有用的那几类。当有人静音了某一类,那就是你的精确率指标在告诉你一件看板没说的事。
衡量行动,不衡量投递。
通知系统通常只在发送侧被埋点,而那衡量的是代码是否工作,不是设计是否工作。三个数字描述这条通道的健康度,其中一个是没人在采集的那个。
- 窗口内被处理率——在那些请求决定的消息里,有多大比例在期限前得到了决定。这是首要指标,而且它应该高到令人尴尬;如果不是,说明你在发不必发的东西。
- 静音与退订率——护栏指标。它移动缓慢、永不回弹,是精确率下滑的领先指标。
- 信号漏报率——有多少本该产生通知的事情发生了却没有通知。它只能靠倒着抽查事故、追问这条通道当时有没有承载它来获得,这就是几乎没人拥有它的原因,也是它最值得建的原因。
- 先在回放上打分,再去线上调。取两周的运行,生成当前策略会发出的内容,请真正的收件人给每一条标上"有用/可忍受/噪声"。这只花一个下午,却是上线前唯一诚实的校准手段。
- 按类别看精确率,不要看总体。一个吵闹的类别会藏在健康的均值背后,然后在收件人整条通道静音时把全部一起带走。
先把"完成通知"删掉,换成一份按"需要决定"排序的晨间摘要——对多数智能体来说,这一步就砍掉了绝大多数消息,而且什么都没损失。然后对剩下的部分埋点"窗口内被处理率",并在通知服务里(而不是在智能体里)设一个按收件人的每日预算。通知策略是环境智能体里决定其余部分会不会被使用的那一部分,也是唯一一个失效起来在你的日志里长得和成功一模一样的组件:已投递、已打开、被无视。
相关:打断、引导与交接——会话内的对应物;审批与确认体验——通知常常承载的那道闸门;成本与配额体验——用户看得见的另一份预算;以及定时与事件触发的智能体——这类流量的主要来源。