DB-GPT Sandbox:为 Agent 构建安全隔离的代码执行运行时
【免费下载链接】DB-GPTopen-source agentic AI data assistant for the next generation of AI + Data products.项目地址: https://gitcode.com/GitHub_Trending/db/DB-GPT
本文基于 DB-GPT 官方文档 Sandbox 总览 并结合dbgpt-sandbox包的真实源码展开,系统讲解 DB-GPT 沙箱的设计动机、分层架构(Execution / Control / User / Display)、Runtime 自动选择机制、有状态 Session 模型以及 HTTP 接口面。读完后你将理解:为什么 Agent 场景必须把"推理"与"执行"隔离、DB-GPT 如何优先选择 Docker/Podman/Nerdctl 容器后端并在受限时安全退化,以及如何在应用中把沙箱接入智能体工具链。
什么是 Sandbox:为什么 Agent 需要隔离执行
DB-GPT 使用 sandbox(沙箱)让智能体在隔离的运行环境中执行代码和工具,而不是直接在宿主机环境中运行。这对 agent 工作流非常重要,因为智能体往往不仅仅需要文本推理,还需要:
- 执行代码
- 运行 shell 命令
- 安装依赖
- 生成文件
- 在多轮执行之间保持状态
Sandbox 就是把这些执行能力放在一个更安全、可控、可管理的边界内。在 DB-GPT 中,sandbox 是一个隔离执行环境,供智能体在任务过程中执行代码、运行命令、处理文件或调用执行型工具。它避免智能体直接操作宿主机,并提供:
- 进程隔离
- 资源限制(内存、CPU、超时)
- 可控工作目录
- 可选依赖安装能力
- 会话生命周期管理
- 清晰的"推理"和"执行"边界
如果智能体可以不受限制地直接执行代码,那么在真实环境中很难安全落地。Sandbox 为 DB-GPT 提供了一个专门的执行层,用于支持代码执行、shell 命令执行、依赖安装、文件创建与读取、多步骤有状态的数据分析。这对数据分析、报表生成和工具驱动型工作流尤其重要,因为这些场景需要把推理和真实执行结合起来。
Sandbox 如何作用于 Agent
智能体负责决定下一步做什么,sandbox 负责安全地执行这个动作怎么运行。官方文档给出的调用链路如下:
从源码看,这条链路中"执行结果 / observation"对应的统一数据结构是ExecutionResult,定义在 execution_layer/base.py 中:
@dataclass class ExecutionResult: """代码执行结果""" status: ExecutionStatus output: str = "" error: str = "" execution_time: float = 0.0 memory_usage: int = 0 # bytes exit_code: int = 0ExecutionStatus枚举提供四种终态:SUCCESS、ERROR、TIMEOUT、RESOURCE_LIMIT(base.py)。也就是说,Agent 观察到的每一次执行都带有状态语义——超时和资源超限是独立的执行结果类型,而不是简单的"报错",这为上层重试、降级逻辑提供了判断依据。
dbgpt-sandbox的分层架构
DB-GPT 当前的 sandbox 实现位于 packages/dbgpt-sandbox/。它是一个分层的、可扩展的沙箱运行时系统,支持多种 backend,分为四层。
1. Execution layer(执行层)
执行层提供具体 runtime 实现与核心抽象,位于packages/dbgpt-sandbox/src/dbgpt_sandbox/sandbox/execution_layer/:
- base.py:定义 runtime / session / result / config 等公共接口
- docker_runtime.py、podman_runtime.py、nerdctl_runtime.py、local_runtime.py:具体运行时实现
- runtime_factory.py:负责自动选择 backend
base.py中的两个抽象基类是整个沙箱的契约:
class SandboxSession(ABC): """沙箱会话抽象类""" async def start(self) -> bool async def stop(self) -> bool async def execute(self, code: str) -> ExecutionResult async def get_status(self) -> Dict[str, Any] async def install_dependencies(self, dependencies: List[str]) -> ExecutionResultclass SandboxRuntime(ABC): """沙箱运行时抽象类""" async def create_session(self, session_id, config) -> SandboxSession async def destroy_session(self, session_id) -> bool async def list_sessions(self) -> List[str] async def get_session(self, session_id) async def cleanup_expired_sessions(self, max_idle_time: int = 3600) -> int async def health_check(self) -> Dict[str, Any] def supports_language(self, language: str) -> bool从接口签名可以推断:会话是运行时下的一等公民,支持过期清理(默认闲置 1 小时)、健康检查与语言支持探测;install_dependencies是可选能力,基类默认返回"未实现"错误,由具体运行时(如容器后端)按需覆盖。
2. Control layer(控制层)
控制层负责任务生命周期与执行编排,实现锚点为 control_layer.py。它处理的操作(完整列表见 schemas.py 中的TASK_TYPES):
| task_type | 处理逻辑(源码中的 handler) |
|---|---|
connect | _handle_connect:创建新的沙箱会话 |
configure | _handle_configure:配置沙箱环境,例如安装依赖 |
execute | _handle_execute:在沙箱中执行代码 |
manual | _handle_manual:进入手动操作模式 |
disconnect | _handle_disconnect:停止并销毁沙箱会话 |
status | _handle_status:获取任务/会话状态 |
list | _handle_list:列出所有活跃会话 |
get_file | _handle_get_file:获取沙箱内指定文件内容 |
控制层入口是ControlLayer.handle_task(task):它按task.task_type查表分发到对应 handler,并用asyncio.Lock对每个task_id加锁,保证同一任务的串行执行。几个值得注意的实现细节:
- 会话标识约定:
connect时若未指定session_id则生成 UUID;用户层则统一使用{user_id}_{task_id}组合作为 session_id(见 service.py),从而把"用户 + 任务"与沙箱会话一一绑定。 - 资源参数注入:
_handle_connect构造SessionConfig时固定working_dir=/workspace、max_memory=512MB,max_cpus与环境变量、network_disabled则从任务的config中读取。 - shell 语言归一化:
_handle_execute会把language="shell"归一化为bash,使 shell 代码走统一的执行路径(control_layer.py)。
3. User layer(用户层)
用户层对外暴露 sandbox 服务接口,实现锚点:
- service.py
- schemas.py
schemas.py定义了TaskObject——控制层的统一输入载体,封装task_type、user_id、task_id、session_id、language、code_content、config、manual_action、file_name等字段,并在构造时校验task_type必须属于TASK_TYPES白名单。
service.py则把控制层封装为UserLayer类,并直接挂载为一套 FastAPI 路由(默认挂在/api前缀下,可通过initialize_sandbox()启动独立服务或注册到已有 FastAPI 应用):
| 接口 | 方法 | 说明 |
|---|---|---|
/health | GET | 健康检查 |
/connect | POST | 建立沙箱会话(user_id+task_id+image_type) |
/configure | POST | 配置沙箱环境(如安装依赖) |
/disconnect | POST | 断开并销毁沙箱会话 |
/execute | POST | 执行代码(session_id+code_type+code_content) |
/manual | POST | 进入手动操作模式 |
/status | POST | 获取任务/会话状态 |
/sessions | GET | 列出所有活跃会话 |
/get_file | POST | 获取沙箱内指定文件内容 |
/methods | GET | 获取所有可用接口和方法 |
对应的请求模型(ConnectRequest、ExecuteRequest等 Pydantic 模型)定义在 service.py 中,字段校验在入口处完成。
4. Display layer(显示层)
显示层用于封装运行时相关的展示结果或文件型结果,实现锚点为 display_layer.py。结合manual任务类型返回的http://sandbox-gui/{session_id}地址可以推断,该层面向的是沙箱产物(文件、GUI 会话地址等)向 Agent / UI 的展示转换。
Runtime backends:Docker → Podman → Nerdctl → Local 的自动选择
运行时工厂会按以下优先级自动选择 backend:
- Docker(基于 Docker SDK,并调用
client.info()做连通性验证) - Podman
- Nerdctl
- Local runtime(本地进程,需显式开启)
实现锚点:runtime_factory.py。关键的安全设计在_local_runtime():本地运行时会直接在宿主机上执行代码,因此默认拒绝退化,必须由用户显式声明:
if not SANDBOX_ALLOW_LOCAL_RUNTIME: raise RuntimeError( "LocalRuntime executes code on the host. Set " "SANDBOX_RUNTIME=local and SANDBOX_ALLOW_LOCAL_RUNTIME=true " "to opt in explicitly." )这意味着 DB-GPT 会优先使用容器隔离;如果部署环境没有容器支持且未显式允许本地运行时,工厂会直接抛出RuntimeError(fail closed),而不是静默地在宿主机上跑代码。相关环境变量定义在 config.py:
SANDBOX_RUNTIME:可选值docker/podman/nerdctl/local;不设时走自动探测。指定后若对应后端不可用会抛出"指定的运行时不可用"错误,而不是继续回退。SANDBOX_ALLOW_LOCAL_RUNTIME:布尔开关(1/true/yes/on),仅在明确允许时才允许使用宿主机本地运行时。
语言镜像映射与执行命令
容器后端按语言选择基础镜像,映射关系定义在 config.py:
| language | 容器镜像 | 执行命令(get_command_by_language) |
|---|---|---|
python | python:3.11-slim | python {filename} |
python-vnc | vnc-gui-browser:latest | python3 {filename} |
javascript | node:18-slim | node {filename} |
java | openjdk:11-jre-slim | javac {filename} && java {filename[:-5]} |
cpp | gcc:latest | g++ -o program {filename} && ./program |
go | golang:1.21-alpine | go run {filename} |
rust | rust:1.75-slim | rustc {filename} -o program && ./program |
python-vnc一项值得注意:它指向带 VNC GUI 的浏览器镜像,对应 sandbox 设计中"未来扩展到 browser / computer 风格运行时"的方向(详见下文)。
会话级配置与资源限制
SessionConfig(base.py)是每次会话的资源契约:
| 字段 | 默认值 | 说明 |
|---|---|---|
language | "python" | 会话执行语言 |
timeout | 30(秒) | 单次执行超时 |
max_memory | 256MB | 内存上限 |
max_cpus | 1 | CPU 上限 |
working_dir | "/workspace" | 容器内工作目录 |
environment_vars | {} | 注入的环境变量 |
network_disabled | False | 是否禁用网络 |
此外,config.py 还定义了一组全局资源常量,作为各后端的限制基线:
| 常量 | 值 | 含义 |
|---|---|---|
MAX_MEMORY | 256MB | 单次执行内存上限 |
MAX_CPU_PERCENT | 50.0 | CPU 百分比上限 |
MAX_EXECUTION_TIME | 30s | 单次执行时间上限 |
MAX_FILE_SIZE | 10MB | 文件大小上限 |
MAX_DEPENDENCY_INSTALL_TIME | 300s | 依赖安装时间上限 |
MAX_DEPENDENCY_INSTALL_SIZE | 200MB | 依赖安装体积上限 |
MAX_PROCESSES | 10 | 进程数上限 |
这些常量与ExecutionStatus.TIMEOUT/RESOURCE_LIMIT两个终态相呼应:任何一条限制被触发,执行都会以可辨识的状态返回给 Agent,而不是无差别地"失败"。
Session 模型与有状态执行
DB-GPT 当前 sandbox 设计的一个重要点,是支持基于 session 的有状态执行。这意味着:
- sandbox session 可以先创建一次;
- 多个执行步骤可以复用同一个 session;
- 上一步安装的依赖在后续步骤中仍然可用;
- 前一步生成的文件也可以在后一步继续使用。
这非常适合 agent 场景,因为很多任务不是一次工具调用就完成,而是需要多轮"推理 → 执行 → 观察"。源码层面,这个能力由三层支撑:
- Runtime 维护会话字典:
SandboxRuntime.__init__中持有sessions: Dict[str, SandboxSession],并通过cleanup_expired_sessions(max_idle_time=3600)回收闲置会话(base.py); - 控制层持久化任务 → 会话映射:
ControlLayer.tasks[task_id]记录session_id与状态(connected/configured/finished/failed/manual/stopped),configure与execute都通过该映射复用同一会话; - 用户层维护活跃会话表:
UserLayer.active_sessions(session_id → task_id)让后续的/execute、/get_file、/status请求无需重复携带 user/task 上下文。
dbgpt-sandbox 的 README 也明确了这一设计目标:支持有状态的沙箱环境,多次代码执行可以在相同环境中,并且上次环境的变更能影响下次的执行(例如第一次执行安装 pypi 依赖,第二次执行安装后的依赖能正常使用);同时以插件化方式支持 Docker、Podman、本地进程(基于 Cgroup/Namespace/WebAssembly 等)等多种实现。
dbgpt-app 中的当前接入方式
目前 DB-GPT 已经在应用侧 agent 工具里实际使用了 sandbox。例如 agentic_data_api.py 中的shell_interpreter工具,就使用了dbgpt-sandbox的LocalRuntime执行 shell 命令(工具实现位于 shell_interpreter.py),并具备:
- 进程隔离
- 内存限制
- 超时限制
- 安全校验
当前这里的实现是单次调用无状态的:每次工具调用都会创建一个临时 sandbox session,执行结束后销毁。
因此仓库里实际上同时存在两层能力:
dbgpt-sandbox中更完整的、可复用 session 的 sandbox 设计;dbgpt-app中已经在实际工具执行里接入的 sandbox 用法。
两者互补:后者验证了"沙箱执行"在生产工具链中的可行性,前者提供了面向多轮 Agent 任务的会话化运行时。
DB-GPT 当前支持的方向
基于当前dbgpt-sandbox实现,DB-GPT 正在走向一个更通用的 agent 执行运行时,支持:
- 多 runtime 的 sandbox 执行;
- 安全代码与 shell 执行;
- 有状态 session;
- sandbox 内依赖安装;
- 任务生命周期控制;
- 文件读取与产物管理。
这使得 sandbox 很适合支撑:代码 agent、数据分析 agent、报告生成 agent,以及未来扩展到 browser / computer 风格运行时(LANGUAGE_IMAGES中的python-vnc条目即为该方向的早期落地)。
这张图是概念性的,表示 sandbox 作为 agent 应用之下的专门运行时层。当前仓库已经在dbgpt-sandbox中具备 execution、control、session 和 runtime selection 的基础能力。
关键实现锚点索引
| 关注点 | 文件路径 |
|---|---|
| 沙箱设计目标与背景 | packages/dbgpt-sandbox/README.md |
| 架构设计文档 | packages/dbgpt-sandbox/src/docs/architecture.md |
| 使用教程文档 | packages/dbgpt-sandbox/src/docs/usage.md |
| 运行时自动选择 | runtime_factory.py |
| Runtime/Session 抽象 | base.py |
| 语言镜像与资源常量 | config.py |
| 任务生命周期编排 | control_layer.py |
| HTTP 服务接口 | service.py |
| 任务模型与类型白名单 | schemas.py |
| 应用侧沙箱接入示例 | agentic_data_api.py |
【免费下载链接】DB-GPTopen-source agentic AI data assistant for the next generation of AI + Data products.项目地址: https://gitcode.com/GitHub_Trending/db/DB-GPT
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考