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

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

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

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

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

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

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

text 复制代码
Agent
  -> Automation Interface
  -> Browser Profile
  -> Session State
  -> Proxy Policy
  -> Page State
  -> Result

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

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

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

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

2. 定义 RunTrace

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

ts 复制代码
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 打开浏览器前,先保存环境快照。

ts 复制代码
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;
};

任务启动前做一次校验:

ts 复制代码
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

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

ts 复制代码
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

失败原因最好结构化。

ts 复制代码
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 };

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

ts 复制代码
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 里,人工复核不是拖慢效率,而是控制风险。

ts 复制代码
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. 一个推荐的数据流

text 复制代码
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 才更像工程系统,而不是一次性脚本。

相关推荐
柒瑞4 小时前
Superpowers结合Claude code浅实战
前端
Nian.Baikal4 小时前
从零搭建离线地图服务:Nginx + Cesium/Leaflet 实战指南
运维·前端·nginx
前端毕业班4 小时前
uniapp web 灵活控制 style scoped
前端·javascript·vue.js
lichenyang4534 小时前
鸿蒙业务需求实战:AI 问题走马灯卡片实现复盘
前端
ZTStory4 小时前
mise 一款可以在项目中独立管理语言、环境变量和任务的工具
前端·rust·命令行
雁北向4 小时前
骨架屏 巴飞特 测试
前端
吴佳浩4 小时前
用 Stitch 实现 AI 前端工程化:找回消失的UI美学(别再 Vibe 瞎Coding 了)
前端·人工智能·llm
lichenyang4534 小时前
鸿蒙业务 UI 实战复盘:AI 问题走马灯卡片与 ArkTS 基础语法
前端
张元清5 小时前
在 React 里写动画又不跟渲染周期较劲:useRafFn、useRafState、useFps、useDevicePixelRatio、useUpdate
前端·javascript·面试