- AI Agent
- 后端
- MCP 服务
- 浏览器控制
- Agent 评测
【免费下载链接】sandbox
All-in-One Sandbox for AI Agents that combines Browser, Shell, File, MCP and VSCode Server in a single Docker container.
在 AIO Sandbox(All-in-One Sandbox for AI Agents)中,Chromium 浏览器下载的文件不会直接出现在宿主机上,而是先落入沙盒容器的文件系统中。本文以官方指南 browser-downloads.md 为核心,系统讲解浏览器下载的默认落盘位置、如何通过 CDP(Chrome DevTools Protocol)配置下载行为、如何用文件 API 查看与导出下载产物,以及下载链路的安全红线。读完本文,你将能够在自己搭建的 AI Agent 工作流中,完整打通"浏览器触发下载 → 沙盒内定位 → 文件 API 导出到宿主机"的闭环。
下载链路总览:为什么下载文件会"消失"在沙盒里
AIO Sandbox 把浏览器、Shell、文件系统、MCP 与 VSCode Server 整合进同一个 Docker 容器。因此 Chromium 进程写入的任何文件,都落在容器的隔离文件系统内,而不是宿主机磁盘上。这一点决定了浏览器下载处理的基本思路:
- 下载产物由 Chromium 写入沙盒文件系统,路径固定、可控;
- Shell 可以直接查看下载目录(因为 Shell 与浏览器共享同一套沙盒文件系统);
- 文件 API 可以把产物拉回宿主机,实现跨容器传输。
换句话说,浏览器下载本质上被拆成了两步:第一步让 Chromium 把文件写进沙盒,第二步通过文件 API 把沙盒里的文件取出来。下面分别展开这两步的实操。
默认下载目录
Chromium 通常会遵循浏览器默认行为,把文件下载到当前运行用户的下载目录。AIO Sandbox 镜像内运行用户为gem,因此默认下载目录为:
/home/gem/Downloads这是一个固定的已知路径,Agent 可以据此预测下载产物的落点,无需先探查用户目录结构。
用文件 API 列出下载目录
Sandbox 的 HTTP 服务默认监听8080端口(本地映射常为127.0.0.1:8080:8080),文件列表接口为POST /v1/file/list。列出下载目录:
curl -X POST "http://localhost:8080/v1/file/list" \ -H "Content-Type: application/json" \ -d '{"path": "/home/gem/Downloads"}'从 SDK 源码看,这一接口在 Python 客户端中对应client.file.list_path(path=...)(见 sdk/python/agent_sandbox/file/client.py),底层请求路径即为v1/file/list。list_path还支持recursive(递归列出)、show_hidden(显示隐藏文件)、file_types(按扩展名过滤,如['.pdf', '.csv'])、include_size(附带文件大小)、sort_by(按 name/size/modified/type 排序)等可选参数,适合在下载目录文件较多时做精准检索。
通过 CDP 配置下载行为
在触发下载之前,先要通过 CDP 配置 Chromium 的下载行为。AIO Sandbox 的浏览器会话会暴露一个 CDP 地址,获取方式有两种:
- 通过 SDK:调用
client.browser.get_info(),其返回结果中的cdp_url字段即为浏览器级 CDP 连接地址(接口定义见 sdk/python/agent_sandbox/browser/client.py); - 直接请求:
GET /v1/browser/info返回同样的信息。
方式一:通过 Playwright 连接 CDP
Playwright 等 CDP 客户端可以在触发下载前配置下载行为。示例(与官方指南一致):
from agent_sandbox import Sandbox from playwright.sync_api import sync_playwright client = Sandbox(base_url="http://localhost:8080") cdp_url = client.browser.get_info().cdp_url with sync_playwright() as p: browser = p.chromium.connect_over_cdp(cdp_url) page = browser.new_page() page.context.set_default_timeout(30_000)这段代码里有两个关键点:
connect_over_cdp(cdp_url)是把 Playwright 附着到沙盒内已运行的 Chromium 实例上,而不是再启动一个新浏览器。仓库中的 examples/playwright-integration/main.py 使用异步写法playwright.chromium.connect_over_cdp(cdp_url)完成同样的连接,可以作为对照参考;page.context.set_default_timeout(30_000)设置 30 秒默认超时,避免下载或页面加载期间操作挂起。
连接成功后,page上发生的页面交互(点击下载链接、触发window.print导出等)就会把文件写入沙盒下载目录。
方式二:直接在浏览器级 CDP 连接上调用Browser.setDownloadBehavior
如果你不依赖 Playwright,而是直接使用 Chrome DevTools Protocol,可以在浏览器级 CDP 连接上发送Browser.setDownloadBehavior命令:
{ "method": "Browser.setDownloadBehavior", "params": { "behavior": "allow", "downloadPath": "/home/gem/Downloads", "eventsEnabled": true } }参数说明:
| 参数 | 取值 | 作用 |
|---|---|---|
behavior | allow/deny/default | allow允许下载并写入downloadPath;deny阻止下载;default沿用浏览器默认行为 |
downloadPath | 沙盒内绝对路径 | 下载文件的落盘目录,与默认下载目录保持一致即可(/home/gem/Downloads) |
eventsEnabled | true/false | 是否派发Browser.downloadWillBegin与Browser.downloadProgress事件,便于程序化跟踪下载进度 |
触发下载后如何确认完成
触发下载后,有两种方式确认下载结果:
- 监听 CDP 事件:订阅
Browser.downloadWillBegin(下载开始,包含下载项 GUID 与建议文件名)与Browser.downloadProgress(下载进度,携带state: completed/canceled等状态),据此判断下载何时结束; - 直接查询文件系统:通过文件 API 检查下载目录,
POST /v1/file/list的返回中确认目标文件已出现。这种方式与事件监听互相独立,即使在 CDP 事件不可用或超时的情况下也能兜底。
下载文件到宿主机
确认下载产物已在沙盒内后,通过文件下载接口把文件拉回宿主机。文件下载接口为GET /v1/file/download,参数为沙盒内绝对路径:
curl -L \ "http://localhost:8080/v1/file/download?path=/home/gem/Downloads/report.pdf" \ --output report.pdf这里的-L用于跟随可能的重定向;--output report.pdf把响应流写入宿主机本地文件。SDK 中对应方法为client.file.download_file(path=..., change_policy=...)(见 sdk/python/agent_sandbox/file/client.py),底层以流式方式消费响应字节,适合大文件下载。
用change_policy=abort防止读取到"写了一半"的文件
下载产物可能仍被后台进程(如正在落盘中的 Chromium)持续写入。若此时直接下载,可能拿到一个不完整或正在变化的文件。此时可以追加change_policy=abort:
curl -L \ "http://localhost:8080/v1/file/download?path=/home/gem/Downloads/report.pdf&change_policy=abort" \ --output report.pdfchange_policy的类型定义见 sdk/python/agent_sandbox/types/file_download_change_policy.py,可取两个值:
| 取值 | 行为 |
|---|---|
ignore | 默认行为,不检测源文件变化,直接流式下发 |
abort | 服务端在开始传输前或传输过程中检测到源文件发生变化时,中断本次下载 |
从 SDK 底层实现(sdk/python/agent_sandbox/file/raw_client.py)可以看出:change_policy=abort时,若服务端检测到文件变化,接口会返回409 Conflict(SDK 中对应抛出ConflictError)。因此在使用该策略时,应把"收到 409"理解为"文件还在变化、需要稍后重试"的信号,而不是真正的失败。
用 SDK 下载的等价写法
不依赖 curl 时,也可以直接在 Python 里完成同样的下载:
from agent_sandbox import Sandbox client = Sandbox(base_url="http://localhost:8080") with open("report.pdf", "wb") as f: for chunk in client.file.download_file( path="/home/gem/Downloads/report.pdf", change_policy="abort", ): f.write(chunk)这样可以把"触发下载 → 轮询目录 → 导出文件"全部收敛进一个 Python 脚本,便于在 Agent 循环里复用。
完整实战:一条龙脚本
把上面的要素组合起来,可以得到一个完整的下载闭环(触发下载 → 确认落盘 → 导出到宿主机):
import time from agent_sandbox import Sandbox from playwright.sync_api import sync_playwright client = Sandbox(base_url="http://localhost:8080") cdp_url = client.browser.get_info().cdp_url # 1. 触发下载 with sync_playwright() as p: browser = p.chromium.connect_over_cdp(cdp_url) page = browser.new_page() page.context.set_default_timeout(30_000) page.goto("https://example.com/report") page.click("a#download") # 2. 轮询等待下载完成 for _ in range(30): result = client.file.list_path(path="/home/gem/Downloads") if any(item.get("name") == "report.pdf" for item in result.items): break time.sleep(1) # 3. 导出到宿主机 with open("report.pdf", "wb") as f: for chunk in client.file.download_file( path="/home/gem/Downloads/report.pdf", change_policy="abort", ): f.write(chunk)几点说明:
- 步骤 2 的轮询用的是文件 API 而非 CDP 事件,即使 CDP 事件流断开也能完成确认;
- 若下载本身耗时较长,可以把
set_default_timeout(30_000)调大,或改用手动轮询; change_policy="abort"保证导出的是一份"稳定"的文件,避免读到半成品。
与浏览器其他配置的衔接
下载行为与浏览器整体配置相互独立但常需协同。AIO Sandbox 支持通过环境变量在容器启动时配置浏览器(详见 browser-config.md),例如BROWSER_EXTRA_ARGS="--disable-dev-shm-usage"追加 Chromium 启动参数、BROWSER_USER_AGENT自定义 User-Agent、HOMEPAGE设置启动首页。这些配置影响页面如何渲染与请求行为,进而影响下载入口是否可用;而下载落盘路径则由 CDP 的downloadPath或浏览器默认行为决定,两者互不覆盖。
此外,运行时也可以通过以下 API 查看或更新浏览器状态:
GET /v1/browser/info:获取 CDP 地址、视口等信息(获取cdp_url的官方入口);POST /v1/browser/config:调整分辨率等浏览器配置;POST /v1/browser/restart:软重启(重连 Playwright 会话)或硬重启(经 supervisorctl 重启浏览器进程)。
安全建议
浏览器下载的文件本质上来自不可信的网页内容,处理时需遵循以下原则:
- 将下载文件视为不可信输入。PDF、Office 文档、脚本等都可能携带恶意内容,Agent 解析或执行前应经过校验;
- 除非用户明确需要,文件应保留在沙盒内处理。沙盒的隔离性是安全边界,把文件导出到宿主机前应确认其必要性;
- 不要开启过宽的本地文件访问能力,除非任务确实需要。下载目录的读写、文件 API 的导出范围都应遵循最小权限原则,避免让 Agent 随意访问沙盒内外的大范围路径。
小结
本文围绕 browser-downloads.md 展开,完整覆盖了 AIO Sandbox 中浏览器下载的三个环节:
- 落盘:Chromium 把下载产物写入沙盒内的
/home/gem/Downloads,可通过POST /v1/file/list查看; - 配置:通过 Playwright 的
connect_over_cdp或 CDP 的Browser.setDownloadBehavior设置下载行为,并用Browser.downloadWillBegin/Browser.downloadProgress事件或文件 API 确认下载完成; - 导出:通过
GET /v1/file/download?path=...&change_policy=abort把稳定版本的产物拉回宿主机。
配合 SDK 中的client.browser.get_info()、client.file.list_path()与client.file.download_file()(实现见 sdk/python/agent_sandbox/browser/client.py 与 sdk/python/agent_sandbox/file/client.py),这一链路可以完全编程化,直接嵌入到 AI Agent 的自动化循环中。
- AI Agent
- 后端
- MCP 服务
- 浏览器控制
- Agent 评测
【免费下载链接】sandbox
All-in-One Sandbox for AI Agents that combines Browser, Shell, File, MCP and VSCode Server in a single Docker container.
相关推荐
Puppeteer BrowserContextOptions:为隔离浏览上下文配置代理与下载行为的完整指南
Puppeteer BrowserContextOptions:为隔离浏览上下文配置代理与下载行为的完整指南 BrowserContextOptions 是 P
浏览器控制测试网页爬虫开发工具Puppeteer 配置深度指南:配置文件、环境变量与浏览器下载行为的完整解析
Puppeteer 配置深度指南:配置文件、环境变量与浏览器下载行为的完整解析 Puppeteer 开箱即用时会自动下载并固定使用一个特定版本的 Chrome
浏览器控制测试网页爬虫开发工具Livewire 文件下载完全指南:从 Laravel 响应到浏览器 Blob 的完整链路
Livewire 文件下载完全指南:从 Laravel 响应到浏览器 Blob 的完整链路 在 Livewire 组件中触发文件下载,用法与 Laravel 原
后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考