Skip to content

使用 AI 驱动的浏览器智能体自动化复杂工作流。

文档索引

可在此获取完整文档索引:https://docs.stagehand.dev/llms.txt

在进一步浏览前,可使用该文件发现所有可用页面。

使用 AI 驱动的浏览器智能体自动化复杂工作流。

await agent.execute("在 Browserbase 申请一份工作")

agent 会把高层级任务转换为全自主的浏览器工作流。你可以通过指定 LLM 提供商与模型、设置行为用的自定义指令,以及配置最大步数,来定制这个智能体。

Agent

视觉理解

像人类一样通过计算机视觉查看并理解 Web 界面。

查看原文

在 Stagehand 中,有三种方式创建 Agent:

  1. 使用 Computer Use Agent(CUA 模式)
  2. 使用任意 LLM 的 Agent(DOM 模式)
  3. 使用视觉与 DOM 的 Agent(Hybrid 混合模式)

某些高级特性仅在特定 Agent 模式下可用:

功能CUADOMHybrid
基础执行
自定义工具
MCP 集成
系统提示词
变量
流式输出
回调
Abort signal
消息续接
排除工具
结构化输出
基于 DOM 的动作
基于坐标的动作
可视光标高亮

你可以像下面这样使用来自 Google、OpenAI、Anthropic 或 Microsoft 的专用 computer-use 模型,并将 mode 设置为 "cua"。若要比较不同 computer-use 模型的表现,可以访问它们的 evals 页面

const agent = stagehand.agent({
mode: "cua",
model: "google/gemini-3-flash-preview",
systemPrompt: "You are a helpful assistant...",
});
await agent.execute({
instruction: "Go to Hacker News and find the most controversial post from today, then read the top 3 comments and summarize the debate.",
maxSteps: 20,
highlightCursor: true
})

将 Stagehand Agent 与任意 LLM 搭配使用

Section titled “将 Stagehand Agent 与任意 LLM 搭配使用”

不指定 provider 也可以使用 agent,从而接入任意模型或 LLM 提供商:

const agent = stagehand.agent();
await agent.execute("在 Browserbase 申请一份工作")

可用的 Agent 模型

查看如何在 Stagehand Agent 中使用不同模型的指南。

查看原文

DOM 模式与 CUA 模式各有优缺点。Hybrid 模式将两者结合,让 Agent 同时访问基于坐标与基于 DOM 的工具,更好地弥补各自短板。

const stagehand = new Stagehand({
env: "BROWSERBASE",
experimental: true, // Hybrid 模式必需
});
await stagehand.init();
const agent = stagehand.agent({
mode: "hybrid",
model: "google/gemini-3-flash-preview",
});
const page = stagehand.context.pages()[0];
await page.goto("https://example.com");
await agent.execute({
instruction: "Click the sign up button and fill out the registration form",
maxSteps: 20,
});

当你使用 agent() 时,Stagehand 会返回一个 Promise<AgentResult>,结构如下:

{
success: true,
message: "The first name and email fields have been filled successfully with 'John' and 'john@example.com'.",
actions: [
{
type: 'ariaTree',
reasoning: undefined,
taskCompleted: true,
pageUrl: 'https://example.com',
timestamp: 1761598722055
},
{
type: 'act',
reasoning: undefined,
taskCompleted: true,
action: 'type "John" into the First Name textbox',
playwrightArguments: {...},
pageUrl: 'https://example.com',
timestamp: 1761598731643
},
{
type: 'close',
reasoning: "The first name and email fields have been filled successfully.",
taskCompleted: true,
taskComplete: true,
pageUrl: 'https://example.com',
timestamp: 1761598732861
}
],
completed: true,
// 仅在提供 `output` schema 时填充(仅 DOM / Hybrid 模式)
output: {
price: "$199",
airline: "Delta"
},
usage: {
input_tokens: 2040,
output_tokens: 28,
reasoning_tokens: 12,
cached_input_tokens: 0,
inference_time_ms: 14079
}
}

Stagehand Agent 自带浏览器自动化工具,但你也可以通过添加自己的自定义工具或排除内置工具来定制工具集。

自定义工具可以为 Agent 增加额外能力,以获得更细粒度的控制和更好的性能。与 MCP 集成不同,自定义工具是内联定义的,并且直接在你的应用内部执行。

使用 @browserbasehq/stagehand 导出的 tool 辅助函数来定义自定义工具:

import { tool } from "@browserbasehq/stagehand";
import { z } from "zod";
const agent = stagehand.agent({
model: "openai/gpt-5",
tools: {
getWeather: tool({
description: 'Get the current weather in a location',
inputSchema: z.object({
location: z.string().describe('The location to get weather for'),
}),
execute: async ({ location }) => {
// 在这里编写你的自定义逻辑
const weather = await fetchWeatherAPI(location);
return {
location,
temperature: weather.temp,
conditions: weather.conditions,
};
},
}),
},
systemPrompt: 'You are a helpful assistant with access to weather data.',
});
await agent.execute("What's the weather in San Francisco and should I bring an umbrella?");
自定义工具MCP 集成
与你的代码内联定义连接到外部服务
直接执行函数标准化协议
性能更好、上下文更优化可跨应用复用
TypeScript 类型安全可访问预构建集成
细粒度控制基于网络的通信

阻止 Agent 在执行期间使用某些特定的内置工具。当你希望限制 Agent 能力,或避免某些行为时,这很有用。

const stagehand = new Stagehand({
env: "LOCAL",
experimental: true, // excludeTools 必需
});
await stagehand.init();
const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
});
const page = stagehand.context.pages()[0];
await page.goto("https://example.com");
// 排除 screenshot 与 extract 工具
const result = await agent.execute({
instruction: "Navigate through the website and click the submit button",
maxSteps: 15,
excludeTools: ["screenshot", "extract"],
});

你可以排除哪些工具,取决于 Agent 的模式:

工具说明
act执行语义动作(点击、输入等)
fillForm使用 DOM 选择器填写表单字段
ariaTree获取页面的无障碍树
extract从页面提取结构化数据
goto导航到 URL
scroll使用语义方向滚动(上 / 下 / 左 / 右)
keys按下键盘按键
navback在历史记录中后退
screenshot截图
thinkAgent 推理 / 规划步骤
wait按时间或条件等待
searchWeb 搜索(需要 useSearch: trueBROWSERBASE_API_KEY
// 阻止 Agent 在执行期间截图
const result = await agent.execute({
instruction: "Fill out the contact form",
excludeTools: ["screenshot"],
});
// 阻止 Agent 提取数据
const result = await agent.execute({
instruction: "Click through the signup flow",
excludeTools: ["extract"],
});
// 禁用 Web 搜索能力
const result = await agent.execute({
instruction: "Find information on the current page",
excludeTools: ["search"],
});

agent.execute() 中设置 useSearch: true,即可启用 search 工具。这会让 Agent 能够使用 Browserbase Search API 执行 Web 搜索,当 Agent 需要在导航前先查找 URL 或收集信息时非常有用。

const result = await agent.execute({
instruction: "Find the latest pricing for Browserbase",
useSearch: true,
maxSteps: 20,
});

使用变量可以把敏感数据(例如密码、API key 或个人信息)传给 Agent,而不会把真实值暴露给 LLM。Agent 只能看到变量名与描述,实际值会在运行时替换进去。

const stagehand = new Stagehand({
env: "LOCAL",
});
await stagehand.init();
const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
});
const page = stagehand.context.pages()[0];
await page.goto("https://example.com/login");
const result = await agent.execute({
instruction: "Log into the website using my credentials",
maxSteps: 10,
variables: {
username: {
value: "john@example.com",
description: "The user's email address for login"
},
password: {
value: process.env.USER_PASSWORD,
description: "The user's password for login"
}
}
});

变量与 act() 使用相同的类型。你可以传入简单值,也可以传入带描述的富对象:

// 简单值(与 act 相同的格式)
variables: {
username: "john@example.com",
password: "secret123",
}
// 带描述的富值(帮助 Agent 理解上下文)
variables: {
username: { value: "john@example.com", description: "The login email" },
password: { value: "secret123", description: "The login password" },
}
  1. LLM 只接收描述: Agent 会在系统提示词中看到变量名和描述,但永远看不到真实值。
  2. 占位符语法: 当 LLM 需要使用变量时,会使用 %variableName% 语法(例如:"type %password% into the password field")。
  3. 运行时替换: 真实值会在动作执行前的最后一刻被替换进去。
  4. 安全日志: 变量值永远不会出现在日志或工具输出中。

变量可与以下 Agent 工具配合使用:

工具用法
act在动作描述中使用 %variableName%
fillForm在字段值中使用 %variableName%

变量在设计上就对缓存友好:

  • 缓存键只使用变量名,不使用变量值。
  • 改变变量值(例如不同密码)不会使缓存执行失效。
  • 这使你能够用不同凭据高效重放同一个工作流。
// 对敏感数据使用变量
variables: {
apiKey: {
value: process.env.API_KEY,
description: "API key for authentication"
}
}

Agent 可以通过 MCP(Model Context Protocol,模型上下文协议)集成外部工具与服务来增强能力。这让你的 Agent 不仅能做浏览器交互,还能访问外部 API 与数据源。

const agent = stagehand.agent({
mode: "cua",
model: "openai/computer-use-preview",
integrations: [
`https://mcp.exa.ai/mcp?exaApiKey=${process.env.EXA_API_KEY}`,
],
systemPrompt: `You have access to web search through Exa. Use it to find current information before browsing.`
});
await agent.execute("Search for the best headphones of 2025 and go through checkout for the top recommendation");

启用流式模式后,你可以接收 Agent 的增量响应。这对于构建实时 UI 很有用,因为你可以在 Agent 推进过程中展示它的推理与状态。

在 Agent 配置中设置 stream: true 以启用流式输出:

const stagehand = new Stagehand({
env: "LOCAL",
experimental: true, // streaming 必需
});
await stagehand.init();
const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
stream: true, // 启用流式模式
});
const streamResult = await agent.execute({
instruction: "Search for headphones on Amazon",
maxSteps: 20,
});
// 增量输出文本流
for await (const delta of streamResult.textStream) {
process.stdout.write(delta);
}
// 流结束后获取最终结果
const finalResult = await streamResult.result;
console.log("Completed:", finalResult.completed);

启用流式输出后,execute() 会返回一个 AgentStreamResult,包含:

属性类型说明
textStreamAsyncIterable<string>Agent 的增量文本输出
fullStreamAsyncIterable<StreamPart>包含工具调用与消息在内的全部流事件
resultPromise<AgentResult>流结束后的最终结果
// 输出所有内容(工具调用、消息等)
for await (const event of streamResult.fullStream) {
console.log(event);
}

回调允许你接入 Agent 的执行生命周期,以便监控进度、记录事件或修改行为。

stream: false(默认)时,可使用以下回调:

回调说明
prepareStep在每个 LLM 步骤前调用,用于修改设置
onStepFinish在每个步骤完成时调用
const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
});
await agent.execute({
instruction: "Fill out the contact form",
maxSteps: 10,
callbacks: {
prepareStep: async (stepContext) => {
console.log(`Starting step ${stepContext.stepNumber}`);
return stepContext; // 返回修改后的或原始上下文
},
onStepFinish: async (event) => {
console.log(`Step finished: ${event.finishReason}`);
if (event.toolCalls) {
for (const tc of event.toolCalls) {
console.log(`Tool called: ${tc.toolName}`);
}
}
},
},
});

你可以通过 AbortSignal 随时取消 Agent 执行。这对于实现超时控制或允许用户手动停止长任务非常有用。

const stagehand = new Stagehand({
env: "LOCAL",
experimental: true, // abort signal 必需
});
await stagehand.init();
const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
});
const controller = new AbortController();
// 设置 30 秒超时
setTimeout(() => controller.abort(), 30000);
try {
const result = await agent.execute({
instruction: "Complete a complex multi-step task",
maxSteps: 50,
signal: controller.signal,
});
} catch (error) {
if (error.name === "AgentAbortError") {
console.log("Task was cancelled");
}
}

Abort signal 也适用于流式模式:

const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
stream: true,
});
const controller = new AbortController();
const streamResult = await agent.execute({
instruction: "Describe every element on the page",
maxSteps: 50,
signal: controller.signal,
callbacks: {
onAbort: (event) => {
console.log(`Aborted after ${event.steps.length} steps`);
},
},
});
// 收到 10 个分块后中止
let chunkCount = 0;
for await (const delta of streamResult.textStream) {
process.stdout.write(delta);
chunkCount++;
if (chunkCount >= 10) {
controller.abort();
break;
}
}
// result promise 会以 AgentAbortError 拒绝
try {
await streamResult.result;
} catch (error) {
console.log("Stream was aborted:", error.message);
}

你可以在中止时传入原因:

controller.abort("User cancelled the operation");
// 错误消息会包含你的原因
// Error: "User cancelled the operation"

通过把上一次结果中的 messages 传回去,你可以在多次 Agent 执行之间延续对话。这对于多轮交互,或在保持上下文的前提下把复杂任务拆成多个步骤,非常有用。

const stagehand = new Stagehand({
env: "LOCAL",
experimental: true, // message continuation 必需
});
await stagehand.init();
const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
});
const page = stagehand.context.pages()[0];
await page.goto("https://example.com/products");
// 第一次执行:搜索产品
const firstResult = await agent.execute({
instruction: "Search for wireless headphones and note the top 3 results",
maxSteps: 10,
});
console.log("First task:", firstResult.message);
// 延续相同上下文:继续追问
const secondResult = await agent.execute({
instruction: "Now filter by price under $100 and tell me which of those 3 are still available",
maxSteps: 10,
messages: firstResult.messages, // 传入上一轮对话
});
console.log("Follow-up:", secondResult.message);
// 继续基于历史上下文执行动作
const thirdResult = await agent.execute({
instruction: "Add the cheapest one to the cart",
maxSteps: 10,
messages: secondResult.messages, // 串联会话
});
console.log("Final action:", thirdResult.message);

定义一个 Zod schema,以便在 Agent 完成任务时接收结构化数据。当你需要从 Agent 执行结果中提取特定信息(例如价格、日期或其他结构化数据)时,这很有用。

import { z } from "zod";
const stagehand = new Stagehand({
env: "LOCAL",
experimental: true, // structured output 必需
});
await stagehand.init();
const agent = stagehand.agent({
model: "anthropic/claude-sonnet-4-5-20250929",
});
const page = stagehand.context.pages()[0];
await page.goto("https://www.google.com/flights");
const result = await agent.execute({
instruction: "Find the cheapest flight from NYC to LA for next week",
maxSteps: 20,
output: z.object({
price: z.string().describe("The price of the flight"),
airline: z.string().describe("The airline name"),
departureTime: z.string().describe("Departure time"),
arrivalTime: z.string().describe("Arrival time"),
}),
});
// 访问结构化输出
console.log(result.output);
// { price: "$199", airline: "Delta", departureTime: "8:00 AM", arrivalTime: "11:30 AM" }

你可以通过 maxSteps 参数控制 Agent 为完成任务最多可以执行多少步。

// 设置 maxSteps,以控制 Agent 最多能执行多少个动作
await agent.execute({
instruction: "Sign me up for a library card",
maxSteps: 15 // 如果任务未完成,Agent 会在 15 步后停止
});

遵循这些最佳实践可以提升 Agent 的成功率、减少执行时间,并尽量降低任务完成过程中的意外错误。

在执行任务之前,先导航到目标页面:

await page.goto('https://github.com/browserbase/stagehand');
await agent.execute('Get me the latest PR on the stagehand repo');

提供更详细的指令,通常能得到更好的结果:

await agent.execute("Find Italian restaurants in Brooklyn that are open after 10pm and have outdoor seating");
Agent 会在完成任务前停止

问题: Agent 在完成你要求的任务前就停止了。

解决方案:

  • 检查 Agent 是否触发了 maxSteps 上限(默认是 20)。
  • 对复杂任务提高 maxSteps:例如 maxSteps: 30 或更高。
  • 将非常复杂的任务拆成更小的连续执行。
// 对复杂任务提高 maxSteps
await agent.execute({
instruction: "Complete the multi-page registration form with all required information",
maxSteps: 40 // 为复杂任务提高上限
});
// 或拆成更小的任务,并检查成功状态
const firstResult = await agent.execute({
instruction: "Fill out page 1 of the registration form",
maxSteps: 15
});
// 只有第一次成功才继续
if (firstResult.success === true) {
await agent.execute({
instruction: "Navigate to page 2 and complete remaining fields",
maxSteps: 15
});
} else {
console.log("First task failed, stopping execution");
}
Agent 无法点击正确的元素

问题: Agent 点击了错误的元素,或无法与正确的 UI 组件交互。

解决方案:

  • 确保使用合适的视口尺寸:Stagehand 默认使用 1288x711(对 Computer Use 模型最优)。
  • 尽量避免修改视口尺寸,因为其他尺寸可能降低性能。

Act

高效执行基于 observe 结果的动作。

查看原文

Extract

从观察到的元素中提取结构化数据。

查看原文

-
0:000:00