AI Agent 可观测性不只是日志:一套可回放的多步执行链

AI Agent 可观测性不只是日志:一套可回放的多步执行链

很多 Agent 项目已经有 Trace、Token、耗时和调用链面板,但一遇到外部写入超时,团队还是只能问一句:"它到底执行成功了吗?"

这说明系统解决了日志展示,还没有解决工程恢复。

我更愿意把 Agent 可观测性定义为一种恢复能力:多步任务中断后,系统能解释停在哪一步、已经产生哪些副作用、下一步是否能安全重放,并用客观证据判断任务是否完成。

这篇文章给出一个最小实现:追加式事件日志、原子检查点、幂等写入和证据门。

观察对象应该是 task → run → step → attempt

只保存 Prompt 和 Response,会遗漏最关键的工程事实:工具是否真正发出、超时发生在写入前还是写入后、外部对象是否已经存在、重试会不会重复副作用。

因此一次执行至少需要四级标识:

  • task_id:稳定业务任务;
  • run_id:一次启动或恢复;
  • step_id:工作流步骤;
  • attempt:该步骤的第几次尝试。

用追加事件记录时间线

python 复制代码
from dataclasses import asdict, dataclass
from datetime import datetime, timezone
import json
from pathlib import Path


@dataclass(frozen=True)
class Event:
    task_id: str
    run_id: str
    step_id: str
    attempt: int
    kind: str
    status: str
    artifact_hash: str | None = None
    external_id: str | None = None
    error_code: str | None = None


def append_event(path: Path, event: Event) -> None:
    record = asdict(event) | {
        "occurred_at": datetime.now(timezone.utc).isoformat()
    }
    with path.open("a", encoding="utf-8") as stream:
        stream.write(json.dumps(record, ensure_ascii=False) + "\n")
        stream.flush()

事件负责回答"发生过什么"。字段要结构化,但不要无边界记录完整 Prompt、Cookie、Token、个人数据或业务正文。生产环境通常只需保留标识、状态、耗时、用量、错误码与脱敏摘要。

检查点保存事实,不保存模型总结

检查点负责快速恢复,应该包含当前步骤、确认过的输入、完成的副作用、证据哈希、重试次数和未决问题。

json 复制代码
{
  "task_id": "publish-20260811-01",
  "run_id": "run-03",
  "workflow_version": "2",
  "current_step": "verify_public_page",
  "confirmed_inputs": {"article_sha256": "..."},
  "completed_effects": [
    {"kind": "platform_publish", "external_id": "article-123"}
  ],
  "retry_count": 1,
  "pending_issue": "public page read timed out"
}

"已经发布"不是事实,外部对象 ID、公开地址和回读状态才是。

检查点还必须原子写入:

python 复制代码
import json
import os
from pathlib import Path


def write_checkpoint(path: Path, payload: dict) -> None:
    temporary = path.with_suffix(".tmp")
    temporary.write_text(
        json.dumps(payload, ensure_ascii=False, indent=2),
        encoding="utf-8",
    )
    with temporary.open("rb") as stream:
        os.fsync(stream.fileno())
    temporary.replace(path)

临时文件加原子替换,可以避免进程中断后留下半份 JSON。

幂等性决定能不能重放

只读查询通常可以重试,创建文章、发送消息、扣费和删除数据则可能重复产生副作用。

python 复制代码
from dataclasses import dataclass
import hashlib


@dataclass(frozen=True)
class PublishRequest:
    task_id: str
    artifact_hash: str
    idempotency_key: str


def publish_key(task_id: str, artifact_hash: str) -> str:
    raw = f"publish:{task_id}:{artifact_hash}".encode()
    return hashlib.sha256(raw).hexdigest()

外部写入超时后,第一动作应该是查询,而不是再次创建。超时只代表调用方没有收到确定结果,不代表平台没有执行。

服务端或适配层应该保证同一个幂等键只对应一个最终对象,并能查询已有结果。如果外部系统没有幂等能力、也无法读取最终状态,自动流程应该暂停并转人工。

完成不是一句话,而是一道证据门

每个阶段都定义自己的完成证据:

  • 写作:目标文件、摘要、哈希;
  • 审查:问题和证据位置;
  • 验证:命令、退出码、输出;
  • 外部写入:幂等键、对象 ID、平台状态;
  • 公开发布:公开地址和页面回读;
  • 验收:通过标准与未决风险。

模型说"完成了"只是一条候选声明。只有外部状态和验证证据满足门禁,工作流才能进入下一阶段。

恢复时先侦察现实

一个安全的恢复顺序是:

  1. 读取最后一个完整检查点;
  2. 核对输入、代码和产物哈希;
  3. 查询外部对象当前状态;
  4. 用事件补齐检查点后的时间线;
  5. 判断上一步是否已产生副作用;
  6. 只重放未完成且具备幂等保护的步骤;
  7. 记录恢复事件并写新检查点。

这个顺序能处理一个典型窗口:平台已经写入成功,但本地在保存结果前崩溃。机械重试会产生重复对象,先查询则能把外部事实补回本地。

比 Token 和延迟更重要的指标

text 复制代码
step_success_rate
attempts_per_step
unknown_external_state_count
checkpoint_recovery_success_rate
duplicate_effect_prevented_count
human_takeover_rate
evidence_gate_failure_count

Token、耗时和成本描述资源消耗;这些指标才描述系统是否可恢复、失败是否受控、证据是否充分。

最后

Agent 可观测性不应止步于一张漂亮的 Trace 瀑布图。

真正可运行的闭环是:事件记录时间线,检查点保存事实,幂等键保护副作用,证据门约束完成声明,恢复前先查询现实。

当一次多步执行能够被解释、被恢复、被验证,Agent 才从"会调用工具的模型"变成工程系统。

相关推荐
Asize31 分钟前
AI 协作开发新范式:我用 SDD 做了个排版 npm 包
前端·人工智能
IT_陈寒3 小时前
用了Proxy才发现以前的JavaScript白写了
前端·人工智能·后端
唐青枫3 小时前
别把 ArrayList 当成会自动管理内存的 List:Zig 动态数组从入门到实战
后端
甲维斯3 小时前
Claude Opus5手搓“NewAPI Plus”首轮成果!
人工智能
程序猿DD3 小时前
分享两个我每天都在用的 Skill,拖进豆包就能跑,限时领 30 天会员
人工智能
鸿蒙开发3 小时前
我为 HarmonyOS 做了一个统一大模型 SDK:@hmkit/ai 正式开源
后端
猪是念来过倒3 小时前
Semaphore 与 RateLimiter:并发控制双雄详解
后端
阿里云大数据AI技术4 小时前
Agentic Search 2.0:从单轮对话迈向企业级 AI 搜索自动驾驶Agent
人工智能·elasticsearch·agent
掘金者阿豪4 小时前
异构数据同步最怕什么?不是同步慢,而是数据对不上
后端
东风破_4 小时前
从 messages 数组到 Memory:大模型到底是怎么“记住”上一轮对话的?
人工智能