给 Agent Browser Workflow 加一层可观测性:Trace、Snapshot 和 Review Queue

0 阅读5分钟

Agent Browser Workflow 的一个典型问题是:任务跑完了,但你不知道它到底经历了什么。

传统脚本至少会在异常点抛错。Agent 不一样,它可能会基于页面内容继续判断、跳过某个步骤、得出一个看似合理但不符合预期的结果。

如果没有 Trace、环境快照和复核入口,最后排查时只剩一句话:这次结果不对。

这篇聊一个工程化做法:给 Agent 浏览器任务补一层可观测性。

1. 问题不是 Agent 不稳定,而是现场不可见

很多问题看起来像模型或脚本问题,实际是运行现场不可见。

Agent
  -> Automation Interface
  -> Browser Profile
  -> Session State
  -> Proxy Policy
  -> Page State
  -> Result

任何一层变化,都会影响最终结果。

如果只保存最终输出,不保存中间证据,就无法回答:

  • Agent 当时看到了什么页面;
  • 浏览器是否处于登录态;
  • Profile 是否和预期一致;
  • Proxy、时区、语言是否变化;
  • 哪一步开始偏离预期;
  • 是否应该进入人工复核。

所以要做的不是单纯增加日志,而是记录能复盘的上下文。

2. 定义 RunTrace

先给每次任务运行一个统一对象。

type RunTrace = {
  runId: string;
  jobId: string;
  workspaceId: string;
  profileId: string;
  startedAt: string;
  finishedAt?: string;
  status: "running" | "success" | "failed" | "paused";
  environmentSnapshotId: string;
  stepEvidenceIds: string[];
  failureReason?: FailureReason;
  reviewQueueId?: string;
};

RunTrace 的作用是把环境、步骤、失败原因和复核记录串起来。

没有它,日志、截图和 Agent 输出会散落在不同地方,很难还原一次任务。

3. 运行前保存 EnvironmentSnapshot

Agent 打开浏览器前,先保存环境快照。

type EnvironmentSnapshot = {
  id: string;
  workspaceId: string;
  profileId: string;
  browser: {
    version: string;
    timezone: string;
    language: string;
    viewport: string;
  };
  session: {
    cookieStatus: "valid" | "expired" | "unknown";
    localStorageStatus: "ready" | "missing" | "unknown";
    indexedDbStatus: "ready" | "missing" | "unknown";
  };
  proxy: {
    policyId: string;
    region: string;
    exitType: "fixed" | "fallback";
  };
  createdAt: string;
};

任务启动前做一次校验:

function canStart(snapshot: EnvironmentSnapshot) {
  const reasons: string[] = [];

  if (snapshot.session.cookieStatus !== "valid") {
    reasons.push("cookie invalid");
  }

  if (snapshot.session.localStorageStatus !== "ready") {
    reasons.push("localStorage missing");
  }

  if (snapshot.session.indexedDbStatus !== "ready") {
    reasons.push("indexedDB missing");
  }

  return {
    ok: reasons.length === 0,
    reasons
  };
}

如果环境不满足条件,任务应该 paused,而不是继续跑。

4. 每个关键步骤保存 StepEvidence

不需要记录每一个鼠标移动,但关键步骤要保留证据。

type StepEvidence = {
  id: string;
  runId: string;
  stepIndex: number;
  action: "open" | "click" | "type" | "read" | "submit" | "wait" | "review";
  target?: string;
  url: string;
  pageTitle?: string;
  beforeScreenshot?: string;
  afterScreenshot?: string;
  assertion?: string;
  result: "passed" | "failed" | "skipped" | "uncertain";
  agentReason?: string;
  createdAt: string;
};

推荐保存截图的场景:

  • 进入关键页面后;
  • 执行提交、保存、删除等高影响操作前;
  • 断言失败时;
  • Agent 判断不确定时;
  • 进入人工复核队列前。

这样排查时不需要完全依赖日志文本,可以直接看到页面现场。

5. FailureReason 不要只有 failed

失败原因最好结构化。

type FailureReason =
  | { type: "session_invalid"; message: string }
  | { type: "env_mismatch"; message: string }
  | { type: "page_changed"; message: string }
  | { type: "action_timeout"; message: string }
  | { type: "agent_uncertain"; message: string }
  | { type: "permission_blocked"; message: string }
  | { type: "unknown"; message: string };

一个简单分类器可以这样写:

function classifyFailure(input: {
  snapshot: EnvironmentSnapshot;
  lastStep?: StepEvidence;
}): FailureReason | undefined {
  const { snapshot, lastStep } = input;

  if (snapshot.session.cookieStatus !== "valid") {
    return { type: "session_invalid", message: "cookie is not valid" };
  }

  if (snapshot.session.localStorageStatus !== "ready") {
    return { type: "env_mismatch", message: "localStorage is not ready" };
  }

  if (lastStep?.result === "uncertain") {
    return { type: "agent_uncertain", message: "agent needs review" };
  }

  if (lastStep?.result === "failed") {
    return { type: "page_changed", message: "step assertion failed" };
  }
}

这个分类不必一开始就特别精确,但它能让排查方向从“全都查一遍”变成“先查最可能的层”。

6. ReviewQueue 是 Agent Workflow 的安全阀

Agent workflow 里,人工复核不是拖慢效率,而是控制风险。

type ReviewItem = {
  id: string;
  runId: string;
  stepEvidenceId: string;
  reason: "high_impact_action" | "agent_uncertain" | "env_mismatch";
  status: "pending" | "approved" | "rejected";
  reviewer?: string;
  createdAt: string;
  resolvedAt?: string;
};

建议触发 review 的场景:

场景动作
环境快照不一致暂停任务
Agent 判断不确定进入复核队列
高影响操作操作前复核
连续失败暂停并要求查看 Trace
失败原因 unknown保存现场并人工分类

对团队来说,这比无限重试更可靠。

7. 一个推荐的数据流

create RunTrace
  -> collect EnvironmentSnapshot
  -> canStart(snapshot)
  -> run Agent steps
  -> collect StepEvidence
  -> classify FailureReason
  -> push ReviewQueue if needed
  -> finalize RunTrace

这里最重要的是两个关口:

  1. 环境不满足条件时,不要开始任务;
  2. Agent 不确定或操作影响较大时,不要直接继续。

这两个关口能避免很多不可复现问题。

8. 工具层应该怎么配合

工具层需要承担的不是“替 Agent 做决定”,而是给 Agent 提供稳定上下文。

它应该能管理:

  • Profile 与 workspace 的绑定;
  • SessionState 与本地状态检查;
  • ProxyPolicy、时区、语言;
  • RunTrace 与 StepEvidence;
  • FailureReason 分类;
  • ReviewQueue 与人工复核;
  • 团队可读的审计记录。

Web4Browser 这类Agent-ready browser environment 的一种实现方向可以作为观察样本:把浏览器环境、Agent workflow、Profile 管理和本地优先的数据控制放到同一套工作台里,而不是让每个脚本各自保存上下文。

9. Review checklist

检查项通过标准
RunTrace 是否存在每次任务有独立 runId
EnvironmentSnapshot 是否完整Profile、Session、Proxy 信息齐全
StepEvidence 是否可读关键步骤有截图或状态记录
FailureReason 是否分类不只写 failed
ReviewQueue 是否接入高影响操作和不确定判断可暂停
AuditLog 是否可追溯能看到最近环境变更
团队成员是否能复盘不依赖原作者口头解释

结尾

Agent 浏览器任务的稳定性,不只是模型能力问题。

如果没有 Trace、Snapshot 和 Review Queue,任务一旦出错,就会变成不可复现问题。

把现场留下来,把失败分类,把高影响操作交给复核,Agent workflow 才更像工程系统,而不是一次性脚本。