跳到正文
Agent 工程实践Observability
返回课程/Agent 工程实践
第 11 / 15 章 约 7 分钟

Observability

还原任务执行链路,定位延迟、成本和错误。

这个模块在 Agent 里的位置

可观测性不是“多打日志”,而是让一次 Agent run:

  1. 可还原。
  2. 可定位。
  3. 可比对。
  4. 可治理。

它要回答:

  • 哪个 run 失败。
  • 失败在模型、工具、数据还是执行器。
  • 调用了多少工具。
  • 上下文为什么膨胀。
  • 成本来自哪个阶段。
  • 压缩后为什么重复查询。

没有观测,prompt 优化和预算治理都是猜。

先记住几个概念

概念含义为什么重要
runId一次逻辑任务 ID贯穿全链路
seq事件顺序支持回放
Event streamappend-only 事件流还原执行过程
Usagetoken 和 cost成本归因
Tool metrics耗时、大小、状态定位工具瓶颈
Sampling高频成功事件采样控制观测成本
Privacy boundary不记录正文和密钥避免泄漏

从一个真实问题开始:用户说“结果错了”,但没人知道错在哪

用户反馈:

这份报告引用了一个不存在的风险窗口。

排查时发现问题:

  1. 模型日志没有 runId。
  2. 工具日志只有“查询成功”。
  3. 上下文压缩没有记录前后大小。
  4. 输出校验失败被吞掉。
  5. 日志里没有引用 ID。

结果只能看到:

ERROR agent failed

这行日志无法回答:

  • 是模型编了引用?
  • 是工具返回错?
  • 是压缩丢了引用?
  • 是 validator 没校验?
  • 是外部数据缺失?

这不是日志量不够,而是事件模型不对。

最小事件集

一个 run 至少要有这些事件:

事件关键字段
run.startedrunId、sessionId、userId、tenantId
prompt.resolvedpromptVersionId
model.startedmodelKind、turnId
model.completedusage、cost、latency
model.failedprovider error、latency
tool.startedtoolName、toolCallId、input summary
tool.completedduration、outputBytes、rows
tool.failederrorCode、retryable
compaction.startedreason、beforeTokens
compaction.endedafterTokens、summary refs
subtask.startedchildAgent、parentRunId
subtask.endedstatus、duration
action.proposedproposalId、actionType、risk
action.approvedapprover、decision
action.executedterminal status
run.finishedstatus、duration、totalCost

这些事件共同构成一次 run 的完整轨迹。

事件必须有序

只记录事件还不够,必须有顺序。

create table agent_run_events (
  id bigint,
  run_id bigint not null,
  tenant_id bigint not null,
  seq int not null,
  event_type text not null,
  payload jsonb not null,
  occurred_at timestamptz not null,
  primary key (id, occurred_at)
) partition by range (occurred_at);

create index agent_run_events_lookup_idx
  on agent_run_events (tenant_id, run_id, seq);

seq 的价值:

  1. 回放时不会乱序。
  2. 并发写入时可检测重复。
  3. 可以判断事件是否缺失。

事件示例

[
    {
        "runId": "run-9f27",
        "seq": 1,
        "type": "run.started",
        "context": {
            "tenantId": 7,
            "sessionId": "session-42"
        }
    },
    {
        "runId": "run-9f27",
        "seq": 2,
        "type": "tool.completed",
        "context": {
            "toolName": "query_top_risk_entities",
            "toolCallId": "call-551",
            "durationMs": 213,
            "inputBytes": 512,
            "outputBytes": 2048,
            "status": "success"
        }
    },
    {
        "runId": "run-9f27",
        "seq": 3,
        "type": "model.completed",
        "context": {
            "turnId": "turn-103",
            "inputTokens": 48200,
            "outputTokens": 1800,
            "latencyMs": 4200
        }
    }
]

这能回答:

  • 哪个工具慢。
  • 哪个 turn 贵。
  • 事件先后顺序。
  • 是否有异常输出大小。

隐私边界

不要记录:

  • 完整 prompt。
  • 完整回复。
  • raw payload。
  • 图片正文。
  • 密钥。

可以记录:

  • 大小。
  • hash。
  • 字段名。
  • ID。
  • 摘要。

例如:

{
    "toolName": "query_events",
    "inputSummary": {
        "startTs": 1790000000000,
        "endTs": 1790086400000,
        "topK": 10
    },
    "inputBytes": 512,
    "outputBytes": 2048,
    "outputHash": "sha256:..."
}

这足以排障,又不暴露正文。

成本归因

一次 run 的成本不止模型 token,还包括:

  1. 模型 usage。
  2. 工具执行成本。
  3. 沙箱资源。
  4. 子 Agent 调用。
  5. 重试成本。

一个汇总事件:

{
    "runId": "run-9f27",
    "totalCost": 0.092,
    "modelCost": 0.071,
    "toolCalls": 12,
    "subagentRuns": 3,
    "durationMs": 84000
}

没有这个数据,就无法判断:

  • prompt 变更是否降低成本。
  • 工具瘦身是否有效。
  • compaction 是否减少重复查询。
  • 子 Agent 是否值得。

采样策略

在 10 万 run / 天、每 run 72 个事件的规模下,不能所有事件全量上传。

建议:

事件类型策略
run started / finished全量
model usage全量
tool failed全量
action executed全量
compaction全量
tool success可采样
高频 debug可采样

失败和成本事件优先保留,成功事件可以采样。

和传统后端的关系

Agent 可观测性并没有脱离传统后端的三大件:

Agent 里的概念传统后端里的对应物
runIdtraceId / requestId
Event stream结构化日志
Usage / cost业务指标
Tool duration下游依赖耗时
失败率error rate
采样日志采样
告警SLO / alerting

区别在于,Agent 还要额外记录模型 token、上下文大小、压缩次数和工具输出大小。

常见工程错误

错误实际后果正确做法
无 runId无法还原链路所有事件带 runId
无 seq回放乱序(runId, seq)
记录全文成本和隐私风险摘要 + hash
只记失败无法优化成本成功也记录
同步上传拖垮业务异步 / 采样
错误无 code无法分类stable errorCode
事件分散无关联无法定位统一事件流

上线前检查

  1. runId 贯穿。
  2. 事件有序。
  3. usage 可归因。
  4. tool 有耗时和大小。
  5. 失败有稳定错误码。
  6. 不记录敏感正文。
  7. 失败可重放。
  8. 高频事件有采样策略。