1574 字
4 分钟
Astrbot电脑执行能力的运行环境
AstrBot Sandbox 交互架构解析
在 AstrBot 的 Sandbox (沙盒) 模式下,computer_tools 与沙盒的交互采用了一套职责分明的分层架构,使得上层工具代码无需关心底层沙盒环境的具体技术实现。以下是该架构的设计详情。
1. 核心架构分层
整个沙盒交互流程从上到下分为四个核心层次:
1.1. 工具层 (Tool Layer)
- 位置:
astrbot.core.tools.computer_tools.* - 职责: 这些是直接暴露给大语言模型 (LLM) 使用的 Function Call 工具(例如
PythonTool、ExecuteShellTool、FileReadTool等)。工具层负责接收 LLM 传入的参数,进行系统级别的权限校验(如判断是否为管理员),然后根据当前上下文获取对应的沙盒实例。拿到实例后,工具会将具体任务委托给沙盒内部的各个组件去执行,并将结果格式化返回给大模型。
1.2. 路由与生命周期层 (Client Routing Layer)
- 位置:
astrbot.core.computer.computer_client.py中的get_booter函数。 - 职责: 充当沙盒的工厂与连接池。当工具层请求一个沙盒环境时,
get_booter会根据用户配置(provider_settings.sandbox.booter)决定实例化哪种具体的沙盒(如shipyard_neo,shipyard,boxlite等)。为了实现会话维度的隔离和状态保持,它维护了一个以 Session ID(统一消息来源umo)为键的连接池。如果当前 Session 尚未启动沙盒,它负责调用对应 Booter 的boot()方法进行初始化。
1.3. 抽象组件层 (olayer)
- 位置:
astrbot.core.computer.olayer.* - 职责: 为工具层提供统一的接口协议(Protocol),抹平不同底层沙盒的 API 差异。定义了以下标准组件能力:
ShellComponent: 执行终端命令PythonComponent: 执行 Python 代码FileSystemComponent: 提供文件操作(读取、写入、编辑、搜索等)BrowserComponent: 执行浏览器自动化操作
1.4. 沙盒实现层 (Booters Layer)
- 位置:
astrbot.core.computer.booters.* - 职责: 针对具体的底层沙盒架构(如
ShipyardNeoBooter、BoxliteBooter),实现上述的olayer组件协议。这些具体组件在内部通过其专属的 SDK 或网络请求,与远程或本地隔离的沙盒服务进行真正的指令通讯。
2. 交互流程生命周期
以大模型在沙盒中执行一段 Shell 命令为例,完整的生命周期如下:
- 大模型发起调用: 大模型决定调用
astrbot_execute_shell,并传入具体的command参数。 - 鉴权与实例获取:
- 工具内部首先调用
check_admin_permission确认权限。 - 然后通过
await get_booter(...)获取沙盒实例。若沙盒尚未启动,computer_client会拉起沙盒容器,并自动调用_sync_skills_to_sandbox将宿主机的 Skills 技能打包同步至沙盒内。
- 工具内部首先调用
- 接口委托调用: 工具获得
sb(Booter 实例) 后,调用统一接口sb.shell.exec(command)。 - 底层真实执行:
sb.shell(例如NeoShellComponent) 将指令转换为对其特定沙盒 SDK (如_sandbox.shell.exec(...)) 的调用。- 指令通过网络层发送到沙盒内真正执行。
- 结果封装返回: 沙盒执行完成返回
stdout,stderr,exit_code。底层组件将其序列化并返回给工具层,工具层将其转化为标准格式输出给大模型的上下文。
3. 文件系统交互:上传与下载机制详解
在 sandbox 模式中,沙盒内的文件系统与宿主机的物理文件系统是完全物理隔离的。大模型无法像 local 模式那样直接读写宿主机上的文件路径。为了打通这一壁垒,AstrBot 特地为 Sandbox 模式注册了独立的 astrbot_upload_file (上传) 和 astrbot_download_file (下载) 工具。
3.1. 文件上传实现 (FileUploadTool)
当用户通过聊天界面发送了一份文件,大模型需要在沙盒内处理该文件时,会触发此工具。
- 入参:
local_path(宿主机上该文件的绝对路径)。 - 处理逻辑:
- 获取到当前的沙盒 Booter。
- 解析出文件名:
remote_path = os.path.basename(local_path)。默认将文件存放到沙盒内部的当前工作目录下。 - 调用
sb.upload_file(local_path, remote_path)交由底层沙盒层处理。
- 底层协议实现 (以
ShipyardNeoBooter为例):- Booter 会在宿主机读取
local_path的二进制字节流 (content = f.read())。 - 调用远程沙盒 SDK
_sandbox.filesystem.upload(remote_path, content)将字节流发送入沙盒。 - 若是
BoxliteBooter,底层则会构造aiohttp.FormData进行multipart/form-data的 HTTP POST 请求上传至本地的 Boxlite 容器中。
- Booter 会在宿主机读取
3.2. 文件下载实现 (FileDownloadTool)
当沙盒中的代码生成了产物(如数据图表、处理后的 Excel 等),大模型希望将这份文件导出给用户时,会触发此工具。
- 入参:
remote_path(文件在沙盒内部的路径),also_send_to_user(是否自动发送给用户,默认 true)。 - 处理逻辑:
- 获取到当前的沙盒 Booter。
- 在宿主机的
get_astrbot_temp_path()(系统临时目录) 下生成一个带 UUID 的防冲突本地路径,如sandbox_a1b2_output.png。 - 调用
sb.download_file(remote_path, local_path)将文件从沙盒拉出并落盘到宿主机的临时目录下。
- 底层协议实现 (以
ShipyardNeoBooter为例):- 调用 SDK
_sandbox.filesystem.download(remote_path)请求文件流。 - 将收到的二进制内容以
"wb"模式写入到宿主机的local_path中。
- 调用 SDK
- 回传用户:
- 若
also_send_to_user为 True,工具内部会构建一个 AstrBot 专用的消息链 (MessageChain),把下载到本地的物理文件包装为File(name=..., file=local_path)发送至聊天平台,此时用户即可在聊天框收到文件。
- 若
3.3. 路径安全与边界隔离差异
- 在 Local 模式下的文件读写工具(
fs.py中的FileReadTool/FileWriteTool等),出于安全考虑,会在工具层通过_normalize_rw_path进行严格的软拦截和约束,防止越权读取。 - 在 Sandbox 模式下,所有的文件读写、编辑、搜索等路径传参几乎直接进行透传。原因是:工具层将所有的操作路径边界安全交给了真正的底层沙盒环境来保证,达到了真正的沙盒级物理隔离,这使得设计异常干净清晰。
分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Astrbot电脑执行能力的运行环境
http://blog.rikka.asia/posts/astrbot_sandbox_env/ 部分信息可能已经过时
相关文章 智能推荐






