Agent 异步处理,别把队列当万能药

Agent 异步处理架构示意图

很多系统一慢,就想上消息队列。Agent 系统也一样:模型调用慢、工具调用慢、用户请求多,于是大家第一反应是“改成异步”。

异步确实有用,但它不是万能药。用对了,系统更稳;用错了,问题会从“等待时间长”变成“状态难追、失败难查、结果不知道去哪了”。

本文要点

  • 异步适合慢任务、批任务、可延后任务,不适合所有请求。
  • 队列解决的是削峰和解耦,不会让任务本身变快。
  • Agent 异步流程必须有任务状态、超时、重试、幂等和结果通知。
  • 背压很重要:处理不过来时,要限制入口,而不是无限堆任务。

什么时候需要异步

判断是否需要异步,先看用户是否必须马上拿到完整结果。

比如“解释这段代码”,用户一般希望马上看到回答,这类任务适合同步或流式输出。

但“审查整个仓库”“批量生成报告”“分析一天的日志”“跑一批测试”,这些任务耗时长,用户不需要一直盯着等待,就适合异步。

异步适合三类任务:

  • 慢任务:模型调用多、工具调用多、执行时间不可控。
  • 批任务:一次处理很多文件、很多用户、很多记录。
  • 可延后任务:结果不需要立即返回,比如日报、巡检、索引更新。

如果任务 2 秒内能稳定完成,不一定要异步化。简单同步反而更容易调试。

同步和异步怎么选

同步流程简单:请求进来,Agent 执行,结果返回。优点是直观,缺点是用户要等。

异步流程复杂一点:请求进来,系统创建任务,返回任务 ID;后台慢慢执行;用户通过通知、轮询或页面状态查看结果。

同步与异步 Agent 流程对比图
同步适合短任务,异步适合长任务。不要为了架构好看,把所有请求都塞进队列。

可以用这张简单规则判断:

结果必须立即返回,并且耗时稳定:同步
结果可以逐步展示:流式输出
结果可以稍后查看:异步任务
任务量大,需要削峰:队列
任务失败需要人工处理:异步 + 状态机

队列能解决什么

队列主要解决两个问题:削峰和解耦。

削峰的意思是,用户请求突然变多时,不要让所有任务同时打到模型、数据库或外部 API。先进入队列,再按系统承受能力慢慢处理。

解耦的意思是,请求入口不需要知道后台怎么执行。入口只负责创建任务,执行器负责消费任务。

但队列不能解决所有问题。

队列不会让模型生成更快,也不会让错误自动消失。它只是把压力从“立即执行”变成“排队执行”。如果消费能力不足,队列会越堆越长,用户还是等不到结果。

所以队列一定要配合背压:

  • 队列太长时,拒绝新任务或提示用户稍后再试。
  • 低优先级任务延后执行。
  • 高成本任务限制并发。
  • 给任务设置最大等待时间,超过就取消或降级。

失败怎么处理

异步任务最怕失败后没人知道。

一个 Agent 异步任务至少要有这些状态:

created -> queued -> running -> succeeded
                         ├-> failed
                         ├-> timeout
                         └-> cancelled

每个状态都要能查到原因。比如失败是模型超时、工具报错、权限不足,还是用户取消。

重试也要谨慎。不是所有失败都应该重试。

  • 网络抖动可以重试。
  • 速率限制可以延迟重试。
  • 参数错误不要重试。
  • 权限不足不要重试。
  • 已经产生副作用的任务,重试前必须保证幂等。

比如“发送通知”失败后重试,如果没有幂等 ID,可能给用户发两次。异步系统里,这类问题很常见。

上线检查清单

上线 Agent 异步流程前,可以用这份清单。

  • 任务是否有唯一 ID?
  • 用户能不能查到任务状态?
  • 每个任务是否有超时时间?
  • 失败原因是否可见?
  • 哪些错误可以重试,哪些不能?
  • 重试是否有最大次数和退避策略?
  • 任务是否幂等,重复执行会不会出事?
  • 队列积压时是否有限流或拒绝策略?
  • 高优先级任务是否会被低优先级任务堵住?
  • 是否有人工接管或补偿流程?

结论

Agent 异步处理的目标,不是把所有事情都丢进队列,而是让慢任务不阻塞主流程,让系统在高峰期还能稳住。

短任务保持简单,长任务再异步。队列只能帮你排队,不能替你处理超时、失败、幂等和背压。把这些边界设计好,异步才是能力;设计不好,它只是把问题藏到了后台。