很多 Agent 浏览器任务跑不稳定,第一眼看像是 prompt、脚本或页面选择器的问题。
但排查一圈后,经常会发现真正的问题在更底层:任务没有稳定的浏览器环境上下文。
同一个 Agent,今天跑在 A Profile,明天跑在 B Profile;Cookie 状态不一致;LocalStorage 关键字段丢了;Proxy 临时切换过;Automation Interface 没有把 workspace、profile 和 session 绑定起来。最后表现出来就是:脚本没明显报错,但结果不可复现。
这篇从工程建模角度聊一个问题:在让 Agent 跑浏览器任务之前,应该怎样把环境上下文设计清楚。
1. Agent 不是直接操作网页,而是在操作环境状态
一个浏览器自动化任务通常不只是:
text
Agent -> Browser -> Page
更真实的链路是:
text
Agent
-> Automation Interface
-> Workspace
-> Browser Profile
-> Session State
-> Proxy / Locale / Timezone
-> Page
-> Logs / Review
如果中间任何一层没有被记录,问题都会在最上层表现成"Agent 不稳定"。
比如:
- Profile 换了,Cookie 和扩展配置随之变化;
- Session 失效了,页面进入登录态或默认态;
- Proxy 策略变化,页面地区、语言、时区表现不一致;
- Automation Interface 没有绑定 profile_id,任务跑进了错误环境;
- 审计日志缺失,无法知道异常前最近一次变更是什么。
所以,Agent workflow 的稳定性,首先是环境层的稳定性。
2. 先定义核心对象
可以先用 TypeScript 描述最小对象模型。
ts
type Workspace = {
id: string;
name: string;
owner: string;
status: "active" | "frozen";
};
type BrowserProfile = {
id: string;
workspaceId: string;
browserVersion: string;
timezone: string;
language: string;
proxyPolicyId: string;
status: "active" | "frozen" | "migrating";
};
type SessionState = {
profileId: string;
cookieStatus: "valid" | "expired" | "unknown";
localStorageStatus: "ready" | "missing" | "unknown";
indexedDbStatus: "ready" | "missing" | "unknown";
lastLoginAt?: string;
lastCheckedAt: string;
};
type ProxyPolicy = {
id: string;
region: string;
exitType: "fixed" | "fallback";
timezone: string;
language: string;
webrtcPolicy: "default" | "restricted";
};
这几个类型解决的是归属问题:
Workspace管业务工作区;BrowserProfile管浏览器环境;SessionState管登录态和本地页面状态;ProxyPolicy管网络、地区、时区、语言等运行条件。
很多项目一开始没有这些对象,只有浏览器目录和一堆脚本。任务少的时候能靠经验,任务多了以后就很难复盘。
3. Automation Job 必须绑定环境上下文
自动化任务不应该只描述"做什么",还应该描述"在哪个环境里做"。
ts
type AutomationJob = {
id: string;
workspaceId: string;
profileId: string;
proxyPolicyId: string;
entrypoint: string;
schedule: string;
status: "enabled" | "paused";
lastRunAt?: string;
};
任务启动前至少做三类校验:
ts
function validateBeforeRun(input: {
job: AutomationJob;
profile: BrowserProfile;
session: SessionState;
proxy: ProxyPolicy;
}) {
const { job, profile, session, proxy } = input;
const reasons: string[] = [];
if (job.profileId !== profile.id) {
reasons.push("profile mismatch");
}
if (profile.workspaceId !== job.workspaceId) {
reasons.push("workspace mismatch");
}
if (profile.proxyPolicyId !== proxy.id || job.proxyPolicyId !== proxy.id) {
reasons.push("proxy policy mismatch");
}
if (session.profileId !== profile.id || session.cookieStatus !== "valid") {
reasons.push("session not ready");
}
if (session.localStorageStatus !== "ready" || session.indexedDbStatus !== "ready") {
reasons.push("local state not ready");
}
return {
ok: reasons.length === 0,
reasons
};
}
这段逻辑不复杂,但它能避免一个常见问题:任务已经开始运行了,才发现环境根本不对。
更好的方式是让任务在环境不满足条件时直接暂停,并把原因写进日志。
4. 把浏览器环境变更写进 AuditLog
Agent workflow 很依赖可复现性。没有审计日志,就很难复现异常。
可以设计一个最小 AuditLog:
ts
type AuditLog = {
id: string;
objectType: "workspace" | "profile" | "session" | "proxy_policy" | "automation_job";
objectId: string;
action: "create" | "update" | "freeze" | "resume" | "run" | "pause";
before?: Record<string, unknown>;
after?: Record<string, unknown>;
operator: string;
createdAt: string;
};
至少记录这些动作:
- Profile 被创建、冻结、迁移;
- Cookie、LocalStorage、IndexedDB 检查结果变化;
- Proxy、时区、语言策略变化;
- Automation Job 被启用、暂停、重试;
- Agent 运行前校验失败原因。
当任务结果异常时,先查最近 24 小时的 AuditLog,通常比直接改 prompt 更有效。
5. 一致性评分可以先做得很轻
不需要一开始就上复杂平台。可以先给工作区算一个简单评分。
ts
type EnvMetrics = {
profileResetCount: number;
sessionInvalidCount: number;
proxySwitchCount7d: number;
envMismatchCount: number;
automationFailureRate: number;
auditGapCount: number;
};
function scoreEnvironment(metrics: EnvMetrics) {
let score = 100;
const reasons: string[] = [];
if (metrics.profileResetCount > 0) {
score -= 20;
reasons.push("profile reset");
}
if (metrics.sessionInvalidCount > 2) {
score -= 20;
reasons.push("session unstable");
}
if (metrics.proxySwitchCount7d > 2) {
score -= 15;
reasons.push("proxy drift");
}
if (metrics.envMismatchCount > 0) {
score -= 25;
reasons.push("env mismatch");
}
if (metrics.automationFailureRate > 0.2) {
score -= 15;
reasons.push("job failure rate high");
}
if (metrics.auditGapCount > 0) {
score -= 10;
reasons.push("audit gap");
}
return {
score,
level: score < 60 ? "critical" : score < 80 ? "warning" : "normal",
reasons
};
}
评分不是为了绝对准确,而是为了让排查有入口。
当某个工作区出现连续失败,可以先看 reasons:到底是 Profile 变了,Session 不稳定,Proxy 有漂移,还是自动化任务没有绑定正确环境。
6. 推荐的 Agent workflow
一个更稳的流程可以这样设计:
text
1. Agent 接收任务
2. 读取 workspace_id
3. 查询 BrowserProfile 和 ProxyPolicy
4. 检查 SessionState
5. 执行 validateBeforeRun
6. 校验通过才打开浏览器页面
7. 运行任务并记录关键步骤
8. 输出结果和 AuditLog
9. 异常时暂停任务,而不是继续重试
这里最关键的是第 5 步。
很多系统会把校验放在失败后补做,但对 Agent 任务来说,前置校验更重要。因为任务一旦在错误环境里运行,后面的日志也会被污染。
7. 工具层应该解决什么
工具层不应该只是"能打开浏览器"。对 Agent 浏览器任务来说,更有价值的是:
- 管理 Profile 与 workspace 的映射;
- 保留 SessionState 的检查结果;
- 约束 Proxy、时区、语言等运行条件;
- 给 Automation Interface 提供稳定环境上下文;
- 记录每一次环境变更和任务运行结果。
如果团队需要把这些能力放到一个工作台里,可以参考 Web4Browser 这类面向 AI Agent 的浏览器环境思路。它适合作为一种观察样本:把 Profile、Proxy、Agent workflow 和本地优先的数据控制放进同一套工作台,而不是让每个脚本各自管理环境。
8. Review checklist
接入 Agent 浏览器任务前,可以先过一遍:
| 检查项 | 通过标准 |
|---|---|
| Workspace 是否明确 | 任务知道自己属于哪个工作区 |
| Profile 是否固定 | job.profileId 能匹配 BrowserProfile |
| Session 是否可用 | Cookie、LocalStorage、IndexedDB 状态 ready |
| ProxyPolicy 是否一致 | Profile、Job、Proxy 三者映射一致 |
| Automation Interface 是否有前置校验 | 环境不满足时暂停任务 |
| AuditLog 是否完整 | 能追溯最近变更和失败原因 |
| Review 是否可复现 | 能根据日志重跑或定位问题 |
结尾
Agent 浏览器任务的稳定性,不只取决于模型和脚本。
如果 Profile、Session、Proxy、Automation Interface 和 AuditLog 没有建模,任务规模一大,所有问题都会在最上层表现成"Agent 不稳定"。
先把环境上下文做稳,再让 Agent 跑任务,后面的调试会轻很多。