☰
腾迅 Agent 与沙箱:架构与关系解析
2026/10/27 1:52:11 网站建设 项目流程

Agent 与沙箱:架构与关系解析

采集环境:主机2663239c2aaa· Ubuntu 24.04.3 LTS · 内核 6.6.117-45.11.6.tl4.x86_64
采集时间:2026-10-15 10:18 CST
证据来源:/proc/<pid>/environ、/proc/<pid>/ns、supervisord 配置、workspace-init启动脚本、ss -tnpsocket 连接、cgroup 文件、mount 表


0. 一句话结论

Agent 不是沙箱之外的东西,而是沙箱内部一个由sandbox-proxy派生出来的普通进程。
控制面不直接连接 Agent:它先把配置注入envd,再由沙箱内的sandbox-proxy拉起 Agent 进程;Agent 通过沙箱共享的文件系统、网络和命令执行能力完成工作,出网统一经由宿主网关172.24.0.1:80。

换句话说:沙箱是"机器",Agent 是跑在这台机器里的"操作员"——两者不是并列关系,而是宿主与租户、容器与进程的关系。


1. 环境身份:这是一个什么沙箱

从 Agent 进程(PID 1416)和sandbox-proxy(PID 125)的环境变量中可以看到完整身份:

类别关键变量值
平台X_IDE_IS_CLOUDSTUDIO/X_IDE_SPACE_HOSTTRUE/sandbox.cloudstudio.club
编排WORKSPACE_NAMESPACEcs-spacelet-v2-headless.coding-workspace.svc.cluster.local.
区域X_IDE_SPACE_REGIONsh4(上海)
环境IDE_ENVprod
运行时镜像IDE_USER_RUNTIME_IMAGEcloudstudio-sh.tencentcloudcr.com/saas.container/full-1.0.0:202505140048
宿主名HOSTNAMEVM-32-6-tencentos
IDEIDE_EDITOR_TYPEVSCODE
工作区IDE_WORK_DIR/workspace
基础目录IDE_EDITOR_SERVER_DIR/.PlnPyKFp4CRfFtgC1

结论:这是腾讯云 CloudStudio 的 spacelet 沙箱,运行在一个名为cs-spacelet-v2-headless的 K8s 工作负载中(命名空间coding-workspace),采用 headless(无界面)形态,区域 sh4。

资源配额(envd 下发与 cgroup 实测一致)

项目envd 声明cgroup 实测一致性
内存X_IDE_MEMORY_LIMIT=8Gmemory.max = 8589934592(8 GiB)✅ 一致
CPUX_IDE_CPU_LIMIT=4cpu.max = 400000/100000(4 核)✅ 一致
磁盘X_IDE_DISK_QUOTA=250G根 overlay 256 G✅ 基本一致
PID 上限—pids.max = 151533—

注意:在容器内直接执行free会看到宿主的 123 GiB 内存(未挂载 lxcfs),判断配额必须读 cgroup。这一点在排障时极易误判。


2. 三层结构总览

┌─ 外部(控制面与网关)────────────────────────────────────┐ │ CloudStudio 控制面(SaaS) 宿主网关 172.24.0.1 │ │ 沙箱调度 · 配置下发 · 会话路由 出网 :80 · 日志 :18100 │ └───────────────────────┬──────────────────────────────────┘ │ 配置下发(HTTP) ┌─ 沙箱边界(K8s Pod / 容器)───────────────────────────────┐ │ │ │ 【沙箱基础服务层】由 supervisord (PID 61) 守护 │ │ envd:49983 sync_server editor_sdk node api │ │ terminal:65310 log-collector dockerd/containerd │ │ │ │ 【Agent 子系统(cbc.d)】 │ │ sandbox-proxy:9090/65225 ← Agent 启动器 + 出网代理 │ │ └─ codebuddy ×3 (prewarm 池) │ │ └─ mcp-stdio / MCP 服务 / zsh 命令 shell │ │ │ │ 【共享资源】/workspace · cgroup 8GiB/4vCPU · cwd 共享 │ └──────────────────────────────────────────────────────────┘

关键点:服务层与 Agent 层位于同一个容器内,共享 PID / 网络 / 挂载命名空间,之间没有硬隔离。


3. 沙箱侧:基础服务与守护体系

3.1 守护骨架

PID 1 docker-init(容器入口,执行 exec supervisord) └ PID 61 supervisord -c supervisord-conf/supervisord.conf ├ [program:proxy] → sandbox-proxy ← 经由 start-cbc.d 拉起 ├ [program:e2b-envd] → envd ├ [program:api] → node api ├ [program:terminal] → terminal/app, local-proxy ├ [program:docker] → dockerd → containerd └ 其他一次性/常驻:init-workspace、sandbox-log-collector、editor_sdk、sync_server

supervisord 配置中autostart=true/autorestart=true,意味着这些服务被杀死后会自动重启——这是沙箱自愈能力的来源。

3.2 服务清单与端口

服务PID监听职责
envd1284*:49983配置权威源 + 控制面入口(/envs接口)
sync_server42496127.0.0.1:8089、*:18601工作区文件双向同步(本地 ↔ 沙箱)
editor_sdk42465127.0.0.1:39099编辑器 SDK(仅回环,--cors_origin=*)
node api107*:65213沙箱 API 服务
terminal / app95*:65310终端服务
local-proxy93*:65216本地代理
sandbox-proxy125*:9090、*:65225出网代理 + Agent 启动器
sandbox-log-collector118出向:18100日志汇聚转发
dockerd/containerd29424 / 29488unix socket容器引擎(供沙箱内嵌套构建)

3.3envd—— 最容易被忽略但最关键的一环

envd不只是"环境变量服务",它是沙箱与控制面之间的唯一配置通道:

  1. 对外做配置分发:GET http://localhost:49983/envs返回所有环境变量,启动脚本靠它决定功能开关。
  2. 对内接收控制面连接:ss显示envd的 49983 端口上有来自172.24.0.1(宿主侧)的已建立连接(fd 6、fd 9),说明控制面是主动连进沙箱的。
# start-cbc.d 和 agent-init 的标准模式ENVD_URL="http://localhost:49983/envs"ENVD_RESPONSE=$(curl-s"${ENVD_URL}")ENABLE_CBC_D_VALUE=$(echo"$ENVD_RESPONSE"|grep-o'"ENABLE_CBC_D":"[^"]*"'|cut-d'"'-f4)if["$ENABLE_CBC_D_VALUE"!="true"];thenexit0;fi

设计含义:功能开关(ENABLE_CBC_D、ENABLE_AGENT_INIT)不在镜像里写死,而是由控制面通过 envd 动态下发。这使得平台可以在不改镜像的前提下灰度开关 Agent 能力。


4. Agent 侧:形态、位置与派生关系

4.1 Agent 是谁

node /root/.nvm/versions/node/v22.13.1/lib/node_modules/@tencent-ai/codebuddy-code/bin/codebuddy --prewarm --prewarm-id sbx-125-N
  • 安装包:@tencent-ai/codebuddy-code
  • 运行时:Node.jsv22.13.1(nvm 管理)
  • 当前沙箱内共3 个实例,构成预热池:
PID启动时间RSS参数角色
141610:04:43~335 MB--prewarm-id sbx-125-1当前活跃会话
141710:04:43162 MB--prewarm-id sbx-125-2预热待命
4224110:18:03162 MB--prewarm-id sbx-125-3预热待命

三者的父进程都是sandbox-proxy(PID 125)——这是判定"Agent 属于沙箱"最直接的证据。

4.2 Agent 的两种形态

形态启动方式监听用途
prewarm 模式sandbox-proxy派生无对外端口预热待命,收到会话请求即接管(当前形态)
serve 模式start-codebuddy-serve脚本0.0.0.0:65222作为常驻 HTTP 服务运行

start-codebuddy-serve脚本内容:

cd"/workspace"# 使用 setsid 完全脱离控制终端,避免 codebuddy 因 tty 问题被挂起execsetsid codebuddy--serve--host0.0.0.0--port65222</dev/null

4.3 Agent 调用外部能力的方式

在/proc/1416/fd与进程树中可以看到 Agent 的两类子进程:

子进程PID作用
sandbox-proxy mcp-stdio42268MCP 协议的 stdio 传输通道
node .../workbuddy-sheetagent/mcp/start.mjs42512表格处理 MCP 服务
zsh53271+由 Agent 派发的命令执行 shell(临时生命周期)

MCP 插件清单(/root/.codebuddy/.mcp.json)包含:agent-browser、docx、pdf、pptx、xlsx、playwright-cli、workbuddy-docx、workbuddy-pptx、workbuddy-sheetagent、hot-skills。

重要机制:Agent 的"工具执行"在本机表现为fork 子 shell / 起 MCP 子进程。每一次工具调用都是沙箱内的一次真实进程创建,而不是远程 RPC。


5. 两者的接口契约:四条通道

Agent 与沙箱/控制面之间只有四条交互通道,边界非常清晰:

#通道方向载体证据
①配置下发控制面 → 沙箱envd:49983的/envs接口启动脚本curl localhost:49983/envs;envd 上有来自172.24.0.1的入站连接
②进程派生沙箱 → Agentsupervisord → start-cbc.d → sandbox-proxy → codebuddyps --ppid 125显示 3 个 codebuddy
③出网访问Agent/沙箱 → 外网宿主网关172.24.0.1:801416的 fd 20/22、125的多个 fd 均指向172.24.0.1:80
④日志上报沙箱 → 宿主log-forward-tee → nc → 172.24.0.1:18100SANDBOX_LOG_FORWARD=1;多个nc 172.24.0.1 18100进程

注意 ③ 的细节:Agent 进程自身也直连172.24.0.1:80,并非所有流量都绕经sandbox-proxy。说明sandbox-proxy的"代理"职责与"启动器"职责是两件独立的事。


6. 完整启动链路(从容器到 Agent)

1. 容器启动 PID 1 docker-init -- bash -c "...exec supervisord" 2. 进程管理 PID 61 supervisord(按 supervisord.conf 拉起各 program) 3. 读取平台配置 start-cbc.d → curl http://localhost:49983/envs(envd) → 解析 ENABLE_CBC_D,为 true 才继续 4. 获取 Agent 运行时(box) 优先:/root/proxy/box-current(sandbox-componentd 版本管理软链) 兜底:curl https://cs-res-1324618448.cos.ap-shanghai.myqcloud.com/sandbox/tools/box.tar.gz → 解压到 /root/proxy/box 5. 识别产物形态并运行 Go 形态: /root/proxy/box/sandbox-proxy → exec 前台运行 Node 形态: ecosystem.config.js → pm2 start → pm2 logs 保持前台 6. Agent 派生 sandbox-proxy(125) → codebuddy --prewarm --prewarm-id sbx-125-{1,2,3} 7. 会话接入 当前会话落在 codebuddy 1416;工具调用 → fork zsh / 启 MCP 子进程

sandbox-proxy二进制实测为46 MB 的 Go 静态链接 ELF(statically linked、带 debug_info),说明它是外部分发、独立升级的组件——这正好解释了start-cbc.d中"从 COS 下载 + 支持box-current软链切换版本"的设计。

启动脚本的一个工程细节

agent-init脚本中有一段明确注释,记录了一个已修复的线上问题,很能反映这套架构的可靠性设计:

历史上这里有 download-if-absent 兜底(文件不存在就从固定 COS URL 拉取)。该兜底有两个问题已移除:

  1. COS 那份长期未更新(停在 2026-02 旧版),一旦触发就把系统盘自带的新版覆盖成旧版(生产实测 sh3:base 盘 1.0.22 被覆盖成 1.0.10);
  2. 触发条件是竞态——warm 空壳的系统盘是 base 盘的 COW fork,脚本在 NBD 盘就绪前的窗口内[ -f ]判为不存在 → 误触下载。

含义:沙箱使用warm 池 + NBD 远程克隆盘做秒级启动,因此启动早期存在"文件尚未可见"的时间窗,任何"文件缺失即下载"的逻辑都会误判。


7. 边界与共享:Agent 到底能看到什么

7.1 命名空间:无隔离

/proc/1416/ns显示 Agent 与沙箱服务处于同一组命名空间:

net:[4026534002] pid:[4026534001] mnt:[4026533985] ipc:[4026534000]

因此:

  • Agent 能直接访问127.0.0.1:49983(envd)、127.0.0.1:8089(sync_server)、127.0.0.1:39099(editor_sdk)
  • Agent 与沙箱服务共享同一张网络栈、同一个 PID 空间、同一套挂载

7.2 文件系统:完全共享

观察项值
/proc/1416/cwd/workspace
/proc/1416/root/
根挂载overlay,upperdir=/mnt/user-data/46e3d0d99e364ee9b2f628933b04a755/diff
warm 池来源/var/run/cloudstudio/warm-b492449d-8153-4eb5-8096-dcd22815b96d...
嵌套容器盘/dev/nbd503(btrfs)→/var/lib/docker、/var/lib/buildkit

Agent 对沙箱文件系统的读写就是直接的磁盘读写,/workspace同时被sync_server同步到用户本地。

7.3 存储分层

NBD 远程盘(/dev/vdb、/dev/nbd503,btrfs) └─ overlay upperdir(/mnt/user-data/<uuid>/diff) └─ 容器根 /(rw) → /workspace(用户工作区)

启动方式为NBD 克隆盘 + overlay,配合 warm 池实现"空壳预热、按需接管"。


8. 通信关系总表

源目标协议/端口用途
控制面envd172.24.0.1 → 172.24.0.11:49983配置/指令下发
codebuddy 1416宿主网关172.24.0.11 → 172.24.0.1:80Agent 出网(云端模型调用等)
sandbox-proxy 125宿主网关→ 172.24.0.1:80(多条)代理出网
sandbox-proxy 125外网→ 43.141.132.124:443HTTPS 出网
sandbox-proxy 125envd127.0.0.1:58324 → :49983本地配置读取
sandbox-proxy 125sync_server127.0.0.1:54252 → :8089同步服务调用
codebuddy 1416自身127.0.0.1:35729内部 RPC / 扩展通道
nc/log-collector宿主→ 172.24.0.1:18100日志转发
sync_server宿主→ 172.24.0.1:80同步数据回传

9. 关键洞察与排障提示

洞察 1:职责分离做得比想象中干净

  • envd管配置,sandbox-proxy管进程与出网,sync_server管文件,log-collector管日志
  • 控制面从不直连 Agent 进程,只通过 envd 注入配置,Agent 由沙箱内部自行派生

洞察 2:Agent 是"可替换的租户",沙箱是"稳定的宿主"

  • 三个codebuddy实例由sandbox-proxy统一派生,会话切换只是换一个 prewarm 实例
  • Agent 崩溃不影响沙箱存活:sandbox-proxy在,随时能再拉一个

洞察 3:prewarm 池 = 首字延迟优化

  • CODEBUDDY_STREAM_TIMEOUT_MS=300000、CODEBUDDY_FIRST_TOKEN_TIMEOUT_MS=300000(均 5 分钟)
  • 两份待命实例让新会话无需冷启动

洞察 4:热升级路径清晰

  • sandbox-proxy从 COS 分发,支持box-current软链切版本
  • Agent 包在codebuddy-codenpm 目录(独立 overlay 挂载),可单独更新

排障提示

现象正确排查方式
内存/CPU 显示与预期不符读cat /sys/fs/cgroup/memory.max、cpu.max,不要用free
判断某能力是否开启curl -s localhost:49983/envs | grep ENABLE_
确认 Agent 归属ps --ppid <sandbox-proxy-pid>看是否为其子进程
出网异常检查到172.24.0.1:80的连接,而非公网直连
日志丢失检查nc 172.24.0.1 18100链路与SANDBOX_LOG_FORWARD=1

附录:一句话对照表

概念具体实体定位
沙箱CloudStudio spacelet(K8s Pod / 容器)宿主,提供机器、文件、网络、命令
控制面CloudStudio SaaS(codingcorp.cloudstudio.net/api)调度与配置来源
配置通道envd:49983控制面进入沙箱的唯一入口
Agentcodebuddy(@tencent-ai/codebuddy-code)沙箱内的租户进程,执行任务
Agent 启动器sandbox-proxy:9090/65225派生 Agent + 出网代理
边界出口宿主网关172.24.0.1(:80出网 /:18100日志)沙箱与外界的唯一出入口

CodeBuddy 沙箱系统架构 — 文字版

一、整体概览

这是一个运行在Docker 容器内的 IDE 沙箱环境,操作系统Ubuntu 24.04,配备123GB 内存 / 256GB 磁盘。容器入口是docker-init(PID 1),由它拉起supervisord作为总控进程,再由 supervisord 逐级启动所有子服务。


二、层级结构(从外到内)

┌─────────────────────────────────────────────────────┐ │ 🐳 Docker 容器 (PID 1: docker-init) │ │ │ │ ┌──────────┐ │ │ │ PM2 │ 独立进程管理器,管着 sandbox-proxy-mock │ │ │ PID 1378 │ │ │ └──────────┘ │ │ │ │ ┌──────────────────────────────────────────┐ │ │ │ supervisord ★ PID 62(总管家) │ │ │ │ │ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ │ IDE 基础服务 │ │ │ │ │ │ · api :65213 (PID 109)│ │ │ │ │ │ · terminal :65310 (PID 103)│ │ │ │ │ │ · local-proxy :65216 (PID 114)│ │ │ │ │ ├─────────────────────────────────┤ │ │ │ │ │ 容器 & 运维 │ │ │ │ │ · envd :49983 (PID 1337) │ │ │ │ · log-collector (PID 95) │ │ │ │ · dockerd (PID 22848) │ │ │ │ · editor_sdk :39099 (PID 42299) │ │ │ │ · sync_server :8089 (PID 42329) │ │ │ └──────────────────────────────────────────┘ │ │ │ │ │ ▼ 启动/控制 │ │ ┌──────────────────────────────────────────┐ │ │ │ 🔀 sandbox-proxy PID 127(网关) │ │ │ │ 对外端口:9090 / 内部:65225 │ │ │ └────────────────┬─────────────────────────┘ │ │ │ │ │ ┌────────┼────────┐ │ │ ▼ ▼ ▼ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │主实例 │ │预热 #2 │ │预热 #3 │ │ │ │PID 1412 │ │PID 1413 │ │PID 41711 │ │ │ │sbx-127-1 │ │sbx-127-2 │ │sbx-127-3 │ │ │ │~355MB │ │~222MB │ │~221MB │ │ │ │ ★活跃 │ │ ⏳待命 │ │ ⏳待命 │ │ │ └────┬─────┘ └──────────┘ └──────────┘ │ │ │ │ │ ▼ 派生 │ │ ┌──────────┐ │ │ │当前会话 │ ← 你现在就在这里 │ │ │·zsh 46046│ │ │ │·SA 41933 │ │ │ │·mcp 41861│ │ │ └──────────┘ │ └─────────────────────────────────────────────────────┘

三、各组件职责

层级组件PID端口职责
总控supervisord62—进程管理器,启动和监控所有子服务
进程管理PM21378—管理 sandbox-proxy-mock
IDE 入口api10965213对外提供 IDE API 接口
终端terminal10365310Web Terminal 服务
本地代理local-proxy11465216本地请求转发代理
环境守护envd133749983e2b 沙箱环境管理
日志log-collector95—日志采集与转发
★ 网关sandbox-proxy1279090 / 65225请求路由核心,分发到 AI Agent
★ AI Agentcodebuddy 主实例141240593(RPC)当前与你对话的实例,派生 zsh Shell
codebuddy 预热#21413—备用实例,毫秒级接管新会话
codebuddy 预热#341711—备用实例
会话zsh Shell46046—你的命令执行环境(由 1412 派生)
SheetAgent MCP41933—表格处理 MCP 子服务
mcp-stdio proxy41861—MCP 标准输入输出代理
编辑editor_sdk4229939099Office/WPS 文件实时编辑
同步sync_server423298089, 18601数据同步服务 (HTTP + gRPC)
容器dockerd22848—Docker 引擎(嵌套容器支持)
containerd22871—容器运行时

四、数据流向

你的浏览器/客户端 │ ▼ HTTP/WebSocket sandbox-proxy (:9090) ← 唯一对外入口,做路由分发 │ ▼ 内部转发 (:65225) codebuddy PID 1412 ← AI Agent 主实例,处理对话逻辑 │ ├──► zsh Shell (PID 46046) → 执行你输入的 bash 命令 ├──► SheetAgent MCP (41933) → 处理 Excel/表格操作 └──► mcp-stdio proxy (41861) → MCP 协议通信

关键点:你看到的终端、执行的每条命令,全部运行在PID 1412 (codebuddy sbx-127-1)这个进程的上下文中。PID 1413 和 41711 是两个已经预热的备用实例,随时可以接手新会话。


五、设计特点

  1. 三级就绪— 1 个活跃 + 2 个预热,新用户进来无需冷启动
  2. 网关隔离— sandbox-proxy 是唯一入口,内部服务不直接暴露
  3. 父子派生— 你的 Shell 会话是 AI Agent 的子进程,资源共享且便于管理
  4. MCP 扩展— SheetAgent 等 MCP 子服务以子进程形式挂载在 Agent 下
  5. 嵌套 Docker— 容器内还跑了 dockerd,支持在沙箱里再起容器

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询