Industry & PracticeTools & Frameworks
Inspect 沙 箱: 把 命令 关 进 隔离 环境 再 评 分
英国 AI Security Institute 的 Inspect 把 shell 和 Python 放进沙箱。读文件默认 100MB,执行输出默认 10MB。Docker 守护进程要 24.0.6 或更高,Compose 要 2.21.0 或更高。Docker 并行沙箱默认是可用处理器数的两倍。

In this piece
沙箱
概述
模型的工具调用发生在跑评测任务的主进程里。工具真正要做的事——跑 shell 命令,或执行 Python 代码——常常必须放到单独、隔离的环境里。例如 bash() 就是在沙箱里跑 shell。沙箱(sandbox)是与评测主进程隔开的执行环境。下面几种情况会用到它:
- 你在写会执行任意代码的工具、智能体或评分器(例如 shell 命令或 Python)。工具(tool)是交给模型调用的函数。智能体(agent)会多轮规划并调用工具。评分器(scorer)给输出打分。
- 你要为每个样本准备文件系统资源。样本(sample)是数据集里的一道题。
- 你要提供更复杂的评测环境(例如为网络安全评测创建网络主机)。
为此,Inspect 提供沙箱支持。通常是准备容器,让工具、智能体和评分器在里面执行命令和代码。Inspect 的若干标准工具必须有沙箱,包括 bash()、python() 和 text_editor()。Docker 沙箱是内置的。扩展 API 可以再增加别的沙箱类型。
示例:列出文件
先看一个小例子,把目录列表这件事走通。我们定义 list_files() 工具。它需要 ls 命令,做法是调用 sandbox(),拿到当前正在执行的 Sample 对应的 SandboxEnvironment 实例。样本还在执行时,这个实例就是该样本自己的沙箱,而不是别的样本的沙箱:
from inspect_ai.tool import ToolError, tool
from inspect_ai.util import sandbox
@tool
def list_files():
async def execute(dir: str):
"""List the files in a directory.
Args:
dir: Directory
Returns:
File listing of the directory
"""
result = await sandbox().exec(["ls", dir])
if result.success:
return result.stdout
else:
raise ToolError(result.stderr)
return executeexec() 用来列出目录内容。它在哪里实现、怎样实现,这里还看不出来(下文会说明)。
下面是使用这个工具的一次评测:
from inspect_ai import task, Task
from inspect_ai.dataset import Sample
from inspect_ai.scorer import includes
from inspect_ai.solver import generate, use_tools
dataset = [
Sample(
input='Is there a file named "bar.txt" '
+ 'in the current directory?',
target="Yes",
files={"bar.txt": "hello"},
)
]
@task
def file_probe():
return Task(
dataset=dataset,
solver=[
use_tools([list_files()]),
generate()
],
sandbox="docker",
scorer=includes(),
)这里写了 sandbox="docker",于是经 sandbox() 发出的操作会在 Docker 容器里跑。只要工具、智能体或评分器调用了 sandbox(),就必须在样本、任务或评测某一层指定沙箱环境。任务(task)是一次评测的数据集、求解器和评分器的组合。
准备沙箱并不会自动把工具、智能体或评分器放进容器里跑。这些代码仍是评测进程的一部分。只有它们通过 sandbox() 接口请求的工作,才会在容器里执行。
files 写在 Sample 上。文件可以是纯文本(如上)、base64 的 data URI,或本地文件、远程资源(例如 S3 桶)的路径。相对路径按底层数据集文件所在位置解析。
环境接口
需要和 SandboxEnvironment 交互的工具、智能体和评分器,可以使用下面这些实例方法。它们都是沙箱环境对象上的方法,不是评测主进程里的普通函数。
exec()
async def exec(
self,
cmd: list[str],
input: str | bytes | None = None,
cwd: str | None = None,
env: dict[str, str] = {},
user: str | None = None,
timeout: int | None = None,
timeout_retry: bool = True,
concurrency: bool = True
) -> ExecResult[str]:
"""
Raises:
TimeoutError: If the specified `timeout` expires.
UnicodeDecodeError: May be raised if the sandbox provider
cannot decode the command output to UTF-8 and does not
support using the UTF-8 replacement character for
characters which cannot be decoded.
PermissionError: If the user does not have
permission to execute the command.
"""
...exec() 应当执行输出上限 SandboxEnvironmentLimits.MAX_EXEC_OUTPUT_SIZE(默认 10MB,可用环境变量 INSPECT_SANDBOX_MAX_EXEC_OUTPUT_SIZE 调整)。超过上限时,从前面截断,只保留尾部,使结果落在上限以内。
容器服务可能不可靠,所以 exec() 有参数 timeout_retry,默认 True。对沙箱实现来说,这个参数是建议性的:只有运行时确实可能不可靠时才应使用。重试不超过 2 次,且每次超时都小于 60 秒。如果命令不是幂等的(第一次失败的副作用会影响后面的尝试),可以设 timeout_retry=False 关掉这一行为。幂等是指同一操作重复做,结果与只做一次相同。
exec_remote()
async def exec_remote(
self,
cmd: list[str],
options: (
ExecRemoteStreamingOptions
| ExecRemoteAwaitableOptions
| None
) = None,
*,
stream: bool = True,
) -> ExecRemoteProcess | ExecResult[str]:
"""
Raises:
TimeoutError: If `timeout` is specified in
ExecRemoteAwaitableOptions and the command
exceeds it (only applicable when `stream=False`).
"""
...exec_remote() 的选项(ExecRemoteStreamingOptions 和 ExecRemoteAwaitableOptions)里有 user 字段,要求命令以指定用户运行,等价于 docker exec --user。这要求沙箱工具服务在容器内以 root 运行。如果服务不能切换用户,会抛出 ToolException。省略 user 时,命令以沙箱的默认用户运行,也就是 sandbox().exec() 所用的那个用户。流式选项与可等待选项都带这个字段;超时只在 stream=False 且选项里写了 timeout 时才会因超时抛出 TimeoutError。
write_file()
async def write_file(
self, file: str, contents: str | bytes
) -> None:
"""
Raises:
TimeoutError: If the operation times out.
PermissionError: If the user does not have
permission to write to the specified path.
IsADirectoryError: If the file exists already and
is a directory.
"""
...write_file() 会在父目录不存在时按需自动创建,调用方不必先单独建目录。
read_file()
async def read_file(
self, file: str, text: bool = True
) -> Union[str | bytes]:
"""
Raises:
TimeoutError: If the operation times out.
FileNotFoundError: If the file does not exist.
UnicodeDecodeError: If an encoding error occurs
while reading the file.
(only applicable when `text = True`)
PermissionError: If the user does not have
permission to read from the specified path.
IsADirectoryError: If the file is a directory.
OutputLimitExceededError: If the file size
exceeds the 100 MiB limit.
"""
...read_file() 应当执行 SandboxEnvironmentLimits.MAX_READ_FILE_SIZE 上限(默认 100MB,可用环境变量 INSPECT_SANDBOX_MAX_READ_FILE_SIZE 调整)。超过时抛出 OutputLimitExceededError。
read_file() 应当保留换行形式(例如保留 crlf,不要转成 lf)。这等价于调用 Python open() 时指定 newline=""。文档字符串里的 100 MiB 上限,与上面这个可配置的默认 100MB 是同一道限制;text = True 时才可能出现 UnicodeDecodeError。
connection()
async def connection(self, *, user: str | None = None) -> SandboxConnection:
"""
Raises:
NotImplementedError: For sandboxes that don't provide connections
ConnectionError: If sandbox is not currently running.
"""
...connection() 是可选的。它提供从终端或 IDE 登录沙箱容器的命令。不提供连接的沙箱会抛出 NotImplementedError;沙箱当前没在运行时抛出 ConnectionError。
预期错误与意外错误
每个方法都有文档写明会抛出的错误。这些是预期错误,工具可以抓住,也可以让它们继续传播。传播之后会报告给模型,以便模型尝试恢复。另外还可能出现意外错误(例如连远程容器时的网络错误)。意外错误不报告给模型,并使该 Sample 以错误状态失败。
环境绑定
Inspect 内置两种沙箱环境,另有六个作为外部包提供。兼容 Dockerfile 的沙箱接受标准的 Dockerfile 和 compose.yaml 配置文件。下表按环境类型列出包、是否接受 Dockerfile,以及它实际跑在哪里。
| 环境类型 | 包 | Dockerfile | 说明 |
|---|---|---|---|
docker | 内置 | 是 | 本机安装的 Docker。 |
k8s | inspect-k8s-sandbox | 是 | Kubernetes 集群。 |
daytona | inspect-sandboxes | 是 | Daytona 云沙箱。 |
modal | inspect-sandboxes | 是 | Modal 云沙箱。 |
ec2 | inspect_ec2_sandbox | 否 | AWS EC2 虚拟机。 |
proxmox | inspect_proxmox_sandbox | 否 | 带虚拟机的 Proxmox。 |
vagrant | inspect_vagrant_sandbox | 否 | 在任意 Vagrant 支持的虚拟化上运行的 Vagrant 虚拟机。 |
openshell | inspect-openshell-sandbox | 是 | 带 Landlock 文件系统与网络策略的 NVIDIA OpenShell 沙箱。 |
local | 内置 | 否 | 本地文件系统(没有沙箱)。 |
docker 用本机安装的 Docker。k8s 跑在 Kubernetes 集群上。daytona 和 modal 都是云沙箱,包都是 inspect-sandboxes。ec2 是 AWS EC2 虚拟机,不接受 Dockerfile。proxmox 带虚拟机。vagrant 在任意 Vagrant 支持的虚拟化上跑虚拟机。openshell 是带 Landlock 文件系统策略和网络策略的 NVIDIA OpenShell 沙箱。local 直接用本地文件系统,没有隔离。接受 Dockerfile 的是 docker、k8s、daytona、modal 和 openshell。不接受 Dockerfile 的是 ec2、proxmox、vagrant 和 local。外部包一共六个:k8s、sandboxes(daytona 与 modal 共用)、ec2、proxmox、vagrant、openshell。内置的两种是本机 Docker,以及没有隔离的本地文件系统。选环境时先看要不要 Dockerfile,再看是本机、集群、云沙箱还是虚拟机。
local 环境始终以当前有效用户执行。在 POSIX 系统上,exec(user=...) 接受该用户的名字或 UID;其他身份会在执行前抛出 SandboxUserUnsupportedError。在其他平台上不要传 user。
沙箱环境可以绑在 Sample、Task 或 eval() 上。绑定优先级从 eval() 到 Task 再到 Sample,外层调用上的绑定盖过内层。但是,当样本的沙箱类型与外层 Task 或 eval() 相同时,写在 Sample 上的沙箱配置文件始终优先,不会被外层同类型配置盖掉。
下面这个 Task 定义了 sandbox:
Task(
dataset=dataset,
plan([
use_tools([read_file(), list_files()])),
generate()
]),
scorer=match(),
sandbox="docker"
)默认会自动发现并使用任务目录里的 Dockerfile 和/或 compose.yaml。如果 compose 文件名不同,可以这样覆盖:
sandbox=("docker", "attacker-compose.yaml")编程方式配置
更动态的场景里,可以在程序里构造 ComposeConfig,而不用静态 YAML。需要按任务参数改变容器配置时,这很有用:
from inspect_ai.util import ComposeConfig, ComposeService, SandboxEnvironmentSpec
@task
def my_task(cpus: float = 1.0):
config = ComposeConfig(
services={
"default": ComposeService(
image="python:3.12-bookworm",
init=True,
command="tail -f /dev/null",
mem_limit="512m",
cpus=cpus,
network_mode="none",
)
}
)
return Task(
dataset=dataset,
solver=[use_tools([read_file()]), generate()],
scorer=match(),
sandbox=SandboxEnvironmentSpec("docker", config),
)ComposeConfig 和 ComposeService 对应 Docker Compose 文件的结构,支持 image、build、command、environment、volumes、ports、mem_limit、cpus 等字段。以 x- 开头的扩展字段也支持。上面的例子把 CPU 数量做成任务参数,默认 1.0,内存上限写成 512m,网络模式写成 none,并用 SandboxEnvironmentSpec("docker", config) 交给任务。
沙箱限制
默认情况下,读文件限制为 100MB,执行输出限制为 10MB。这些上限用来挡住不结束的输出或执行,避免内存耗尽(OOM)或评测挂起。OOM 是进程把可用内存用完。这类情况通常表示模型出错。
两种上限的执行方式不同。read_file() 超过上限时总会抛出 OutputLimitExceededError。exec() 则取决于沙箱提供方:内置提供方会从前面截断每一路输出(只保留尾部),因此 exec() 返回成功的 ExecResult,其 stdout 或 stderr 可能被悄悄截断,而不是抛错。不要靠异常来发现 exec() 溢出。解析 JSON 这类结构化输出时尤其要注意。如果命令的输出可能接近上限,而你需要全部内容,让命令把结果写进文件,再用 read_file() 去读。
也可以用环境变量提高上限。下面把读文件设为 200MB,执行输出设为 20MB:
export INSPECT_SANDBOX_MAX_READ_FILE_SIZE=209715200
export INSPECT_SANDBOX_MAX_EXEC_OUTPUT_SIZE=20971520按样本准备
Sample 有 sandbox、files 和 setup 字段,分别指定每个样本的沙箱配置、要放进环境的文件,以及复制文件之后要跑的准备逻辑。
沙箱
可以像上面那样给整个 Task 设一个默认 sandbox,也可以为每个样本单独设 sandbox。例如每个样本有自己的 Dockerfile 或自定义 compose 文件时就会这样做。注意:即使沙箱定义在任务层,每个样本仍有自己的沙箱实例,样本之间不会互相干扰。
sandbox 可以是字符串(例如 "docker")、沙箱类型与配置文件的元组(例如 ("docker", "compose.yaml")),或带 ComposeConfig 的 SandboxEnvironmentSpec(见上文「编程方式配置」)。最后一种特别适合按样本改变容器配置(例如每个样本用不同的 Docker 镜像)。
文件
样本的 files 是 dict[str,str],指定要复制进沙箱的文件。字典的键是要写入的文件名。默认写入默认沙箱;也可以加前缀,写到指定沙箱(例如 "victim:flag.txt": "flag.txt")。
字典的值可以是文件内容本身、指向文件的路径,或 base64 编码的 Data URL。键里的环境前缀只决定写进哪一个沙箱,值的三种写法对默认沙箱和具名沙箱同样适用。
脚本
如果样本有 setup bash 脚本,会在样本的 files 复制进环境之后,在默认沙箱里执行。顺序是先复制文件,再跑脚本。setup 可以是脚本内容、含脚本的文件路径,或 base64 编码的 Data URL。它只在默认沙箱里执行,不会自动跑到具名沙箱。
Docker 配置
安装
使用 Docker 沙箱之前,请先安装 Docker Engine。Inspect 会检查已连接的 Docker 守护进程,要求版本不低于 24.0.6。
Docker Compose 单独检查:Inspect 要求版本不低于 2.21.0;当 Inspect 从镜像仓库拉取沙箱镜像时,要求不低于 2.22.0。
如果评测要并发大量容器(多于 30 个),还应配置 Docker 的默认地址池,否则地址不够时容器起不来。守护进程版本与 Compose 版本是两条分开的检查。
任务配置
Docker 沙箱可以不做专门配置就用。更常见的是用 Dockerfile 或 Docker Compose 配置文件(compose.yaml)显式配置。
任务目录里有没有 Dockerfile 和/或 compose.yml,决定沙箱如何创建:
| 配置文件 | 行为 |
|---|---|
| 无 | 用标准的 inspect-tool-support 镜像创建沙箱环境。 |
Dockerfile | 通过构建镜像创建沙箱环境。 |
compose.yaml | 按 compose.yaml 创建沙箱环境。 |
并不强制提供 compose.yaml。需要时 Inspect 会自动生成。生成的 Compose 配置设置 network_mode: none,在容器运行时阻止网络访问。
提供自定义 Compose 配置——无论是 Compose 文件还是 ComposeConfig——会替换生成的配置,而不是在它上面扩展,其中也包括 network_mode: none。Docker Compose 的默认是项目范围的网络,并且可以访问外网。因此,除非评测需要网络,否则应在自己的配置里写上 network_mode: none。
如果评测确实需要网络,就不要写 network_mode。这样既有出站访问,又保持项目网络隔离(network_mode: bridge 会加入 Docker 共享的内置网桥,所以更倾向于省略该字段)。服务之间只需要互相通信时,使用内部网络,允许服务之间的流量,但不允许对外连通。
下面的 compose.yaml 设置容器资源上限,并把它与包括互联网在内的全部网络交互隔开:
compose.yamlservices:
default:
build: .
init: true
command: tail -f /dev/null
cpus: 1.0
mem_limit: 0.5gb
network_mode: nonenetwork_mode: none 只作用于容器内的进程。它不限制评测进程或模型提供方的网络。因此,自定义工具、智能体或评分器里的代码仍可能在 Docker 沙箱之外访问互联网。不使用 Inspect 沙箱的工具,例如 web_search(),也不受影响。init: true 让容器能响应关闭请求。command 用来防止容器启动后马上退出。
下面是本地预构建镜像 ctf-agent-environment 的简单 compose.yaml(为简短起见不含资源上限):
compose.yamlservices:
default:
image: ctf-agent-environment
x-local: true
init: true
command: tail -f /dev/null
network_mode: nonectf-agent-environment 不在远程仓库上,所以加上 x-local: true,表示不要拉取。如果本地镜像带了标签,默认也不会拉取(因此不需要 x-local: true)。例如:
compose.yamlservices:
default:
image: ctf-agent-environment:1.0.0
init: true
command: tail -f /dev/null
network_mode: none使用远程仓库上的镜像时,同样不必写 x-local:
compose.yamlservices:
default:
image: python:3.12-bookworm
init: true
command: tail -f /dev/null
network_mode: none全部容器选项见 Docker Compose 文档。
预构建镜像
如果沙箱镜像已经在本地 Docker 镜像库里(例如一台到不了仓库的隔离机器),传入 --sandbox-prebuilt,完全跳过镜像构建:
inspect eval ctf.py --sandbox-prebuilt在 Python 里:
eval("ctf.py", sandbox_prebuilt=True)打开这个选项后,任务启动时核验镜像,而不是构建。每个带 build 段或 x-local: true 的服务,都必须指定一个本地已经存在的 image。Inspect 的内部镜像(例如计算机工具用的镜像)也必须在本地。其他服务在本地有镜像时用本地镜像;缺失镜像拉取失败也算错误。缺镜像会在任何样本运行之前报错。该选项也可以用环境变量 INSPECT_EVAL_SANDBOX_PREBUILT 设置。
多个环境
有时要建多个沙箱环境(例如一个环境的复杂依赖与其他环境冲突)。做法是指定多个具名服务:
compose.yamlservices:
default:
image: ctf-agent-environment
x-local: true
init: true
cpus: 1.0
mem_limit: 0.5gb
network_mode: none
victim:
image: ctf-victim-environment
x-local: true
init: true
cpus: 1.0
mem_limit: 1gb
network_mode: none列出的第一个环境是“默认”环境,工具里普通调用 sandbox() 就会用到它。其他环境按名字访问,例如:
sandbox() # default sandbox environment
sandbox("victim") # named sandbox environment定义了多个沙箱环境时,默认环境按下面的顺序决定:
- 先取名为
default的沙箱环境; - 再取把
x-default设为true的环境; - 最后用第一个沙箱环境作为默认。
可以用 sandbox_default() 上下文管理器临时改默认沙箱(例如有些工具总是打到默认沙箱,你想暂时把它们转走):
with sandbox_default("victim"):
# call tools, etc.基础设施
很多时候还要准备额外基础设施(例如其他主机或卷)。下面定义了额外容器 “writer”,以及默认容器与 writer 容器共享的卷:
services:
default:
image: ctf-agent-environment
x-local: true
init: true
network_mode: none
volumes:
- ctf-challenge-volume:/shared-data
writer:
image: ctf-challenge-writer
x-local: true
init: true
network_mode: none
volumes:
- ctf-challenge-volume:/shared-data
volumes:
ctf-challenge-volume:完整模式和功能见 Docker Compose 文件文档。上面这个例子里,default 与 writer 都挂到同一个具名卷 ctf-challenge-volume 的 /shared-data,两边网络模式都是 none,并且都标了 x-local: true。
样本元数据
可以把样本元数据插进 Docker compose 文件。用标准的 compose 环境变量语法即可。样本里的任何元数据都会带上前缀 SAMPLE_METADATA_。例如按样本设内存上限,未指定时默认 0.5gb:
services:
default:
image: ctf-agent-environment
x-local: true
init: true
cpus: 1.0
mem_limit: ${SAMPLE_METADATA_MEMORY_LIMIT-0.5gb}
network_mode: none注意 - 后缀提供默认值 0.5gb。这很重要:compose 文件在没有样本上下文时被读取(例如启动时拉取或构建镜像),仍要有一个默认值。
挂载宿主机目录
恶意智能体如果通过卷挂载获得对宿主机的写权限,就能改沙箱外面的文件。即使只限制在一个目录里,它也可能改写 compose.yml,让以后的样本或评测拿到超出你本意的权限;或者用符号链接改掉后面某个样本的挂载,暴露你并不打算共享的宿主机文件。
出于安全,Inspect 会阻止让 Docker 沙箱对宿主机文件或目录拥有写权限的卷挂载。
只读共享宿主机目录时,在挂载上加 :ro:
services:
default:
image: ubuntu:24.04
volumes:
- ./host-dir:/container-dir:ro只读共享要求 Docker Engine 25 或更高、Compose 2.24 或更高,以及 Docker 宿主机上的 Linux 内核 5.12 或更高。Inspect 还会检查容器运行时能否让共享目录内的挂载保持只读。这些检查也适用于 Compose 的 configs 和 secrets。
如果服务的权限或挂载选项可能把只读宿主机挂载变成可写,Inspect 也会拒绝。
这些检查只覆盖挂载。特权容器、宿主机设备或 Docker 套接字仍可能让智能体访问宿主机。
需要可写数据时,可以用 Sample.files 复制输入,或使用 Docker 管理的卷。
如果评测确实需要不安全的宿主机写访问,可以在 Compose 文件里为全部服务打开:
x-inspect_docker_sandbox:
unsafe_allow_writable_host_mounts: truevolumes_from,以及带自定义名称、驱动、驱动选项或外部存储的卷,也需要这一选择加入。它同时会绕过上面的只读兼容性检查。
环境清理
任务完成后,Inspect 会自动清理与沙箱环境相关的资源(例如容器、镜像和网络)。如果因为某种原因没有清掉(例如清理本身被 Ctrl+C 打断),可以用 inspect sandbox cleanup 全局清理全部环境。下面清理与 docker 提供方相关的全部环境:
$ inspect sandbox cleanup docker有时你更希望不清理环境。例如要从 shell 交互查看状态,以便调试智能体。使用 --no-sandbox-cleanup:
$ inspect eval ctf.py --no-sandbox-cleanup使用 eval( 时也可以:
eval("ctf.py", sandbox_cleanup = False)这样做之后,会打印沙箱容器列表,其中有每个容器的 ID。可以用这个 ID 进入某个容器的 shell:
docker exec -it inspect-task-ielnkhh-default-1 bash -l不再需要这些环境时,可以一次全部清理,或按项目名单独清理。打印出的列表末尾有每个环境的清理命令:
# cleanup all environments
inspect sandbox cleanup docker
# cleanup single environment
inspect sandbox cleanup docker inspect-task-ielnkhh资源管理
在 Docker 容器里创建并执行代码,内存和 CPU 都很贵。Inspect 提供一些自动资源管理,让默认情况下的用量保持合理。这一节说明这一行为,以及怎样按你的用途调整。
最大沙箱数
max_sandboxes 决定可以并行执行多少个沙箱。各沙箱提供方可以有自己的默认上限。例如 Docker 提供方默认是评测可用处理器数量的两倍。在容器 CPU 限制下(例如 docker --cpus 或 Kubernetes 的 limits.cpu),用的是这个限制,而不是宿主机的处理器数量。你可以按需要修改该选项,但容器运行时有资源上限,顶到或超过这些上限会导致不稳定和评测失败。
应用了 max_sandboxes 时,任务状态屏幕底部会显示一个指示:
max_sandboxes 在使用同一沙箱提供方类型的全部任务之间共享。每种提供方类型有自己独立的上限。
最大子进程数
max_subprocesses 决定可以并行运行多少个子进程调用。默认是评测可用的处理器数量(在容器 CPU 限制下,用该限制,而不是宿主机处理器数量)。按沙箱里执行的性质,增加或减少 max_subprocesses 都可能有好处。
最大样本数
另一项是 max_samples,即一个任务里可以并发运行的最大样本数。并发样本越多,吞吐越高,但已完成样本写入日志的频率越低,任务被打断时能恢复的样本总数也越少。
默认情况下,max_samples 跟随模型当前的连接上限:自适应连接(默认)时跟随控制器;静态并发时设为 max_connections(把它设得比 max_connections 更低通常没有意义)。较小的上限通常会让样本较频繁地写入日志。另一方面,设得非常大(例如数据集有 100 个样本,就把 max_connections 设为 100)时,一旦中断,能恢复的样本可能很少。
如果任务包含工具调用和/或沙箱,通常会想把 max_samples 设得大于 max_connections。因为样本有时在调用模型(占用并发连接),有时在沙箱里执行代码(占用并发子进程)。跑任务时可以实时看到连接和子进程的利用率,并据此调整 max_samples。
容器资源
用 compose.yaml 限制每个正在运行的容器所消耗的资源。例如:
compose.yamlservices:
default:
image: ctf-agent-environment
x-local: true
command: tail -f /dev/null
cpus: 1.0
mem_limit: 0.5gb
network_mode: none排障
要诊断沙箱执行问题(例如命令不能正常结束、容器生命周期问题等),应使用 Inspect 的 Tracing。追踪(tracing)记录调用的开始和结束,用来定位没有返回的命令。
追踪日志记录对 subprocess() 的调用何时开始、何时结束(例如在沙箱里跑命令的工具调用),以及发给 Docker Compose 的控制命令。子命令 inspect trace anomalies 可以查询不结束、超时或出错的命令。更多细节见 Tracing。
UK AI Security Institute,Sandboxing,文档页无单独发布日期(检索于 2026-10-29),https://inspect.aisi.org.uk/sandboxing.html ,MIT License(Copyright (c) 2024 UK AI Security Institute)。
Found it useful? Pass it on
Scan with WeChat to open it on your phone and forward it.