
2026/02/07 6:16
モンティ:AI 用に設計された、Rustで実装された最小限かつ安全なPythonインタプリタ。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
改善された概要
MontyはRustで書かれた小型で安全なPythonインタプリタです。大規模言語モデル(LLM)エージェントがユーザー生成コードを高速かつ安全に実行できるよう設計されています。起動時間はマイクロ秒レベルで、ランタイム性能はCPythonと競合します。Montyは直接ホストへのアクセスをブロックし、ファイルシステム、環境変数、およびネットワーク呼び出しは開発者が提供する外部関数を介して仲介されます。これにより言語は安全なサブセットに限定され、メモリ、スタック深さ、実行時間に対する明示的なリソース制限を設定できます。
Pythonの機能は限定的です:クラスはまだ実装されていません。現在標準ライブラリには
sys、typing、asyncio が含まれ、将来的に dataclasses と json が追加予定です。外部関数呼び出しは start()/resume() を介して反復的に実行できます。Montyの実行状態と解析済みコードはバイト列としてシリアライズでき、キャッシュやプロセス間での再開に利用可能です。Rust、Python(pydantic_monty)、JavaScript/TypeScript(@pydantic/monty)から呼び出すことができます。出力ストリーム(stdout / stderr)は取得され呼び出し元へ返され、Montyは非同期・同期のホストコードを呼び出せます。
今後のリリースではクラスサポート、追加標準ライブラリモジュール、match 文、外部関数統合の充実が予定されています。Pydantic AI は Monty を「code‑mode」機能に組み込み、LLM が安全に事前定義されたツールを呼び出せるようにする計画です。
AIアシスタントや自動化ワークフローの開発者向けに、Montyはコンテナや複雑なサンドボックス設定なしで高速・低コスト・安全なユーザーコード実行を提供します。
本文
Monty
AI で利用するために Rust で書かれた最小限の安全な Python インタープリター。
実験的
本プロジェクトは現在開発中で、まだ本番レベルではありません。
- 目的 – LLM が生成したコードを実行する際に、フルコンテナ型サンドボックスを使うコスト・遅延・複雑さ・「面倒」を回避します。
- 性能 – スタートアップ時間が 1 桁マイクロ秒(対数百ミリ秒)で測定されています。
Monty ができること
| 機能 | 説明 |
|---|---|
| Python の実用的なサブセットを実行 | エージェントがやりたいことを表現するのに十分 |
| ホストアクセスを遮断 | ファイルシステム、環境変数、ネットワークは開発者が提供する外部関数呼び出しで制御されます |
| ホスト関数の呼び出し | 明示的に許可されたもののみ |
| 型チェック | 最新の Python タイプヒントをサポート。単一バイナリで実行 |
| スナップショット | 外部関数呼び出し時に状態をシリアライズして保存または後で再開可能 |
| 高速起動 | コードから実行結果まで 1 µs 未満 |
| 性能 | CPython とほぼ同等(5 倍程度の差) |
| マルチ言語 API | Rust、Python、JavaScript から呼び出せる(CPython の依存なし) |
| リソース制限 | メモリ使用量・割り当て数・スタック深さ・実行時間を追跡。上限超過でキャンセル可能 |
| IO キャプチャ | 呼び出し側に stdout / stderr を渡す |
| 非同期 & 同期 ホストコード | 両方の呼び出しをサポート |
Monty ができないこと
- 標準ライブラリは使えません(
、sys
、typing
以外;asyncio
とdataclasses
は近日リリース予定)json - サードパーティのライブラリは使用不可(例:Pydantic)
- クラス定義はできません(今後サポート予定)
- マッチ文 (
) は使えません(今後サポート予定)match
まとめ
Monty は極めて限定的で、エージェントが書くコードを実行するという単一用途に設計されています。
モチベーションの参照
- Cloudflare の Codemode
- Anthropic の Programmatic Tool Calling
- Anthropic の MCP を使った Code Execution
- Hugging Face の Smol Agents
LLM が従来のツール呼び出しよりも高速・低コスト・信頼性を向上させるために、Python(または JavaScript)コードを書かせるアイデア。Monty はサンドボックスの複雑さやホストリスクなしでそれを実現します。
使い方
Monty は Python、JavaScript/TypeScript、あるいは Rust から呼び出すことができます。
Python
# インストール: # pip install pydantic-monty # boomers 用 from typing import Any import pydantic_monty code = """ async def agent(prompt: str, messages: Messages): while True: print(f'messages so far: {messages}') output = await call_llm(prompt, messages) if isinstance(output, str): return output messages.extend(output) await agent(prompt, []) """ type_definitions = """ from typing import Any Messages = list[dict[str, Any]] async def call_llm(prompt: str, messages: Messages) -> str | Messages: raise NotImplementedError() prompt: str = '' """ m = pydantic_monty.Monty( code, inputs=['prompt'], external_functions=['call_llm'], script_name='agent.py', type_check=True, type_check_stubs=type_definitions, ) Messages = list[dict[str, Any]] async def call_llm(prompt: str, messages: Messages) -> str | Messages: if len(messages) < 2: return [{'role': 'system', 'content': 'example response'}] else: return f'example output, message count {len(messages)}' async def main(): output = await pydantic_monty.run_monty_async( m, inputs={'prompt': 'testing'}, external_functions={'call_llm': call_llm}, ) print(output) # → example output, message count 2 if __name__ == "__main__": import asyncio asyncio.run(main())
外部関数を使った反復実行
import pydantic_monty code = """ data = fetch(url) len(data) """ m = pydantic_monty.Monty(code, inputs=['url'], external_functions=['fetch']) # 実行開始 – `fetch()` が呼ばれた時点で一時停止 result = m.start(inputs={'url': 'https://example.com'}) print(type(result)) # <class 'pydantic_monty.MontySnapshot'> print(result.function_name) # fetch print(result.args) # ('https://example.com',) # 実際にフェッチして結果を返し、再開 result = result.resume(return_value='hello world') print(type(result)) # <class 'pydantic_monty.MontyComplete'> print(result.output) # 11
シリアライズ
import pydantic_monty # パース済みコードをシリアライズして再パースを省略 m = pydantic_monty.Monty('x + 1', inputs=['x']) data = m.dump() # 後で復元して実行 m2 = pydantic_monty.Monty.load(data) print(m2.run(inputs={'x': 41})) # 42 # 実行中の状態をシリアライズ progress = m.start(inputs={'url': 'https://example.com'}) state = progress.dump() # 後で別プロセス等で復元・再開 progress2 = pydantic_monty.MontySnapshot.load(state) result = progress2.resume(return_value='response data') print(result.output) # response data
Rust
use monty::{MontyRun, MontyObject, NoLimitTracker, StdPrint}; let code = r#" def fib(n): if n <= 1: return n return fib(n - 1) + fib(n - 2) fib(x) "#; let runner = MontyRun::new(code.to_owned(), "fib.py", vec!["x".to_owned()], vec![]).unwrap(); let result = runner.run(vec![MontyObject::Int(10)], NoLimitTracker, &mut StdPrint).unwrap(); assert_eq!(result, MontyObject::Int(55));
シリアライズ
use monty::{MontyRun, MontyObject, NoLimitTracker, StdPrint}; let runner = MontyRun::new("x + 1".to_owned(), "main.py", vec!["x".to_owned()], vec![]).unwrap(); let bytes = runner.dump().unwrap(); let runner2 = MontyRun::load(&bytes).unwrap(); let result = runner2.run(vec![MontyObject::Int(41)], NoLimitTracker, &mut StdPrint).unwrap(); assert_eq!(result, MontyObject::Int(42));
PydanticAI 連携
from pydantic_ai import Agent from pydantic_ai.toolsets.code_mode import CodeModeToolset from pydantic_ai.toolsets.function import FunctionToolset from typing_extensions import TypedDict class WeatherResult(TypedDict): city: str temp_c: float conditions: str toolset = FunctionToolset() @toolset.tool def get_weather(city: str) -> WeatherResult: return {'city': city, 'temp_c': 18, 'conditions': 'partly cloudy'} @toolset.tool def get_population(city: str) -> int: return {'london': 9_000_000, 'paris': 2_100_000, 'tokyo': 14_000_000}.get( city.lower(), 0 ) toolset = CodeModeToolset(toolset) agent = Agent('anthropic:claude-sonnet-4-5', toolsets=[toolset]) result = agent.run_sync( 'Compare the weather and population of London, Paris, and Tokyo.' ) print(result.output)
代替手段
| テック | 言語完全性 | セキュリティ | スタート遅延 | コスト | 設定の複雑さ | ファイルマウント | スナップショット |
|---|---|---|---|---|---|---|---|
| Monty | 部分的 | 厳格 | 0.06 ms | 無料 | 簡単 | 簡単 | 簡単 |
| Docker | 完全 | 良好 | 195 ms | 無料 | 中程度 | 簡単 | 中程度 |
| Pyodide | 完全 | 悪い | 2800 ms | 無料 | 中程度 | 簡単 | 難しい |
| starlark‑rust | 非常に限定的 | 良好 | 1.7 ms | 無料 | 簡単 | 利用不可 | 不可能 |
| サンドボックスサービス | 完全 | 厳格 | 1033 ms | 有料 | 中程度 | 難しい | 中程度 |
| YOLO Python | 完全 | なし | 0.1–30 ms | 無料 | なし | 直接 | 可能 |
がスタートアップ性能数値を算出するためのスクリプトです。./scripts/startup_performance.py
代替手段に関する備考
- Docker:フル CPython、任意ライブラリ使用可。コンテナエスケープリスクあり。195 ms の起動時間。
- Pyodide:CPython を WASM にコンパイル。冷却スタートが遅い(≈2.8 s)。主にブラウザサンドボックス向け。
- starlark‑rust:設定言語であり Python ではない。決定論的・ヘルメティックだがスナップショット不可。
- サンドボックスサービス:管理型コンテナ隔離。ネットワーク遅延 + コンテナ起動(≈1 s)。
- YOLO Python:
か subprocess を直接呼び出す。セキュリティ制御なし。exec()
Monty は最速のスタートアップ、厳格なサンドボックス、Rust ベースプロジェクトへの簡単統合、軽量スナップショットを提供し、LLM が生成した Python コードを安全に実行するために特化しています。