news 2026/9/12 10:16:01

Stagehand × Eve Agent:三工具驱动持久化浏览器的 Agent 指令契约解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Stagehand × Eve Agent:三工具驱动持久化浏览器的 Agent 指令契约解析

Stagehand × Eve Agent:三工具驱动持久化浏览器的 Agent 指令契约解析

【免费下载链接】stagehandThe SDK For Browser Agents项目地址: https://gitcode.com/GitHub_Trending/stag/stagehand

在 Stagehand 开源仓库中,Eve 集成示例通过facade(门面)模式把 Stagehand 的浏览器能力直接暴露为 Eve Agent 的原生工具,并配套了一份作为 Agent 系统提示词的指令文档 agent/instructions.md。这份文档只有 10 行,却是整个工具面(tool surface)的“使用契约”:它规定了 Agent 只能通过snapshotrunscreenshot三个工具操作浏览器,并约束了快照 ID 的时效性、动作字段的命名(op/id)以及会话的关闭方式。读完本文,你将完整理解这三工具契约的每一个细节、它在 contract.ts 中的源码级定义与运行时校验,以及如何搭建环境、运行示例并遵守其安全与会话生命周期约束。

一、指令文档全貌:三工具契约原文

instructions.md是注入 Eve Agent 的规范提示词(canonical prompt)。原文如下:

You control one persistent browser through exactly three tools:

  • snapshot: inspect the active page and hydrate bracketed element IDs.
  • run: provide either snapshot actions or JavaScript using the Playwright-shaped page API.
  • screenshot: inspect the rendered page visually.

Use snapshot actions for simple interactions and run code for multi-step workflows. Pass run exactly one of code or actions; every action uses "op" and "id", never "kind" or "ref". Snapshot IDs are valid only for the latest snapshot of the active page; snapshot again after navigation or stale IDs. Do not launch another browser. To end a session you must run browser.close() to close the browser.

逐条拆解,这份契约包含五条核心规则:

  1. 工具边界:Agent 只能接触三个工具,不存在独立的navigatestart工具,导航一律通过run里的 JavaScript 完成(await page.goto(...))。
  2. snapshot 的职责:检查当前活动页面的无障碍树(accessibility tree),并把可交互元素的 ID 以[bracketed]形式“水合”(hydrate)出来,供后续run动作引用。
  3. run 的双模式:要么传code(Playwright 形状的页面 API 的 JavaScript),要么传actions(基于快照 ID 的动作批次),二者必须恰好提供一个。
  4. 字段命名纪律:每个 action 必须使用"op""id",禁止使用"kind""ref";快照 ID 只对最新一次快照有效,导航后或 ID 过期必须重新 snapshot。
  5. 会话纪律:不得另起浏览器;结束会话的唯一方式是执行browser.close()

需要说明的是,指令原文中最后一句关于browser.close()的会话关闭指引,属于 Eve facade 示例在自身系统提示词上的本地补充(原文见 instructions.md);而 contract.ts 中定义的规范提示词FACADE_AGENT_INSTRUCTIONS到 "snapshot again after navigation or stale IDs." 即结束,其目的正是让 Eve、Vercel AI SDK、deepagents 等所有宿主框架共享完全一致的 Agent 引导文本。

二、契约的源码出处与测试保证

instructions.md并不是一份“随手写的小纸条”,它由契约测试严格钉死:测试 tools.test.ts 读取instructions.md,与FACADE_AGENT_INSTRUCTIONS进行规范化比较(压缩空行后逐字相等),任何一边的漂移都会导致测试失败。

三工具的描述与输入 Schema 全部定义在 contract.ts:

  • run 的工具描述(RUN_TOOL_DESCRIPTION):明确“导航用await page.goto(...),没有独立的 navigate/start 工具”,并给出三个动作示例:{"actions":[{"op":"click","id":"1-42"}]}{"actions":[{"op":"fill","id":"2-14","value":"Miami"}]}{"actions":[{"op":"select","id":"3-9","values":"Lowest price"}]}。这些措辞是模型被提示时所依赖的精确文本(pinned string-exact)。
  • snapshot 的工具描述(SNAPSHOT_TOOL_DESCRIPTION):每次调用都会替换活动页面的 ID 映射,这正是“ID 仅对最新快照有效”的底层语义。
  • screenshot 的工具描述(SCREENSHOT_TOOL_DESCRIPTION):对尺寸受限的 MCP 客户端建议视口 JPEG,如{"type":"jpeg","quality":40,"fullPage":false}

运行时的双重校验

contract.ts 有意把契约写了两遍(文件头部注释):

  • JSON Schema 字面量是“线上契约”(wire contract),即通过tools/list广播给 MCP 客户端的精确字节;const类型的op判别字段与逐属性引导说明无法由 zod 转换保留,故手工编写。
  • 底部的 zod Schema是运行时校验器。其中 CodeModeRunInputSchema 用.refine强制codeactions的互斥性(恰好一个),这正是指令里 “Pass run exactly one of code or actions” 的机器可执行版本。

值得注意的是,契约在顶层刻意省略oneOf: [{required:["code"]},{required:["actions"]}](注释说明):因为 Eve、Vercel AI SDK 这类基于 AI-SDK 的 MCP 客户端会拒绝带顶层 oneOf 的输入 Schema,导致每次run调用在客户端就失败。互斥性改为由描述文本声明、运行时由.refine兜底。这解释了为何指令文本反复强调“exactly one”。

run 动作支持的操作族

依据 RefActionSchema,actions共支持六种操作:

op必填字段说明
clickid点击快照中的元素
hoverid悬停
fillid,value填入字符串值(如表单输入)
typeid,text,delay?逐键输入,delay为可选的非负毫秒数
pressid,key按键(如Enter
selectid,values下拉选择,values可为单个字符串或字符串数组

每个动作都必须包含"op""id"两个字段(required: ["op", "id", ...]),additionalProperties: false保证多余字段会被拒绝——这是 “neverkindorref” 的机器强制。

三、三工具在 Eve Agent 中的落地实现

Eve 集成把上述契约封装为三个defineTool

  • run.ts:先用CodeModeRunInputSchema.parse校验输入(测试 tools.test.ts 验证了未传任何参数、或同时传codeactions都会被拒绝),随后按input.code !== undefined分发到tools.run(code)tools.runActions(actions),结果统一字符串化返回(对象走JSON.stringify(value, null, 2))。出错时调用discardFacadeToolsIfUnhealthy检查连接健康度。
  • snapshot.ts:解析includeIframes后直接返回tools.snapshot(input)的结果。
  • screenshot.ts:同样转发到tools.screenshot(input),并通过toModelOutput把截图以type: "file"、data URI 的形式喂回模型(文本为 "Screenshot captured."),让 Eve 可以“看图”。

三个工具共享同一个由 session.ts 管理的持久化 Stagehand 会话——无需 MCP 连接或任何桥接进程,这正是 “Eve + Stagehand facade(native tools)” 集成名称的由来。Agent 本体 agent.ts 只有一句话:defineAgent({ model: openai(...) }),默认模型gpt-5.6-luna,可用EVE_STAGEHAND_MODEL覆盖。

四、环境变量与运行方式

环境配置

变量用途
STAGEHAND_BROWSER浏览器后端。设置了BROWSERBASE_API_KEY时默认为browserbase,否则为local
BROWSERBASE_API_KEYBrowserbase API Key,使用 Browserbase 后端时必填
STAGEHAND_MODEL_NAME可选的 Stagehand 模型名,如openai/gpt-5.6-luna
STAGEHAND_MODEL_API_KEYSTAGEHAND_MODEL_NAME显式指定 API Key;否则在受支持时推断对应提供方 Key
STAGEHAND_EVE_SESSION_FILE持久化 Browserbase 会话 ID 的路径;默认放在系统临时目录
EVE_STAGEHAND_MODELEve Agent 模型,默认gpt-5.6-luna
OPENAI_API_KEYEve Agent 模型使用的 OpenAI 凭据,OpenAI 类型的 Stagehand 模型也会推断使用它
GOOGLE_GENERATIVE_AI_API_KEY/GEMINI_API_KEY/GOOGLE_API_KEYStagehand 推断的 Google 凭据;若设置了其一而未显式配置 Stagehand 模型,模型默认google/gemini-3.6-flash

构建与测试

示例包名@browserbasehq/stagehand-integrations-example-eve-facade(见 package.json),要求 Node.js 24 及以上。从仓库根目录先构建 integrations 包:

pnpm exec turbo run build --filter @browserbasehq/stagehand-integrations

契约测试不需要网络、浏览器或任何 API Key,可离线运行:

pnpm --filter @browserbasehq/stagehand-integrations-example-eve-facade test pnpm --filter @browserbasehq/stagehand-integrations-example-eve-facade typecheck

交互式运行与扩展资源解析

配置好浏览器与模型凭据后:

pnpm --filter @browserbasehq/stagehand-integrations-example-eve-facade dev

该脚本并不直接调用eve,而是经 scripts/eve-with-stagehand-env.mjs 启动:Eve 的打包器(build 用 nitro、dev-runtime 用 authored-module 编译器)会把@browserbasehq/stagehand内联进 bundle 并重定位import.meta.url,导致 SDK 派生的扩展资源路径在 bundle 内失效。该脚本在bundle 之外解析真实安装的 SDK 资产,并通过STAGEHAND_EXTENSION_ARCHIVE_PATHSTAGEHAND_EXTENSION_DIRECTORY_PATH两个环境变量转发给eve子进程;Windows 下.cmdshim 需要 shell 才能启动,因此shell: process.platform === "win32"

五、安全模型与 session 生命周期

安全模型

run(code)执行的模型编写的 JavaScript 运行在extension service worker中——即浏览器侧,而不是宿主进程(README.md 的 Security model 一节)。Eve 的 world 进程只持有浏览器会话句柄,模型编写的 JavaScript 不会在 world 进程内执行。官方推荐 Browserbase 作为隔离边界。

会话生命周期

从 session.ts 的源码可以还原出完整的生命周期设计:

  • 单会话共享:每个 Eve world 进程持有一个共享浏览器会话。同一进程服务的并发 Eve 会话会共享页面、认证与其他浏览器状态,因此该示例仅面向单会话使用。
  • Browserbase 会话持久化:通过browserbase.launch({ ..., keepAlive: true })(createResources)创建 keep-alive 会话,并把 sessionId 写入临时文件;STAGEHAND_EVE_SESSION_FILE可覆盖默认路径(默认路径按 API Key 的 SHA-256 前 8 位做作用域隔离,见 sessionFilePath,避免多进程/多 Key 互相抢占)。进程重启后重新挂载(reattach)该会话,而不是再创建一个遗留会话。
  • 保持在线即计费:等待复用的期间,会话持续运行并计费,直到被重新挂载、通过 Browserbase 控制台或 API 释放、或达到项目超时。
  • 无“卡死”(no brick)与无“遗留”(no strand)两个不变量:连接失败的会话最多重试一次(connectToSession带 500ms 退避);若会话“可连接但已损坏”(wedged),会被标记为suspectSessionId,下次创建时先 best-effort 释放旧 keep-alive 会话再全新启动,绝不反复重连死循环;释放失败被吞掉,避免阻塞全新启动。
  • 错误不重置会话:模型编写的工具代码出错不会重置会话;只有当连接不健康(browser.closedcontext.pages()抛错)时才会重建浏览器会话(discardFacadeToolsIfUnhealthy)。

六、从指令到可运行的实战总结

  • Agent 视角:永远只依赖三个工具——先snapshot拿到当前页面的水合 ID,简单交互用actions批次(op/id),多步骤工作流用run的 JavaScript(Playwright 形状的pageAPI);每轮只喂codeactions其一,导航或 ID 失效后立刻重新snapshot
  • 接入视角instructions.md是规范提示词,与 contract.ts 中的FACADE_AGENT_INSTRUCTIONS逐字对齐并由测试守护;任何自研宿主集成都应复用这份文本与FACADE_TOOLS定义,以保证跨框架(Eve、Vercel AI SDK、deepagents)的 Agent 引导完全一致。
  • 运维视角:本地开发用local后端零成本跑通契约测试;生产建议用 Browserbase 后端并接受 keep-alive 会话的计费模型,借助STAGEHAND_EVE_SESSION_FILE持久化、重启自动重挂载;记得通过browser.close()结束会话以停止计费。

【免费下载链接】stagehandThe SDK For Browser Agents项目地址: https://gitcode.com/GitHub_Trending/stag/stagehand

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 10:13:13

SwiftUI跨平台AI内容生成工具开发实践

1. 项目概述:为创作者打造的AI内容生成工具 这个项目本质上是一个面向内容创作者(特别是小红书和公众号作者)的跨平台生产力工具。它基于SwiftUI框架开发,整合了Core Data本地存储和多模态AI能力,目标是解决创作者在日…

作者头像 李华
网站建设 2026/9/12 10:10:54

Python3使用PyMySQL操作MySQL数据库全指南

1. Python3与MySQL数据库交互基础PyMySQL是Python3中用于连接MySQL数据库的纯Python实现库,它完全遵循Python DB API 2.0规范。与MySQLdb相比,PyMySQL不需要编译安装,兼容性更好,特别适合Python3环境。1.1 环境准备与安装在开始使…

作者头像 李华
网站建设 2026/9/12 10:09:10

C++享元模式:内存优化与高效对象管理

1. 享元模式核心概念解析享元模式(Flyweight Pattern)是一种用于优化内存使用的结构型设计模式,特别适合处理需要创建大量相似对象的场景。这个模式的精髓在于区分对象的"内在状态"和"外在状态",通过共享内在…

作者头像 李华
网站建设 2026/9/12 10:07:17

使用impress.js构建智能3D棱柱演示器

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 10:06:49

Java HashMap核心原理与性能优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华