使用 Vercel Sandbox 进行浏览器自动化
在临时的 Vercel Sandbox 微型虚拟机中运行 agent-browser + 无头 Chrome。按需启动 Linux 虚拟机,执行浏览器命令,然后关闭。适用于任何基于 Vercel 部署的框架(Next.js、SvelteKit、Nuxt、Remix、Astro 等)。
依赖
pnpm add @agent-browser/sandbox @vercel/sandbox
Sandbox 虚拟机需要 Chromium 的系统依赖以及 agent-browser 本身。@agent-browser/sandbox 辅助函数默认为全新的 Sandbox 安装这些依赖,并使用 Sandbox 快照(见下文)实现亚秒级启动。仅当 Sandbox 镜像已提供 Chromium 所需的库时,才传递 installSystemDependencies: false。
核心模式
import {
createAgentBrowserSnapshot,
runAgentBrowserCommand,
withAgentBrowserSandbox,
type VercelSandboxSession,
} from "@agent-browser/sandbox/vercel";
async function withBrowser<T>(
fn: (sandbox: VercelSandboxSession) => Promise<T>,
): Promise<T> {
return withAgentBrowserSandbox(fn);
}
截图
screenshot --json 命令将截图保存到文件并返回路径。以 base64 格式读取文件:
export async function screenshotUrl(url: string) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const titleResult = await runAgentBrowserCommand<{ data?: { title?: string } }>(sandbox, [
"get", "title",
]);
const title = titleResult.json?.data?.title || url;
const ssResult = await runAgentBrowserCommand<{ data?: { path?: string } }>(sandbox, [
"screenshot",
]);
const ssPath = ssResult.json?.data?.path;
if (!ssPath) throw new Error("Screenshot did not return a file path.");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { title, screenshot };
});
}
无障碍快照
export async function snapshotUrl(url: string) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const titleResult = await runAgentBrowserCommand<{ data?: { title?: string } }>(sandbox, [
"get", "title",
]);
const title = titleResult.json?.data?.title || url;
const snapResult = await runAgentBrowserCommand(sandbox, ["snapshot", "-i", "-c"], {
json: false,
});
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { title, snapshot: snapResult.stdout };
});
}
多步骤工作流
Sandbox 在命令之间保持持久化,因此您可以运行完整的自动化序列:
export async function fillAndSubmitForm(
url: string,
data: Record<string, string>,
postSubmitWaitArgs: string[],
) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const snapResult = await runAgentBrowserCommand(sandbox, ["snapshot", "-i"], {
json: false,
});
const snapshot = snapResult.stdout;
// 解析快照以查找元素引用...
for (const [ref, value] of Object.entries(data)) {
await runAgentBrowserCommand(sandbox, ["fill", ref, value]);
}
await runAgentBrowserCommand(sandbox, ["click", "@e5"]);
// 传递特定于应用程序的等待条件,例如 ["--url", "**/checkout/complete"],
// ["--text", "Thanks"], 或 ["#confirmation"]。
await runAgentBrowserCommand(sandbox, ["wait", ...postSubmitWaitArgs]);
const ssResult = await runAgentBrowserCommand<{ data?: { path?: string } }>(sandbox, [
"screenshot",
]);
const ssPath = ssResult.json?.data?.path;
if (!ssPath) throw new Error("Screenshot did not return a file path.");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { screenshot };
});
}
Sandbox 快照(快速启动)
Sandbox 快照 是一个已保存的 VM 映像,其中预装了系统依赖、agent-browser 和 Chromium。可以将其视为 Docker 镜像:无需每次都从头安装依赖,Sandbox 从预先构建的映像启动。
这与 agent-browser 的无障碍快照特性(agent-browser snapshot)无关,后者用于转储页面的无障碍树。Sandbox 快照是 Vercel 基础设施中的一个概念,用于实现 VM 的快速启动。
如果没有 Sandbox 快照,每次运行都需要安装系统依赖、agent-browser 和 Chromium(约 30 秒)。使用快照后,启动时间可缩短至亚秒级。
创建 Sandbox 快照
快照必须包含系统依赖(通过 dnf)、agent-browser 和 Chromium:
const snapshotId = await createAgentBrowserSnapshot();
运行一次,然后设置环境变量:
AGENT_BROWSER_SNAPSHOT_ID=snap_xxxxxxxxxxxx
演示应用程序中提供了一个辅助脚本:
npx tsx examples/environments/scripts/create-snapshot.ts
对于任何使用 Sandbox 模式的生产部署,建议采用此方式。
身份验证
在 Vercel 部署上,Sandbox SDK 通过 OIDC 自动进行身份验证。对于本地开发或显式控制,请设置:
VERCEL_TOKEN=<personal-access-token>
VERCEL_TEAM_ID=<team-id>
VERCEL_PROJECT_ID=<project-id>
这些变量会被传递到 Sandbox.create() 调用中。如果不存在,SDK 将回退到 VERCEL_OIDC_TOKEN(在 Vercel 上自动生效)。
定时工作流(Cron)
与 Vercel Cron Jobs 结合,用于重复的浏览器任务:
// app/api/cron/route.ts (或您框架中的等效文件)
export async function GET() {
const result = await withBrowser(async (sandbox) => {
await sandbox.runCommand("agent-browser", ["open", "https://example.com/pricing"]);
const snap = await sandbox.runCommand("agent-browser", ["snapshot", "-i", "-c"]);
await sandbox.runCommand("agent-browser", ["close"]);
return await snap.stdout();
});
// 处理结果,发送告警,存储数据...
return Response.json({ ok: true, snapshot: result });
}
// vercel.json
{ "crons": [{ "path": "/api/cron", "schedule": "0 9 * * *" }] }
环境变量
| 变量 | 是否必需 | 描述 |
|---|---|---|
AGENT_BROWSER_SNAPSHOT_ID | 否(但推荐) | 预构建的 Sandbox 快照 ID,用于亚秒级启动(参见上文) |
VERCEL_TOKEN | 否 | Vercel 个人访问令牌(用于本地开发;在 Vercel 上 OIDC 是自动的) |
VERCEL_TEAM_ID | 否 | Vercel 团队 ID(用于本地开发) |
VERCEL_PROJECT_ID | 否 | Vercel 项目 ID(用于本地开发) |
框架示例
该模式在所有框架中的工作方式相同。唯一的区别在于放置服务器端代码的位置:
| 框架 | 服务器端代码位置 |
|---|---|
| Next.js | 服务器操作、API 路由、路由处理器 |
| SvelteKit | +page.server.ts, +server.ts |
| Nuxt | server/api/, server/routes/ |
| Remix | loader, action 函数 |
| Astro | .astro frontmatter, API 路由 |
示例
有关使用 Vercel Sandbox 模式的工作示例,请参阅 agent-browser 仓库中的 examples/environments/ 目录,其中包含 Sandbox 快照创建脚本、流式进度 UI 和速率限制。