
monty v0.0.20
Un interprete Python minimale e sicuro scritto in Rust per uso da parte dell'IA
Monty
Un interprete Python minimale e sicuro scritto in Rust, pensato per l'uso da parte di IA.
Sperimentale - Questo progetto è ancora in fase di sviluppo e non è pronto per l'uso in produzione.
Un interprete Python minimale e sicuro scritto in Rust, pensato per l'uso da parte di IA.
Monty evita i costi, la latenza, la complessità e il fastidio generale di usare una sandbox completa basata su container per eseguire codice generato da LLM.
Invece, ti permette di eseguire in sicurezza codice Python scritto da un LLM integrato nel tuo agente, con tempi di avvio misurati in microsecondi a una cifra, non in centinaia di millisecondi.
Cosa Monty può fare:
- Eseguire un sottoinsieme ragionevole di codice Python, sufficiente affinché il tuo agente possa esprimere ciò che vuole fare
- Bloccare completamente l'accesso all'ambiente host: filesystem, variabili d'ambiente e accesso alla rete sono tutti implementati tramite chiamate a funzioni esterne che lo sviluppatore può controllare
- Chiamare funzioni sull'host, solo quelle a cui gli concedi l'accesso
- Eseguire il typechecking: Monty supporta i moderni type hint di Python e include ty in un singolo binario per eseguire il controllo dei tipi
- Essere serializzato in byte in corrispondenza delle chiamate a funzioni esterne, consentendo di salvare lo stato dell'interprete in un file o in un database e riprenderlo in seguito
- Avviarsi estremamente in fretta (<1μs dal codice al risultato dell'esecuzione) e avere prestazioni a runtime simili a CPython (in genere tra 5 volte più veloce e 5 volte più lento)
- Essere richiamato da Rust, Python o JavaScript: poiché Monty non ha dipendenze da CPython, puoi usarlo ovunque riesca a eseguire Rust
- Controllare l'uso delle risorse: Monty può tracciare l'uso della memoria, la profondità dello stack e il tempo di esecuzione e annullare l'esecuzione se supera i limiti predefiniti
- Raccogliere stdout e stderr e restituirli al chiamante
- Eseguire codice async o sync sull'host tramite codice async o sync sull'host
- Usare un piccolo sottoinsieme della libreria standard:
sys,os,typing,asyncio,re,datetime,json,dataclasses(presto)
Cosa Monty non può fare:
- Usare il resto della libreria standard
- Usare librerie di terze parti (come Pydantic); il supporto per librerie Python esterne non è un obiettivo
- definire classi (il supporto arriverà presto)
- usare i match statement (anche qui, il supporto arriverà presto)
In breve, Monty è estremamente limitato e progettato per un caso d'uso:
Eseguire codice scritto da agenti.
Per capire perché potresti volerlo fare, vedi:
- Codemode di Cloudflare
- Programmatic Tool Calling di Anthropic
- Code Execution with MCP di Anthropic
- Smol Agents di Hugging Face
In parole molto semplici, l'idea alla base di tutto ciò è che gli LLM possono lavorare più velocemente, a costi inferiori e in modo più affidabile se viene chiesto loro di scrivere codice Python (o JavaScript) invece di affidarsi alle tradizionali chiamate a strumenti. Monty rende tutto questo possibile senza la complessità di una sandbox o il rischio di eseguire codice direttamente sull'host.
Nota: Monty verrà (presto) utilizzato per implementare codemode in Pydantic AI
Utilizzo
Monty può essere richiamato da Python, JavaScript/TypeScript o Rust.
Python
Per installare:```bash uv add pydantic-monty
(Oppure `pip install pydantic-monty` per i boomer)
`pydantic-monty` è un metapackage che abbina `pydantic-monty-client` (il
modulo `pydantic_monty`) con `pydantic-monty-runtime` (il binario del
worker `monty`). Installa `pydantic-monty-client` da solo se il binario proviene già da
un'altra parte.
Uso:```python
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 = ''
"""
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():
async with pydantic_monty.AsyncMonty() as pool:
async with pool.checkout(
script_name='agent.py',
type_check=True,
type_check_stubs=type_definitions,
) as session:
output = await session.feed_run(
code,
inputs={'prompt': 'testing'},
external_lookup={'call_llm': call_llm},
)
print(output)
#> example output, message count 2
if __name__ == '__main__':
import asyncio
asyncio.run(main())
L'esecuzione avviene in un pool di subprocessi worker monty, quindi anche un errore di
memoria innescato da codice avversario (stack overflow, abort dell'allocatore) non può
mai mandare in crash il tuo processo — il worker muore, solleva MontyCrashedError e
viene sostituito. C'è anche un'API completamente sincrona:```python
import pydantic_monty
with pydantic_monty.Monty() as pool: with pool.checkout() as session: # session state persists between feed_run calls session.feed_run('x = 21') print(session.feed_run('x * 2')) #> 42
### JavaScript / TypeScript
Per installare:```bash
npm install @pydantic/monty
The JS package is a native (napi) binding over the same Rust worker pool the
Python package uses — the binding and the monty worker binary ship via
platform-specific npm packages:```ts
import { Monty } from '@pydantic/monty'
await using pool = await Monty.create() await using session = await pool.checkout()
// session state persists between feedRun calls await session.feedRun('x = 21') console.log(await session.feedRun('x * 2')) // 42