本文介绍如何在RDS Supabase沙箱中使用Browser-Use(浏览器自动化)能力,通过e2b-code-interpreter SDK结合Chrome DevTools Protocol(CDP)驱动AI Agent直接操作浏览器DOM,涵盖4个典型使用场景。
前提条件
-
已创建RDS Supabase实例,且实例处于运行中状态。
-
实例所在地域为华北2(北京)、华东2(上海)、华东1(杭州)、华南1(深圳)或西南1(成都)。
-
已完成关联角色
AliyunServiceRoleForRDSAISupabase授权。 -
已在RDS控制台的沙箱和边缘函数页面启用沙箱功能。具体操作,请参见使用沙箱和边缘函数。
使用限制
-
Browser-Use仅面向浏览器场景,直接操作浏览器DOM,不支持任意桌面应用,桌面场景请使用沙箱Computer-Use场景使用。
-
沙箱默认超时时长为3600秒,可通过
timeout参数调整,超时后需重新创建。
配置Browser-Use
依次完成以下6个配置项,准备Browser-Use运行环境。
步骤一:创建steel-browser沙箱模板
在RDS Supabase实例详情页创建steel-browser公共模板,并记录模板ID供后续代码使用。
-
在实例详情页左侧导航栏,选择组件 > 沙箱和边缘函数。
-
确认启用沙箱和边缘函数开关已开启。
-
在沙箱模板区域,单击模板市场。
-
在右侧弹出的模板市场面板中,找到模板名称列为
steel-browser、描述列为Image used in browser-use scenarios.的行,单击该行操作列的创建。 -
创建完成后返回沙箱模板列表,找到配置项为
steel-browser的行,复制模板ID列的完整值,格式为steel-browser-<6位随机后缀>。此模板ID将作为后续代码中Sandbox.create(template="<模板id>")参数的取值,请妥善保存。
步骤二:绑定域名
为Supabase实例的IP地址绑定域名。
-
在实例详情页中获取实例的外网连接地址对应的IP地址。
-
在本地
/etc/hosts文件中添加域名映射记录。本文以<实例ID>.sb.rds.com为示例域名:<实例IP地址> <实例ID>.sb.rds.com
开发测试场景建议直接写入/etc/hosts;生产环境请使用DNS解析。
步骤三:下载e2b SDK的patch代码
从GitHub仓库下载e2b SDK的patch代码,该patch用于适配RDS Supabase的路由方式。
步骤四:(可选)配置SSL实现HTTPS访问
如需通过HTTPS访问沙箱,请先为Supabase实例配置SSL证书。配置SSL后,设置以下环境变量:
# rootCA.pem为生成Supabase实例SSL证书对应的CA证书
export SSL_CERT_FILE="/xxx/rootCA.pem"
export REQUESTS_CA_BUNDLE="/xxx/rootCA.pem"
后续Python代码中调用patch_e2b()方法即表示对e2b SDK进行patch,其入参True或False表示是否使用HTTPS访问沙箱。传入True时使用HTTPS,此时需先为RDS Supabase实例开通HTTPS,并参见使用沙箱和边缘函数文档设置HTTPS相关的环境变量;传入False时使用HTTP访问。
步骤五:配置环境变量
设置以下环境变量,用于e2b SDK连接Supabase实例、以及AI Agent调用大模型:
# E2B_DOMAIN:步骤二:绑定域名中绑定的域名
export E2B_DOMAIN=<实例ID>.sb.rds.com
# E2B_API_KEY:Supabase实例的Service Key
export E2B_API_KEY=<your_service_key>
# LLM_API_KEY:大模型API密钥(如通义千问、OpenAI等OpenAI兼容接口)
export LLM_API_KEY=<your_llm_api_key>
# LLM_BASE_URL:大模型API基础URL
export LLM_BASE_URL=<your_llm_base_url>
Service Key获取路径:在实例详情页右上角,单击获取API Key,在弹出的对话框中复制ServiceKey的值。
Browser-Use场景由AI Agent直接驱动浏览器,需要调用大模型完成任务分析与决策,因此必须配置LLM_API_KEY与LLM_BASE_URL。LLM_BASE_URL需指向OpenAI兼容的接口地址(如通义千问兼容模式)。
步骤六:安装依赖
执行以下命令安装Browser-Use SDK及沙箱运行时:
pip install browser-use e2b-code-interpreter
Browser-Use使用示例
Browser-Use的核心工作流程依次为:接收用户指令、创建浏览器沙箱、通过CDP连接浏览器、AI Agent解析页面DOM、执行操作(点击/输入/导航等),并循环直至任务完成。与Computer-Use的截图、视觉分析、操控模式不同,Browser-Use直接操作浏览器DOM,执行更精准、速度更快。以下4个使用场景各自提供一份完整可运行的Python脚本,复制后按运行示例代码的说明保存为.py文件即可执行。
场景一:基础网页浏览与信息提取
让AI Agent自主访问指定网页并提取关键信息,是Browser-Use最基础的使用形态。
import asyncio
import json
import os
from browser_use import Agent, BrowserSession
from browser_use.llm import ChatOpenAI
from e2b_code_interpreter import Sandbox
from patch_e2b import patch_e2b
# 未配置SSL时传False;已在配置Browser-Use步骤四配置SSL时改为True
patch_e2b(False)
async def get_cdp_url(sbx, debug_port: int = 9222, proxy_port: int = 9223) -> str:
"""从沙箱内查询Chromium的CDP WebSocket URL。
Chromium在沙箱内监听debug_port(默认9222),通过 curl 拿到
webSocketDebuggerUrl,再通过 sbx.get_host(proxy_port) 映射为外部可达地址。
"""
result = sbx.commands.run(f'curl -s http://127.0.0.1:{debug_port}/json/version')
if not result.stdout.strip():
raise Exception("获取CDP URL失败,请确认Chromium已在沙箱内启动")
version_info = json.loads(result.stdout)
ws_path = version_info['webSocketDebuggerUrl'].split('/', 3)[-1]
return f"ws://{sbx.get_host(proxy_port)}/{ws_path}"
async def main():
# 使用配置Browser-Use步骤一记录的steel-browser模板ID创建沙箱
sandbox = Sandbox.create(template="<模板id>", timeout=3600)
try:
cdp_url = await get_cdp_url(sandbox)
browser_session = BrowserSession(
cdp_url=cdp_url,
headers={"X-API-Key": os.getenv('E2B_API_KEY')},
)
await browser_session.start()
agent = Agent(
task="访问阿里云官网,找到RDS Supabase的产品介绍页面,总结其主要功能。",
llm=ChatOpenAI(
api_key=os.getenv("LLM_API_KEY"),
base_url=os.getenv("LLM_BASE_URL"),
model="qwen3-vl-plus",
temperature=1,
),
browser_session=browser_session,
)
result = await agent.run()
print(f"任务结果: {result}")
await browser_session.close()
finally:
sandbox.kill()
asyncio.run(main())
场景二:表单填写与提交
让AI Agent自动填写网页表单并提交。任务描述通过多行字符串给出结构化指令,便于AI理解字段与操作对应关系;温度设为0提升字段填写的确定性。
import asyncio
import json
import os
from browser_use import Agent, BrowserSession
from browser_use.llm import ChatOpenAI
from e2b_code_interpreter import Sandbox
from patch_e2b import patch_e2b
patch_e2b(False)
async def get_cdp_url(sbx, debug_port: int = 9222, proxy_port: int = 9223) -> str:
result = sbx.commands.run(f'curl -s http://127.0.0.1:{debug_port}/json/version')
if not result.stdout.strip():
raise Exception("获取CDP URL失败,请确认Chromium已在沙箱内启动")
version_info = json.loads(result.stdout)
ws_path = version_info['webSocketDebuggerUrl'].split('/', 3)[-1]
return f"ws://{sbx.get_host(proxy_port)}/{ws_path}"
async def main():
sandbox = Sandbox.create(template="<模板id>", timeout=3600)
try:
cdp_url = await get_cdp_url(sandbox)
browser_session = BrowserSession(
cdp_url=cdp_url,
headers={"X-API-Key": os.getenv('E2B_API_KEY')},
)
await browser_session.start()
agent = Agent(
task="""
打开 https://example.com/contact 页面,
在姓名栏填写 "张三",
在邮箱栏填写 "zhangsan@example.com",
在留言栏填写 "你好,这是一条测试消息",
然后点击提交按钮。
""",
llm=ChatOpenAI(
api_key=os.getenv("LLM_API_KEY"),
base_url=os.getenv("LLM_BASE_URL"),
model="qwen3-vl-plus",
temperature=0, # 表单类任务用0温度,减少随机性
),
browser_session=browser_session,
)
result = await agent.run()
print(f"表单提交结果: {result}")
await browser_session.close()
finally:
sandbox.kill()
asyncio.run(main())
表单类任务对确定性要求高,建议将temperature设为0,避免模型输出偏差影响字段填写。
场景三:多步骤复杂任务
AI Agent可以处理包含搜索、筛选、对比等多步骤的复杂浏览任务。任务描述用有序列表结构化多步骤指令,AI会按顺序执行。
import asyncio
import json
import os
from browser_use import Agent, BrowserSession
from browser_use.llm import ChatOpenAI
from e2b_code_interpreter import Sandbox
from patch_e2b import patch_e2b
patch_e2b(False)
async def get_cdp_url(sbx, debug_port: int = 9222, proxy_port: int = 9223) -> str:
result = sbx.commands.run(f'curl -s http://127.0.0.1:{debug_port}/json/version')
if not result.stdout.strip():
raise Exception("获取CDP URL失败,请确认Chromium已在沙箱内启动")
version_info = json.loads(result.stdout)
ws_path = version_info['webSocketDebuggerUrl'].split('/', 3)[-1]
return f"ws://{sbx.get_host(proxy_port)}/{ws_path}"
async def main():
sandbox = Sandbox.create(template="<模板id>", timeout=3600)
try:
cdp_url = await get_cdp_url(sandbox)
browser_session = BrowserSession(
cdp_url=cdp_url,
headers={"X-API-Key": os.getenv('E2B_API_KEY')},
)
await browser_session.start()
agent = Agent(
task="""
1. 打开百度搜索 "RDS Supabase"
2. 记录前3条搜索结果的标题和摘要
3. 然后点击第一条结果进入详情页
4. 总结该页面的核心内容
""",
llm=ChatOpenAI(
api_key=os.getenv("LLM_API_KEY"),
base_url=os.getenv("LLM_BASE_URL"),
model="qwen3-vl-plus",
temperature=1,
),
browser_session=browser_session,
)
result = await agent.run()
print(f"多步骤任务结果: {result}")
await browser_session.close()
finally:
sandbox.kill()
asyncio.run(main())
场景四:带截图回调的Agent
通过on_step_end回调在每一步结束后截取页面截图,脚本会自动在当前目录创建./screenshots/目录并按Unix时间戳保存每步截图,便于调试和审计。
import asyncio
import base64
import json
import os
import time
from browser_use import Agent, BrowserSession
from browser_use.llm import ChatOpenAI
from e2b_code_interpreter import Sandbox
from patch_e2b import patch_e2b
patch_e2b(False)
async def get_cdp_url(sbx, debug_port: int = 9222, proxy_port: int = 9223) -> str:
result = sbx.commands.run(f'curl -s http://127.0.0.1:{debug_port}/json/version')
if not result.stdout.strip():
raise Exception("获取CDP URL失败,请确认Chromium已在沙箱内启动")
version_info = json.loads(result.stdout)
ws_path = version_info['webSocketDebuggerUrl'].split('/', 3)[-1]
return f"ws://{sbx.get_host(proxy_port)}/{ws_path}"
async def screenshot(agent: Agent):
"""每步结束后截取浏览器页面截图并保存到 ./screenshots/ 目录。"""
try:
page = await agent.browser_session.get_current_page()
if page is None:
print("截图跳过: 当前无可用页面")
return
b64_data = await page.screenshot(format='png')
screenshots_dir = os.path.join(".", "screenshots")
os.makedirs(screenshots_dir, exist_ok=True)
screenshot_path = os.path.join(screenshots_dir, f"{time.time()}.png")
with open(screenshot_path, "wb") as f:
f.write(base64.b64decode(b64_data))
print(f"截图已保存至 {screenshot_path}")
except Exception as e:
print(f"截图失败: {e}")
async def main():
sandbox = Sandbox.create(template="<模板id>", timeout=3600)
try:
cdp_url = await get_cdp_url(sandbox)
browser_session = BrowserSession(
cdp_url=cdp_url,
headers={"X-API-Key": os.getenv('E2B_API_KEY')},
)
await browser_session.start()
agent = Agent(
task="访问阿里云官网,找到RDS Supabase的产品介绍页面,总结其主要功能。",
llm=ChatOpenAI(
api_key=os.getenv("LLM_API_KEY"),
base_url=os.getenv("LLM_BASE_URL"),
model="qwen3-vl-plus",
temperature=1,
),
browser_session=browser_session,
)
# 每一步执行后自动截图
await agent.run(on_step_end=screenshot)
await browser_session.close()
finally:
sandbox.kill()
asyncio.run(main())
运行示例代码
完成前面6个配置步骤后,按以下流程运行本文中的Python示例。
步骤一:创建脚本文件
将示例代码保存为.py文件,必须与配置Browser-Use步骤三下载的patch_e2b源码放在同一目录,否则会报ModuleNotFoundError: No module named 'patch_e2b'。目录结构示例:
e2b-sdk-patch/
├── patch_e2b/ # 配置Browser-Use步骤三下载的patch源码
└── demo.py # 您的示例脚本
如需将脚本放在其他目录,请将patch_e2b源码路径加入PYTHONPATH:
export PYTHONPATH="/path/to/e2b-sdk-patch:$PYTHONPATH"
其中/path/to/e2b-sdk-patch为占位符,需替换为本地patch_e2b源码所在的实际绝对路径(例如/Users/yourname/code/e2b-sdk-patch);:$PYTHONPATH用于保留原有路径,避免覆盖。设置完成后,在同一终端窗口中运行脚本即可生效。
步骤二:替换代码中的占位符
示例代码中的<模板id>需替换为配置Browser-Use步骤一记录的模板ID(格式为steel-browser-<后缀>)。
步骤三:确认环境变量已生效
在运行脚本的终端中执行以下命令,确认配置Browser-Use步骤五配置的4个环境变量已加载:
echo $E2B_DOMAIN # 应输出 <实例ID>.sb.rds.com
echo $E2B_API_KEY # 应输出 Supabase ServiceKey
echo $LLM_API_KEY # 应输出 大模型API密钥
echo $LLM_BASE_URL # 应输出 大模型API基础URL
步骤四:运行脚本
python3 demo.py