Почему Wippy использует Lua
Этот вопрос задаёт каждый, кто оценивает платформу с технической стороны, поэтому вот прямой ответ.
Требования к среде выполнения
Wippy выполняет пользовательскую логику внутри изолированных процессов. Каждому процессу нужны собственное пространство памяти, собственный набор доступных возможностей и отсутствие способа выйти за свои границы, если среда выполнения этого явно не разрешила. Платформа выполняет тысячи таких процессов одновременно на одном инстансе, и каждый из них потенциально исполняет разный код для разных арендаторов.
Это означает, что среда выполнения языка, встроенная в каждый процесс, должна быть:
- Крошечной. Каждый процесс работает в собственном изолированном окружении. При тысячах одновременных процессов память на процесс имеет значение. Wippy ориентируется на базовые накладные расходы порядка ~13 КБ на процесс.
- Полностью изолируемой. Среда выполнения должна точно контролировать, к каким модулям, функциям и системным вызовам имеет доступ каждый процесс. Никаких неявных полномочий. Никакого глобального состояния, протекающего между процессами.
- Встраиваемой. Среда выполнения языка должна быть библиотекой, которую ядро Wippy (написанное на Go) может создать, настроить и уничтожить для каждого процесса. Она не может быть внешним процессом или отдельным бинарником.
- Детерминированной в загрузке модулей. При старте процесса среда выполнения решает, какой код ему виден. Никакого доступа к файловой системе. Никакого
require, который дотягивается до произвольных путей. Зависимости приходят из реестра и ограничены областью процесса. - С понятным для LLM синтаксисом. Агенты генерируют и изменяют код. Язык должен быть достаточно простым, чтобы LLM могла надёжно читать, писать и рассуждать о нём, не выдумывая синтаксис.
Рассмотренные языки: Python, JavaScript, Go и WASM
Python
Выбор по умолчанию для AI-нагрузок. Мы отказались от него, потому что объём памяти CPython составляет 10-30 МБ на интерпретатор — на порядки больше, чем процесс на Lua. Система импорта Python даёт коду неявный доступ к файловой системе, сети и ОС. Изоляция Python требует либо компиляции в WASM (что ломает большинство библиотек), либо тяжёлого патчинга интерпретатора. Модель конкурентности Python (GIL) также конфликтует с нашей моделью изоляции по процессам. Экосистема — сильная сторона для самостоятельных скриптов, но обуза для изолированной среды выполнения, где нужен детерминированный контроль над тем, к чему код имеет доступ.
JavaScript (V8/QuickJS)
V8 быстрый, но огромный (десятки МБ на изолят). QuickJS достаточно мал для встраивания, но цепочка прототипов JavaScript и его динамическая модульная система делают изоляцию сложнее, чем кажется. import и require стремятся дотянуться до файловой системы. Экосистема рассчитывает на npm, который предполагает доступ к сети и записываемую файловую систему — ни того, ни другого внутри процесса Wippy нет. Мы потратили бы больше времени на борьбу с допущениями языка, чем на создание продукта.
Go
Ядро Wippy написано на Go, так что вариант был соблазнительным. Но Go не встраивается. Нельзя создать среду выполнения Go как библиотеку внутри другой Go-программы. Плагины Go существуют, но они хрупкие, разделяют память с хост-процессом и не поддаются изоляции. Go подходит для самой среды выполнения, но не для пользовательского кода.
WASM
По-настоящему силён в изоляции, и мы сделали его второй средой выполнения Wippy (см. ниже). Но одного WASM недостаточно в роли основного языка для разработки агентов. Опыт разработки и отладки напрямую на WASM всё ещё сырой, а LLM генерируют код под WASM менее надёжно, чем Lua. WASM — правильный выбор, когда нужно выполнить скомпилированный код с других языков внутри песочницы Wippy. Lua — правильный выбор для основной разработки и написания кода агентами.
Почему Lua отвечает всем пяти требованиям
Lua был создан именно для такого сценария. Это самый встраиваемый скриптовый язык в продакшене: он работает внутри World of Warcraft, Roblox, Redis, Nginx/OpenResty, сетевого оборудования Cisco и Juniper, Adobe Lightroom и сотен игровых движков. Он встраивался во враждебные окружения (игры, где пользователи запускают недоверенный код) более 25 лет.
Память
Базовые накладные расходы процесса Wippy на Lua составляют ~13 КБ. При 10 000 одновременных процессов это примерно 130 МБ базовых накладных расходов. На Python то же количество потребовало бы 100-300 ГБ. Это не теоретическая проблема: это разница между работой на одной машине и необходимостью в кластере.
Изоляция
Модульная система Lua — это одна функция (require), которую хост контролирует полностью. Замените её собственным загрузчиком, который разрешает только то, что выдано процессу, и процесс увидит только разрешённое. Нет ни import os, ни subprocess, ни неявного доступа к файловой системе — этих функций просто нет в окружении процесса. Песочница здесь состояние по умолчанию, а не заплатка поверх открытой системы.
Встраивание
Интерфейс Lua знаменит своей компактностью. Каноническое C API насчитывает около 60 функций, а реализации на чистом Go делают встраивание в Go-ядро Wippy простым и без cgo. Создание и уничтожение Lua-окружения процесса обходится дёшево; Wippy делает это при каждом старте процесса без измеримых накладных расходов.
Детерминированный контроль модулей
В Wippy код, который процесс может загрузить, определяется его областью в реестре. Загрузчик Lua разрешает модули из реестра, а не из файловой системы. Если процессу не выдан модуль, то с точки зрения процесса этого модуля не существует. Так работает многопользовательская изоляция на уровне кода: разным арендаторам доступны разные модули, и это обеспечивает среда выполнения, а не логика приложения.
Понятность для LLM
Синтаксис Lua минимален: нет классов, декораторов, встроенных в язык аннотаций типов, async/await и сложного разрешения модулей. LLM, видевшая Lua, генерирует корректный Lua с первой попытки куда надёжнее, чем корректный Python (с его паттернами декораторов, контекстными менеджерами и системой типов) или JavaScript (с цепочкой прототипов, привязкой this и разновидностями модулей). Для платформы, где агенты пишут и изменяют собственные инструменты, это важно. Wippy расширяет Lua системой аннотаций типов (обобщения, объединения, типы каналов) и встроенным линтером, так что вы получаете типобезопасность без синтаксической сложности.
Корутины
В Lua есть нативная поддержка корутин, которая напрямую ложится на модель конкурентных процессов Wippy. Каждый процесс выполняется в корутине, которая уступает управление планировщику. Никаких потоков. Никаких блокировок. Никаких гонок между процессами. Тысячи одновременных процессов кооперируются без сложности потоковой конкурентности.
Чем приходится жертвовать
Экосистема Lua невелика. Нет аналога pip или npm с десятками тысяч пакетов. Это сделано намеренно: в Wippy зависимости — это записи реестра с объявленными возможностями и политиками безопасности, а не произвольные пакеты, скачанные из интернета. Но это значит, что внутри процесса Wippy нельзя выполнить pip install pandas. Обработка данных, требующая тяжёлых библиотек (инференс ML-моделей, сложные численные вычисления), должна выполняться либо как внешние сервисы, которые агенты Wippy вызывают через инструменты, либо как WASM-функции внутри песочницы Wippy.
Кроме того, Lua незнаком большинству разработчиков. Кривая обучения реальна, но короткая: полный справочник по языку Lua занимает около 30 страниц. Большинство разработчиков, знающих любой язык программирования, начинают писать на Lua за день. Незнакомость — это издержка трения, но архитектурные преимущества (изоляция, память, встраивание) перевешивают её для платформы времени выполнения, где основная часть пользовательского кода короткая, ориентированная на инструменты и всё чаще сгенерированная ИИ.
Lua + WASM: полная картина
Wippy — не платформа только для Lua. Она поставляется с двумя средами выполнения:
Lua — основная среда выполнения для разработки агентов, написания инструментов и логики приложений. Именно на ней пишется большая часть кода Wippy и её генерируют агенты. Малый объём, полная изолируемость и понятный для LLM синтаксис делают её правильным выбором по умолчанию.
WASM — вторичная среда выполнения для скомпилированных нагрузок. Если у вас есть код на Rust, Go, C или любом языке, компилирующемся в WebAssembly, вы можете выполнять его внутри Wippy с той же изоляцией процессов и интеграцией с реестром, что и Lua. WASM-функции и процессы интегрируются с WASI для часов, ввода-вывода, файловой системы (через смонтированные записи файловой системы Wippy) и доступа к окружению. Это значит, что вы можете перенести существующую бизнес-логику в песочницу Wippy, не переписывая её на Lua.
Обе среды выполнения используют одну модель процессов, один реестр и одни политики безопасности. Агент на Lua может вызвать WASM-функцию. WASM-процесс может вызвать Lua-функции через реестр. Они равноправны в одной системе.
См. также
- Обзор среды выполнения Lua - Среда выполнения Lua и её модули
- Типы - Аннотации типов, обобщения и объединения
- Линтер - Статический анализ для Lua
- Среда выполнения WASM - Выполнение скомпилированного кода в песочнице