当5分钟不够时:将 AI Ingestion 从 Sync 转为 Async(并节省 99% Compute)
Source: Dev.to
背景
在之前的文章中,我介绍了 Synapse——我为妻子构建的 AI 系统,它使用知识图谱为她的 LLM 提供“深度记忆”。早期演示显示,图谱在聊天结束后约 50 秒内更新,但实际使用很快暴露出一个根本性缺陷。
问题
在 45 分钟的聊天会话中发送了数十条消息后,“结束会话”按钮会转圈数分钟,最终崩溃。根本原因并不是简单的超时 bug,而是架构本身。
最初的同步实现
- Convex (Orchestrator) → 触发对我的 Python 后端的 HTTP POST。
- FastAPI (Brain) → 调用 Graphiti + Gemini 处理文本。
- FastAPI 等待结果并返回。
- Convex 将结果保存到数据库。
这是一种经典的同步请求‑响应模式。
失败原因: Convex Actions 有硬性执行时限(5–10 分钟,取决于套餐)。短会话在 1–2 分钟内完成,但较大的会话需要 12–18 分钟,远超限制。
连锁故障
- 在 Convex actions 上添加了指数退避重试。
- 每次重试都会启动一个新的后台进程,而之前的进程仍在运行,导致 token 使用翻倍并产生“僵尸”作业。
- 用户仍然看到错误,后端被压垮。
诊断
发送到 Axiom 的 OpenTelemetry 跟踪显示,摄取并未失败——只是慢,针对大规模会话始终需要 12–18 分钟。
转向异步轮询架构
当任务超过客户端或服务器愿意等待的时间时,请求必须与响应解耦。
新的流程
- Convex 发送
POST /ingest。 - FastAPI 立即返回
202 Accepted并附带jobId(≈ 300 ms)。 - FastAPI 在后台任务中启动耗时的处理(
asyncio.create_task)。 - Convex 休眠,然后每隔几分钟轮询作业状态。
轮询策略
- 从指数退避改为 线性退避。
- 调度:5 分钟后检查一次,随后 10 分钟后检查一次,之后每隔 10 分钟检查一次。
- 减少了不必要的负载和服务器噪音。
资源使用对比
| 场景 | 操作时间 | 总计计费计算量 | Token 浪费 |
|---|---|---|---|
| 同步 | 5 分钟(阻塞)→ 超时 → 重试(再 5 分钟) | ~10–15 分钟 | 高(重复处理) |
| 异步轮询 | 触发 ≈ 300 ms,轮询 ≈ 300 ms,最终获取 ≈ 300 ms | < 2 秒 | 最小 |
我们将每个作业的计算浪费从约 10 分钟降至不到 2 秒的活跃执行时间,同时消除了重复处理。
经验教训
- **AI 任务本质上很慢。**一次“快速”LLM 调用可能需要 30 秒;一次“深度”知识图谱更新可能需要 15 分钟。
- **不要仅仅增加超时。**通过解耦请求与响应来保持系统的弹性和成本效益。
- 线性退避用于轮询 与长时间运行作业的预期时长相匹配,能够降低服务器的聊天频率。
代码仓库
该异步请求‑响应模式的实现可在以下仓库中找到:
- 前端 (Body):
synapse-chat-ai - 后端 (Cortex):
synapse-cortex
征求反馈
我想了解大家是如何处理长时间运行的 LLM 任务的。欢迎在 X 或 LinkedIn 上联系我。