生产运行时:请求-响应、流式、持久、队列、事件与定时 本节摘要:Jupyter notebook 里跑得好好的 Agent,到了生产会以 notebook 暴露不出的方式失败:第 37 步网络超时、语音通话中途用户挂断、cron 任务在机器重启时死掉、后台 worker 内存耗尽。运行时形态决定了哪些失败可存活。2026 年的生产 Agent 跑在六种运行时形态上:请求-响应(同步 HTTP,用户等完成,仅短任务 30 秒即需)。 五、练习 (Easy) 把你的第 01 节 ReAct 循环移植到全部六种形态。哪种形态适合哪个产品界面? (Medium) 给队列演示加 DLQ。模拟 10% 任务失败,暴露 DLQ 大小。
本节摘要:Jupyter notebook 里跑得好好的 Agent,到了生产会以 notebook 暴露不出的方式失败:第 37 步网络超时、语音通话中途用户挂断、cron 任务在机器重启时死掉、后台 worker 内存耗尽。运行时形态决定了哪些失败可存活。2026 年的生产 Agent 跑在六种运行时形态上:请求-响应(同步 HTTP,用户等完成,仅短任务<30 秒可行,Agno 的 FastAPI、Mastra 的 Express/Hono)、流式(SSE/WebSocket 渐进输出,LiveKit 扩到 WebRTC 给语音/视频)、持久执行(每步后状态检查点,失败自动续跑,LangGraph 的核心差异化、AutoGen v0.4 Actor 隔离故障)、基于队列/后台(任务入队,worker 取,结果经 webhook/pub-sub 回流,长程 Agent 必备——Anthropic computer use 公告称每任务数十到数百步)、事件驱动(Agent 订阅触发器:新邮件、PR 开了、cron 触发,Claude Managed Agents 开箱覆盖)、定时(cron 形态周期跑,配持久执行让失败的夜间任务下次 tick 续跑)。本节吃透六种形态、2026 部署模式,以及一个铁律:可观测性在每种形态下都是承重的——没有 OTel GenAI span(第 23 节)+ Langfuse/Phoenix/Opik 后端(第 24 节),你无法调试一个在第 40 步失败的多步 Agent,这不是可选项。读完本节,你应能避免「形态选错、无 DLQ、后台工作不透明、跳过持久状态」四种生产失败。
对应原课程:Phase 14 · Lesson 29 ·
production-runtimes(原英文phases/14-agent-engineering/29-production-runtimes/docs/en.md)。前置:第 13 节(LangGraph)、第 22 节(语音)。
阅读完本节,你应当能够:
生产 Agent 失败的方式,Jupyter notebook 根本暴露不出来:
运行时形态决定了哪些失败可存活。选错形态,等于把本可存活的失败变成灾难。所以铁律是:先选形态,再选框架。
没有 OTel GenAI span(第 23 节)+ Langfuse/Phoenix/Opik 后端(第 24 节),你无法调试一个在第 40 步失败的多步 Agent。这不是可选——这是「我们快速调试」与「我们从头重放加更多日志」的差别。六种形态,每一种都承重于它。
⚠️ 四种生产失败:① 形态选错——给 5 分钟任务选请求-响应;用户挂断、worker 堆积、重试叠加。② 无 DLQ——队列 worker 没有死信队列;失败任务消失。③ 后台工作不透明——后台 Agent 跑却不导出追踪;失败直到用户报告才可见。④ 跳过持久状态——任何超过 30 秒、又重启不起的运行,都需要持久执行。
原课程 code/main.py 是一个标准库多形态演示:
def request_response(task): # 同步,用户等 return agent.run(task) def streaming(task): # 生成器,渐进产出 for chunk in agent.run_stream(task): yield chunk
class Queue: def __init__(self): self.jobs, self.dlq = deque(), [] def enqueue(self, job): self.jobs.append(job) def worker(self): while self.jobs: job = self.jobs.popleft() try: result = agent.run(job) except Exception: if job.retries < MAX: job.retries += 1; self.jobs.append(job) else: self.dlq.append(job) # 死信,不丢
class EventBus: def __init__(self): self.handlers = defaultdict(list) def subscribe(self, trigger, fn): self.handlers[trigger].append(fn) def emit(self, trigger, payload): for fn in self.handlers[trigger]: fn(payload) def cron(agent, schedule_fn): while True: schedule_fn.wait_next() # 等下一次 tick durable_run(agent) # 配持久,失败下次续跑
运行 python3 code/main.py 会输出五条轨迹,展示同一任务在每种形态下的行为——同样的 Agent 逻辑,不同的外壳。第六种(持久执行)在第 13 节用 LangGraph 检查点专门讲过。
💡 设计要点:六种形态不是互斥的,而是可组合的——一个生产 Agent 可能是「事件驱动触发 + 队列入队 + 持久执行 + 流式回传」。选形态的本质是回答「失败发生时,用户和系统各自经历什么」:请求-响应里用户等到超时;队列里用户立即收到「处理中」,后台慢慢跑;持久执行里失败后从最后检查点续跑而非从头。可观测性则贯穿所有形态——没有它,你连失败发生在哪一步都不知道。
| 形态 | 代表框架/产品 | 适合 |
|---|---|---|
| 请求-响应 | Agno(FastAPI)、Mastra | 聊天式 UX、短任务 |
| 流式 | 任意流式框架、LiveKit(WebRTC) | 渐进响应、语音/视频 |
| 持久执行 | LangGraph、AutoGen v0.4 | 长程、步数未知、恢复成本高 |
| 队列/后台 | Celery、BullMQ、SQS+Lambda | 批量/异步/长跑(数十到数百步) |
| 事件驱动 | Claude Managed Agents、CrewAI Flows | 响应外部触发(邮件/PR/cron) |
| 定时 | K8s CronJob、Vercel cron | 例行维护(记忆整理/评估/成本报告) |
原课程 outputs/skill-runtime-shape.md:为给定任务选运行时形态并接好可观测性要求,含形态选择决策树、DLQ 配置、持久执行阈值(>30 秒即需)。
下一节,我们进入 Agent 工程的方法论核心——评估驱动开发:用一套持续运行的评估集,在写第一行业务代码前先定义「好」长什么样,把「感觉它挺好」变成「它在 N% 的任务上通过,回归在第 K 次提示改动引入」。