AgentRun 实践指南:Agent 的宝藏工具——All-In-One Sandbox
作者:辰泉 函数计算 AgentRun 是一个以高代码为核心的一站式 Agentic AI 基础设施平台。秉持生态开放和灵活组装的理念,为企业级 Agent 应用提供从开发、部署到运维的全生命周期管理。 在开发 AgentRun 的过程中,我们发现了一个让人头疼的问题:现有的沙箱方案太零散了。浏览器、代码执行、Shell 环境各自为政,导致开发效率大打折扣。于是我们决定自己动手,打造一个真正一体化的解决方案——All-In-One Sandbox(AIO)。 AIO 是 AgentRun 提供的云上浏览器自动化沙箱环境,它把浏览器、终端和代码执行能力全部集成在一个容器里。通过简单的 SDK 调用,你就能让 LLM 驱动复杂的 Web 自动化任务,再也不用在多个沙箱之间疲于奔命。 说实话,传统的沙箱方案让我们吃尽了苦头。大多数沙箱都是单一用途的(要么只能跑浏览器,要么只能执行代码),这带来了几个实实在在的痛点: 架构一览 统一文件系统 我们的解决方案很简单粗暴:把所有组件(浏览器、Shell、代码执行、文件系统)都塞进同一个沙箱实例里。 性能对比一目了然: 底层技术栈很扎实: 五大核心能力,开箱即用: 云上沙箱,真的零配置 基于函数计算架构,我们做到了: 多种访问方式,灵活到飞起 不管你是开发者还是运维,都能找到适合自己的使用方式: 这些场景特别适合用 AIO: 每个沙箱实例本质上就是一个基于函数计算环境的会话容器,里面已经预装好了你需要的一切: 注意:本文假设你已经看过前面的实践系列文章,了解 template 和 sandbox 的关系,并且正确创建了 template。如果你还没做过这些,建议先回去补课。 推荐用 python 3.11 环境,兼容性最好。 关键技巧: 用 第一步:打开登录页 第二步:保存 Cookie 第三步:用 Cookie 爬数据 为什么要用多步骤模式? 完整代码参见文末附录:Github 示例仓库。 通过 返回格式很清晰: 什么时候用? 需要登录、人工介入、或者数据量很大的时候。 标准流程: 实操要点: 1. 适用场景: 让 AI 自动生成和执行浏览器自动化代码,非技术用户也能用。 整体架构: 三条铁律(必须遵守): 为什么这么严格? 什么时候需要? 要保持登录状态,跨会话复用的时候。 完整流程: Cookie 保存示例: Cookie 恢复示例: 关键提醒: 适用场景: 需要并发处理大量任务的时候。 两种策略: 选择建议: 并发控制示例: 完整的 Demo 代码可以在示例仓库里找到。 目标很明确: 抓取豆瓣电影 Top250 的电影信息(标题、评分、导演、年份等)。 实际挑战: 我们的解法: AIO Sandbox 的 Cookie 持久化 + 多步骤任务模式。 操作说明: 具体实现可以参考项目的 核心逻辑: 系统提示词(System Prompt)是 LLM Agent 的大脑,直接决定了 AI 如何理解和执行你的需求。对于 AIO Sandbox 集成来说,提示词必须明确告诉 AI 如何生成符合沙箱规范的代码。 在设计提示词之前,你得先理解 All-In-One Sandbox 的核心理念,这直接影响提示词的结构。 我们承认有些事情 AI 就是搞不定,比如验证码、滑块验证、短信验证。所以 AIO 采用“人机协作”的设计理念: 可观测性优先 人机协作而非完全自动 状态持久化 提示词必须明确告诉 AI 这些关键约束: 为什么?看看对比就知道了: 技术原因很简单: 关键区别在这: 登录状态的本质就是 Cookie: 没有持久化会怎样? 标准做法 保存 Cookie: 加载 Cookie: AI 对话模式让非技术用户也能用浏览器自动化,系统提示词在里面起着关键的“翻译”作用。 好的提示词要能指导 AI 自动判断何时拆分任务: 简单任务(不拆分) 需要登录(自动拆分) 遇到需要人工介入的步骤,AI 要明确告诉用户该怎么做: 永远用 try-catch 包裹核心操作: 禁用不必要的资源加载 Cookie 安全(重中之重) 代码注入防护 VNC 实时观察(最有效) 截图调试(关键时刻救命) 使用 AIO sandbox 能够将状态传递和文件共享复杂度进行有效地降低,并且能够有如下收益: 1. 源码分析: https://github.com/devsapp/agentrun-sandbox-demos/tree/main/sandbox-all-in-one-demo 2. 性能调优: 3. 错误处理: 附录:Demo 代码
概述
为什么选择 AIO?
1. 文件共享简直是个噩梦
2. 工具协调复杂到想哭
3. 环境配置繁琐到崩溃
4. 成本和效率双重打击
AIO 沙箱的核心优势


对比项 传统多沙箱方案 All-In-One 沙箱 启动时间 2 个沙箱启动 = 4-15秒(串/并行创建) 1 个沙箱启动 = 5秒 文件传递 通过 OSS,耗时 2-3秒 直接访问,<100ms 内存占用 2×独立运行 = 2c2g+2c2g 1×共享运行 = 2c2g 接口 用途 访问方式 代码执行 API 执行 Node.js/Python 脚本 SDK 方法 VNC 可视化浏览器交互、人工介入 Web 集成 Terminal WebSocket 实时 Shell 交互 WebSocket 文件 API 读写持久化文件 SDK 方法 AIO 沙箱集成指南
1.1 核心概念
沙箱实例到底是什么?
1.2 快速开始
安装 SDK(很简单)
pip install agentrun-sdk['server','playwright']第一个任务:验证沙箱基本功能
from agentrun.sandbox import Sandbox, TemplateType
import asyncio
async def quick_start():
"""验证沙箱基本功能"""
sandbox = Sandbox.create(
template_type=TemplateType.AIO,
template_name="quick-test",
sandbox_idle_timeout_seconds=600
)
print(f"沙箱已创建: {sandbox.sandbox_id}")
# 核心:连接已运行的浏览器,提取页面信息
code = """
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://example.com');
console.log(await page.title());
await browser.disconnect();
"""
await sandbox.context.execute_async(code=code, language="javascript")
sandbox.destroy()
asyncio.run(quick_start())多步骤任务实战
disconnect() 保持浏览器运行,通过文件系统传递状态。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://example.com/login');
console.log('请在 VNC 中完成登录');
await browser.disconnect();const fs = require('fs');
const puppeteer = require('puppeteer-core');
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));
console.log('Cookie 已保存');
await browser.disconnect();const fs = require('fs');
const puppeteer = require('puppeteer-core');
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://localhost:5000/ws/automation'
});
const page = (await browser.pages())[0];
const cookies = JSON.parse(fs.readFileSync('/home/user/data/cookies.json'));
await page.setCookie(...cookies);
await page.goto('https://example.com/data');
// 执行数据采集
await browser.disconnect();1.3 关键概念说明
代码执行方式
sandbox.context.execute_async() 方法执行代码:result = await sandbox.context.execute_async(
code="console.log('Hello')",
language="javascript", # 或 "python"
timeout=300 # 超时时间(秒)
){
"contextId": "ctx_xxx", # 上下文 ID
"results": [
{"type": "stdout", "text": "Hello\n"},
{"type": "result", "value": null}
]
}文件操作(超简单)
# 写入文件
sandbox.file.write(
path="/home/user/data/result.json",
content='{"key": "value"}',
encoding="utf-8"
)
# 读取文件
content = sandbox.file.read("/home/user/data/result.json")
# 上传本地文件
sandbox.file_system.upload(
local_file_path="./local_file.txt",
target_file_path="/home/user/data/file.txt"
)
# 下载文件
sandbox.file_system.download(
path="/home/user/data/result.json",
save_path="./result.json"
)最佳实践
2.1 多步骤任务模式
步骤 1:打开登录页 → 通过 VNC 人工登录
步骤 2:保存 Cookie 到文件系统
步骤 3:使用 Cookie 执行数据采集sandbox_idle_timeout_seconds >= 1800 保持一定时间状态可用,闲置超时后自动回收。disconnect() 保持浏览器运行,close() 会关掉浏览器。/home/user/data/ 目录传递 Cookie 和进度。sandbox.sandbox_id 和 base URL 拼起来就行。sandbox.file.read() 和 sandbox.file.write()。2.2 LLM Agent 集成模式

puppeteer.launch() → 必须:puppeteer.connect()browser.close() → 必须:browser.disconnect()/home/user/data/xxx.json2.3 Cookie 持久化模式
首次登录:
1. 人工登录 → 2. 保存 Cookie → 3. 持久化存储
后续使用:
1. 上传Cookie -> 2. 读取 Cookie → 3. 恢复会话 → 4. 执行任务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();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];
// 读取 Cookie
const 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();/home/user/data/ 目录,这样才有权限page.cookies() 获取所有 Cookie,一个都不能少page.setCookie(...cookies) 恢复,顺序很重要2.4 批量任务模式
策略 1:单沙箱顺序执行(简单任务,有依赖关系)
策略 2:多沙箱并发执行(复杂任务,无依赖关系)策略 适用场景 优势 单沙箱顺序执行 简单任务,依赖前序结果 资源占用低,状态连续 多沙箱并发执行 复杂任务,无依赖关系 执行速度快,并行处理 # 使用 asyncio.gather() 实现并发
tasks = [
process_item(item)
for item in items
]
results = await asyncio.gather(*tasks, return_exceptions=True)实战案例:豆瓣电影 Top250 爬取

3.1 需求分析
3.2 核心实现流程
步骤 1:首次登录并保存 Cookie

// 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();步骤 2:保存 Cookie
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 爬取数据

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];
// 恢复 Cookie
const cookies = JSON.parse(fs.readFileSync('/home/user/data/douban_cookies.json'));
await page.setCookie(...cookies);
// 访问 Top250
await 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();3.3 完整 Python 代码
src/ai_code_generator.py 和 src/sandbox_executor.py。from agentrun.sandbox import Sandbox, TemplateType
import asyncio
async 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())3.4 核心技术点总结
3.5 扩展功能
分页爬取(完整 Top250)
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));错误处理和重试(生产必备)
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;
}系统提示词设计
4.1 为什么提示词这么重要?

4.2 我们的设计哲学
人机协作,不是完全自动化
disconnect() 保持浏览器运行,状态不会丢4.3 核心约束与最佳实践
1. 必须用 connect(),别用 launch()
传统方式 (错误):
const browser = await puppeteer.launch(); // 启动新浏览器 (1-3 秒)
// 执行任务
await browser.close(); // 状态全部丢失
All-In-One 方式 (正确):
const browser = await puppeteer.connect({ // 连接已运行的浏览器 (<100ms)
browserWSEndpoint: 'ws://localhost:5000/ws/automation'
});
// 执行任务
await browser.disconnect(); // 保持浏览器运行launch() 会启动第二个浏览器,纯属浪费资源connect() 几乎瞬间连接,特别适合多步骤任务2. 必须用 disconnect(),别用 close()
browser.close():
- 关闭所有页面
- 终止浏览器进程
- 清理所有状态
- 无法支持多步骤任务
- VNC 显示中断
browser.disconnect():
- 只断开 Puppeteer 连接
- 浏览器继续运行
- 所有状态保留
- 支持多步骤任务
- VNC 显示连续3. Cookie 持久化是王道
用户登录 → 服务器设置 Cookie → 后续请求携带 Cookie → 服务器识别用户const cookies = await page.cookies();
fs.writeFileSync(
'/home/user/data/cookies.json',
JSON.stringify(cookies, null, 2)
);const cookies = JSON.parse(
fs.readFileSync('/home/user/data/cookies.json')
);
// 先访问对应域名
await page.goto('https://example.com');
// 再设置 Cookie
await page.setCookie(...cookies);4.4 实用提示词模板
基础模板(直接复制就能用)
你是 AgentRun AIO Sandbox 的代码生成助手。你的任务是将用户需求转换为可在沙箱中执行的 Puppeteer 代码。
【环境信息】
- 浏览器:Chromium (已预启动)
- 连接端点:ws://localhost:5000/ws/automation
- 文件系统:/home/user/data/ (持久化目录)
- 超时限制:单次执行 300 秒
【代码规范】
1. 连接浏览器:
const puppeteer = require('puppeteer-core');
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://localhost:5000/ws/automation'
});
2. 结束会话:
await browser.disconnect();
3. 文件读写:
const fs = require('fs');
// 读取
const data = fs.readFileSync('/home/user/data/file.json');
// 写入
fs.writeFileSync('/home/user/data/file.json', JSON.stringify(data));
4. 错误处理:
try {
// 代码逻辑
} catch (error) {
console.error(`错误: ${error.message}`);
throw error;
}
【输出要求】
- 生成完整的 JavaScript 代码
- 包含必要的错误处理
- 关键步骤用 console.log() 记录
- 重要结果保存到文件系统4.5 AI 对话模式的工作原理

智能任务拆分
用户: 访问 example.com,获取页面标题
AI 直接生成单个代码块,执行后返回结果用户: 登录豆瓣,然后获取我的收藏
AI 自动拆分为 3 个步骤:
步骤 1: 打开登录页 → [生成代码1] → "请在 VNC 中完成登录"
步骤 2: 保存 Cookie → [生成代码2] → "已保存 15 个 Cookie"
步骤 3: 获取收藏 → [生成代码3] → "找到 25 部收藏电影"引导人工操作
AI: 我已经打开了登录页面,请在 VNC 窗口中:
1. 输入用户名和密码
2. 输入验证码
3. 点击登录按钮
完成后告诉我"登录完成",我将继续后续步骤。高级技巧与注意事项
5.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;
}5.2 性能优化(速度提升明显)
await page.setRequestInterception(true);
page.on('request', (req) => {
const resourceType = req.resourceType();
// 丢弃图片、样式、字体等非关键资源
if (['image', 'stylesheet', 'font', 'media'].includes(resourceType)) {
req.abort();
} else {
req.continue();
}
});5.3 安全注意事项
# .gitignore 中必须包含
*_cookies.json
cookies.json
*.env// 危险:直接拼接用户输入
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);5.4 调试技巧(省时省力)
# 创建沙箱后立即获取 VNC URL
vnc_url = f"https://vnc.example.com/sandbox/{sandbox.sandbox_id}"
print(f"打开 VNC: {vnc_url}")// 登录前后都截图
await page.screenshot({ path: '/home/user/data/before_login.png', fullPage: true });
await page.screenshot({ path: '/home/user/data/after_login.png', fullPage: true });核心总结
技术收益一目了然
7 条黄金法则
puppeteer.connect(),禁止 launch()browser.disconnect(),禁止 close()/home/user/data/ 目录常见陷阱避坑指南
陷阱 症状 解决方案 用 launch() 浏览器重复启动,内存爆了 改用 connect() 用 close() 后续步骤失败,状态丢了 改用 disconnect() Cookie 没持久化 每次都要重新登录 保存到 /home/user/data/cookies.json 等待时间不足 元素找不到报错 用 waitForSelector + networkidle2 路径不规范 文件丢失或权限错误 统一用 /home/user/data/ 目录 进阶学习路径
networkidle2 等待策略