CloudWatch Omni:把应用与自主 AI Agent 纳入同一套可观测体系

2026-09-30 24 预计阅读时间: 1 分钟
来源: infoq.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

传统应用的可观测性通常围绕日志、指标和链路展开,但自主 AI Agent 带来了新的问题:一次请求可能触发多轮模型推理、工具调用、外部检索和决策循环。Amazon 最近推出的 CloudWatch Omni 被定位为 AI-first 可观测平台,目标是在统一环境中监控、评估并排查普通应用与自主 Agent。

这项变化的重点并不只是“给 CloudWatch 加一个 AI 页面”,而是把 Agent 的执行过程变成可检查、可关联、可评估的运行数据。

为什么 Agent 不能只靠普通 APM 监控

传统 APM 擅长回答这些问题:

  • 哪个 HTTP 接口变慢了?
  • 哪个数据库查询导致超时?
  • 某个服务版本是否提高了错误率?
  • 一次请求经过了哪些微服务?

Agent 系统还需要回答另一组问题:

  • Agent 为什么选择了这个工具?
  • 一次任务执行了多少轮推理?
  • 工具调用成功,但最终答案为什么仍然错误?
  • 延迟来自模型、检索、工具,还是重试循环?
  • 哪个提示词或模型版本让任务成功率下降?
  • Agent 是否泄露敏感信息,或者执行了不应执行的动作?

因此,Agent 的一次运行不能只表示为单个请求。更实用的数据模型至少要包含以下层级:

层级 建议记录的内容
请求 用户请求、租户、会话、入口服务
Agent 运行 run ID、Agent 版本、模型、提示词版本
推理步骤 步骤序号、耗时、输入输出摘要、停止原因
工具调用 工具名、参数摘要、状态、耗时、重试次数
评估结果 是否完成任务、质量分数、安全检查、人工反馈
资源消耗 Token、模型调用次数、外部 API 调用量、估算成本

CloudWatch Omni 的统一环境定位,正是为了减少应用遥测与 Agent 执行记录之间的割裂。例如,当客服 Agent 返回错误答案时,排障人员不仅需要看到模型输出,还要继续追踪检索服务、订单 API 和数据库调用。

“监控”之外,评估为何成为核心能力

对确定性服务来说,HTTP 500、异常栈和延迟通常已经能说明很多问题。Agent 的失败则可能表现为一个格式正确的 HTTP 200:请求成功返回,但内容答非所问、引用了错误资料,或者调用了不合适的工具。

这意味着可观测平台需要同时处理两类信号:

  1. 运行信号:延迟、异常、吞吐量、依赖状态和资源消耗。
  2. 质量信号:任务完成度、答案正确性、工具选择、安全性和用户反馈。

评估也不应该只有一个总分。更稳妥的做法是分别维护可解释的指标,例如:

  • task_completed:任务是否完成;
  • groundedness_score:回答是否有检索内容支持;
  • tool_selection_correct:是否选择了正确工具;
  • policy_violation:是否违反安全策略;
  • human_rating:人工或用户评分。

这样,当总体成功率下降时,团队可以区分“基础设施故障”“模型行为退化”和“评估规则发生变化”,避免把所有问题都归结为模型不稳定。

可以这样实践:先建立可关联的 Agent 事件

目前给出的产品摘要没有说明 CloudWatch Omni 的具体采集 API、SDK 或部署方式,因此下面不是某个官方接口示例,而是一份可以直接运行并改造的最小遥测程序。它展示了接入统一可观测平台前应保留哪些关联字段。

将以下内容保存为 agent_observability.py:

import json
import logging
import time
import uuid
from contextlib import contextmanager

logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger("agent")

TRACE_ID = uuid.uuid4().hex
RUN_ID = str(uuid.uuid4())


def emit(event_type, **fields):
    event = {
        "timestamp_ms": int(time.time() * 1000),
        "service": "support-agent",
        "environment": "development",
        "trace_id": TRACE_ID,
        "agent_run_id": RUN_ID,
        "agent_version": "2025-03-01",
        "prompt_version": "support-v3",
        "model": "example-model",
        "event_type": event_type,
        **fields,
    }
    logger.info(json.dumps(event, ensure_ascii=False))


@contextmanager
def measured_step(step_name, **attributes):
    started = time.perf_counter()
    emit("step.started", step_name=step_name, **attributes)
    try:
        yield
    except Exception as exc:
        emit(
            "step.failed",
            step_name=step_name,
            duration_ms=round((time.perf_counter() - started) * 1000, 2),
            error_type=type(exc).__name__,
            error_message=str(exc),
            **attributes,
        )
        raise
    else:
        emit(
            "step.completed",
            step_name=step_name,
            duration_ms=round((time.perf_counter() - started) * 1000, 2),
            **attributes,
        )


def lookup_order(order_id):
    time.sleep(0.08)
    return {"order_id": order_id, "status": "shipped"}


def main():
    emit("run.started", input_category="order_status")

    with measured_step("tool_call", tool_name="lookup_order"):
        order = lookup_order("ORDER-1042")
        emit(
            "tool.result",
            tool_name="lookup_order",
            tool_status="success",
            result_summary={"status": order["status"]},
        )

    answer = f"Order {order['order_id']} is {order['status']}."
    emit(
        "evaluation.completed",
        task_completed=True,
        tool_selection_correct=True,
        policy_violation=False,
        quality_score=0.96,
    )
    emit("run.completed", output_length=len(answer))


if __name__ == "__main__":
    main()

运行:

python3 agent_observability.py | tee agent-events.jsonl

接入 CloudWatch Omni 时,可以根据正式文档把 emit() 替换成对应 SDK、日志处理器或遥测导出器。无论最终采用哪种传输方式,都建议保留 trace_id 与 agent_run_id:前者用于连接应用调用链,后者用于聚合 Agent 的多轮推理和工具调用。

生产环境还应补充模型延迟、输入与输出 Token、重试次数、工具调用错误码以及评估器版本。评估规则变化会直接影响分数,因此 evaluator_version 与模型版本一样需要可追踪。

接入前必须划清的数据边界

Agent 遥测很容易包含用户对话、检索文档、工具参数和模型输出。如果不做治理,可观测系统本身可能成为新的敏感数据集中点。

建议在采集侧实施以下规则:

  • 不记录密码、访问令牌、银行卡号等原始值;
  • 对用户 ID、订单号等标识符进行哈希或令牌化;
  • 默认记录提示词和输出的摘要,而不是完整内容;
  • 为调试采样设置时间限制、权限控制和审计记录;
  • 将开发、测试和生产环境的数据隔离;
  • 对日志、链路与评估数据分别设置保留周期;
  • 给高风险工具记录审批结果,但避免保存秘密参数。

还要警惕高基数问题。完整提示词、原始答案和随机会话 ID 不适合作为指标标签,否则会显著增加存储与查询成本。它们更适合进入受控日志或追踪事件,指标标签则应使用模型版本、工具名称、环境和结果类别等有限集合。

采用 CloudWatch Omni 时的检查清单

CloudWatch Omni 展示了一个明确方向:应用健康度与 Agent 行为不应由两套完全分离的系统管理。不过,在正式接入前仍应结合产品文档验证具体能力、区域可用性、权限模型、数据保留方式、价格以及与现有 CloudWatch 和 OpenTelemetry 链路的兼容性。

可以按以下顺序推进:

  1. 选一个工具数量有限、结果容易验证的 Agent 作为试点;
  2. 统一 trace_id、agent_run_id、模型版本和提示词版本;
  3. 同时建立运行指标与质量评估,避免只观察延迟和错误率;
  4. 先定义脱敏、采样与保留策略,再采集完整对话;
  5. 用真实故障演练验证能否从错误答案追踪到具体模型步骤或后端服务;
  6. 比较新增遥测成本与故障定位时间、任务成功率之间的收益。

真正有价值的 Agent 可观测性,不是生成更多日志,而是让团队能从一次异常结果出发,沿着模型推理、工具调用和后端服务找到可执行的原因。CloudWatch Omni 是否适合某个团队,也应由这种端到端排障能力来衡量。


相关推荐