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、平台状态;
- 公开发布:公开地址和页面回读;
- 验收:通过标准与未决风险。
模型说"完成了"只是一条候选声明。只有外部状态和验证证据满足门禁,工作流才能进入下一阶段。
恢复时先侦察现实
一个安全的恢复顺序是:
- 读取最后一个完整检查点;
- 核对输入、代码和产物哈希;
- 查询外部对象当前状态;
- 用事件补齐检查点后的时间线;
- 判断上一步是否已产生副作用;
- 只重放未完成且具备幂等保护的步骤;
- 记录恢复事件并写新检查点。
这个顺序能处理一个典型窗口:平台已经写入成功,但本地在保存结果前崩溃。机械重试会产生重复对象,先查询则能把外部事实补回本地。
比 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 才从"会调用工具的模型"变成工程系统。