【智能体工具使用实战04】构建执行沙盒与安全边界

第4章 构建执行沙盒与安全边界

本章你将学到

  • 为什么不能让AI生成的代码直接在你的电脑上裸跑
  • 用纯Python实现一个轻量级执行沙盒,不需要Docker
  • 沙盒的五层安全机制:临时文件、超时终止、模块白名单、输出限制、网络隔离
  • 如何测试沙盒本身是否可靠
  • 将沙盒封装为Agent可调用的 execute_python 工具

本章你将产出 :一个经过安全测试的执行沙盒模块 sandbox.py,以及一个新增了 execute_python 工具的Agent

全部章节 :收录在专栏《AI应用工程化实战教程》之【智能体工具使用实战】


4.1 一个必须面对的问题

第3章结束时,你的Agent能读文件了。它成功读取了 scores.csv,描述了数据的基本情况------有多少行、多少列、各列的名称。

但有一个问题它始终没解决:计算。

你让它分析成绩数据,它能告诉你"这份数据包含10名学生、4门课程",但当你追问"高数的平均分是多少"时,它要么凭"感觉"估算一个数字,要么老老实实告诉你"我无法执行计算,建议你使用pandas的mean()函数"。

你在第1章就见过这个场景了。现在Agent有了 read_file,但它依然缺一只真正能干活的"手"------执行代码的能力

如果Agent能调用一个 execute_python 工具,它就可以自己写一段 pandas 代码,在数据上跑一遍,拿到精确的结果。这正是我们要添加的第二个工具。

但在动手之前,有一个必须正视的问题:AI生成的代码,你敢直接在自己的电脑上跑吗?


4.2 AI生成的代码不可信

2024年,一位开发者在让AI帮他写一段数据处理脚本时,AI生成的代码里包含了一行 os.remove("/")。幸亏他在执行前看了一眼。

2025年,另一个开发者让AI写一段测试脚本,AI引入了一个 while True 的死循环。他的电脑风扇狂转了五分钟,直到强制关机。

这不是AI"故意作恶"。而是语言模型不理解"安全"------它只是根据训练数据中的模式生成文本。它不知道 os.remove("/") 意味着什么,不知道死循环会让CPU占满,不知道有些库你不希望它调用。

当你的Agent学会执行代码之后,它会自己写代码、自己执行。你不是那个在编辑器里写完代码、检查一遍、再点运行的人。Agent是一个自动化的流程------它收到任务,生成代码,调用 execute_python,然后拿结果。

这意味着:你必须给Agent造一个受控的执行环境,让它在里面"随便搞",搞不出事。

这个受控的执行环境,就是沙盒。


4.3 轻量级沙盒的设计思路

提到"沙盒",很多人首先想到Docker容器------完整的文件系统隔离、网络隔离、资源限制。Docker确实是工业级沙盒的标准方案,但它有两个问题:

第一,学习曲线陡。 装Docker、理解镜像、配置容器、处理权限------这对第一次接触容器化的本科生来说,认知负荷远超本章的教学目标。我们的重点是"让Agent安全地执行代码",不是"学会Docker"。

第二,它太重了。 你只是想让Agent执行一段 pandas 计算,就启动一个完整的Linux容器?光是容器启动的时间可能比代码执行本身还长。

好在,对于我们的场景------执行有限功能的Python代码片段------我们完全可以用纯Python实现一个足够安全的轻量沙盒。

设计思路很简单:

安全目标 实现方式
防止删除/修改你的文件 代码写入临时文件,执行完自动删除
防止死循环占满CPU 设置超时时间,超时强制终止
防止调用危险函数 限制可用的模块,只允许 pandasnumpymath 等安全模块
防止输出撑爆内存 限制stdout和stderr的最大长度
防止访问网络 在subprocess中不提供网络访问(或通过防火墙规则)

核心实现就靠一个Python标准库模块:subprocess。它能启动一个独立的子进程,在这个子进程里执行代码。子进程有自己的内存空间,出问题不会影响主进程。你可以设置超时,超时了就杀掉子进程。你可以捕获它的输出,限制输出大小。执行完毕,子进程销毁,一切都消失。


4.4 沙盒的完整实现

4.4.1 用Trae生成沙盒代码

在Trae的AI对话面板中输入:

复制代码
在项目 data-analyst-agent 中创建一个 sandbox.py 模块。

这个模块实现一个 execute_python(code: str, timeout: int = 10) -> dict 函数,用于在受控环境中执行Python代码。

要求:

## 核心实现
- 使用 subprocess.run 在子进程中执行代码
- 代码写入 tempfile.NamedTemporaryFile(后缀.py),执行完自动删除
- 设置 timeout 参数,超时则强制终止子进程
- 捕获 stdout 和 stderr
- 返回统一格式的字典

## 返回格式
{
    "success": True/False,
    "stdout": "标准输出内容(截断到5000字符)",
    "stderr": "标准错误输出(截断到5000字符)",
    "returncode": 0或其他,
    "error": "如果有超时或其他异常,在此说明"
}

## 安全机制
1. 临时文件隔离:代码写入临时文件,文件名随机,执行后自动删除
2. 超时终止:默认10秒,可在调用时自定义
3. 模块白名单:在执行前检查代码中的 import 语句。只允许以下模块:
   - pandas, numpy, math, statistics, json, csv, collections, itertools, datetime, re, string, decimal, fractions
4. 输出限制:stdout 和 stderr 各截断到5000字符
5. 禁止危险关键字:代码中不得包含 os.system, subprocess, eval, exec, __import__, open, shutil, sys., os., pathlib 等危险调用

## 代码风格
- 清晰的注释,说明每一层安全机制
- 类型注解
- docstring 说明用法和限制
4.4.2 审查生成的代码

Trae生成 sandbox.py 后,打开它,对照以下清单逐项检查:

核心实现检查

  • 是否使用了 tempfile.NamedTemporaryFile
  • 文件后缀是否为 .py
  • 是否设置了 delete=False(因为需要在另一个进程中读取)?
  • 执行后是否用 os.unlink() 手动删除了临时文件?
  • 是否使用了 subprocess.run 并传入了 timeout
  • 返回格式是否与要求一致?

安全机制检查

  • 是否定义了白名单模块列表?
  • 是否在代码中扫描了 import 语句并与白名单对比?
  • 是否定义了危险关键字列表并扫描了代码?
  • stdout和stderr是否做了截断?
  • 异常情况(超时、代码中有危险操作)是否返回了清晰的错误信息?

如果发现缺失或实现不当,在Trae对话面板中要求修正。例如:

复制代码
sandbox.py 中,你只检查了 "import os" 这种形式,但 "from os import system" 这种形式不会被检测到。请同时检查两种 import 形式。

或者:

复制代码
sandbox.py 中,白名单模块检查后如果发现非法模块,应该返回 "success": false 和具体的错误信息,而不是抛出异常。

以下是沙盒核心逻辑的参考实现(供对照,不是让你手写):

python 复制代码
import subprocess
import tempfile
import os

# 模块白名单
ALLOWED_MODULES = {
    'pandas', 'numpy', 'math', 'statistics', 'json', 'csv',
    'collections', 'itertools', 'datetime', 're', 'string',
    'decimal', 'fractions'
}

# 危险关键字
DANGEROUS_KEYWORDS = [
    'os.system', 'subprocess', 'eval(', 'exec(', '__import__',
    'shutil', 'sys.', 'os.', 'pathlib', 'requests', 'urllib',
    'socket', 'ftp', 'http'
]

def check_code_safety(code: str) -> tuple:
    """检查代码是否安全。返回 (is_safe, error_message)"""
    # 检查危险关键字
    for keyword in DANGEROUS_KEYWORDS:
        if keyword in code:
            return False, f"代码包含危险操作:{keyword}"

    # 检查 import 语句(简单字符串扫描)
    import_lines = [l for l in code.split('\n')
                    if l.strip().startswith('import ') or l.strip().startswith('from ')]
    for line in import_lines:
        # 提取模块名
        parts = line.strip().split()
        if parts[0] == 'import':
            modules = [p.split('.')[0] for p in parts[1:] if p != 'as']
        else:  # from X import Y
            modules = [parts[1].split('.')[0]]

        for mod in modules:
            if mod not in ALLOWED_MODULES:
                return False, f"不允许导入模块:{mod}(白名单之外的模块)"

    return True, None

4.5 安全机制逐层拆解

现在花一点时间,理解沙盒每一层安全机制的设计逻辑。这不仅是审查代码,更是培养设计安全系统的工程思维。

第一层:临时文件隔离

每次执行代码,都创建一个随机的临时文件(如 /tmp/tmpabc123.py),把代码写进去,执行完立刻删除。这样做的好处是:即使代码里写入了某些文件,也只会影响临时文件(已经被删了),不会污染你的项目目录。每次执行都是"全新的",上一次执行的残留不会影响下一次。

第二层:超时终止

subprocess.run(timeout=10) 意味着如果代码在10秒内没有执行完,子进程会被强制杀死。这防止了死循环永远运行下去。10秒是一个合理的默认值------大多数数据分析操作(计算平均值、筛选数据)都在1秒内完成。如果你的数据特别大,可以在调用时传入更大的 timeout

第三层:模块白名单

这是最核心的一层。代码在执行前会被扫描------它导入了哪些模块?如果发现不在白名单里的模块,直接拒绝执行。

白名单的设计原则是最小权限 :只给Agent完成任务必需的模块,不给多余的。数据分析需要 pandasnumpy,数学计算需要 math,文件解析需要 csvjsonossys 不需要------Agent不应该有能力操作操作系统。requests 不需要------Agent不应该能发起网络请求。

第四层:输出限制

如果Agent写了一段代码,生成了10万行输出,你的终端和内存都会撑爆。所以 stdout 和 stderr 各截断到5000字符------足够看到计算结果和错误信息,但不会造成资源问题。

第五层:危险关键字扫描

模块白名单能拦住 import os,但如果Agent不写 import 而是直接调用内置的危险函数呢?危险关键字扫描就是为此设计的------它直接在代码文本中搜索 os.systemsubprocessevalexec 等字符串。只要出现,就拒绝执行。

当然,这种基于关键字扫描的方式不是100%安全的(比如有人可以把危险代码混淆),但对于我们的教学场景已经足够。工业级沙盒会使用更复杂的技术(如seccomp、ptrace),但那超出了本书的范围。


4.6 【避坑指南】AI生成代码的五种危险操作

当Agent开始自己写代码并自动执行时,你可能会遇到以下情况。提前了解,能帮你快速诊断问题。

危险操作 表现 沙盒防御层 如果沙盒没有拦住
死循环 while True: pass 超时终止(10秒后强制杀掉) CPU风扇狂转,Agent卡住不动
文件删除 os.remove("important.txt") 模块白名单(os不允许)+ 临时文件隔离 项目文件被删除
网络请求 requests.get("恶意网址") 模块白名单(requests不允许)+ 危险关键字 数据泄露
系统命令 os.system("rm -rf /") 危险关键字扫描 + 模块白名单 灾难性后果
内存炸弹 [0] * 10**12 或无限递归 超时终止(内存耗尽前进程被杀死) 系统卡死

如果Agent生成的代码被沙盒拦截了怎么办?

这本身就是一个很好的学习机会。在终端日志里,你会看到Agent调用了 execute_python,但沙盒返回了 {"success": false, "error": "代码包含危险操作:os.system"}。Agent拿到这个结果后,通常会尝试修改代码------去掉危险操作,换一种安全的方式。这个过程就是"Agent在沙盒的约束下学会安全编程"。

如果你想让Agent更好地理解沙盒的限制,在它的系统提示词中加入:

复制代码
你可以使用 execute_python 工具来执行Python代码。但请注意:
- 只允许使用以下模块:pandas, numpy, math, statistics, json, csv, collections, itertools, datetime, re, string, decimal, fractions
- 不要使用 os、sys、subprocess、requests 等模块
- 代码必须在10秒内完成执行
- 如果沙盒拒绝了你的代码,请检查是否有不允许的导入或操作,修改后重试

4.7 测试沙盒本身是否可靠

沙盒是给你Agent用的安全基础设施。在把它交给Agent之前,你需要先验证它自己是否可靠。

创建 test_sandbox.py

python 复制代码
"""测试沙盒的安全性和功能"""
from sandbox import execute_python

# 测试1:正常代码
print("测试1:正常计算")
result = execute_python("print(sum([1,2,3,4,5]))")
print(f"结果: {result}\n")

# 测试2:死循环(应该被超时终止)
print("测试2:死循环")
result = execute_python("while True: pass", timeout=3)
print(f"结果: {result}\n")

# 测试3:尝试导入 os(应该被白名单拦截)
print("测试3:尝试导入os")
result = execute_python("import os\nprint(os.getcwd())")
print(f"结果: {result}\n")

# 测试4:尝试执行系统命令(应该被关键字扫描拦截)
print("测试4:尝试执行系统命令")
result = execute_python("import os\nos.system('ls')")
print(f"结果: {result}\n")

# 测试5:超长输出(应该被截断)
print("测试5:超长输出")
result = execute_python("for i in range(10000): print(f'Line {i}')")
print(f"stdout长度: {len(result.get('stdout', ''))}\n")

# 测试6:pandas 操作(应该正常执行)
print("测试6:pandas操作")
result = execute_python("""
import pandas as pd
data = {'name': ['Alice', 'Bob'], 'score': [90, 85]}
df = pd.DataFrame(data)
print(df.describe())
""")
print(f"结果: {result}")

运行测试:

bash 复制代码
python test_sandbox.py

期望结果:

  • 测试1:返回 success: true,stdout为 15
  • 测试2:返回 success: false,error中包含"超时"
  • 测试3:返回 success: false,error中包含"不允许导入模块:os"
  • 测试4:返回 success: false(要么被模块白名单拦,要么被关键字扫描拦)
  • 测试5:返回 success: true,但stdout被截断到5000字符
  • 测试6:返回 success: true,stdout中包含pandas的描述统计

如果所有测试都通过,你的沙盒可以交付给Agent使用了。


4.8 将沙盒封装为Agent工具

沙盒就绪,现在把它添加到Agent的工具箱里。

4.8.1 设计 execute_python 工具描述

在Agent看来,execute_python 是一个可以执行Python代码的工具。它需要知道:这个工具能做什么、什么时候该用它、有什么限制。

打开 agent.py,在Trae对话面板中输入:

复制代码
请修改 agent.py,增加第二个工具 execute_python。

工具描述:
- 名称:execute_python
- 用途:在安全沙盒中执行Python代码,返回执行结果。适用于需要计算、数据处理、统计分析的任务。
- 限制:只允许使用 pandas, numpy, math, statistics, json, csv, collections, itertools, datetime, re, string, decimal, fractions 模块。代码需在10秒内完成。不支持网络访问、文件系统操作(除了沙盒内部的临时文件)。
- 参数:
  - code(必填,字符串):要执行的Python代码
  - timeout(可选,整数,默认10):超时时间(秒)

实现:
- 导入 sandbox 模块中的 execute_python 函数
- 在 TOOL_MAP 中添加 "execute_python"
- 在 tools 列表中添加新工具的定义
- 在系统提示词中补充:当需要计算、统计、数据处理时,使用 execute_python 工具
4.8.2 审查新增的工具代码

确认以下几点:

  • 工具定义中的 name 是否与 TOOL_MAP 的键一致?
  • description 中是否说明了限制(白名单模块、超时)?
  • 系统提示词中是否更新了 execute_python 的使用指引?
  • sandbox.execute_python 的导入路径是否正确?

4.9 集成测试:读取数据并执行计算

现在 agent.py 有了两个工具:read_fileexecute_python

运行以下测试,观察Agent如何组合使用它们:

bash 复制代码
python agent.py

修改 agent.py 底部的测试请求为:

python 复制代码
run_agent("请读取 scores.csv,然后计算高数的平均分。")

观察终端日志。你期望看到的流程是:

复制代码
第1轮:Agent调用 read_file("scores.csv")
第2轮:Agent调用 execute_python("import pandas as pd\ndf = pd.read_csv('scores.csv')\nprint(df['高数'].mean())")
第3轮:Agent基于两次工具调用的结果,生成最终分析

如果Agent在第2轮写入的代码中尝试 df = pd.read_csv('scores.csv'),这是可以的------pandas 在白名单中,read_csv 是pandas的正常功能。沙盒不会拦截它。

但注意:沙盒中的代码执行环境和Agent的主进程是隔离的。 在沙盒里 pd.read_csv('scores.csv') 能读到文件,是因为 scores.csv 在项目根目录,而沙盒子进程的工作目录继承了主进程的目录。如果你想让沙盒更安全,可以在 sandbox.py 中切换工作目录到一个临时文件夹------但那样Agent就必须在代码中处理文件路径问题。当前方案在安全性和可用性之间取了一个平衡。


4.10 本章小结

  • AI生成的代码不可信------语言模型不理解安全,它生成的代码必须放在受控环境中执行。
  • 轻量级沙盒不需要Docker ------用 subprocess + tempfile + 超时 + 模块白名单,纯Python即可实现足够安全的执行环境。
  • 五层安全机制:临时文件隔离、超时终止、模块白名单、输出限制、危险关键字扫描。每一层解决一类安全威胁。
  • 沙盒本身必须先测试------在交给Agent使用之前,用各种攻击场景验证沙盒的可靠性。
  • Agent现在有了两只手read_file 读取数据,execute_python 执行计算。组合使用,它就能完成第1章那个"分析成绩单"的任务。

下一章,我们将为Agent添加第三个工具------write_file,并构建一个完整的 ToolManager 类来管理工具箱。Agent将能够读取数据、执行计算、保存分析报告------一个完整的数据分析闭环。


课后练习

  1. 运行 test_sandbox.py 中的全部六个测试,确认沙盒正常工作。如果某个测试失败了,分析是哪一层安全机制没有生效。
  2. 修改 sandbox.py,在白名单中增加 matplotlib.pyplot(但 matplotlib 可能依赖 os 等模块------这会触发什么安全拦截?你如何解决这个矛盾?)
  3. 运行集成测试------让Agent读取 scores.csv 并计算高数平均分。如果Agent在代码中写了 import os 然后被沙盒拒绝,观察Agent的后续行为------它会怎么修改代码?
  4. (进阶)在 sandbox.py 中增加第六层安全机制:限制子进程的内存使用。提示:在Linux/macOS上可以使用 resource 模块,在Windows上可以研究 job objects

相关推荐
AI客栈1 小时前
云原生 AI 平台架构设计:从模型服务到弹性调度的全链路工程实践
人工智能
AI原来如此1 小时前
阿里云百炼上线DeepSeek,OpenAI发布GPT-5.5,模型服务战升级
人工智能·gpt·阿里云·ai·大模型·ai编程
果丁智能1 小时前
物联网智能锁在网约房、民宿场景的落地实践:身份核验与远程授权的全链路解决方案
人工智能·物联网·智能家居
jinxindeep1 小时前
ω-EVA:基于隐变量交互式世界模型的机器人动作生成新范式(星源智)
人工智能·机器人
hnult1 小时前
2026在线笔试平台选型指南:考试云九重防作弊与六大AI能力解析
人工智能·笔记·microsoft·课程设计
Mr. zhihao1 小时前
SDD(规范驱动开发):AI 编程时代的范式革命——因果链视角
人工智能·ai编程
大腾智能1 小时前
华为开发者大会2026观察:鸿蒙底座成型,大腾智能锚定工业AI路径
人工智能·华为·harmonyos
rising start1 小时前
ReAct Agent:让 AI 学会思考与行动
人工智能·agent
奔袭的算法工程师1 小时前
论文解读--Sparse4D v3: Advancing End-to-End 3D Detection and Tracking
人工智能·目标检测·计算机视觉·自动驾驶·信号处理