文章publicstaticStringmemoryLimit="512m";//内存限制512MB
publicstaticdoublecpuLimit=1.0;//CPU限制1核
publicstaticinttimeout=300;//超时5分钟
publicstaticbooleannetworkEnabled=false;//禁用网络访问!
}
networkEnabled
=
false是最关键的安全决策——容器无法访问网络,防止恶意代码外传数据或发起攻击。
2.2
容器启动
publicclassDockerSandbox{privatefinalDockerClientdockerClient;privateStringcontainerId;privatebooleanisRunning=false;publicDockerSandbox(){DefaultDockerClientConfigconfig=DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost("unix:///var/run/docker.sock").build();DockerHttpClienthttpClient=newApacheDockerHttpClient.Builder().dockerHost(config.getDockerHost()).build();this.dockerClient=DockerClientImpl.getInstance(config,httpClient);}publicvoidstart()throwsException{if(isRunning)return;//如果镜像不存在则自动拉取
pullImageIfNeeded();//创建容器,配置资源限制
HostConfighostConfig=newHostConfig().withMemory(parseMemoryLimit(SandboxSettings.memoryLimit)).withCpuQuota((long)(SandboxSettings.cpuLimit*100000)).withCpuPeriod(100000L).withNetworkMode(SandboxSettings.networkEnabled?"bridge":"none").withAutoRemove(true);//容器停止后自动删除
CreateContainerResponsecontainer=dockerClient.createContainerCmd(SandboxSettings.image).withWorkingDir(SandboxSettings.workDir).withHostConfig(hostConfig).withAttachStdout(true).withAttachStderr(true).withTty(true).exec();containerId=container.getId();dockerClient.startContainerCmd(containerId).exec();isRunning=true;}}2.3
命令执行
在运行的容器中执行命令,捕获stdout和stderr,并支持超时控制:
publicSandboxExecutionResultexecuteCommand(Stringcommand)throwsException{if(!isRunning){thrownewIllegalStateException("Sandboxnot
running"
);}//创建exec实例
ExecCreateCmdResponseexecResponse=dockerClient.execCreateCmd(containerId).withAttachStdout(true).withAttachStderr(true).withCmd("/bin/sh","-c",command).exec();StringexecId=execResponse.getId();//执行并捕获输出
ByteArrayOutputStreamstdout=newByteArrayOutputStream();ByteArrayOutputStreamstderr=newByteArrayOutputStream();ExecStartResultCallbackcallback=newExecStartResultCallback(stdout,stderr);dockerClient.execStartCmd(execId).exec(callback);//等待完成,带超时控制
booleanfinished=callback.awaitCompletion(SandboxSettings.timeout,TimeUnit.SECONDS);if(!finished){callback.close();returnnewSandboxExecutionResult(null,"Commandtimed
out"
,124,true);}//获取退出码
InspectExecResponseexecInfo=dockerClient.inspectExecCmd(execId).exec();IntegerexitCode=execInfo.getExitCode();returnnewSandboxExecutionResult(stdout.toString(StandardCharsets.UTF_8),stderr.toString(StandardCharsets.UTF_8),exitCode!=null?exitCode:0,false);}2.4
执行结果封装
publicstaticclassSandboxExecutionResult{privatefinalStringstdout;privatefinalStringstderr;privatefinalintexitCode;privatefinalbooleantimedOut;publicbooleanisSuccess(){returnexitCode==0&&!timedOut;}publicStringgetCombinedOutput(){StringBuildersb=newStringBuilder();if(stdout!=null&&!stdout.trim().isEmpty()){sb.append(stdout);}if(stderr!=null&&!stderr.trim().isEmpty()){if(sb.length()>0)sb.append("\n");sb.append("STDERR:"
).append(stderr);}returnsb.toString();}}三、SandboxTool:面向Agent的工具封装
SandboxTool将Docker沙箱封装为Agent可以调用的工具,支持四种操作:
publicclassSandboxToolextendsBaseTool{privateDockerSandboxsandbox;publicSandboxTool(){super("sandbox","Executecommands
sandbox"
);}@OverridepublicMap<String,Object>getParametersSchema(){returnbuildSchema(Map.of("action",enumParam("Sandboxaction"
,List.of("start","stop","execute","status")),"command",stringParam("Commandexecute
sandbox"
),"language",enumParam("Programminglanguage"
,List.of("python","bash","node","java")),"code",stringParam("Codeexecute"
),"working_dir",stringParam("Workingdirectory
container"
)),List.of("action"));}}3.1
多语言代码执行
关键在于buildCodeExecutionCommand方法——它使用Heredoc语法将代码安全地传递给解释器,避免复杂的字符转义:
privateStringbuildCodeExecutionCommand(Stringcode,Stringlanguage){switch(language.toLowerCase()){case"python":returnbuildHeredocCommand(code,"python3");case"bash":returncode;//Bash直接执行
case"node":returnbuildHeredocCommand(code,"node");case"java"://Java需要写文件
执行
StringjavaHeredoc=buildHeredocToFile(code,"/tmp/Main.java");returnjavaHeredoc+"&&
Main"
;default:thrownewIllegalArgumentException("Unsupportedlanguage:
"
+language);}}privateStringbuildHeredocCommand(Stringcode,Stringinterpreter){//使用时间戳生成唯一分隔符,确保不与代码冲突
Stringdelimiter="OPENMANUS_CODE_EOF_"+System.currentTimeMillis();returnString.format("%s<<
'%s'\n%s\n%s"
,interpreter,delimiter,code,delimiter);}为什么用Heredoc?相比其他方式传递代码,Heredoc可以原样保留代码中的引号、换行、特殊字符,避免转义地狱。
3.2
自动启动机制
执行代码时,沙箱会自动启动,无需用户手动操作:
privateToolResulthandleExecute(Map<String,Object>parameters){//自动启动沙箱
if(sandbox==null){sandbox=newDockerSandbox();sandbox.start();}elseif(!sandbox.isRunning()){sandbox.start();}Stringcommand=getString(parameters,"command");Stringcode=getString(parameters,"code");Stringlanguage=getString(parameters,"language");StringactualCommand;if(command!=null){actualCommand=command;}elseif(code!=null&&language!=null){actualCommand=buildCodeExecutionCommand(code,language);}else{returnToolResult.error("Ei***r'command'
provided"
);}DockerSandbox.SandboxExecutionResultresult=sandbox.executeCommand(actualCommand);if(result.isSuccess()){returnToolResult.success(result.getCombinedOutput());}elseif(result.isTimedOut()){returnToolResult.error("Commandtimed
out"
);}else{returnToolResult.error("Commandfailed
"
+result.getExitCode()+":\n"+result.getCombinedOutput());}}四、注册工具并更新系统提示词
在ManusAgent中注册沙箱工具,并添加使用规则:
//ManusAgent构造函数中
toolCollection.addTool(newSandboxTool());//系统提示词新增规则
privatefinalstaticStringSYSTEM_PROMPT="""角色定义
你是Manus,一个多功能的AI代理,能够使用可用的工具处理各种任务。
利用Sandbox执行代码时,直接把代码内容传给Sandbox,而不是把代码脚本文件传给Sandbox
一次只能执行一个工具
"""
;注意两条新增的规则:
- “Sandbox里面不使用工作目录”——容器内有自己的文件系统,不需要使用宿主机路径
- “直接把代码内容传给Sandbox”——让大模型使用
code+language参数,而非先写文件再执行
五、完整执行流程
用户输入:“写一个计算前10个斐波那契数的Python脚本,然后把结果保存到fibonacci.txt文件中”
Step1:LLM推理->调用sandbox工具action:"execute"language:"python"code:|fib=[0,1]fori
inrange(8):fib.append(fib[-1]+fib[-2])print(fib)->Docker自动启动,执行Python代码->返回:[0,1,1,2,3,5,8,13,21,34]Step2:LLM推理->调用write_file工具
file_path:"workspace/fibonacci.txt"content:"[0,
13,
34]"->文件写入成功Step3:LLM推理->finish_reason="stop"->任务完成
总结
通过Docker沙箱,我们的Agent获得了安全执行任意代码的能力:
- 安全隔离:内存限制、CPU限制、网络禁用、自动清理
- 多语言支持:Python、Bash、Node.js、Java
- Heredoc传输:优雅地将代码传入容器,避免转义问题
- 自动管理:容器按需启动,无需用户关心底层细节
结合之前的文件读写工具,Agent已经可以完成"思考->编程->执行->保存"的完整工作流。
/>
- 上一篇: 如何免费利用官网资料搭建网站空间?
- 下一篇: 2025年珠海豪宅装修公司推荐榜单:哪些企业技术领先?


