找回密码
 立即注册
首页 业界区 安全 AgentRun实践指南:Agent 的宝藏工具—All-In-One Sandb ...

AgentRun实践指南:Agent 的宝藏工具—All-In-One Sandbox

撇瞥 昨天 18:55

一、概述

在开发 AgentRun 的过程中,我们发现了一个让人头疼的问题:现有的沙箱方案太零散了。浏览器、代码执行、Shell 环境各自为政,导致开发效率大打折扣。于是我们决定自己动手,打造一个真正一体化的解决方案——All-In-One Sandbox(AIO)。
AIO 是 AgentRun 提供的云上浏览器自动化沙箱环境,它把浏览器、终端和代码执行能力全部集成在一个容器里。通过简单的 SDK 调用,你就能让 LLM 驱动复杂的 Web 自动化任务,再也不用在多个沙箱之间疲于奔命。
为什么选择 AIO?

说实话,传统的沙箱方案让我们吃尽了苦头。大多数沙箱都是单一用途的(要么只能跑浏览器,要么只能执行代码),这带来了几个实实在在的痛点:
1. 文件共享简直是个噩梦


  • 浏览器沙箱下载的文件得先上传到 NAS/OSS,代码沙箱才能用
  • 代码生成的文件又要重新上传,其他沙箱再下载
  • 多个沙箱之间的文件传递慢得像蜗牛爬
2. 工具协调复杂到想哭


  • 一个完整的 Agent 任务通常需要同时调用浏览器 + 代码 + Shell
  • 得手动编排多个沙箱的启动、通信和数据传递
  • 调试时要在好几个地方来回切换看日志,效率低得让人抓狂
3. 环境配置繁琐到崩溃


  • 本地方案:Node.js、浏览器、各种系统依赖,装得手都酸了
  • 多沙箱方案:每个环境都要单独配置和管理
  • 最要命的是环境污染问题——任务之间互相干扰,资源清理成了日常难题
4. 成本和效率双重打击


  • 多个沙箱同时运行,内存占用翻倍
  • 文件传输走网络 I/O,延迟高得离谱
  • 还得额外付费买 OSS/NAS 存储服务
AIO 沙箱的核心优势

架构一览

统一文件系统
我们的解决方案很简单粗暴:把所有组件(浏览器、Shell、代码执行、文件系统)都塞进同一个沙箱实例里。

性能对比一目了然:
对比项传统多沙箱方案All-In-One 沙箱启动时间2 个沙箱启动 = 4-15秒(串/并行创建)1 个沙箱启动 = 5秒文件传递通过 OSS,耗时 2-3秒直接访问,= 1800 避免超时断连一定要用 disconnect() 保持浏览器运行,close() 会关掉浏览器
通过 /home/user/data/ 目录传递 Cookie 和进度
VNC URL 用 sandbox.sandbox_id 和 base URL 拼起来就行
文件操作就用 sandbox.file.read() 和 sandbox.file.write()
</ol>3.2 LLM Agent 集成模式

适用场景: 让 AI 自动生成和执行浏览器自动化代码,非技术用户也能用。
整体架构:
flowchart TD    A["用户需求    (自然语言)"] --> B["LLM生成    Puppeteer代码"]    B --> C["AIO Sandbox    执行代码"]    C --> D["返回结果    (文件/日志)"]    style A fill:#fff,stroke:#000,color:#000    style B fill:#fff,stroke:#000,color:#000    style C fill:#fff,stroke:#000,color:#000    style D fill:#fff,stroke:#000,color:#000三条铁律(必须遵守):

  • 禁止:puppeteer.launch() → 必须:puppeteer.connect()
  • 禁止:browser.close() → 必须:browser.disconnect()
  • 禁止:随便存文件 → 必须:/home/user/data/xxx.json
为什么这么严格?

  • 违反约束会导致浏览器重启,之前的状态全没了
  • AI 生成代码需要明确指导,不能指望它有"常识"
  • 详细内容见第 4 章系统提示词设计
3.3 Cookie 持久化模式

什么时候需要? 要保持登录状态,跨会话复用的时候。
完整流程:
  1. 首次登录:1. 人工登录 → 2. 保存 Cookie → 3. 持久化存储后续使用:1. 上传Cookie -> 2. 读取 Cookie → 3. 恢复会话 → 4. 执行任务
复制代码
Cookie 保存示例:
  1. const puppeteer = require('puppeteer-core');const fs = require('fs');const browser = await puppeteer.connect({  browserWSEndpoint: 'ws://localhost:5000/ws/automation'});const page = (await browser.pages())[0];const cookies = await page.cookies();// 保存到文件系统fs.writeFileSync('/home/user/data/cookies.json', JSON.stringify(cookies, null, 2));console.log('Cookie 已保存');await browser.disconnect();
复制代码
Cookie 恢复示例:
  1. const puppeteer = require('puppeteer-core');const fs = require('fs');const browser = await puppeteer.connect({  browserWSEndpoint: 'ws://localhost:5000/ws/automation'});const page = (await browser.pages())[0];// 读取 Cookieconst cookies = JSON.parse(fs.readFileSync('/home/user/data/cookies.json'));// 恢复会话await page.setCookie(...cookies);await page.goto('https://example.com/protected');console.log('登录状态已恢复');await browser.disconnect();
复制代码
关键提醒:

  • Cookie 一定要保存到 /home/user/data/ 目录,这样才有权限
  • 用 page.cookies() 获取所有 Cookie,一个都不能少
  • 用 page.setCookie(...cookies) 恢复,顺序很重要
  • 别忘了检查 Cookie 过期时间和安全性
3.4 批量任务模式

适用场景: 需要并发处理大量任务的时候。
两种策略:
  1. 策略 1:单沙箱顺序执行(简单任务,有依赖关系)策略 2:多沙箱并发执行(复杂任务,无依赖关系)
复制代码
选择建议:
[table]策略适用场景优势单沙箱顺序执行简单任务,依赖前序结果资源占用低,状态连续多沙箱并发执行复杂任务,无依赖关系执行速度快,并行处理并发控制示例:
  1. # 使用 asyncio.gather() 实现并发tasks = [    process_item(item)    for item in items]results = await asyncio.gather(*tasks, return_exceptions=True)
复制代码
四、实战案例:豆瓣电影 Top250 爬取


完整的 demo 代码可以在示例仓库里找到
4.1 需求分析

目标很明确: 抓取豆瓣电影 Top250 的电影信息(标题、评分、导演、年份等)
实际挑战:

  • 豆瓣必须登录才能看完整信息
  • 数据分页展示,需要多步骤采集
  • 反爬虫机制相当严格
我们的解法: AIO Sandbox 的 Cookie 持久化 + 多步骤任务模式
4.2 核心实现流程

步骤 1:首次登录并保存 Cookie

  1. // 1. 打开登录页const puppeteer = require('puppeteer-core');const browser = await puppeteer.connect({  browserWSEndpoint: 'ws://localhost:5000/ws/automation'});const page = (await browser.pages())[0];await page.goto('https://accounts.douban.com/passport/login');console.log('请在 VNC 中完成登录');console.log('登录完成后,程序将自动保存 Cookie');await browser.disconnect();
复制代码
操作说明:

  • 用户在 VNC 中手动完成登录(包括验证码)
  • 登录成功后进入下一步
步骤 2:保存 Cookie
  1. const puppeteer = require('puppeteer-core');const fs = require('fs');const browser = await puppeteer.connect({  browserWSEndpoint: 'ws://localhost:5000/ws/automation'});const page = (await browser.pages())[0];const cookies = await page.cookies();fs.writeFileSync('/home/user/data/douban_cookies.json', JSON.stringify(cookies, null, 2));console.log(`Cookie 已保存,共 ${cookies.length} 条`);await browser.disconnect();
复制代码
步骤 3:用 Cookie 爬取数据

  1. const puppeteer = require('puppeteer-core');const fs = require('fs');const browser = await puppeteer.connect({  browserWSEndpoint: 'ws://localhost:5000/ws/automation'});const page = (await browser.pages())[0];// 恢复 Cookieconst cookies = JSON.parse(fs.readFileSync('/home/user/data/douban_cookies.json'));await page.setCookie(...cookies);// 访问 Top250await page.goto('https://movie.douban.com/top250', { waitUntil: 'networkidle2' });// 提取数据const movies = await page.evaluate(() => {  return Array.from(document.querySelectorAll('.item')).map(item => ({    title: item.querySelector('.title')?.textContent,    rating: item.querySelector('.rating_num')?.textContent,    quote: item.querySelector('.inq')?.textContent  }));});// 保存结果fs.writeFileSync('/home/user/data/movies.json', JSON.stringify(movies, null, 2));console.log(`爬取完成,共 ${movies.length} 部电影`);await browser.disconnect();
复制代码
4.3 完整 Python 代码

具体实现可以参考项目的 src/ai_code_generator.py 和 src/sandbox_executor.py。
核心逻辑:
  1. from agentrun.sandbox import Sandbox, TemplateTypeimport asyncioasync def scrape_douban():    # 1. 创建沙箱    sandbox = Sandbox.create(        template_type=TemplateType.AIO,        template_name="douban-scraper",        sandbox_idle_timeout_seconds=1800    )    # 2. 执行登录步骤(代码略,参考上面)    # 3. 保存 Cookie(代码略,参考上面)    # 4. 爬取数据(代码略,参考上面)    # 5. 读取结果    result = sandbox.file.read('/home/user/data/movies.json')    print(result)asyncio.run(scrape_douban())
复制代码
4.4 核心技术点总结


  • Cookie 持久化:避免重复登录,通过文件系统保存和恢复登录状态
  • connect() + disconnect():保持浏览器运行,完美支持多步骤任务
  • 文件系统状态传递:跨步骤共享数据,无需网络 I/O 开销
4.5 扩展功能

分页爬取(完整 Top250)
  1. const movies = [];for (let page_num = 0; page_num < 250; page_num += 25) {  await page.goto(`https://movie.douban.com/top250?start=${page_num}`);  const items = await page.evaluate(() => {    // 提取逻辑  });  movies.push(...items);  // 延迟防止反爬  await page.waitForTimeout(2000);}fs.writeFileSync('/home/user/data/all_movies.json', JSON.stringify(movies));
复制代码
错误处理和重试(生产必备)
  1. async function scrapeWithRetry(url, maxRetries = 3) {  for (let i = 0; i < maxRetries; i++) {    try {      await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });      return true;    } catch (error) {      console.log(`重试 ${i + 1}/${maxRetries}: ${error.message}`);      await page.waitForTimeout(5000);    }  }  return false;}
复制代码
五、系统提示词设计

5.1 为什么提示词这么重要?

系统提示词(System Prompt)是 LLM Agent 的大脑,直接决定了 AI 如何理解和执行你的需求。对于 AIO Sandbox 集成来说,提示词必须明确告诉 AI 如何生成符合沙箱规范的代码。

5.2 我们的设计哲学

在设计提示词之前,你得先理解 All-In-One Sandbox 的核心理念,这直接影响提示词的结构。
人机协作,不是完全自动化

我们承认有些事情 AI 就是搞不定,比如验证码、滑块验证、短信验证。所以 AIO 采用"人机协作"的设计理念:
可观测性优先

  • 通过 VNC 让执行过程完全透明,你能亲眼看到浏览器在做什么
  • 不用再通过日志猜来猜去,直接看页面状态快速定位问题
人机协作而非完全自动

  • 遇到验证码?没问题,人工介入搞定
  • 人工操作完,自动化任务接着跑,无缝衔接
状态持久化

  • 浏览器会话和数据可以跨步骤保存和恢复
  • 用 disconnect() 保持浏览器运行,状态不会丢
5.3 核心约束与最佳实践

提示词必须明确告诉 AI 这些关键约束:
1. 必须用 connect(),别用 launch()

为什么?看看对比就知道了:
  1. 传统方式 (错误):const browser = await puppeteer.launch();  // 启动新浏览器 (1-3 秒)// 执行任务await browser.close();  // 状态全部丢失All-In-One 方式 (正确):const browser = await puppeteer.connect({  // 连接已运行的浏览器 (>LLM: 自然语言需求    LLM->>Sandbox: 生成并执行代码    Sandbox-->>LLM: 执行结果/状态    LLM->>User: 返回结果或请求人工介入    User->>Sandbox: 通过VNC人工操作    Sandbox-->>LLM: 更新状态    LLM->>Sandbox: 继续执行后续步骤    Sandbox-->>User: 最终结果AI 对话模式让非技术用户也能用浏览器自动化,系统提示词在里面起着关键的"翻译"作用。
  2. [size=3]智能任务拆分[/size]
  3. 好的提示词要能指导 AI 自动判断何时拆分任务:
  4. [b]简单任务(不拆分)[/b]
  5. [code]用户: 访问 example.com,获取页面标题AI 直接生成单个代码块,执行后返回结果
复制代码
需要登录(自动拆分)
  1. 用户: 登录豆瓣,然后获取我的收藏AI 自动拆分为 3 个步骤:步骤 1: 打开登录页 → [生成代码1] → "请在 VNC 中完成登录"步骤 2: 保存 Cookie → [生成代码2] → "已保存 15 个 Cookie"步骤 3: 获取收藏 → [生成代码3] → "找到 25 部收藏电影"
复制代码
引导人工操作

遇到需要人工介入的步骤,AI 要明确告诉用户该怎么做:
  1. AI: 我已经打开了登录页面,请在 VNC 窗口中:1. 输入用户名和密码2. 输入验证码3. 点击登录按钮完成后告诉我"登录完成",我将继续后续步骤。
复制代码
六、高级技巧与注意事项

6.1 错误处理(生产环境必备)

永远用 try-catch 包裹核心操作:
  1. try {  // 核心操作  await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });} catch (error) {  // 明确的错误信息  console.error(`操作失败: ${error.message}`);  // 可选:重试逻辑  if (error.name === 'TimeoutError' && retryCount < maxRetries) {    console.log(`超时,重试第 ${retryCount + 1} 次`);    await new Promise(resolve => setTimeout(resolve, 5000));    return executeWithRetry(url, retryCount + 1);  }  throw error;}
复制代码
6.2 性能优化(速度提升明显)

禁用不必要的资源加载
  1. await page.setRequestInterception(true);page.on('request', (req) => {  const resourceType = req.resourceType();  // 丢弃图片、样式、字体等非关键资源  if (['image', 'stylesheet', 'font', 'media'].includes(resourceType)) {    req.abort();  } else {    req.continue();  }});
复制代码
性能提升效果惊人:
优化项优化前优化后提升幅度资源加载数量~100个请求~20个请求↓80%页面加载时间3-5秒1-2秒↑60%网络流量5-10MB0.5-1MB↓90%6.3 安全注意事项

Cookie 安全(重中之重)
  1. # .gitignore 中必须包含*_cookies.jsoncookies.json*.env
复制代码
代码注入防护
  1. // 危险:直接拼接用户输入const userInput = req.query.selector;await page.click(userInput);// 安全:白名单验证const allowedSelectors = ['.button-primary', '.submit-btn'];if (!allowedSelectors.includes(userInput)) {  throw new Error('非法选择器');}await page.click(userInput);
复制代码
6.4 调试技巧(省时省力)

VNC 实时观察(最有效)
  1. # 创建沙箱后立即获取 VNC URLvnc_url = f"https://vnc.example.com/sandbox/{sandbox.sandbox_id}"print(f"打开 VNC: {vnc_url}")
复制代码
截图调试(关键时刻救命)
  1. // 登录前后都截图await page.screenshot({ path: '/home/user/data/before_login.png', fullPage: true });await page.screenshot({ path: '/home/user/data/after_login.png', fullPage: true });
复制代码
七、核心总结

技术收益一目了然

使用 AIO sandbox 能够将状态传递和文件共享复杂度进行有效地降低,并且能够有如下收益:

  • 启动延迟低,从原有的多个 sandbox 优化为了一个 sandbox, 降低了至少 50%的启动时间;
  • 状态保持轻量,在代码执行和浏览器操作的过程中,能够尽量使用本地文件系统实现状态保持,符合最佳实践;
  • VNC 的透出提供了人工介入的手段,有效帮助用户解决了自动化的卡点,如验证等。
7 条黄金法则


  • 必须用 puppeteer.connect(),禁止 launch()
  • 必须用 browser.disconnect(),禁止 close()
  • 必须保存数据到 /home/user/data/ 目录
  • 登录流程拆分:打开登录页 → 人工登录 → 保存 Cookie → 执行任务
  • Cookie 先访问域名再设置,避免跨域问题
  • 多步骤任务用文件系统传递状态,别用全局变量
  • 重要操作必须加错误处理,别让错误静默失败
常见陷阱避坑指南

陷阱症状解决方案用 launch()浏览器重复启动,内存爆了改用 connect()用 close()后续步骤失败,状态丢了改用 disconnect()Cookie 没持久化每次都要重新登录保存到 /home/user/data/cookies.json等待时间不足元素找不到报错用 waitForSelector + networkidle2路径不规范文件丢失或权限错误统一用 /home/user/data/ 目录进阶学习路径


  • 源码分析:github.com/devsapp/agentrun-sandbox-demos/src/
  • 性能调优

    • 禁用图片/字体资源
    • 用 networkidle2 等待策略
    • 批量处理数据,减少 I/O

  • 错误处理

    • 指数退避重试策略
    • 最大重试次数控制
    • 超时和网络错误处理

附录:Demo 代码


  • GitHub:https://github.com/devsapp/agentrun-sandbox-demos
  • 官方文档:https://docs.agent.run/
  • 沙箱教程:https://docs.agent.run/docs/tutorial/core/sandbox

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册