
Un intérprete de Python minimalista y seguro escrito en Rust para uso por IA
Experimental - Este proyecto aún está en desarrollo y no está listo para producción.
Un intérprete de Python mínimo y seguro escrito en Rust para uso por parte de la IA.
Monty evita el costo, la latencia, la complejidad y la molestia general de usar un sandbox basado en contenedores completos para ejecutar código generado por LLM.
En cambio, te permite ejecutar de forma segura código Python escrito por un LLM integrado en tu agente, con tiempos de inicio medidos en microsegundos de un solo dígito, no en cientos de milisegundos.
Lo que Monty puede hacer:
sys, os, typing, asyncio, re, datetime, json, dataclasses (pronto)Lo que Monty no puede hacer:
En resumen, Monty es extremadamente limitado y está diseñado para un caso de uso:
Ejecutar código escrito por agentes.
Para motivación sobre por qué podrías querer hacer esto, consulta:
En términos muy simples, la idea de todo lo anterior es que los LLM pueden trabajar más rápido, de forma más económica y más fiable si se les pide que escriban código Python (o Javascript), en lugar de depender de las llamadas a herramientas tradicionales. Monty hace eso posible sin la complejidad de un sandbox ni el riesgo de ejecutar código directamente en el host.
Nota: Monty se usará (pronto) para implementar codemode en Pydantic AI
Se puede llamar a Monty desde Python, JavaScript/TypeScript o Rust.
Para instalarlo:```bash uv add pydantic-monty
(O `pip install pydantic-monty` para los boomers)
`pydantic-monty` es un metapaquete que combina `pydantic-monty-client` (el módulo `pydantic_monty`) con `pydantic-monty-runtime` (el binario del worker `monty`). Instala `pydantic-monty-client` por sí solo si el binario ya viene de otro lugar.
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())
La ejecución se realiza en un grupo de subprocesos worker monty, por lo que incluso un error
de memoria provocado por código adversarial (desbordamiento de pila, aborto del asignador)
nunca puede hacer fallar tu proceso — el worker muere, lanza MontyCrashedError, y
es reemplazado. También hay una API totalmente síncrona:```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
Para instalar:```bash
npm install @pydantic/monty
El paquete JS es un binding nativo (napi) sobre el mismo pool de workers Rust que
usa el paquete Python — el binding y el binario worker monty se distribuyen mediante
paquetes npm específicos de cada plataforma:```ts
import { Monty } from '@pydantic/monty'
await using pool = await Monty.create() await using session = await pool.checkout()