Agent里的耗时任务老超时?改成异步回调就好了
如果你的Agent里有一步要跑很久——生成一份长报告、批量处理几百条数据、调一个慢吞吞的外部接口——还在同步等结果,迟早会撞超时。这篇讲怎么改成异步回调,带最小代码。
先认清超时是从哪来的
链路上的超时不止一道,我数了下至少四道:
-
用户端(网关/前端)等响应的超时,通常30秒到60秒
-
Agent平台执行单个流程的总时长上限
-
你调用的外部HTTP接口自己的超时
-
中间网关、负载均衡的连接超时
只要任务真实耗时超过其中最短那道,链路就断。一个生成报告的任务跑了两分钟,前端早在第50秒就报504了,哪怕后台还在老老实实算。
所以同步等长任务,本质是拿一个"必须很快返回"的通道去扛一个"注定很慢"的活,设计上就拧着。
正确姿势:提交即返回,干完回调
把一个动作拆成两段:
-
提交阶段:Agent收到请求,生成一个任务ID,把活儿丢进后台队列,立刻返回"已受理,任务号 xxx"。这步几十毫秒就完事,绝不会超时。
-
回调阶段:后台慢慢跑,跑完了主动把结果POST到一个回调地址(或者把状态写进库,让前端轮询)。
伪代码大概长这样:
# 提交阶段:Agent 节点里
def submit_task(payload):
task_id = uuid4().hex
queue.push({"id": task_id, "payload": payload})
# 立刻返回,不等执行
return {"task_id": task_id, "status": "accepted"}
# 后台 worker:独立进程,慢慢跑
def worker():
job = queue.pop()
result = run_heavy_job(job["payload"]) # 这步可能跑几分钟
# 干完主动回调
requests.post(CALLBACK_URL, json={
"task_id": job["id"],
"status": "done",
"result": result,
}, timeout=10)
回调接收端记得做这几件事:校验task_id、幂等处理(同一个任务回调可能来两次)、失败重试。回调本身也会失败,别假设它一定送达。
用户体验这块别忘了
异步最大的副作用是用户得等。体验上要补两件事:
-
提交后立刻给个明确反馈:"正在生成,预计一两分钟,好了通知你",别让对话框空着,用户以为卡死。
-
结果回来后主动推给用户。我的做法是回调命中后,往原对话里追发一条消息把结果带上,用户不用守着刷新。
我踩的两个坑
坑一:回调地址写成了内网地址。 worker跑在另一台机器上,POST不到我那个只在本机能访问的回调URL,任务全"成功执行但结果丢了",查了半天才发现是网络不通。回调地址一定是双方都能访问到的。
坑二:没做幂等,结果发了两遍。 重试逻辑触发后,同一份报告推给用户两次,用户问我是不是系统抽风。后来用task_id做了去重表,处理过的直接跳过。
收尾
判断标准很简单:这一步可能超过10秒,就别同步等,拆成提交+回调。架构上多绕一道,但比线上动不动504强太多。
我现在搭这类带耗时步骤的智能体,用的是一个零代码、还能把流程发布成API的平台,它的工作流支持异步节点和回调出口,不用我自己搭队列加worker那一整套。要做异步长任务的可以去讯飞星辰看看,它模型走MaaS、现成接口直接调,不用自建算力,这样我能把心思全放在拆任务和处理回调失败上。
你们的长任务是用回调还是让前端轮询?评论区说说,我俩方案来回换过好几次也没定论。
更多推荐
所有评论(0)