# Agent 工程运维（五）：监控、扩容与上线维护

作者：zhongling
原文：https://zhixia.pages.dev/posts/agent-infra-production/
发布日期：2026-11-12
更新日期：2026-11-12
语言：zh

摘要：围绕一次 Excel 分析任务，梳理 Agent 的日志、指标、链路追踪、容量与成本控制，以及发布兼容、权限和备份恢复。让运行中的问题能够被发现、定位和处理。

---


前面几篇把网络、运行环境和任务恢复串了起来。这一篇继续看系统上线之后：用户说“分析一直没有完成”，应该从哪里查？任务越来越多，增加 Worker 就够了吗？发布一个新版本，会不会让昨天等待人工确认的任务无法继续？

仍然以同一条流程为例：用户上传 Excel，API 创建任务，Worker 调用模型，沙箱执行分析代码，报告存入 OSS，前端接收执行事件。**线上维护的目标，是让这条流程的状态、耗时、资源和结果都有依据可查，并且能够控制变更带来的影响。**

[系列导读：Agent 工程需要补哪些运维知识](/posts/agent-infra-overview/)

> 本文由 AI 辅助整理，资料核对于 2026 年 11 月。容量数字是假设条件下的推导，检查项是工程建议；未对生产环境做压测或故障演练。

## 用户说“很慢”，先知道时间花在哪里

我会先把观测分成三类。它们记录的对象不同，组合起来才容易还原问题。

| 类型 | 观察什么 | Excel 分析场景 |
| --- | --- | --- |
| 日志 Logs | 某个时刻发生的具体事件 | 文件解析失败，异常类型和步骤是什么 |
| 指标 Metrics | 一段时间内的数量和分布 | 任务完成率、排队时长、内存峰值 |
| 链路 Traces | 一次调用在多个组件间的经过 | API、Worker、模型和工具分别用了多久 |

[OpenTelemetry 的 Signals 文档](https://opentelemetry.io/docs/concepts/signals/)介绍了这些观测信号。它提供采集与关联的基础，哪些事件对自己的业务有意义，仍然需要应用定义。

例如用户觉得慢，可能是任务尚未被 Worker 领取，也可能是模型首个 Token 返回慢，或者 Excel 解析已经完成、上传报告时卡住了。只有一个“总耗时”很难区分这些情况。

可以分别记录排队、模型调用、工具执行、产物上传和端到端耗时，观察平均值以外的分位数。告警也应有明确对象，例如“已接收的任务长时间没有推进”“最旧待执行任务持续变老”，并附上查询路径和处理负责人。

### 让日志、任务和调用链对应起来

业务任务使用稳定的 `run_id`，步骤使用 `step_id`，每次尝试保留 `attempt_id`；Trace 使用 `trace_id` 串联调用。异步任务要在消息中传递必要的关联信息，Worker 不能每次都生成一个完全无法关联的上下文。

日志中可以保留任务 ID、步骤、错误分类和版本；文件正文、模型密钥和用户敏感信息则需要按用途脱敏、限制访问和保留期限。

这些 ID 适合用于定位具体执行，指标标签更适合使用模型、工具类型、结果类别等有限集合。如果把每个 `run_id` 都做成指标标签，组合数量会持续增长。[OpenTelemetry 的基数说明](https://opentelemetry.io/docs/concepts/signals/metrics/#cardinality-limits)解释了这类属性对内存和聚合的影响。

### 运行成功，还要检查结果是否有用

报告成功写入 OSS，只能说明流程完成了。报告是否漏了工作表、统计口径是否正确、引用的数据是否来自当前文件，需要另外评测。

我会同时记录执行完成率和结果质量。前者用于判断服务是否稳定，后者用于比较模型、Prompt、工具或检索方案的变化。发布时保留一组固定输入及评判规则，才能知道“运行更快了”是否伴随着质量下降。

## 扩容前，先算清楚正在等待什么

假设系统长期平均每秒接收 2 个任务，每个任务从进入到结束平均停留 30 秒，并且系统处于稳定状态，那么平均在途任务数约为：

`2 个/秒 × 30 秒 = 60 个任务`

这里统计的是系统内的平均任务数量，包括等待和执行。它提供容量分析的起点；实际需要多少 Pod，还取决于单实例并发、内存、CPU 和外部服务能力。流量突发或队列持续增长时，需要重新分析，不能把这个平均值当成容量上限。

Agent 等待模型时 CPU 可能很低，因此我会结合队列等待时间、在执行任务数和资源利用率来判断扩容。[K8s HPA](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/)支持资源、自定义和外部指标，但对应的指标采集与适配需要实际接好。

还要一起检查下游预算。假设每个 Worker 实例的数据库连接池上限为 20，扩到 50 个实例后，潜在连接需求就是 1000，再加上 API、管理任务和发布时并存的新旧实例。数据库也许会先到达上限。

队列可以吸收短时峰值，同时应有等待期限、容量边界和租户配额。下游接近上限时，通过限制领取速度、暂停部分消费或明确拒绝新任务来形成背压。无边界地接收任务，只会把压力转换成更长的等待。

## 模型限流和成本需要独立控制

增加 Worker 会增加本地执行能力，上游模型的账号配额仍按供应商规则执行。一次 Agent 任务还可能包含多轮模型调用和并行工具，任务数与模型请求数也不能直接画等号。

以 [Claude 的限流文档](https://platform.claude.com/docs/en/api/rate-limits)为例，请求速率、输入 Token、输出 Token 和消费额度属于不同限制；返回 429 时，也要继续检查错误信息和响应头。

对于暂时的速率限制，可以按 `Retry-After` 等信息等待，并设置退避、抖动和总重试预算。对于消费额度耗尽，持续重试通常无法解决。配置错误、权限失败、外部操作结果不确定，也应进入各自的处理分支。

重试预算最好覆盖整条调用链。SDK 重试、Worker 重试、Agent 自己再次调用工具，如果各自独立放大，实际请求数可能远高于界面看到的次数。

成本记录可以按 `run_id` 汇总模型用量、重试消耗、沙箱运行时间和文件存储。再为任务设置最大步骤、总时长、Token 预算和工具调用次数。到达边界后，保存已有结果并明确结束或转人工处理。

沙箱回收也要有可观察的状态。任务取消之后，应确认子进程和浏览器是否退出、实例是否释放、产物是否已经上传；回收失败需要后台清理与告警。等待人工时是否保留沙箱，则要结合恢复成本、等待时长和平台计费规则选择。

## 发布时，程序版本和任务版本一起考虑

一条可追溯的发布流程，可以包含这些步骤：

1. 记录代码提交，执行必要测试与固定样本的 Agent 回归评测。
2. 构建镜像并推送 ACR，记录确定的镜像标识。
3. 配置运行环境、网络和受控凭据。
4. 部署新版本，验证启动、工具访问和流式事件。
5. 逐步接入任务，观察完成率、延迟、质量和成本变化。
6. 保留可回退版本，并确认回退后的任务状态仍可读取。

每个任务最好能关联到代码、模型、Prompt、工具和状态格式的版本。这样才能回答：这份报告是在什么条件下生成的？同样的输入，为什么新旧版本行为不同？

### 回滚前，先检查数据是否兼容

假设新版本把检查点中的 `file_path` 改成了 `artifact_id`，发布后老任务怎样恢复？如果回退镜像，旧代码是否又读不懂新状态？

可以先增加兼容字段，让新旧版本都能读取；完成存量迁移后再删除旧字段。对于变化较大的执行逻辑，也可以让存量任务继续绑定旧版 Worker，明确设置退役期限。

这需要与数据库结构变更一起设计。[K8s Deployment 的回滚](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-back-a-deployment)恢复的是 Pod 模板部分，数据库内容、外部工具效果和业务状态需要自己的恢复方案。

## 权限跟着任务走，凭据跟着工作负载走

API、Worker 和沙箱承担不同职责，权限也应分别配置。例如 API 可以创建任务，Worker 可以读本次输入并写入结果，分析代码只获得当前任务需要的文件和工具能力。

[阿里云函数角色](https://help.aliyun.com/zh/functioncompute/grant-function-compute-permissions-to-access-other-alibaba-cloud-services)和 [IAM 最佳实践](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)都可以作为理解工作负载身份的入口：使用角色和临时凭据，并将操作权限限定到必要资源。

云账号权限之外，工具服务还要检查业务授权。用户提交一个 `run_id`、文件 ID 或下载地址时，服务端应核验它属于哪个租户、当前用户有什么权限。数据库查询、缓存键、对象路径和恢复接口，都要保持同一套租户边界。

## 备份需要以恢复结果验收

副本可以帮助服务在实例故障后继续运行，备份则提供历史恢复点。错误删除可能被同步到副本，所以需要单独保留能够恢复的数据。

这里先认识两个目标：**RPO 是允许丢失的数据时间窗口，RTO 是允许服务中断到恢复的时间。** 它们决定备份频率、日志保留和恢复流程的要求。

[PostgreSQL 的备份文档](https://www.postgresql.org/docs/current/backup.html)区分了 SQL 导出、文件系统备份和持续归档等方式。选择方案时，还要核对检查点引用的 OSS 文件能否同步恢复，避免数据库里保留了记录，文件却已过期删除。

恢复演练应使用隔离环境：恢复一批真实结构的任务记录与产物，验证权限、文件引用和状态读取，并记录耗时。恢复出的历史任务先保持受控状态，核对外部操作记录后再允许执行，避免旧队列或旧检查点再次触发已完成的动作。

## 第一版上线前，实际走一遍这些场景

| 演练 | 需要留下的证据 |
| --- | --- |
| 一次正常 Excel 分析 | 用 `run_id` 找到完整步骤、耗时、模型用量和产物 |
| 临时模型限流 | 任务有界等待，重试有上限，其他任务仍能推进 |
| 模型额度不足 | 能识别原因并停止无效重试，告警指向正确配置 |
| 发布时存在在途任务 | 新旧任务都能完成，检查点能够正确读取 |
| 用户取消正在分析的任务 | 后台停止推进，沙箱最终被回收，已产生效果有记录 |
| 使用另一租户的任务或文件 ID | 查询、恢复与下载入口都拒绝越权访问 |
| 从备份恢复任务及文件 | 引用完整，恢复时间可记录，外部动作不会直接重放 |

## 参考资料

- [OpenTelemetry：Signals](https://opentelemetry.io/docs/concepts/signals/) 与 [Metrics](https://opentelemetry.io/docs/concepts/signals/metrics/)
- [Kubernetes：HPA](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/) 与 [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
- [Claude：Rate limits](https://platform.claude.com/docs/en/api/rate-limits)
- [阿里云：函数角色与云服务访问权限](https://help.aliyun.com/zh/functioncompute/grant-function-compute-permissions-to-access-other-alibaba-cloud-services)
- [AWS：IAM 最佳实践](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
- [PostgreSQL：Backup and Restore](https://www.postgresql.org/docs/current/backup.html)

上一篇：[让长任务能够恢复](/posts/agent-infra-durable-execution/) · [返回系列导读](/posts/agent-infra-overview/)

