API интерпретатора кода для кода, который пишет LLM
Интерпретатор кода запускает код, который пишет языковая модель, и возвращает ей результат. В Lizard (lizard.build) это делает CodeSandbox из Lizard SDK внутри sandbox на базе microVM Firecracker. Поэтому код выполняется отдельно от вашего приложения и компьютера. CodeSandbox запускает шаблон interpreter с Python и основными библиотеками для работы с данными. Python работает в ядре Jupyter, которое сохраняет переменные между вызовами, а каждый результат содержит напечатанный вывод, значение последнего выражения, графики в формате image/png и ошибку с трассировкой, если она возникла.
Запуск кода с сохранением состояния
import { CodeSandbox } from '@lizard-build/sdk';
const sandbox = await CodeSandbox.create({ projectId: 'proj_123', timeoutMs: 300_000 });
try {
await sandbox.runCode('import pandas as pd\ndf = pd.DataFrame({"x": [1, 2, 3]})');
const run = await sandbox.runCode('df.x.sum()');
console.log(run.results[0]?.data); // "6"
const bad = await sandbox.runCode('1/0');
console.log(bad.error?.name); // "ZeroDivisionError"
} finally {
await sandbox.kill();
}from lizard import CodeSandbox
with CodeSandbox.create(project_id="proj_123", timeout_ms=300_000) as sandbox:
sandbox.run_code('import pandas as pd\ndf = pd.DataFrame({"x": [1, 2, 3]})')
run = sandbox.run_code("df.x.sum()")
print(run.results[0].data) # "6"
print(sandbox.run_code("1/0").error.name) # "ZeroDivisionError"Ошибка в коде возвращается в результате, а не вызывает исключение в SDK. Сбои запроса, например неверный API-ключ, выбрасывают исключение.
Что возвращает runCode?
runCode (в Python: run_code) возвращает Execution:
| Поле | Содержимое |
|---|---|
stdout, stderr | Всё, что напечатал код |
results | Расширенный вывод: значение последнего выражения как text/plain, графики matplotlib и изображения как base64 image/png, HTML и другие типы, каждый с mime и data |
error | name, message и traceback, если код выбросил исключение |
executionCount | Счётчик ячеек ядра (в Python: execution_count) |
Передайте onStdout, onStderr, onResult или onError (в Python: on_stdout и т. д.), чтобы получать вывод, пока код выполняется.
Использование как инструмента LLM
Дайте модели один инструмент, например run_python с единственным строковым аргументом code. Когда модель вызывает его, выполните код в sandbox и отправьте текст обратно как результат инструмента. Держите один sandbox на весь диалог, чтобы переменные модели сохранялись между вызовами.
import { CodeSandbox } from '@lizard-build/sdk';
const sandbox = await CodeSandbox.create({ projectId: 'proj_123', timeoutMs: 600_000 });
// Call this when the model asks to run Python. Return the text to send back to it.
async function runPython(code: string): Promise<string> {
const run = await sandbox.runCode(code, { timeoutMs: 30_000 });
if (run.error) return `${run.error.name}: ${run.error.message}\n${run.error.traceback}`;
const values = run.results.flatMap((r) =>
r.type === 'result' && r.mime === 'text/plain' ? [r.data] : [],
);
return [run.stdout, ...values].filter(Boolean).join('\n');
}
// When the conversation ends:
await sandbox.kill();from lizard import CodeSandbox
sandbox = CodeSandbox.create(project_id="proj_123", timeout_ms=600_000)
def run_python(code: str) -> str:
"""Call this when the model asks to run Python. Return the text to send back to it."""
run = sandbox.run_code(code, timeout_ms=30_000)
if run.error:
return f"{run.error.name}: {run.error.message}\n{run.error.traceback}"
values = [r.data for r in run.results if r.mime == "text/plain"]
return "\n".join(filter(None, [run.stdout, *values]))
# When the conversation ends:
sandbox.kill()В этом примере sandbox работает десять минут. Для более длинных диалогов увеличьте срок через setTimeout (в Python: set_timeout) или задайте timeoutMs: 0 и останавливайте sandbox сами.
Графики
Когда код рисует график matplotlib, в results появляется элемент с mime, равным image/png, и изображением в base64 в data:
import base64
from pathlib import Path
run = sandbox.run_code("import matplotlib.pyplot as plt\nplt.plot([1, 4, 9])\nplt.show()")
png = next(r.data for r in run.results if r.mime == "image/png")
Path("chart.png").write_bytes(base64.b64decode(png))Контексты, таймауты и языки
- Контексты.
createContext()(в Python:create_context()) запускает отдельное ядро со своими переменными и рабочей папкой; передайте его какcontextвrunCode.listContexts(),restartContext(ctx)иdeleteContext(ctx)управляют контекстами. Без контекста каждый язык использует свой контекст по умолчанию. - Таймауты.
timeoutMs(в Python:timeout_ms) ограничивает один вызов, по умолчанию 60 секунд. Ядро Python, которое работает дольше, прерывается и сохраняет состояние;error.nameв результате равноTimeoutError. - Другие языки. JavaScript и bash выполняются как новый процесс при каждом вызове, поэтому состояние не сохраняется, а
resultsостаётся пустым. Для JavaScript нуженnode, которого нет в шаблонеinterpreter. - Пауза и снимки. Ядра работают внутри sandbox, поэтому
pause()иresume()сохраняют их переменные, аsnapshot()иfork()их копируют.
Запуск команд
process.exec создаёт отдельный процесс для каждой команды, поэтому переменные Python между вызовами не сохраняются. Используйте его для команд оболочки, например pip install, а результаты, которые понадобятся позже, сохраняйте в файлы. См. запуск команды и справочник SDK.
Недоверенный код
Считайте недоверенным всё, что пишет модель. Не передавайте lizardToken, если коду не нужен Lizard CLI; этот ключ может прочитать всё, что работает в sandbox, поэтому в таком случае используйте ключ с доступом только к рабочему пространству. Не кладите другие секреты в envs. Sandbox с томом на базе pod использует ядро хоста; см. runtime и шаблоны.
Хранение и оплата
Переменные и файлы доступны, только пока работает sandbox. Правила оплаты и хранения смотрите в разделе хранение и оплата; размеры и цены смотрите в лимитах.
Обзор Sandboxes · Быстрый старт · Справочник SDK · Persistent Volumes · Страница продукта Sandboxes
Обновлено