
Минимальный, безопасный интерпретатор Python, написанный на Rust для использования ИИ.
Экспериментально — проект всё ещё находится в разработке и пока не готов к использованию в продакшене.
Минимальный, безопасный интерпретатор Python, написанный на Rust для использования ИИ.
Monty позволяет избежать затрат, задержек, сложности и лишней возни, связанных с полноценной песочницей на основе контейнеров для выполнения кода, сгенерированного LLM.
Вместо этого он позволяет безопасно запускать Python-код, написанный LLM, встроенным в вашего агента, со временем запуска, измеряемым в однозначных микросекундах, а не в сотнях миллисекунд.
Что Monty может:
sys, os, typing, asyncio, re, datetime, json, dataclasses (скоро)Что Monty не может:
Короче говоря, Monty крайне ограничен и предназначен для одного сценария использования:
Для запуска кода, написанного агентами.
О мотивации, почему вам может это понадобиться, см.:
Если очень просто, идея всего вышеперечисленного в том, что LLM могут работать быстрее, дешевле и надёжнее, если их просить писать код на Python (или JavaScript) вместо традиционных вызовов инструментов. Monty делает это возможным без сложности песочницы и без риска запуска кода напрямую на хосте.
Примечание: Monty (в ближайшее время) будет использоваться для реализации codemode в Pydantic AI
Monty можно вызывать из Python, JavaScript/TypeScript или Rust.
Для установки:```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