Stagehand:Web自动化AI框架

StagehandPlaywright 的 AI 继任者,提供三个简单的 API( actextractobserver),为自然语言驱动的 Web 自动化提供构建模块。

Stagehand 的目标是提供一个轻量级、可配置的框架,没有过于复杂的抽象,以及对不同模型和模型提供者的模块化支持。它不会为你订购披萨,但它会帮助你可靠地实现 Web 自动化。

每个 Stagehand 函数都会接受一个原子指令,例如 act("click the login button")extract("find the red shoes"),生成适当的 Playwright 代码来完成该指令,并执行它。

指令应该是原子的以提高可靠性,步骤规划应该由更高级别的代理处理。你可以使用 observer() 获取可以在当前页面上采取的建议操作列表,然后使用这些操作来制定步骤规划提示。

Stagehand 是开源的,由 Browserbase 团队维护。我们相信,通过让更多开发人员能够构建可靠的 Web 自动化,我们将扩大受益于我们的无头浏览器基础设施的开发人员市场。这​​是我们在修改自己的应用程序时希望拥有的框架,我们很高兴与你分享它。

1、安装 Stagehand 包

我们还安装了 zod 来支持类型提取

npm install @browserbasehq/stagehand zod

2、配置你的模型提供程序

需要为要使用的模型提供程序提供 API 密钥。默认模型提供程序是 OpenAI,但你也可以使用 Anthropic 或其他。有关受支持模型的更多信息,请参阅 API 参考

确保你的本地环境中可以访问 OpenAI API 密钥或 Anthropic API 密钥:

export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-...

3、创建 Stagehand 实例

如果你计划在本地运行浏览器,还需要安装 Playwright 的浏览器依赖项:

npm exec playwright install

然后你可以像这样创建一个 Stagehand 实例:

import { Stagehand } from "@browserbasehq/stagehand";
import { z } from "zod";

const stagehand = new Stagehand({
  env: "LOCAL",
});

如果你计划远程运行浏览器,需要设置 Browserbase API 密钥和项目 ID:

export BROWSERBASE_API_KEY=...
export BROWSERBASE_PROJECT_ID=...
import { Stagehand } from "@browserbasehq/stagehand";
import { z } from "zod";

const stagehand = new Stagehand({
  env: "BROWSERBASE",
  enableCaching: true,
});

4、运行你的第一个Web自动化脚本

await stagehand.init();
const page = stagehand.page;
await page.goto("https://github.com/browserbase/stagehand");
await page.act({ action: "click on the contributors" });
const contributor = await page.extract({
  instruction: "extract the top contributor",
  schema: z.object({
    username: z.string(),
    url: z.string(),
  }),
});
await stagehand.close();
console.log(`Our favorite contributor is ${contributor.username}`);

这个简单的代码片段将打开浏览器,导航到 Stagehand 存储库,并记录顶级贡献者。

5、Stagehand API 速查

5.1 Stagehand()

此构造函数用于创建 Stagehand 的实例。

参数:

  • env:'LOCAL' 或 'BROWSERBASE'。默认为 'BROWSERBASE'。
  • modelName:(可选)一个可用模型字符串,用于指定要使用的默认模型。
  • modelClientOptions:(可选)模型客户端的配置选项。
  • enableCaching:一个布尔值,用于启用 LLM 响应的缓存。设置为 true 时,LLM 请求将缓存在磁盘上并重新用于相同的请求。默认为 false
  • headless:一个布尔值,用于确定浏览器是否以无头模式运行。默认为 false。当 env 设置为 BROWSERBASE 时,将忽略此参数。
  • domSettleTimeoutMs:一个整数,用于指定等待 DOM 稳定下来的超时时间(以毫秒为单位)。默认为 30000(30 秒)。
  • apiKey:(可选)你的 Browserbase API 密钥。默认为 BROWSERBASE_API_KEY 环境变量。
  • projectId:(可选)你的 Browserbase 项目 ID。默认为 BROWSERBASE_PROJECT_ID 环境变量。
  • browserbaseSessionCreateParams:用于创建新 Browserbase 会话的配置选项。
  • browserbaseSessionID:现有实时 Browserbase 会话的 ID。覆盖 browserbaseSessionCreateParams
  • logger:处理日志消息的函数。适用于自定义日志实现。
  • verbose:一个整数,在自动化过程中启用多个级别的日志记录。0:限制为无日志记录;1:SDK 级别日志记录;2:LLM 客户端级别日志记录(最精细)
  • debugDom:一个布尔值,在自动化过程中围绕呈现给 LLM 的元素绘制边界框。

返回:

使用指定选项配置的 Stagehand 类的实例。

示例:

// Basic usage
const stagehand = new Stagehand();

// Custom configuration
const stagehand = new Stagehand({
  env: "LOCAL",
  verbose: 1,
  headless: true,
  enableCaching: true,
  logger: (logLine) => {
    console.log(`[${logLine.category}] ${logLine.message}`);
  },
});

// Resume existing Browserbase session
const stagehand = new Stagehand({
  env: "BROWSERBASE",
  browserbaseSessionID: "existing-session-id",
});

5.2 init()

init() 异步初始化 Stagehand 实例。它应该在任何其他方法之前调用。

警告!将参数传递给 init() 已弃用,并将在下一个主要版本中删除。请改用构造函数选项。

参数:

  • modelName:(已弃用,可选)一个可用模型字符串,用于指定要使用的模型。除非被覆盖,否则将用于所有其他方法。
  • modelClientOptions:(已弃用,可选)模型客户端的配置选项
  • domSettleTimeoutMs:(已弃用,可选)等待 DOM 稳定下来的超时时间(以毫秒为单位)

返回:

解析为包含以下内容的对象的 Promise:

  • debugUrl:表示实时调试 URL 的字符串。仅在使用 Browserbase 浏览器时才可用。
  • sessionUrl:表示会话 URL 的字符串。仅在使用 Browserbase 浏览器时才可用。
  • sessionId:表示会话 ID 的字符串。仅在使用 Browserbase 浏览器时才可用。

示例:

await stagehand.init();

5.3 act()

act() 允许 Stagehand 与网页交互。提供“搜索‘x’”或“选择显示的最便宜航班”等操作(小原子目标表现最佳)。

警告!Stagehand 实例上的 act() 已弃用,将在下一个主要版本中删除。改用 stagehand.page.act()。

参数:

  • action:描述要执行的操作的字符串
  • modelName:(可选)用于指定要使用的模型的可用模型字符串
  • modelClientOptions:(可选)模型客户端的配置选项
  • useVision:(可选)布尔值或“fallback”,用于确定是否应使用基于视觉的处理。默认为“fallback”
  • variables:(可选)操作中使用的变量的 Record<string, string>。使用 %variable_name% 引用操作字符串中的变量
  • domSettleTimeoutMs:(可选)等待 DOM 稳定下来的超时时间(以毫秒为单位)

返回:

解析为包含以下内容的对象的承诺:

  • success:指示操作是否成功完成的布尔值。
  • message:提供有关操作执行的详细信息的字符串。
  • action:描述执行的操作的字符串。

示例:

// Basic usage
await stagehand.page.act({ action: "click on add to cart" });

// Using variables
await stagehand.page.act({
  action: "enter %username% into the username field",
  variables: {
    username: "john.doe@example.com",
  },
});

// Multiple variables
await stagehand.page.act({
  action: "fill in the form with %username% and %password%",
  variables: {
    username: "john.doe",
    password: "secretpass123",
  },
});

5.4 extract()

extract() 使用 zod 从当前页面抓取结构化文本。给定指令和架构,你将收到结构化数据。与某些提取库不同,stagehand 可以提取页面上的任何信息,而不仅仅是主要文章内容。

警告!Stagehand 实例上的 extract() 已弃用,将在下一个主要版本中删除。请改用 stagehand.page.extract()。

参数:

  • instruction:提供提取说明的字符串
  • schema:定义要提取的数据结构的 z.AnyZodObject
  • modelName:(可选)用于指定要使用的模型的可用模型字符串
  • modelClientOptions:(可选)模型客户端的配置选项
  • domSettleTimeoutMs:(可选)等待 DOM 稳定下来的超时时间(以毫秒为单位)
  • useTextExtract:(可选)布尔值,用于确定是否应使用基于文本的提取。默认为 false

返回:

解析为提供的架构定义的结构化数据的 Promise。

示例:

const price = await stagehand.page.extract({
  instruction: "extract the price of the item",
  schema: z.object({
    price: z.number(),
  }),
});

5.5 observe()

警告!Stagehand 实例上的 observe() 已弃用,将在下一个主要版本中删除。改用 stagehand.page.observe()。
注意!observe() 目前仅评估页面中的第一个块。

observe() 用于获取当前页面上可执行的操作列表。它可用于为你的规划步骤添加上下文,或者在你不确定自己位于哪个页面上时使用。

如果你正在寻找特定元素,还可以通过以下方式传入要观察的指令:

observe({instruction: "{your instructions}"})

参数:

  • instruction:(可选)提供观察指令的字符串。默认为“查找可在此页面上执行的操作。”
  • modelName:(可选)用于指定要使用的模型的可用模型字符串
  • modelClientOptions:(可选)模型客户端的配置选项
  • useVision:(可选)用于确定是否应使用基于视觉的处理的一个布尔值。默认为 false
  • domSettleTimeoutMs:(可选)等待 DOM 稳定下来的超时时间(以毫秒为单位)

返回:

解析为n 个对象数组,包含:

  • selector:表示元素选择器的字符串
  • description:描述可能操作的字符串

示例:

const actions = await stagehand.page.observe();

5.6 close()

close() 是一种清理方法,用于删除 Stagehand 创建的临时文件。强烈建议您在完成自动化后调用此方法。

示例:

await stagehand.close();

5.7 page 和 context

pagecontext 分别是 Playwright 的 PageBrowserContext 的实例。使用这些方法与 Stagehand 正在使用的 Playwright 实例进行交互。最常见的是,你将使用 page.goto() 导航到 URL。

示例:

await stagehand.page.goto("https://github.com/browserbase/stagehand");

5.8 log()

log() 用于将消息打印到浏览器控制台。这些消息将保留在 Browserbase 会话日志中,并可用于在会话完成后调试会话。

确保日志级别高于初始化 Stagehand 实例时设置的详细级别。

示例:

stagehand.log("Hello, world!");

6、Stagehand模型支持

Stagehand 利用通用 LLM 客户端架构来支持来自不同提供商的各种语言模型。这种设计具有灵活性,可以在对核心系统进行最小更改的情况下集成新模型。不同的模型更适合不同的任务,因此你可以选择最适合自己需求的模型。

Stagehand 当前支持 OpenAI 和 Anthropic 的以下模型:

OpenAI 模型:

  • gpt-4o
  • gpt-4o-mini
  • gpt-4o-2024-08-06

Ant​​hropic 模型:

  • claude-3-5-sonnet-latest
  • claude-3-5-sonnet-20240620
  • claude-3-5-sonnet-20241022

可以在初始化 Stagehand 实例或调用 act()extract() 等方法时指定这些模型。

7、Stagehand工作原理

SDK 有两个主要阶段:

  • 处理 DOM(包括分块 - 见下文)。
  • 根据 DOM 的当前状态采取 LLM 支持的操作。

7.1 DOM 处理

Stagehand 使用多种技术来准备 DOM。

DOM 处理步骤如下:

  • 通过 Playwright,将脚本注入 SDK 可访问的 DOM 中,以运行处理。
  • 抓取 DOM 并创建候选元素列表。
  • 候选元素要么是叶元素(包含实际面向用户的内容的 DOM 元素),要么是交互元素。
  • 交互元素由角色和 HTML 标签的组合决定。
  • 不活跃、不可见或不在 DOM 顶部的候选元素将被丢弃。
  • LLM 应仅接收它可以代表代理/用户忠实地采取行动的元素。
  • 对于每个候选元素,都会生成一个 xPath。这保证了如果 LLM 选择了这个元素,我们将能够可靠地定位它。
  • 将候选元素列表以及元素到浏览器中的 xPath 选择器的映射返回到 SDK,以供 LLM 分析。

7.2 分块

虽然 LLM 将继续增加上下文窗口长度并减少延迟,但减少任何推理系统的思考内容应该会使其更加可靠。因此,DOM 处理以块的形式进行,以便每次推理调用时保持上下文较小。为了进行分块,SDK 将从视口的某个部分开始的候选元素视为该块的一部分。将来,将添加填充以确保单个块不会缺少相关上下文。请参阅此图以了解其外观:

7.3 Vision

act()observer() 方法可以使用 useVision 标志。如果将其设置为 true,则将为 LLM 提供当前页面的带注释的屏幕截图,以识别要对哪些元素采取行动。这对于 LLM 难以推理的复杂 DOM 非常有用,即使在处理和分块之后也是如此。默认情况下,此标志设置为 fallback,这意味着如果 LLM 无法成功识别单个元素,Stagehand 将使用 vision 重试该尝试。

7.4 LLM 分析

现在我们有了一个候选元素列表和一种选择它们的方法。我们可以将这些元素与附加上下文一起呈现给 LLM 以供提取或采取行动。虽然尚未大规模测试,但呈现“元素编号列表”会引导模型不将上下文视为完整的 DOM,而是将其视为要操作的相关但独立元素列表。

在操作的情况下,我们要求 LLM 编写一个 playwright 方法来做正确的事情。在我们有限的测试中,playwright 语法比依赖内置的 javascript API 更有效,这可能是由于分词处理。

最后,我们使用 LLM 向自身编写未来指令,以帮助管理跨块操作时的进度和目标。

8、Stagehand vs. Playwright

以下是如何使用 Stagehand 和 Playwright 从 AI Grant 网站提取公司列表的示例:

9、提示技巧

与其他高级框架(包括代理框架)相比,提示 Stagehand 更直观、更原子化。以下是一些帮助你制作有效提示的指南。

应该:

  • 使用具体而简洁的操作
await stagehand.page.act({ action: "click the login button" });

const productInfo = await stagehand.page.extract({
  instruction: "find the red shoes",
  schema: z.object({
    productName: z.string(),
    price: z.number(),
  }),
});
  • 将复杂任务分解为更小的原子步骤,而不是合并操作

避免这种情况:

// Avoid this
await stagehand.page.act({ action: "log in and purchase the first item" });

将它们拆分为单独的步骤:

await stagehand.page.act({ action: "click the login button" });
// ...additional steps to log in...
await stagehand.page.act({ action: "click on the first item" });
await stagehand.page.act({ action: "click the purchase button" });
  • 使用 observe()从当前页面获取可操作的建议
const actions = await stagehand.page.observe();
console.log("Possible actions:", actions);

不要:

  • 使用宽泛或模棱两可的指令
// Too vague
await stagehand.page.act({ action: "find something interesting on the page" });
  • 将多个操作合并为一个指令
// Avoid combining actions
await stagehand.page.act({ action: "fill out the form and submit it" });
  • 期望Stagehand执行高级规划或推理
// Outside Stagehand's scope
await stagehand.page.act({ action: "book the cheapest flight available" });

通过遵循这些准则,你将提高使用Stagehand进行网络自动化的可靠性和有效性。请记住,Stagehand擅长执行精确、定义明确的操作,因此保持指令的原子性将带来最佳结果。

我们将代理行为留给可以使用Stagehand作为工具的更高级别的代理系统。


原文链接:An AI web browsing framework focused on simplicity and extensibility

汇智网翻译整理,转载请标明出处