Monty Runtime 二进制Monty 沙箱 Python 解释器的 CLI 与 Worker 子进程实战指南【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/montymonty-runtime是 Monty一个用 Rust 编写的轻量级、面向 AI 场景的沙箱化 Python 解释器的命令行二进制载体。本文以 crates/monty-runtime/README.md 为主体结合 入口实现、CLI 运行逻辑、Worker 子进程实现 与集成测试系统讲解它的三种安装途径、完整 CLI 参数、文件系统挂载、资源限制、类型检查、可观测性以及用于崩溃隔离的monty subprocess线协议模式。读完你既能直接用命令行跑起一个沙箱 Python 环境也能理解宿主进程是如何通过它获得 crash isolation 能力的。1. monty-runtime 是什么Monty 是一个以最小、安全、面向 AI 使用为目标、用 Rust 实现的 Python 解释器。monty-runtimecrate 构建出的就是monty这个可执行二进制它对外呈现两类职责独立 CLIstandalone提供交互式 REPL、运行 Python 文件、执行-c字符串代码以及类型检查、文件系统挂载、资源限制等沙箱能力Worker 子进程subprocess以线协议子进程的方式被monty-pool之类的父进程驱动读取 stdin 上分帧的 protobuf 请求、向 stdout 写分帧事件实现沙箱代码执行的崩溃隔离。二进制内部还注册了monty-alloc的全局分配器 LimitedAllocator对每个执行模式CLI 与 subprocess 一视同仁施加内存软/硬限制。crate 的入口定义在 crates/monty-runtime/src/main.rsCLI 运行路径在 crates/monty-runtime/src/run.rsworker 模式在 crates/monty-runtime/src/subprocess.rs。2. 三种安装方式monty-runtime的安装路径有 PyPI wheel、cargo 与 Python 工具安装三种适用场景各不相同。2.1 通过 PyPI 安装pydantic-monty-runtime安装 wheel 会把编译好的二进制放进环境如虚拟环境的scripts目录。正常情况下你不应直接安装它——pydantic-monty元包会把它与 Python 绑定一并拉取Python 绑定需要它来派生 worker 子进程。独立安装它是为了只拿到 CLI或者为已有的pydantic-monty-client安装提供monty二进制uv add pydantic-monty-runtime # 或 pip install pydantic-monty-runtime包内pyproject.toml采用了与uv、ruff相同的打包模式[tool.maturin]中bindings bin让 maturin 把编译好的monty二进制放进 wheel 的 scripts 目录见 crates/monty-runtime/pyproject.toml安装后即在 PATH 上可用pydantic-monty的find_monty_binary会通过sysconfig.get_path(scripts)定位它。2.2 作为独立工具安装把monty作为命令行工具安装之后直接在任何目录调用uv tool install pydantic-monty-runtime monty --help2.3 通过 cargo 安装如果你是 Rust 开发者希望从源码构建也可以直接从 crate 安装cargo install monty-runtime安装后即可验证$ monty -c print(hello world) hello world3. CLI 基础用法REPL、文件与-cmonty二进制与 CPython 的调用风格高度对齐核心执行模式有三种命令行为monty启动交互式 REPL无文件或命令时的默认行为monty file.py运行一个 Python 文件monty -c code以字符串形式运行一段程序等价于python -c从 main.rs 的 clap 定义 可以看到这些参数都被声明为可选-c是command位置参数file是可选文件路径-i/--interactive用于切换 REPL 会话。当-c与文件同时给出时CLI 会报错拒绝见 run.rs避免歧义。REPL 会话的提示符与 CPython 一致语句行提示符为❯多行续行提示符为…。REPL 是有状态的——MontyRepl实例在会话期间持续存在逐条喂入代码片段exit或 EOF 退出见 run.rs。4. 交互式执行-i/--interactive-i/--interactive让文件或-c程序跑完后停留在 REPL 会话中等价于python -imonty -i script.py # 运行 script.py 后进入 REPL monty -i -c x 1 # 执行代码后进入 REPLx 保持在作用域内实现上run_cli会先执行给出的代码片段再初始化 rustyline 编辑器进入交互循环见 run.rs。REPL 循环内部使用 CPython 风格的续行检测ReplContinuationMode支持多行块输入Ctrl-C会清空待输入并重新开始。5. 执行前类型检查-t与--type-check-format-t/--type-check在执行前对沙箱代码做类型检查底层由 ty 类型检查器驱动仓库内封装在monty-type-checkingcrate。这对 AI 生成的代码尤其有价值——在执行前拦截类型错误而不是等运行时才报错。--type-check-format控制诊断的渲染格式full默认、concise、json、jsonlines、github、azure、rdjson、pylint、gitlab等详见 main.rs 参数定义必须与--type-check搭配使用否则 clap 会因requires type_check拒绝。脚本模式下类型检查的结果会以带时间戳的形式输出到 stderrtype check passed或type check failed见 run.rs。6. 文件系统挂载-m/--mount沙箱内的 Python 代码默认无法访问宿主文件系统。-m/--mount把宿主目录映射进沙箱格式为/host/path::/virtual/path[::mode[::write_limit_bytes]]分隔符特意用::避免与 Windows 盘符如C:产生歧义。模式mode有三种模式含义说明ro只读默认值未指定 mode 时生效rw读写沙箱写入会真实持久化到宿主目录overlay内存写时复制COW覆盖层沙箱内写入只停留在内存不触碰宿主第 4 段write_limit_bytes为可选的写入字节上限对所有写模式生效# 只读挂载等价于省略 mode monty -m /data/share::/mnt script.py # 读写挂载最多写 1,000,000 字节 monty -m /data/share::/mnt::rw::1000000 script.py # 内存 overlay 挂载 monty -m /data/share::/mnt::overlay script.py⚠️ 安全警告使用rw时沙箱代码写入的文件会持久化到宿主磁盘宿主侧自己的工具日后可能执行这些文件。因此默认优先推荐overlay见 main.rs 参数注释。解析逻辑在 run.rs 的parse_mount先按::拆分2/3/4 段分别对应不同的可选层级非法模式非ro/rw/overlay、空路径、非法字节限制都会在挂载表构建阶段直接报错fail-fast而不是运行到一半才暴露。集成测试 crates/monty-runtime/tests/mounts.rs 验证了三个关键行为访问未挂载路径报PermissionError: Permission denied超过配置的 write limit 报OSError: disk write limit of N bytes exceeded非法 write limit如abc在参数解析阶段即被拒绝。7. 沙箱资源限制monty提供一组资源限制参数用于约束沙箱内代码的执行消耗参数含义示例--max-memory最大堆内存--max-memory 10MB--max-duration最大执行时长秒可小数--max-duration 0.5--max-recursion-depth最大调用栈深度默认 1000--max-recursion-depth 100--gc-interval每 N 次分配执行一次 GC--gc-interval 10000--max-suspensions单次 CLI 会话最多服务的挂起次数默认 1000--max-suspensions 1007.1 内存单位解析--max-memory接受裸字节数或带大小写不敏感后缀的值1024、512KB、10MB、1GB。解析器在 main.rs 的parse_memory_size实现KB为 1024、MB为 1024²、GB为 1024³且使用checked_mul防止溢出。7.2 时间限制--max-duration以秒为单位、支持小数如0.5表示 500ms内部通过std::time::Duration::try_from_secs_f64转换非法值会返回明确的invalid --max-duration错误见 main.rs。7.3 限制如何生效所有限制参数最终聚合成monty_types::ResourceLimits未提供任何资源参数时使用仅含递归限制的默认值main.rs。随后monty_alloc::set_limit把软限制交给全局分配器 LimitedAllocator分配器记录会话的软限制用量同时强制一个更高的硬上限——跨过软限制会在解释器检查点抛出MemoryError跨过硬上限则以专用退出状态退出让父进程可以分类处理详见 crates/monty-runtime/README-crate.md 的 Worker mode 一节。8. Worker 模式monty subprocess与崩溃隔离8.1 什么是 worker 模式monty subprocessmonty subprocess让二进制以线协议子进程运行stdin 读入分帧的 protobuf 请求stdout 写分帧的事件。这是pydantic-monty运行沙箱代码并获得崩溃隔离的方式设计上应由父进程驱动而不是手工调用。该模式的完整定义在 subprocess.rs围绕monty_proto::worker::Child与传输无关的状态机做了一层薄薄的 stdio 外壳。协议严格按回合制turn-based推进一个请求进来 → 可能流式输出零或多个Print事件 → 恰好一个回合结束事件。崩溃隔离正是这种模式存在的全部意义父进程必须把未发FatalError事件就退出或 EOF的子进程视为崩溃——栈溢出、分配器 abort 都不会产生最终的结束帧父进程据此发现并替换 worker。这种设计下沙箱代码把子进程搞死只是父进程的一个可恢复事件而不是宿主进程的灾难。8.2 关键退出码语义worker 模式定义了若干有明确语义的退出码见 subprocess.rs退出码含义0干净退出收到Shutdown回合结束事件或父进程关闭 stdin 后的帧边界处干净 EOF3stdout 写入失败父进程已消失4子进程发出FatalError如协议版本不匹配后退出76协议错误EX_PROTOCOL取自 BSD sysexits.h帧流失去同步或事件过大无法完成分帧子进程还安装了 panic hook普通 panic 在默认 unwind 前尽力向 stdout 写一帧FatalError给父进程一个可解析的最后遗言而栈溢出、分配器 abort 这类硬崩溃会绕过 hook父进程的契约就是没有FatalError就退出 崩溃subprocess.rs。8.3 与 CLI 参数的互斥subprocess从协议中读取全部配置因此任何正常执行参数与它同时出现都是误配置会被拒绝而非静默忽略见 main.rs 的subprocess_conflict--interactive、-c、文件参数、--type-check、--mount或任何资源限制参数都会被逐一检查并报错。8.4 测试如何验证crates/monty-runtime/tests/subprocess.rs 直接 spawn 真实二进制并走完整线协议覆盖了 worker 模式的方方面面会话保持session_state_persists_across_feeds验证第一个 feed 定义的变量在第二个 feed 中可见输入注入inputs_are_injected通过NamedValue向沙箱注入命名输入打印流式输出print_output_is_streamed_in_order验证print输出按序到达且无换行的部分行也会在回合结束前到达错误恢复runtime_error_preserves_session验证1 / 0抛出带 traceback 的ZeroDivisionError后会话仍可用外部函数往返external_function_round_trip演示FunctionCall挂起 → 父进程ResumeCall→Complete的完整流程名称查找往返name_lookup_round_trip演示裸名称读取挂起为NameLookup由父进程回填值时间限制child_enforces_time_limit验证超时抛出TimeoutError且Reset 重新Configure可以复用同一子进程内存软限制exceeding_the_soft_memory_limit_preserves_the_worker验证跨过软限制抛MemoryError而非杀死 worker之后会话仍可用大分配预检large_allocations_are_rejected_before_the_hard_limit对十余种大分配场景断言其恰好在软/硬限制之间被拒绝并留下可恢复的会话挂起状态可迁移suspended_call_keeps_its_arguments_for_a_dump与suspended_os_call_keeps_its_payload_for_a_dump验证在挂起点Dump后再Load到新子进程参数与载荷完整保留。9. Cargo featuresstandalone 与 telemetrymonty-runtime提供两个 cargo feature控制二进制的能力裁剪见 crates/monty-runtime/Cargo.tomlFeature默认内容standalone✅ 开启monty file/-c/ REPL 路径及其终端栈rustyline、anstream、anstyle。关闭后二进制只服务monty subprocess参数照常解析但除subprocess外的任何行为都会被拒绝telemetry关闭引入 Logfire/tracing 遥测隐含standalone只对独立 CLI 路径插桩不带standalone构建的二进制会打印this build runs monty subprocess only — rebuild with the standalone feature for the CLI见 main.rs。这对池化部署很有价值一个 worker-only 构建体积更小、攻击面更少因为池只需要派生monty subprocess。10. 可观测性Logfire 与 OpenTelemetry 环境变量telemetryfeature 默认关闭因为其 exporter 会链接进数 MB 的 TLS 代码——而monty subprocess从不导出遥测不应背负这些体积。不带该 feature 构建时LOGFIRE_TOKEN会被直接忽略。以--features telemetry构建后独立 CLI 在设置LOGFIRE_TOKEN时会配置 Rust 的 Logfire SDK服务名monty版本取CARGO_PKG_VERSION并持有 SDK 生命周期、退出前完成 flush见 run.rs 的configure_logfire。SDK 同样遵循标准的 OpenTelemetry exporter 与 resource 环境变量。关键设计是对称性monty subprocess刻意忽略 telemetry 环境配置——worker 进程由父进程池插桩避免重复 exporter也避免把凭据留在沙箱 worker 中。11. 在 Monty 生态中的位置从 crates/monty-runtime/README-crate.md 的 crate 清单可以看到monty-runtime处于解释器与宿主之间的桥梁位置monty— 核心解释器Python 解析器、字节码 VM 与沙箱monty-types— 宿主无需链接解释器即可使用的共享边界数据类型值、异常、OS 调用、资源限制monty-fs— 宿主侧文件系统挂载把虚拟沙箱路径映射到真实宿主目录monty-runtime—monty二进制REPL、文件运行器与 subprocess worker 模式本文主题monty-pool— 崩溃隔离的montyworker 子进程弹性池monty-proto— 池父进程与 worker 之间使用的 protobuf 线协议monty-type-checking— 沙箱代码的类型检查由 ty 驱动monty-typeshed— 描述 Monty 实现的 stdlib 子集的精简 typeshed stubsmonty-macros—monty参数解析背后的 proc macros。一句话总结使用链路monty核心解释器提供沙箱能力monty-runtime把它封装成可执行二进制——要么作为独立 CLI 供人使用要么作为monty subprocess供monty-pool驱动在宿主与沙箱之间提供可靠的崩溃隔离边界。【免费下载链接】montyA minimal, secure Python interpreter written in Rust for use by AI项目地址: https://gitcode.com/GitHub_Trending/monty3/monty创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考