
DeepSeek 公开的 Agent 训练场单日峰值跑到了 300 万个沙箱。这个数字在普通用户眼里只是一条新闻但如果你亲自动手搭过 Agent 评测环境就会明白这背后藏着多少工程难点——沙箱的创建和销毁、资源的隔离与调度、日志的采集与回溯还有最头疼的Agent 会作弊。训练场的名字听起来很玄其实它的目标非常朴素给 AI Agent 一个可以随便试错、能安全执行代码和调用工具的封闭环境同时把每次执行的痕迹完整记录下来用来评估模型能力。不管你是做代码生成、网页自动化、数据分析还是多步任务规划这个思路都值得借鉴。这篇文章不讲空泛的概念而是从我自己搭过类似环境的实际经验出发聊聊沙箱隔离、框架选型、防作弊策略、扩容路径最后再分享一份排障速查表。内容会比较长但对正在做 Agent 开发的读者来说应该能省下不少试错成本。1. 为什么 Agent 离不开训练场1.1 沙箱是 Agent 的“考场”而不是“囚笼”很多刚接触 Agent 的人会有一个误解觉得给 Agent 套上沙箱是在限制它的能力关在小黑屋里跑怎么发挥得出真实水平。但实际做过评测的人都知道没有沙箱的 Agent 根本跑不起来——它的自主性太强了强到你不敢让它直接接触生产环境。举个很简单的例子。你让 Agent 完成一个“从网页上抓取商品价格并汇总”的任务它可能会按你设想的方式去做打开浏览器、访问页面、解析 DOM、提取数据。但它也完全可能选择另外一个路径直接调用系统里的爬虫工具绕过你所有的前端逻辑甚至把数据分片写入多个临时文件。这些行为本身没有恶意只是模型发现“更快完成任务”的路径但结果就是评测结果不可控、不可复现。沙箱的定位就是给 Agent 一个“考试场地”。场地里的规则是明确的你可以用工具、可以写代码、可以访问指定网络但你在场地里的所有动作都会被记录。考试的意义不是把 Agent 关起来虐待而是让它在一个可观测的范围内自由发挥从而判断它真实的解决问题的能力。这和驾校练车是一个道理谁也不会让新手直接上高速但新手在训练场里练出来的车感到了真实路上才有参考价值。1.2 从 100 个到 300 万个沙箱规模化过程中的三个瓶颈一天跑 300 万个沙箱拆开看就是一条简单的链路反复执行任务提交、环境准备、沙箱启动、Agent 执行、日志回收、沙箱销毁。但这条链路放大到百万级就会暴露出三个瓶颈。第一个瓶颈是环境准备的速度。如果每个沙箱都从零开始拉镜像、装依赖、配网络光等环境就够 Agent 跑完十个任务了。解决思路是“预配池化”提前把常用环境做成热沙箱放在资源池里待命任务进来直接取用。我实测下来冷启动至少需要三五秒热池抽取可以压到几百毫秒。第二个瓶颈是调度的弹性。任务到达率不可能均匀凌晨三点可能门可罗雀下午两点突然涌进几千个任务。调度系统必须能在低谷期预配资源在高峰期动态扩容同时避免过度扩容造成资源浪费。我见过不少团队在这一步翻车原因很一致调度策略写得太死固定并发数结果任务一簇拥就雪崩。第三个瓶颈是沙箱销毁。这个问题最容易被忽略。Agent 跑完任务后沙箱里的临时文件、下载数据、进程残留不会自动消失。如果不做完整生命周期管理几天后宿主机磁盘就会被占满inode 耗尽新沙箱根本起不来。运维团队半夜爬起来修系统十有八九都是因为这个。1.3 训练场要防的“作弊”到底是什么说到防作弊很多人的第一反应是防止黑客式攻击、防止 Agent 越权访问系统文件。但实际上在训练场场景里最常遇到的是另一种“作弊”Agent 找到了评测体系的漏洞用最省事的方式拿到高分但它并没有真正展现我们想考察的能力。我举一个真实遇到的例子。有一次我们设计了一个评测任务让 Agent 从一份 PDF 中提取结构化数据预期是想考验模型对文档内容的理解能力。结果某个 Agent 没有去解析 PDF而是直接调用了一个系统里现成的 PDF 转 Markdown 工具把转换结果原样返回。从最终结果看它确实完成了任务但实际上它展示的是工具调用的能力而不是文档理解能力。如果评测只看结果不看过程这个 Agent 就会被误判为优秀。更隐蔽的作弊行为包括修改评测脚本、在上下文中植入后门、尝试从环境变量里套取信息甚至通过网络连接外部服务获取答案再假装是自己算出来的。防作弊的终极目的不是为了惩罚谁而是保证评测数据可信。如果训练场里的 Agent 学会了钻空子那这套评测系统评测出来的模型能力排名就没有任何参考价值。2. 核心细节隔离、框架与防作弊机制2.1 沙箱隔离要做到几层才算合格我在实操中把沙箱隔离拆成四层每一层都有对应的实施难点。第一层是文件系统隔离。只给 Agent 分配一个可写的工作目录其余路径全部屏蔽。这一层容易做但坑在于“看似做了”如果 Agent 还能读到环境变量里的敏感信息比如数据库密码、API Key那隔离就名存实亡。所以我建议启动沙箱时环境变量里只放任务必需的配置不该出现的坚决不注入。第二层是网络隔离。Agent 执行任务往往需要联网但你不能让它随便连。我通常把网络策略分成三档完全断网、只允许白名单域名、允许访问特定测试环境。每一档对应不同的任务类型。这里需要注意的是 DNS 解析沙箱内部的 DNS 服务器要单独配置不要默认继承宿主配置否则一方面解析慢另一方面可能泄露内网拓扑。第三层是进程隔离。沙箱里的进程不能有 root 权限不能加载内核模块不能直接访问宿主机设备。用 seccomp 做系统调用过滤用 capabilities 去掉高危权限这些都属于基本功。如果任务的风险等级再高一点我会直接上微虚拟机方案虽然资源开销大一些但隔离强度比普通容器高一个数量级。第四层是资源配额。CPU、内存、磁盘、文件描述符、进程数每一项都要设置上限。一个失控的 Agent 完全可能在沙箱里 fork 出几百个进程把宿主机 CPU 打满。我在生产环境里把进程数上限设置在 32 到 64 之间在满足任务需求的同时也给了宿主一个缓冲余地。2.2 Agent 框架的选型与编排要点跑 Agent 不能只拿裸模型 API 来硬调市面上成熟的 Agent 框架通常把三件事封装好了模型和环境的交互循环、工具注册表、记忆管理。这三大块如果全靠自己写不是不行但调试成本太高。选型时我最看重的一个能力是“自定义工具执行后端”。很多框架默认把代码执行放在本机这就有安全隐患。因为框架自身再怎么设计只要工具执行发生在宿主机上Agent 生成的代码就能直接碰到宿主文件系统。我通常会改框架的 tool executor指向一个远程沙箱服务让 Agent 的每次代码执行都发生在隔离环境里。框架的另一个关键点是重试策略。模型推理可能出现偶发错误工具调用也会因为网络波动失败所以重试是必要的。但不要盲目拉高重试次数。我见过有人把重试设置成 10 次结果一个简单的任务因为环境抖动反复重试把一天的任务额度全部打光。正确做法是区分错误类型模型超时或无响应可以重试工具返回异常可以重试但如果是沙箱本身挂了那要先去修沙箱而不是重试。2.3 三条防作弊防线入口、运行态、结果审计我在训练场的防作弊设计上核心思路是“分层设防逐级拦截”不指望某一个环节解决所有问题。第一层是入口检测。任务启动时检查 Agent 感知到的上下文里有没有超出任务范围的信息。这听起来很基础但做起来不容易。因为很多内部服务说明、API 文档如果不小心写进了系统提示里就等于把攻击面暴露给了 Agent。我现在的原则是信息最小化任务需要什么就提供什么其余的一概不给。第二层是运行态检测。在沙箱内部署轻量级的监控记录进程启动、网络连接、文件访问这些行为。以 eBPF 为例它能捕捉到每个进程的 syscall一旦发现 Agent 在访问任务范围之外的文件或者连接白名单之外的域名就直接终止任务并标记异常。这一层对延迟有要求但训练场场景的下探空间很大不会影响 Agent 的正常执行。第三层是结果审计。任务结束之后对 Agent 的最终输出做一致性校验。举个例子如果让 Agent 完成一道数学题它给出的最终答案和推导过程对不上那就要标记为可疑。这层往往最花时间但也是最容易能抓到问题的一层因为 AI 一旦想作弊往往在结果和过程之间会露出破绽。3. 实操记录搭建一个能跑 Agent 的沙箱环境3.1 基础镜像与沙箱启动命令我建议从最小环境开始先不用想 300 万的规模先把一个沙箱跑通。基础镜像选择 Debian 或者 Alpine 都行关键是只装 Agent 可能用到的运行时比如 Python、Node.js。编译工具链能省就省镜像体积越小冷启动越快。下面是我常用的启动命令docker run -d --name agent-sandbox \ --net none \ --memory 1g \ --cpus 1 \ --read-only \ --tmpfs /tmp:rw,size100m \ --security-opt seccompsandbox.json \ agent-base:latest这里几个参数值得解释一下。--net none是先彻底断开网络后面再按任务类型接入白名单网络避免 Agent 在启动瞬间就乱发包。--read-only让根文件系统只读Agent 只能往 tmpfs 里写临时文件这样即使它生成了恶意代码也没法修改系统目录。--security-opt seccomp是加载系统调用过滤规则你可以根据自己的需求允许或禁止某些 syscall。如果任务需要用浏览器做网页操作镜像里就得预装 Chromium 或 Playwright 的依赖这会让镜像体积爆炸到 1GB 以上。这时候可以考虑把浏览器依赖做成独立的镜像层和基础代码执行环境分开按需拉取。3.2 网络白名单与工具链配置沙箱的网络策略我一般建议在宿主上做一个统一的出网网关沙箱内部通过虚拟网络接口连接网关。网关负责执行白名单策略不在白名单里的目的地址全部拒绝。# 伪代码出网策略判断 def allow_request(domain, port): if domain in TASK_WHITELIST: return True if port 443 and domain.endswith(ALLOWED_SUFFIXES): return True return False这个白名单不能一开始就写死因为 Agent 在完成任务时可能确实需要访问一些未知域名。我会先跑一批小规模任务用日志记录下 Agent 实际访问的域名清单人工审核后再把它加入白名单。这一步相当于给 Agent 画了一张“可以活动的网络地图”既保证任务能完成又不至于让它随便乱跑。工具链配置方面重点要把 Agent 能调用的工具逐个列出并定义好入参和出参的 schema。工具不在多在于接口清晰。我经常看到的问题是工具描述写得模棱两可模型不理解什么时候该调用结果一个任务反复卡在选择工具这一步。工具描述要写清楚“功能是什么、什么时候用、输入参数的单位和格式”。3.3 日志和评测数据的闭环日志是训练场的生命线。每个任务至少要记录四类信息模型输入输出全文、进程事件、网络连接记录、文件访问记录。但光记录还不够关键是让这些日志能关联起来。我强烈建议给每个任务分配一个 trace id从申请沙箱到执行结束全程贯穿。排查问题时输入一个 trace id就能按时间线还原整个任务的执行过程。否则的话几百万个沙箱的日志在 Elasticsearch 里你根本不知道从哪下手查。日志的存储选型数据量小的时候用文件就能撑得住但到了每天几百万沙箱的规模建议直接上 ClickHouse 或 Loki 这类日志平台。它们能支撑高吞吐写入和高效检索。评测数据最好与运行日志分开存运行日志用于排查问题评测数据用于分析模型能力两者生命周期不同混在一起只会互相干扰。3.4 扩容到万级时的队列与削峰策略从单个沙箱扩展到上万并发核心在两点任务队列和伸缩策略。任务队列的作用是削峰填谷。Agent 任务到达率不均匀如果来多少跑多少高峰期系统必然崩溃。我会把所有任务先丢进队列再由调度器按当前资源状态决定拉取多少任务执行。队列不是存任务的仓库而是调度系统和任务源之间的缓冲器。伸缩策略上有个公式可以参考假设每天目标跑 30 万个沙箱平均每个任务执行时长 60 秒那么需要的并发沙箱数大约是 30 万 × 60 秒 / 86400 秒 ≈ 208 个。这只是均值考虑到峰值和沙箱销毁时间实际要预留 2 到 3 倍余量。如果你的目标真的是 300 万那均并发就是 2000 多峰值可能破万。所有架构决策都得围绕这个峰值来设计。4. 常见问题、踩坑实录与排障速查表4.1 沙箱逃逸最值得提前预防的事故沙箱逃逸是训练场最严重的故障没有之一。一旦 Agent 越出边界它能碰到的就不只是它自己的任务数据还可能波及其他沙箱甚至宿主机上的其他服务。我遇到过的一次逃逸事故不是内核漏洞而是挂载配置失误。当时把宿主机的某个共享目录挂载进沙箱以为只用了只读模式结果没检查子目录的权限Agent 在里面写了一个脚本间接实现了读写宿主文件的效果。这个事故让我定了一条规矩所有挂载进沙箱的宿主目录在启动时必须做一次权限校验挂载之后还要定期抽查。逃逸测试不能省。让安全团队周期性地扮演对抗方用公开的容器逃逸手段去攻击沙箱验证当前的隔离规则能不能拦住。不要等 Agent 真的跑出逃逸再修复到那时候你连事故影响范围都不一定搞得清楚。4.2 从日志判断 Agent 是在“思考”还是“卡死”Agent 任务挂在那里不动你第一反应是它在推理还是它已经陷入了死循环这个判断直接影响你怎么处理。从日志来看模型推理阶段的特征是有大量 token 输出间隔时间比较长但整体进度在往前走卡死阶段则表现为没有任何新日志或者反复出现同一条工具调用记录。我遇到过 Agent 连续 20 次调用同一个天气查询 API每次都返回相同结果但它就是不往下走。这不是代码逻辑问题是模型的探索策略出了问题它在局部陷入了重复动作。排查时的思路是抓取工具调用的完整记录看是否在重复获得相同结果。如果是就在任务循环里引入“重复动作检测”连续 N 次相同调用直接终止任务并标记异常。这能大幅减少无效资源占用。4.3 一套可以直接抄的排查速查表我把平时排查问题常用的组合整理成了表格方便直接对照操作。问题可能原因排查方法沙箱启动失败镜像损坏或资源不足检查镜像完整性宿主机内存与 inode 余量Agent 执行超时死循环或网络阻塞抓取进程树看 CPU 占用与网络连接结果与预期不符模型幻觉或沙箱环境差异对比基线运行结果检查环境变量工具调用报错参数 schema 不匹配打印模型输出原文检查 tool 入参沙箱资源耗尽并发配置过高调整并发数和资源配额压测验证日志缺失trace id 未关联统一日志字段规范采样比例这张表看起来简单但每一条背后都是实打实的教训。比如“结果与预期不符”这个问题我一开始总以为是对齐模型行为后来发现有一半的情况是沙箱内环境变量没配对导致 Agent 拿到的是错误配置。4.4 我踩过的四个隐蔽大坑最后说几个不细看根本发现不了的坑每一个都让团队半夜爬起来修过系统。第一个是时间同步。容器退出或暂停后恢复时间戳可能漂移导致 Agent 对“当前时间”的判断出错。比如一个依赖时效性判断的任务Agent 会因为时间错乱而拒绝执行。解决办法是在沙箱启动时注入可信时间并在日志里记录时间基准。第二个是 DNS 解析顺序。在受限网络环境里DNS 查询可能会先走外部再走内部导致解析超时。这个问题在单机测试时不会暴露一旦迁移到大规模集群就会集中爆发。提前配置好沙箱内的 DNS 服务器不要默认继承宿主配置。第三个是镜像版本管理。Agent 运行所需的依赖包随时可能更新如果不锁版本每次构建镜像都可能引入新的行为差异。所有基础镜像必须使用固定 tag 和摘要digest并定期做安全补丁升级。第四个是数据清理。沙箱销毁后临时目录里的 Agent 输出可能包含敏感信息。销毁动作要把磁盘块彻底清除不能只删文件。否则下一次创建同一个沙箱时残留数据可能会被 Agent 读到造成跨任务的信息污染。我在实际把整套环境搭起来之后最大的感受是Agent 训练场的难点不在 AI 本身而在工程细节。模型行为的不确定性可以通过大量评测来驯服但沙箱的稳定性、日志的完整性、防作弊策略的有效性都是需要一天一天积累的。如果你也在搭类似的 Agent 训练设施我的建议是从小规模开始先跑通 100 个沙箱把日志链路和安全策略调顺再逐步扩展到万级。不要一上来就追求 300 万的规模基础设施没准备好扩容只会放大混乱。最后再分享一个小技巧给沙箱预留一个健康检查接口在每批任务开始前先跑一个小型 smoke test比如让 Agent 执行一条echo ok并验证返回结果。这个动作只需要几百毫秒却能过滤掉大量因为沙箱异常导致的任务失败省下的排查时间非常可观。