Назад к обновлениям
New releaseAug 9, 2026

monty v0.0.20

Минимальный, безопасный интерпретатор Python, написанный на Rust для использования ИИ.

Поделиться

Monty

Минимальный, безопасный интерпретатор Python, написанный на Rust для использования ИИ.

CI Codspeed Coverage PyPI versions license Join Slack

Экспериментально — проект всё ещё находится в разработке и пока не готов к использованию в продакшене.

Минимальный, безопасный интерпретатор Python, написанный на Rust для использования ИИ.

Monty позволяет избежать затрат, задержек, сложности и лишней возни, связанных с полноценной песочницей на основе контейнеров для выполнения кода, сгенерированного LLM.

Вместо этого он позволяет безопасно запускать Python-код, написанный LLM, встроенным в вашего агента, со временем запуска, измеряемым в однозначных микросекундах, а не в сотнях миллисекунд.

Что Monty может:

  • Выполнять достаточное подмножество Python-кода — достаточно, чтобы ваш агент мог выразить то, что он хочет сделать
  • Полностью блокировать доступ к хостовому окружению: файловая система, переменные окружения и сетевой доступ реализованы через внешние вызовы функций, которые разработчик может контролировать
  • Вызывать функции на хосте — только те функции, к которым вы предоставили доступ
  • Выполнять проверку типов — Monty поддерживает современные подсказки типов Python и поставляется с ty в одном бинарном файле для проверки типов
  • Сохраняться в байты в точках внешних вызовов функций, что позволяет хранить состояние интерпретатора в файле или базе данных и возобновлять работу позже
  • Запускаться чрезвычайно быстро (<1мкс от кода до результата выполнения), а производительность во время выполнения сопоставима с CPython (обычно от 5 раз быстрее до 5 раз медленнее)
  • Вызываться из Rust, Python или JavaScript — поскольку Monty не зависит от CPython, его можно использовать везде, где можно запустить Rust
  • Контролировать использование ресурсов — Monty может отслеживать использование памяти, глубину стека и время выполнения, а также отменять выполнение при превышении заданных лимитов
  • Собирать stdout и stderr и возвращать их вызывающему коду
  • Выполнять асинхронный или синхронный код на хосте через асинхронный или синхронный код на хосте
  • Использовать небольшое подмножество стандартной библиотеки: sys, os, typing, asyncio, re, datetime, json, dataclasses (скоро)

Что Monty не может:

  • Использовать остальную часть стандартной библиотеки
  • Использовать сторонние библиотеки (например, Pydantic); поддержка внешних библиотек Python не является целью
  • определять классы (поддержка должна появиться в ближайшее время)
  • использовать match-выражения (опять же, поддержка должна появиться в ближайшее время)

Короче говоря, Monty крайне ограничен и предназначен для одного сценария использования:

Для запуска кода, написанного агентами.

О мотивации, почему вам может это понадобиться, см.:

Если очень просто, идея всего вышеперечисленного в том, что LLM могут работать быстрее, дешевле и надёжнее, если их просить писать код на Python (или JavaScript) вместо традиционных вызовов инструментов. Monty делает это возможным без сложности песочницы и без риска запуска кода напрямую на хосте.

Примечание: Monty (в ближайшее время) будет использоваться для реализации codemode в Pydantic AI

Использование

Monty можно вызывать из Python, JavaScript/TypeScript или Rust.

Python

Для установки:```bash uv add pydantic-monty

(Или `pip install pydantic-monty` для бумеров)

`pydantic-monty` — это метапакет, объединяющий `pydantic-monty-client` (модуль `pydantic_monty`) с `pydantic-monty-runtime` (двоичный файл воркера `monty`). Установите только `pydantic-monty-client`, если двоичный файл уже поступает откуда-то ещё.

Использование:```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())

Выполнение происходит в пуле рабочих подпроцессов monty, поэтому даже ошибка памяти, вызванная вредоносным кодом (переполнение стека, прерывание аллокатора), никогда не приведёт к падению вашего процесса — рабочий процесс погибает, вызывает MontyCrashedError и заменяется. Существует также полностью синхронный API:```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

Для установки:```bash
npm install @pydantic/monty

Пакет JS — это нативный (napi) биндинг поверх того же пула воркеров Rust, что использует пакет Python — биндинг и рабочий бинарник monty поставляются через платформозависимые npm-пакеты:```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

Категории