跳到主要内容

你的智能体没读过的那条休假自动回复

· 阅读需 9 分钟
Tian Pan
Software Engineer

凌晨两点,你的客服智能体呼叫一位真人。那位真人已经请假一周了。休假自动回复就躺在智能体正在读取的同一个邮箱里。智能体仍然 ping 了过去。自动回复弹了出来。智能体礼貌地道了声谢,然后又 ping 了一次——因为回复里没有它在等的那个工单解决码。十二个循环之后,另一支团队的人偶然发现这个未读会话已经堆了六十条消息,才手动去把值班的人叫醒。

智能体完全照着 prompt 说的做了。Prompt 让它升级给一个人。这个"人"在它眼里只是一个字符串,不是一个角色。这个字符串不知道什么叫 PTO。

这是一个小 bug,但它揭示了一个大教训。人有边界——睡眠、周末、年假、出差开会、随便哪个周二请半天去看牙。除非有人把这些边界明确接进系统,否则智能体一概不知。而承载这些信息的天然位置——日历、休假自动回复、值班表——几乎总是在你的智能体没有去看的地方。

升级目标应当是一个角色,而不是一个人

第一个设计修正最便宜,可是多数智能体堆栈仍然搞错了:智能体的升级目标应该是一个角色,而不是一个用户名。

这在事件响应领域早已是老生常谈。PagerDuty 整个服务所有权(service ownership)模型的核心,就是把升级策略路由到值班表而不是个人。值班表会动态解析为当前正在值班的人。如果主值班无响应,策略会在超时后升级到二线。线上的智能体根本不需要知道这些人是谁——它只路由到一个角色,由角色在呼叫的那一刻去解析具体的人。

我见过的大多数 LLM 智能体却采用了相反的设计。某个人在 system prompt 里硬编码了一个 Slack handle。半年后那位工程师换了团队。智能体还在 ping 他。这些通知被静音了。真正的升级丢进了大家学会忽略的那个机器人频道。

这条规则虽小,但值得刻进石头里:永远不要让你的智能体直接持有对某个人的引用。让它持有对一个角色的引用,由角色自己去做解析。就像你的服务架构把用户当作 ID 再解析为名字一样,你的智能体架构应该把人当作角色,再解析为具体的人。

日历和休假状态是一等的上下文

更难的问题是,即使升级路由是基于角色的,当这个角色为空、或者持有这个角色的人本身就不在时,依然会失败。某人"理论上"在值班,但他在没有信号的婚礼现场,或者他在一个 Slack DM 不弹通知的会议上,又或者他今天早晨临时请了假但忘记更新值班表。

人的旁路信号——休假自动回复、设置成沙滩 emoji 的 Slack 状态、日历上那个叫 OOO 的事件、头像旁边的离线标识——是你的组织对"现在到底谁能干活"产生的最有上下文的信号。可几乎没有任何智能体堆栈把它当作输入。它被当作会话里的输出,智能体读一读,简单推理一下,然后就被 prompt 里写好的指令盖过去了。

修正办法是把休假和日历状态从会话表面提升到路由决策层。在智能体升级之前,它应该向路由层询问类似这样的问题:

  • 解析出来的角色持有者现在可用吗?
  • 他的日历里有 OOO 或者一整天的忙碌事件吗?
  • 他的自动回复打开了吗?
  • 他的 Slack 状态是不是属于那一小撮代表不可达的状态之一?

只要任何一个返回 false,智能体就不应该呼叫那个人。它应该按升级策略走到下一个人——正是 PagerDuty 处理 SEV-1 事件的方式。这不是什么新鲜事。这是已经在值班轮换里跑了十五年的逻辑。唯一新鲜的事是,你的智能体得参与到这套逻辑里,而不是绕过它。

循环为什么会发生

一旦你接受了智能体绝不应该呼叫一个正在休假的人这一前提,下一个问题就是:循环到底是怎么发生的?答案很机械,值得直说。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates