08 - 终端后端抽象
学习目标
本章聚焦 Hermes Agent 的终端后端抽象实现。你将了解:
tools/environments/中 12 个文件的后端实现架构- 七种终端后端的隔离级别与适用场景
- 无服务器持久化(Modal/Daytona)的空闲休眠与按需唤醒
- 文件工具的 shell 契约与路径限制
- 安全边界:终端后端隔离不覆盖进程内代码执行
前置知识
本章涉及安全沙箱的通用原理,建议先阅读:
下文直接聚焦 Hermes 的终端后端具体实现。
项目实践
终端后端架构
tools/environments/ 目录(12 个文件):
| 文件 | 职责 |
|---|---|
base.py | 后端抽象基类 |
local.py | 本地执行(默认) |
docker.py | Docker 容器隔离 |
ssh.py | 远程主机执行 |
singularity.py | HPC Singularity 容器 |
modal.py | Modal 云函数 |
managed_modal.py | 托管 Modal 实例 |
modal_utils.py | Modal 工具函数 |
daytona.py | Daytona 云沙箱 |
vercel_sandbox.py | Vercel 云沙箱 |
file_sync.py | 文件同步工具 |
__init__.py | 后端注册与发现 |
tools/terminal_tool.py(~102949 行)是终端工具的核心实现,负责所有后端的统一接口。
七种终端后端对比
| 后端 | 隔离级别 | 适用场景 | 特点 |
|---|---|---|---|
| 本地(默认) | 无 | 信任 LLM 的个人开发 | 零配置,直接执行 |
| Docker | 容器隔离 | 项目级隔离 | 文件系统只读挂载 + 可写目录 |
| SSH | 远程主机 | 远程执行 | 通过网络连接到远程机器 |
| Singularity | HPC 容器 | 科研计算 | 适用于 HPC 环境 |
| Modal | 云函数 | 无服务器持久化 | 空闲休眠、按需唤醒 |
| Daytona | 云沙箱 | 无服务器持久化 | 空闲休眠、按需唤醒 |
| Vercel Sandbox | 云沙箱 | 低成本闲置 | 低成本云执行 |
无服务器持久化
Modal 和 Daytona 后端实现了无服务器持久化模式:
空闲休眠:沙箱在空闲一段时间后自动休眠,减少云成本。 按需唤醒:新命令到达时自动唤醒或创建沙箱。
文件工具的 Shell 契约
文件工具通过 shell 契约实现,受后端路径限制:
- 所有文件操作(读、写、删除、搜索)通过 shell 命令执行
- 路径限制在配置的工作目录内
- 不同后端对路径限制的执行方式不同(Docker 通过只读挂载、SSH 通过受限用户)
安全边界
重要:终端后端隔离仅覆盖通过 shell/文件操作执行的内容,不覆盖:
- Python 进程内的代码执行工具(作为宿主子进程运行)
- MCP 子进程
- 插件加载
- 技能加载
需要完整进程隔离的场景应使用全进程包装(见安全与信任模型)。
问题与规避
无服务器冷启动延迟
问题:Modal/Daytona 沙箱休眠后,唤醒需要时间,导致命令执行延迟。
对策:唤醒时间与云提供商的冷启动策略相关。可通过配置 keepalive 时间减少休眠频率。
SSH 后端的认证管理
问题:SSH 后端需要管理密钥或密码认证。
对策:推荐使用 SSH 密钥认证,密钥存储在 Hermes 配置中。密码认证不支持(安全问题)。
设计取舍
Shell 契约 vs API 契约
| 方案 | 优势 | 代价 |
|---|---|---|
| Shell 契约(Hermes) | 后端无关、任何支持 shell 的后端都可用 | 文件操作效率低(需要序列化/反序列化) |
| API 契约 | 高效、类型安全 | 每个后端需要独立的 API 实现 |
Hermes 选择 shell 契约,因为终端后端的多样性(从本地到云函数)使得统一的 API 契约难以设计。Shell 是所有后端都支持的最小公分母。
参考来源
- 源码验证:
tools/environments/目录、tools/terminal_tool.py