Agent 生产化:性能、成本、并发与失败恢复
# Agent 生产化:性能、成本、并发与失败恢复
把 Agent 从单人 Demo 放进真实流量:设定服务等级和预算,处理队列、并发、重试、降级、恢复和版本发布。
# 先记住一句话
生产级 Agent 的目标不是让模型尽可能多思考,而是在质量、安全、延迟和成本约束内稳定完成任务,并能在失败后解释、恢复或降级。
# 先定义 SLO 和预算
SLO(Service Level Objective,服务等级目标)是系统准备长期达到的可量化运行目标。它不是一句 “尽量快、尽量稳定”,而要写成可以持续监控的数字。
不同任务不能共用一个指标:简单问答可能要求首字延迟低于 1 秒,长时研究允许后台运行数分钟,但必须持续反馈进度。至少定义:
- 成功率和正确拒绝率;
- 首字延迟、总延迟和 P95/P99;P95 表示 95% 的请求不超过这个耗时,P99 同理表示 99%;
- 单任务 Token、费用和工具次数;
- 并发、队列等待和超时;
- 人工介入率、恢复成功率和错误预算。
# 延迟从哪里来
总延迟 = 排队 + 上下文/RAG + 模型决策 + 工具调用 + 重试 + 最终生成
优化顺序通常是减少不必要步骤、并行独立 I/O、流式输出、缓存稳定结果,最后才是盲目更换更快模型。并行会增加瞬时负载和合并复杂度,只用于真正独立任务。
# 成本控制
- 根据任务难度路由模型,小模型处理分类和结构提取;
- 动态加载工具、Skill 和文档,减少上下文;
- 为 task 和用户设置 Token/费用/调用次数预算;
- 缓存 Embedding、检索和确定性工具结果;
- 先用 Workflow 缩小问题,再让模型处理开放部分;
- 监控每个成功任务的成本,而不只看单次调用价格。
# 并发、队列和状态
短请求可以同步返回,长任务则进入队列并持久化状态。这里的 Worker 是后端的任务执行单元,不是浏览器 Web Worker;它读取任务最近的 Checkpoint(持久化检查点)并继续执行。
同一任务要防止被多个 Worker 同时处理。常见方法是租约或乐观锁:租约是在一段有效期内把执行权交给一个 Worker;乐观锁则在更新时检查状态版本,版本已经变化就拒绝本次写入。
队列通常采用 “至少投递一次”,意思是系统保证消息不会轻易丢失,但异常重试时可能把同一条消息交付多次。因此产生外部副作用的写操作必须幂等,也就是同一个业务请求重复执行,最终效果仍与执行一次相同。执行事件可通过 SSE 或 WebSocket 推送给前端。
SSE 是什么
SSE(Server-Sent Events,服务器发送事件)是服务器通过一条 HTTP 长连接持续向前端推送消息的方式。例如 Worker 执行长任务时,可以依次推送 “开始检索”、“正在调用工具”、“等待审批” 和 “任务完成”。它通常使用 text/event-stream 响应,浏览器可通过 EventSource 接收事件并在断线后重连。
SSE 主要是服务器向前端单向推送,适合流式回答、进度和日志;WebSocket 支持双方随时发送消息,适合实时控制和频繁双向交互。如果前端只需接收 Agent 状态,SSE 通常已经足够;前端要发送操作时,仍可另外调用普通 HTTP 接口。
# 错误分类和重试
| 错误 | 策略 |
|---|---|
| 限流、网络抖动、临时 5xx | 逐次延长等待时间,并加入少量随机延迟,设置次数上限 |
| 参数/Schema 错误 | 返回模型修正一次,重复则失败 |
| 权限不足、审批拒绝 | 不重试,明确返回状态 |
| 外部服务长期异常 | 暂时停止继续调用(熔断)、改用有限能力(降级)或排队稍后恢复 |
| 模型无进展循环 | 提前停止,返回 incomplete |
重试预算要属于整个任务,不能每一层各自重试三次导致调用指数放大。
# 降级与恢复
- 搜索服务失败:允许回答已有上下文,并明确证据不完整;
- 主模型不可用:路由到经过评测的备选模型;
- 长任务超时:保留 Checkpoint 和已生成产物(Artifacts,例如文件、报告和中间结果);
- 写工具结果不确定:先查询幂等状态,不能直接重做;
- 可选能力异常:关闭该工具并继续有限功能。
# 版本管理与发布
一次 Agent 行为由模型、Prompt、工具、Skill、知识索引和代码共同决定。Trace 和评测结果要记录这些版本。发布时先离线回归,再使用影子流量或小比例灰度。
影子流量是什么
影子流量(Shadow Traffic)是把一部分真实请求复制给待验证的新版本:旧版本照常处理并把结果返回给用户,新版本也会处理同一请求,但结果只用于记录、对比和评测,不会影响用户看到的内容。它就像让新员工在旁边用真实订单练习,正式答复仍由老员工给出。
真实用户请求
├── 旧版本处理 → 结果返回给用户
└── 新版本处理 → 结果只记录和评测
2
3
它和灰度发布的区别是:
- 影子流量:新版本接收复制的真实请求,结果只用于测试和对比,不影响用户。
- 灰度发布:让少量真实用户直接使用新版本,新版本的处理结果会返回给用户。
使用影子流量时,必须关闭转账、发邮件和删除文件等真实副作用,敏感数据也要按生产标准保护。影子请求还会增加模型费用和系统负载,因此通常只复制一小部分流量。
观察质量、安全和成本等分组指标后,再决定扩大流量或回滚整套配置。
# 贯穿项目的部署形态
前端发送任务后立即获得 taskId;API 创建任务并把长流程入队;worker 执行检索和模型循环,在每一步写 checkpoint 和事件;前端订阅事件;敏感写入进入 requires_action;失败可以从最近 checkpoint 重试。静态笔记网站只承担阅读,Agent 后端单独部署并保护凭据。
# 高频面试题与回答
回答顺序:先说结论,再解释原因,最后补一个例子或工程边界。不要逐字背诵,记住这条表达主线即可。
1. 2 分钟回答:怎样把 Agent Demo 做成生产系统参考答案
我会先定义生产标准,例如任务完成率、最慢一批请求的延迟、单个成功任务的费用和安全目标。架构上把短请求和长任务分开:长任务进入队列,状态和 Checkpoint 持久化,前端通过事件流看到进度。执行过程限制总时间和费用,只重试暂时性错误,写操作必须幂等并按风险审批。最后把模型、Prompt、工具和索引统一版本化,发布前做回归和小流量灰度,线上用 Trace 排查,再把真实失败加入评测集。
2. 为什么要看每个成功任务的成本?参考答案
因为单次模型调用便宜,不代表完成一项任务便宜。如果便宜模型经常失败或需要多次重试,最后总费用可能更高。用总成本除以真正完成的任务数,才能比较不同模型和架构的实际业务价值。
3. 怎样避免多层重试放大流量?参考答案
关键是只让一层统一决定是否重试,并为整项任务设置总次数和最终截止时间。下层服务只返回这个错误能不能重试,上层负责退避、熔断和累计次数。否则模型、工具和 HTTP 客户端各重试三次,实际请求量可能被成倍放大。
4. 模型切换为什么也需要回归?参考答案
因为 API 能兼容,只代表代码还能调用,不代表行为一样。不同模型在工具选择、参数格式、语言风格和安全判断上都可能不同。切换前要用同一套任务比较结果质量、执行路径、延迟和费用,确认没有引入新的失败。
# 接下来学什么
下一篇学习 Agent 前端交互,重点理解怎样把流式输出、工具进度、人工审批和任务恢复设计成用户看得懂、能控制的交互。