Agent 多开之后,人为什么更忙了?缺的是 Attention Queue

0 阅读5分钟

你把四个工作委托给四个 Agent,原以为自己可以专心做判断。

结果每几分钟就有一条新消息:“正在运行”、“已完成”、“需要确认”、“查询失败,是否重试”。最后你没在做决策,而在给 Agent 消通知。

这是多 Agent 系统很容易漏掉的一层:我们设计了执行队列,却没有设计人的注意力队列。

9 月 4 日的 GitHub Copilot 周报把 VS Code 新的会话管理放到了明显位置:相关 chat 组织成层级,并显示哪些需要用户关注。VS Code 1.136 的官方说明还提到,每个 chat 有状态和待批准项,通知可分别区分“需要你输入”和“已收到回复”。发布摘要 · 1.136 完整说明

这不是对它们内部实现的推测。但它提醒了一个很实际的工程问题:“需要注意”不能只是 UI 上一个红点,它应该是可检查、可去重的业务状态。

多个 Agent 的状态不应直接倾倒给一个人

一个反直觉规则:失败也不一定要通知人

下面几种状态可以留在任务系统里,不必立刻打断人:

  • 任务健康运行中;
  • 遇到已知短暂故障,还在安全重试额度内;
  • 非关键批任务的一个子项失败,可以进稍后异常汇总;
  • 任务成功,但后续无需立即验收。

只有当一个人能提供不可替代的输入,而系统无法继续安全推进时,才进入 BLOCKED_HUMAN

type TaskState =
  | "QUEUED"
  | "RUNNING"
  | "RETRY_WAIT"
  | "BLOCKED_EXTERNAL"
  | "BLOCKED_HUMAN"
  | "SUCCEEDED"
  | "FAILED_FINAL";

function shouldOpenAttention(state: TaskState) {
  return state === "BLOCKED_HUMAN";
}

这个判断很简单,但比“模型觉得好像该问用户”稳定。模型可以帮忙整理问题,不要让它绕过状态机任意打断人。

AttentionItem 交付的不是报错,是最小人工动作

一条“请检查任务”的通知,只是把排查工作甩给人。一个可用的队列项至少应包含:

type AttentionItem = {
  taskId: string;
  reason: "missing_input" | "approval" | "conflict" | "retry_exhausted";
  question: string;
  nextAction: string;
  safeWhileWaiting: "pause" | "save_draft" | "continue_read_only";
  risk: "low" | "medium" | "high";
  blockedTaskIds: string[];
  sourceUrl: string;
  evidenceRevision: number;
  dedupeKey: string;
};

比如:

报价中的税率与客户档案不一致。请选择使用档案中的 6%,或上传新计税依据。未选择前,报价只保留草稿,不发送。影响报价、合同和邮件三个下游任务。

这里同时给了冲突、选项、等待期的安全动作和影响面。用户不需要先翻日志,才知道按钮会改什么。

用去重键合并“四个 Agent 同时缺一份资料”

如果四个下游任务都缺同一份产品参数,应该让人补一次,而不是弹四次。

我会用 resourceId + reason + evidenceRevision 构造去重键:

const key = [resourceId, reason, evidenceRevision].join(":");

await db.transaction(async (tx) => {
  const current = await tx.attention.findOpenByKey(key);
  if (current) {
    await tx.attention.addBlockedTask(current.id, taskId);
    return;
  }
  await tx.attention.create({ ...item, dedupeKey: key });
});

不要只用 resourceId + reason。资料版本已变,旧问题的答案不一定还能解锁新任务。

去重后也要显示 blockedTaskIds。一份参数正在阻塞一篇文章,和它正在阻塞全部对外报价,优先级应该不同。

排序不需要假装精确

与其让模型打一个“紧急度 86.7”,不如按稳定维度做字典序:

  1. 高风险对象优先:资金、数据、合规、对外发送;
  2. 有明确有效期的优先;
  3. 阻塞下游更多的优先;
  4. 其他条件相同时,等待更久的优先。

队列先处理高风险、快过期且阻塞多个下游的项目

这不是说永远不用分数,而是在数据还不够时,可解释的顺序比伪精确更容易维护。

队列满了,先减少新任务

注意力队列已有十几个未处理项时,系统还继续创建新的低优先级子任务,只会制造更多未来打断。

加一个简单的 WIP 上限:

attention:
  maxOpen: 8
  whenFull:
    highRisk: allow
    normal: queue
    lowPriority: pause_new_tasks

数字 8 只是示例,应由实际队列数据调整。真正该观察的不是“同时运行了多少 Agent”,而是:

  • 开放项的年龄分布;
  • 处理一个有效决定需要几次打断;
  • 重复项合并率;
  • 人回答后因版本变化或上下文不足导致的返工率。

如果点击率很高,但每个决定要打开五个窗口,这个界面仍然是失败的。

处理后的恢复,比弹出通知更难

用户点了“批准”,并不意味着旧任务可以无条件继续。在等待期间,报价单、政策或源文件可能已经变了。

恢复前至少做两件事:

1. 记录 actor + action + timestamp + evidenceRevision
2. 比对当前依赖版本;不一致则让旧项过期,重新生成问题

超时也不能默认等于批准。执行 safeWhileWaiting:保留草稿、暂停,或只继续只读步骤。

不要把 Attention Queue 又做成一个通知中心

通知中心的默认是“尽可能记录发生过的事”。Attention Queue 的默认应该是“尽可能安静,只保留当前可操作的阻塞”。

实现时可以守住四条边界:

  1. 外部限流先自动处理,不立即找人;
  2. 通知已送达不等于事项已解决,服务端保留真实状态;
  3. 高风险操作不与普通偏好合并;
  4. 每个项都能回到发起它的任务、子步骤和证据版本。

岗位 Agent 的协作不该让老板一直值班

这也是我们做 Tipkay 时关注的一个取舍。Tipkay 面向小微企业、一人公司和小团队提供按需 AI 员工。不同岗位助手带着各自的经验、Skill、MCP 和流程接力,并把工作从生成推进到素材、排版、文件与发布准备。

本文的 Attention Queue 数据结构和调度方法是通用设计建议,不是对 Tipkay 已有完整实现的宣称。不过岗位化协作的目标应该很明确:不是把更多 Agent 窗口交给一个人巡逻,而是让大部分步骤安静接力,只在必要时交回一个说得清的问题。

一个人的生意,也能有一支专业团队。团队的价值不是同时有多少人在说话,而是你不必反复问:“还有谁卡住了?”