ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Coding Agent安全沙箱实践:OpenSandbox与Agent Runtime隔离边界设计

Coding Agent安全沙箱实践:OpenSandbox与Agent Runtime隔离边界设计 年初我在内部团队做过一次很有意思的演示给一个 Coding Agent 完整的代码仓库访问权让它修复一个“无害”的测试失败。它很快定位到问题然后顺手执行了一行构建脚本这行脚本里夹着一个清理临时目录的命令路径写错了一位。于是整个工作区的源代码被删掉了三分之一。那一刻我意识到我们真正需要的不是更聪明的 Agent而是先把 Agent 那双不受控的手关进一个足够结实的沙箱里。这篇内容想分享的正是我那段时间围绕 OpenSandbox 与 Agent Runtime 做的一次完整工程实践。我会把最核心的问题——Coding Agent 为什么必须跑在沙箱里、OpenSandbox 是如何构成隔离边界的、Agent Runtime 怎么把模型决策翻译成可审计的沙箱内动作、以及实操中踩过的那些真实坑——全部交代清楚。阅读这篇文章的人我默认是对 Coding Agent 有一定了解的后端或平台工程师如果你正在设计自己的 Agent 执行环境或者让现有的 Coding Agent 具备安全的代码执行能力这篇文章应该能直接帮你省下一到两周的弯路。1. 为什么 Coding Agent 必须被“关”起来一次代码执行权限的失控演练1.1 Agent 的双手从“读代码”到“改代码”再到“执行代码”市面上的 Coding Agent 大多经历了三代能力演进。第一代只做代码生成输出文本后由人粘贴进编辑器权限边界天然存在人就是缓冲区。第二代开始具备读代码能力Agent 可以自主检索仓库内容、定位函数、分析调用关系但仍然不落盘不产生副作用。第三代则完全不同——它能直接修改文件、创建提交、安装依赖、执行测试命令这时候 Agent 已经从“智能输入法”变成了“拥有系统权限的协作者”。问题是绝大部分第三代 Coding Agent 的设计重心都放在模型推理能力和工具调度策略上执行层的边界设计反而被当成“配置问题”处理。常见做法是在宿主机上直接跑一个通用子进程工作目录指向仓库路径然后祈祷 prompt 里的 system message 能约束住模型的行为。这种做法在模型“听话”时确实够用但问题就在于模型本质上是一个概率系统它的每一步动作都存在一个非零的错误率。当这个错误率乘以“执行权限”这一系数时结果就不再是概率问题而是必然发生的事故。1.2 失控现场还原一条 rm -rf 指令与磁盘告警说回开头那个演示Agent 在执行构建脚本前其实已经通过了单元测试、静态检查和人工确认三个环节。它运行在宿主机的一个专用用户下没有 root 权限但可以读写仓库所属的整个目录。那条错误的清理指令被包装在连接符后面Agent 没有意识到前面的命令一旦失败后面的删除命令仍会执行。我后来复盘时把整个过程画成了一条链路模型输出命令 → shell 解析 → 权限检查通过 → 目录遍历开始 → 文件被批量删除。这条链路里没有任何一个环节设计来拦截“合理命令错误参数”这种组合。系统不再需要防范恶意攻击恰恰相反它需要防范的是无恶意但存在认知偏差的“善意操作”。这件事给我最大的教训是在 Coding Agent 场景下我们不能假设 Agent 的行为总是符合预期也不能假设通过提示词就能兜底。必须把 Agent 放进一个默认拒绝的沙箱让它所有的动作都发生在受限空间内即使某个动作真的出错了损失也只局限于沙箱内部。1.3 隔离粒度对比VM 太重、chroot 太虚、容器刚刚好确定要上沙箱后第一步是选隔离粒度。我对比了三种常见方案结论很明确。VM 虚拟机隔离最彻底每个 Agent 任务开一个轻量虚拟机内核被隔离硬件虚拟化兜底安全性无懈可击。但开销太大了一个 Agent 会话可能要持续几十分钟期间要不断执行小工具调用。如果每个工具调用都对应一次 VM 生命周期管理延迟和资源消耗都不可接受。chroot 方案最轻量但隔离能力太弱。chroot 只是把进程的根目录视角切换了一下进程仍然共享宿主机的内核、网络栈、进程表。一旦 Agent 拿到的是编译好的二进制或者通过/proc接口读取宿主机信息chroot 基本就是一层纸。最终我选择了 OCI 容器作为隔离边界也就是用 Docker/Podman 这类运行时来承载 Agent 的执行环境。容器的隔离粒度足够覆盖文件系统、网络、PID、用户开销又远低于 VM可以在百毫秒级完成一个沙箱的创建和销毁。这个粒度不会根治所有安全问题——容器逃逸漏洞依然存在——但结合 seccomp、capabilities 禁止、只读文件系统等手段已经能把风险降低到可以接受的程度。这也是 OpenSandbox 选择 OCI 容器作为底层实现的核心原因。2. OpenSandbox 的边界设计我给 Agent 划定的“安全活动范围”2.1 最小权限原则在 Agent 场景下的落地清单OpenSandbox 这个名字很容易让人误以为它是一个单独的沙箱产品实际上它是一个桥接层上层接收 Agent Runtime 发出的执行请求下层操作容器运行时为每个任务创建独立的隔离环境。它的价值不在于“能不能跑”而在于“跑的时候默认拒绝一切非必要能力”。在我这里OpenSandbox 的权限基线是这样设计的容器的用户空间映射到一个非 root UID容器内没有 sudo只保留必要的 Linux capabilities其余全部 drop--cap-drop ALL是起点挂载只读的根文件系统只有显式声明的目录可写启用no_new_privs阻止通过 setuid 等方式提权默认使用独立网络命名空间出网策略白名单化。这个清单的核心思想是Agent 的每个行为都要经过“能力确认”。它只能在你给它的脚手架上活动脚手架之外一切都是禁区。实际部署中OpenSandbox 还会对 Agent 的执行参数做一次静态扫描拦截包含--privileged、--pidhost、--networkhost这类危险参数防止上层的 Runtime 因为配置错误而把沙箱变成裸奔环境。2.2 只读根文件系统 tmpfs让 Agent 的每个改动都明确可回收我见过很多沙箱方案在隔离网络和用户上做得很足却在文件系统边界上偷懒。它们让 Agent 直接对着一个可写的/workspace工作整个容器文件系统也可以自由写入。这会导致两个问题容器退出时如果没有彻底清理镜像层Agent 写入的临时文件、缓存、日志会残留在宿主机上久而久之形成磁盘黑洞更严重的是一旦 Agent 运行了类似journalctl或读取敏感系统文件的命令可写的根文件系统常常和宿主机过度共享信息。OpenSandbox 在这块的处理方式是根文件系统一律只读容器内唯一可写目录是/workspace和一个挂在内存中的/tmp。/tmp走 tmpfs一旦进程退出内存页直接释放连清理动作都省了。/workspace则是在每次任务开始时由沙箱管理组件从镜像仓库克隆而来任务结束后整体丢弃下一次任务再从干净状态拉起。这个设计的额外好处是可审计性变得很强。因为可写区域被严格限定所以只要对/workspace做一次 diff就能精确看到 Agent 到底改了什么文件、生成了什么内容。相当于把 Agent 的行为记录从“日志级”提升到了“文件变动级”。2.3 网络策略只给该通的端口开一扇小门Coding Agent 的沙箱网络策略是个容易被忽视的重灾区。很多团队的沙箱直接开着宿主机网络Agent 可以访问内网任意 IP。对于要做仓库操作、安装依赖的 Agent 来说这看似方便实际却是一座随时可能引爆的火药桶——Agent 一个误操作的请求就可能打到内网的管理面板上。OpenSandbox 的网络策略默认开启独立网络命名空间然后通过 eBPF 或 iptables 做一个出网白名单。白名单规则从需求中解析出来Agent 要连 GitHub 就只放行 GitHub 相关的域名和 IP 段要拉 npm 包就只放行 npm registry 的地址其余的一律丢弃并记录日志。这样即使 Agent 的某个行为被诱导或误判它也无法成为攻击内网跳板。这里有个容易被忽略的性能点容器网络转发有额外的 NAT 开销高频工具调用场景下延迟会上升。我的实践是在底层用 macvlan 或 ipvlan 做直通网络容器直接获得独立 IP绕开 NAT。代价是隔离性稍弱所以只建议在受控的内网环境里使用对外服务场景还是保持 NAT 模式更稳妥。3. Agent Runtime 的执行循环从自然语言需求到沙箱内行动3.1 Runtime 的核心职责把模型决策翻译成受控系统调用如果说 OpenSandbox 是墙Agent Runtime 就是住在墙里的管家。它负责接收 Coding Agent 发出的高层次意图比如“运行一下测试”“安装这个依赖”“帮我查看 package.json”然后把意图拆解成具体的沙箱内动作发往 OpenSandbox 执行。我在设计 Runtime 时参考了 ReAct 模式的思路Agent 每次决策后先输出一个结构化的 JSON 动作Runtime 解析这个动作检查它是否在注册过的工具列表内然后向 OpenSandbox 发送execute请求。执行结果经过 sanitize 后回传给模型模型根据结果继续下一步决策。这样一个闭环的价值在于模型永远不能直接操作文件或进程它只能通过 Runtime 暴露的“操作 API”间接行动。举个例子模型说“请查看 src/utils/string.ts 的前 100 行”Runtime 不会直接把 shell 交出去而是映射为一次read_file工具调用路径参数经过规范化处理拒绝任何包含..的越权路径限制读取行数上限并把读取结果截断到模型上下文允许的长度。每个工具调用都带上独立的 trace_id方便最后审计。3.2 工具注册表与超时控制Agent 卡死时谁来做“监护人”Agent Runtime 很容易犯的一个错误是把工具调用设计得太宽泛。很多早期实现就暴露一个run_shell接口参数是任意 shell 命令整个沙箱等同于一个高级 SSH。这种做法等于把 Agent 的错误率又放大了——shell 的自由度太高模型在组合参数时出错几乎是必然的。我的做法是建立一个受控工具注册表初始只注册六个工具read_file、write_file、patch_file、run_tests、install_dependency、git_operation。每个工具有独立的参数 schema由 JSON Schema 校验不符合直接拒绝。工具注册表存放在一个配置文件里后续要扩充工具时走代码评审流程这样扩容的每一步都有痕迹可查。超时控制是另一个关键点。模型在执行长任务时经常出现“在想”但底层进程已经卡死的情况。Runtime 对每个工具调用都设置了硬超时默认写操作 20 秒读操作 10 秒测试命令 5 分钟超时后直接 kill 对应的进程组。注意不是 kill 单个 PID而是整个进程组否则 Agent 创建的子树进程会变成孤儿进程继续消耗资源。3.3 事件流与会话管理把沙箱变成可审计的“工作台”Agent Runtime 和传统后端服务最大的区别在于会话的持久性。一次 Coding Agent 任务可能持续 20 到 40 分钟期间会创建几十次工具调用每次调用之间沙箱状态必须保留。这要求 Runtime 管理好会话生命周期会话创建时预拉起沙箱会话期间分发工具调用会话结束或异常时销毁沙箱并归档结果。我在内部实现中采用了事件驱动架构。Runtime 内部跑了一个事件总线每个工具调用产生一个AgentActionEvent每个执行结果产生一个AgentObservationEvent会话状态变化产生StatusChangeEvent。下游的日志系统、指标系统、审计系统都订阅这个总线而不是各自反向 pull 状态。这样做的好处是调试 Agent 行为时可以按 trace_id 串起整条事件链某个操作请求什么时候发出、沙箱什么时候收到、进程什么时候退出、输出是什么、模型又是怎么解析的全部有迹可循。会话管理还需要处理一个现实问题Agent 任务常常因为网络抖动或模型 API 超时而中断。Runtime 需要支持沙箱会话的“暂停”和“恢复”。我的方案是给沙箱加一层磁盘快照能力任务中断时把容器当前状态打成快照恢复时再加载快照而不是从零开始。这个功能让我省掉了大量重跑任务的成本。4. 实操部署从零搭建一个可复用的 Agent 沙箱环境4.1 环境准备与镜像构建要点开源的 OpenSandbox 部署起来不算复杂但有不少细节要提前规划。首先是宿主机选型。我在三台 8C16G 的 Linux 服务器上构建测试环境内核版本要求高于 5.10因为新版 runc 依赖比较新的内核特性。存储驱动我选择 overlay2这几乎是当前容器运行时的默认选项性能和稳定性都经过大规模验证。镜像构建是整个环境里最值得花时间的部分。我不建议直接用通用的 node 镜像或 ubuntu 镜像作为 Agent 沙箱镜像因为它们的体积太大每次拉起沙箱都要消耗大量 IO。我用的基础镜像是 alpine node 20 的裁剪版再手动装上 git、bash、curl、jq 这些 Agent 高频使用的工具整体镜像体积控制在 120MB 左右。构建镜像时有一点必须注意不要在镜像的层里固化任何用户凭据包括 git token、npm token 和 SSH 私钥。这些凭据应该由 Agent Runtime 在沙箱启动时通过环境变量注入并且只在沙箱容器生命周期内有效。动态注入的一个额外好处是token 可以按任务粒度去签发一个任务的 token 只拥有该任务所需的最小权限泄露了也能快速单独吊销不用牵连其他任务。4.2 容器编排参数详解与安全基线如果直接裸调 Docker API参数维护会非常痛苦。我这里直接给一份我在生产中使用的docker run参数基线你在设计自己的编排层时可以照搬docker run -d \ --name agent-sndbox-{task_id} \ --read-only \ --tmpfs /tmp:rw,noexec,nosuid,size256m \ --tmpfs /var/tmp:rw,noexec,nosuid,size256m \ --security-opt no-new-privileges \ --cap-drop ALL \ --cap-add NET_BIND_SERVICE \ --cap-add CHOWN \ --cap-add SETGID \ --cap-add SETUID \ --pids-limit 512 \ --memory 1.5g \ --memory-swap 0 \ --cpus 1.5 \ --network agent-net \ --workdir /workspace \ -v /srv/agent-workspace/{task_id}:/workspace \ agent-runtime-base:20.04逐条解释几个关键参数。--read-only是核心开关它让整个容器根文件系统变成只读。容器内的进程只能往显式挂载的/workspace和 tmpfs 目录里写东西。这个参数必须配合 tmpfs 使用否则很多运行时写文件的工具会在容器里直接崩溃。--cap-drop ALL后面再按需放行个别 capabilities。这里我放行了NET_BIND_SERVICE让 Agent 可能启动的开发服务器能绑定 80 端口放行CHOWN、SETGID、SETUID是让 npm install 之类的工具在本地安装依赖时能修改文件属主。这三个权限确实扩大了攻击面但对比全量 capabilities已经是相当收敛的配置。如果你的 Agent 不需要起开发服务建议把NET_BIND_SERVICE也去掉。--pids-limit是个经常被忽略的参数。没有它一个失控的进程可以不断 fork 子进程直到宿主机 cgroup 触发 OOM。512 的限制对编码任务足够宽裕同时对 fork 炸弹形成了有力约束。--memory-swap 0表示禁用 swap。Agent 一旦内存申请陷入无限循环swap 会让整个系统变得不可响应不如直接触发 OOM kill让沙箱内的进程死得干净利落。4.3 沙箱生命周期管理 API 设计编排参数搞好之后还需要一个管理沙箱生命周期的接口层。我是用 Python 写了 OpenSandbox 的管理组件对外暴露一组 REST APIAgent Runtime 通过这组 API 和沙箱交互。核心接口就四个POST /sandbox # 创建一个沙箱返回 sandbox_id POST /sandbox/{id}/exec # 在沙箱内执行一条命令 DELETE /sandbox/{id} # 销毁沙箱并回收资源 GET /sandbox/{id}/events # 拉取沙箱内的操作日志流POST /sandbox 创建时要传镜像名、资源配额、网络策略、环境变量这几个关键参数。管理组件收到请求后生成唯一的 sandbox_id 和对应的工作目录然后调用容器运行时创建容器。创建完成后管理组件会等容器内的 init 进程启动并返回 ready 信号这个过程我做了 10 秒超时超时直接销毁重建。POST /sandbox/{id}/exec 是执行入口。参数是一个 JSON包含命令本身、工作目录、环境变量、超时时间。容器运行时会启动一个一次性进程执行命令并把 stdout、stderr 和退出码打包返回。这里我要求所有执行操作都使用exec而不是直接 attach 到容器的主进程目的就是让每个操作都干净、独立、可审计不依赖容器内正在运行的 agent 主进程状态。整个生命周期管理组件是无状态的。每个请求都通过 Redis 缓存沙箱的元数据管理组件本身挂在负载均衡后面可以水平扩展。我最初以为这里会有很多状态同步的麻烦实际上因为沙箱之间完全隔离每个请求只关心自己对应的那个容器状态同步的压力非常小。5. 沙箱不是保险箱逃逸尝试与资源耗尽攻防实录5.1 第一次调试事故npm install 引发的文件系统权限谜题OpenSandbox 上线后遇到的第一个问题很典型Agent 执行npm install时大量报 EACCES 错误。错误信息显示编译器工具链无法访问/workspace/node_modules/.cache。我当时第一反应是权限配置写错了但一顿检查之后发现挂载权限正常目录属主和容器内 UID 也能对上。最后定位到根因在 umask。宿主机的 umask 是 0022容器内的基本镜像把 umask 设成了 0002。npm 创建缓存目录时按照容器的 umask 设置了 0775 权限但/workspace作为挂载卷其目录权限由宿主机侧决定。宿主机上创建/workspace的用户是 root目录默认权限是 0755而容器内进程是 UID 1000写入子目录没问题但 npm 需要对/workspace/node_modules/.cache执行 chmod 操作结果因为不是 owner 被拒绝。修复方式有两个。一是统一容器内外的 umask在 Dockerfile 里固定ENV UMASK0022二是不要直接把宿主机的目录挂进去而是用一个中间层初始化目录属主比如在容器启动命令里加一步chown -R agent:agent /workspace。两个方案我都在线上验证过推荐第一种更干净。5.2 网络链路里藏着的坑代理与 DNS 的超时假象另一类高频事故不在沙箱本身而在网络链路。Agent 在沙箱内执行git clone时频繁超时但直接在宿主机跑同样的命令又是秒连。排查链路从容器内 curl 开始发现容器内访问外网整体都很慢而宿主机正常。我查了 iptables NAT 规则又查了 DNS 配置最后发现根因是容器内/etc/resolv.conf指向的 DNS 服务器地址被防火墙拦了。宿主机使用的是内网 DNS但容器默认继承宿主机的 DNS 配置而内网 DNS 服务器只监听在宿主机的网络命名空间里容器所在的独立网络命名空间无法直接访问。再加上iptables规则里 NAT 表放行了 DNS 流量但 FORWARD 链对来自容器网络的 UDP 流量没有放行导致 DNS 包被静默丢弃。修复方案是在 Docker daemon 的配置里显式指定 DNS 服务器地址--dns 10.0.0.2并且在 iptables 的 FORWARD 链上单独放行来自agent-net网段的 DNS 查询。这个坑几乎不在 OpenSandbox 的文档里属于部署环境特有的配置问题。如果你在自建环境部署建议在上线前先做一次简单的网络连通性冒烟测试直接从容器内 ping 外网、解析 DNS、拉取一个 GitHub 小仓库三关过了再放 Agent 进来跑。5.3 资源配额与镜像分层爆炸给沙箱上“财政预算”第三个坑是资源配额的粒度问题。我一开始只给沙箱配了内存和 CPU 上限没有对容器可写的镜像层数据量做限制。结果跑了几十个任务之后发现宿主机磁盘被撑爆了。原因很直接Agent 在/workspace里装了若干 GB 的 node_modules任务异常退出时容器销毁不彻底可写层残留了一部分加上我给每个任务都构建了独立快照快照叠加起来占用了大量磁盘空间。解决方法是双管齐下。第一在容器启动参数里加上--storage-opt size2g限制每个容器的可写层最大 2GB超了直接 I/O 错误。第二在管理组件里增加定时回收任务每个任务结束后不是简单删除容器而是先导出日志和/workspacediff再把整个容器的可写层删除。数据要留但容器不能留这个界线一定要清楚。给任务挂快照的时机也很讲究。我的经验是只在 Agent 完成一个里程碑时打快照比如“完成了测试修复”“完成了需求实现”。而不是每执行一条命令就快照一次那样磁盘和延迟都扛不住。快照名用语义化命名比如snapshot_{task_id}_{step_id}方便后续回滚时快速定位。5.4 真实逃逸面检查privileged、cap 与宿主机挂载最后是逃逸面的整体检查。即使你的沙箱配置看起来已经很安全仍然要建立一套“最坏情况假设”来做验证。我常用的方法是准备一个恶意镜像在里面尝试三种典型的逃逸路径检查是否以 privileged 模式运行、检查能否通过--privileged相关的 cgroup 设备获得宿主机磁盘访问权、检查是否能通过 mount 操作读取宿主机文件系统。以 privileged 模式运行的容器对宿主机几乎是透明的/dev/sda、宿主机内核模块、cgroup 设备统统可以访问。我的基线配置里没有--privileged所以这个面是关上的。--cap-add SYS_ADMIN也没有放行意味着 mount 系统调用大概率会被no_new_privs加上 cgroup 策略拦截。剩下最需要警惕的是/workspace挂载是否存在目录穿越比如 Agent 能不能通过符号链接指向宿主机路径。我在挂载时特意在宿主机侧创建了独立目录并给openat2这类系统调用加了 seccomp 限制从多个维度交叉验证之后才认为逃逸面收敛到了可接受的水平。沙箱永远不可能做到绝对安全但可以通过纵深防御把攻击成本抬高到攻击者不愿意承受的程度。对你来说要做的不是追求“完美隔离”而是确保每一条逃逸路径都被至少两层措施挡住这样即使某一层失效下面还有第二层兜底。6. 验收与后续让 Agent Runtime 变得更好用的几个方向6.1 沙箱预热与复用把冷启动从秒级降到毫秒级初版上线后遇到的最大体验问题是沙箱冷启动时间太长。创建容器、挂载工作目录、启动 init 进程、等 ready 信号全流程大概需要 4 到 8 秒。Agent 高频执行工具调用时每次都要等这么久体验完全不可接受。我的优化方案是引入沙箱池机制。启动时预先创建 5 个干净的沙箱容器它们处于 paused 状态不执行任务也不占用额外计算资源。Agent Runtime 发出创建请求时管理组件直接从池里取一个容量预热好的容器改名为当前任务的沙箱然后恢复运行整体耗时降到毫秒级。任务结束后容器被清理池子里再补齐一个新的空白容器。预热池要考虑镜像更新问题。如果你改了 base 镜像旧的池子容器就失效了。我这边维护了一个版本号字段镜像构建完成后递增版本号管理组件对比池内容器的镜像版本不匹配就全部重建。6.2 快照与回滚让 Agent 可以大胆试错Coding Agent 在沙箱里探索时经常会做出一些当前看起合理、实际上会污染后续步骤的操作。比如安装了错误的依赖版本或者修改配置文件时写入了不该有的参数。如果没有快照能力Agent 要么将错就错继续跑要么只能中止任务重新开始。快照能力上线后效果非常明显。我给 Agent 的工具注册表增加了一个checkpoint动作Agent 在执行高风险操作前主动打一个快照。如果后续步骤发现状态不对或者运行时检测到异常退出就可以恢复到这个快照继续探索而不是重新经历前面全部步骤。实现上快照不是完整备份整个容器而是利用 overlayfs 的层特性只记录容器可写层的差异数据。恢复时把当前可写层丢弃换回快照时的数据即可。整个恢复操作在 1 秒内完成代价极低收益却很大。6.3 观测性建设一个请求在沙箱里到底干了什么最后一定要聊聊观测性。我初版上线时犯了一个错误只关注了沙箱“能不能跑”没有同步建设“跑得怎么样”的观测链路。结果 Agent 在沙箱里执行了大量可疑操作而没有任何告警直到磁盘告警才知道出了问题。现在我的观测体系分三层。第一层是执行日志每一个工具调用的输入和输出都记录在结构化日志里格式为 JSON包含 task_id、operation、command、exit_code、duration 这些字段。第二层是行为指标包括每个沙箱的进程创建速率、文件写入量、网络连接数、内存涨速。一旦某个指标超过预设阈值自动触发告警。第三层是审计回放把所有事件流按时间轴串起来UI 上可以看到一个完整的“Agent 行为回放”就像看一段录像一样还原沙箱内的所有操作。建好这套观测体系之后我对沙箱里的 Agent 就不再是“盲目信任”了。每次 Agent 做了出乎意料的事情我都能在几分钟内定位到它到底干了什么、为什么这么干、影响范围有多大。这比任何安全审查都更直观也更接近沙箱设计的本质——让它成为一个可理解、可预测、可控制的黑盒。回头看这次实践我最深的体感是Coding Agent 的能力边界和它的安全边界是同步演进的。模型越来越强Agent 能做的事越来越多但如果我们不花同样多的精力去设计它的执行环境这些能力最后都会变成隐患。把 Agent 的手放进沙箱不是为了束缚它而是为了让它在安全可控的前提下大胆地把事情做完。
返回列表