MAATRIX / Блог / OpenHands: агент, который сам пишет и запускает код

OpenHands: агент, который сам пишет и запускает код

MAATRIX

Обычный ИИ-помощник в редакторе кода подсказывает следующую строку и останавливается — дальше решение принимаете вы. OpenHands устроен иначе: он получает задачу на естественном языке, пишет код, реально его выполняет в терминале, смотрит на результат или ошибку и сам правит код заново, пока задача не будет решена или не кончится лимит попыток. Это удобно, когда нужно быстро закрыть рутинную задачу без постоянного присмотра — но именно из-за того, что агент реально исполняет свой код, а не просто предлагает его на просмотр, тема безопасности здесь не факультативная, а обязательная часть настройки.

Что такое OpenHands и чем он отличается от автодополнения кода

OpenHands (бывший OpenDevin) — открытый проект автономного ИИ-агента для разработки. Ключевое отличие от Copilot-подобных инструментов не в том, какую модель он использует, а в замкнутости цикла: агент не просто генерирует текст кода, который вы читаете и запускаете сами, а делает это за вас — от постановки задачи до проверки результата.

Практическая разница проявляется на простом примере. Если вы просите обычного ассистента «напиши функцию парсинга CSV», вы получаете код и сами его тестируете. Если вы даёте ту же задачу OpenHands, он пишет файл с функцией, запускает тестовый скрипт, читает вывод в терминале — traceback, если код упал, или неверный результат, если тест не прошёл, — вносит правку и запускает снова. Цикл повторяется, пока тест не пройдёт или пока не будет исчерпан лимит шагов/токенов, заданный в конфигурации. Внешне это выглядит как работа джуниора, которому дали тикет и не мешают — он сам компилирует, сам смотрит на ошибку и сам чинит, обращаясь к модели за каждым следующим шагом.

Базовый принцип: цикл «написал → выполнил → увидел ошибку → исправил»

Внутри у большинства подобных агентов, включая OpenHands, один и тот же паттерн, который в индустрии иногда называют ReAct-подобным циклом (reason + act):

  1. Постановка задачи. Пользователь описывает, что нужно сделать: «добавь эндпоинт в Flask-приложении», «почини падающий тест test_parser.py», «перепиши скрипт на использование pandas вместо ручного парсинга».
  2. Генерация действия. Модель решает, что сделать дальше: написать файл, отредактировать существующий, выполнить команду в терминале, посмотреть содержимое директории.
  3. Реальное выполнение. Это критический шаг, отличающий агента от автодополнения — действие не показывается человеку на утверждение, а тут же выполняется в среде выполнения (runtime): команда уходит в shell, код запускается интерпретатором, файл действительно записывается на диск.
  4. Наблюдение за результатом. Агент получает обратно то, что получил бы человек за терминалом: stdout, stderr, код возврата, содержимое изменённого файла.
  5. Анализ и следующая итерация. Если результат не совпал с ожидаемым (тест не прошёл, интерпретатор выбросил исключение, команда завершилась с ненулевым кодом), агент интерпретирует ошибку и генерирует следующее действие — как правило, правку кода с учётом текста ошибки.
  6. Условие остановки. Цикл прерывается, когда задача решена (тесты зелёные, требуемый файл создан и работает) либо когда исчерпан лимит: число итераций, бюджет токенов, время выполнения.

Здесь и кроется суть отличия от простого чат-бота с примерами кода в ответе: у OpenHands нет паузы для человека между «написал код» и «выполнил код». Это именно то, что делает агента полезным — не нужно вручную копировать код в терминал и разбирать traceback самому. И это же то, что делает его опасным без должных ограничений.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть ИИ на сервере

Архитектура: агент, среда выполнения и интерфейс

В OpenHands (как и в схожих проектах) обычно выделяют три логических слоя:

  • Агент (agent) — сама логика, которая на основе задачи и истории действий решает, что делать дальше, обращаясь к LLM (может быть как облачная модель через API, так и локально развёрнутая).
  • Среда выполнения (runtime/sandbox) — изолированное окружение, где реально исполняются команды и код агента. Обычно это отдельный Docker-контейнер с рабочей директорией, куда у агента есть доступ к shell, файловой системе и, при необходимости, к браузеру для веб-задач.
  • Интерфейс — веб-UI или CLI, где человек ставит задачу, наблюдает за логом действий агента в реальном времени и может вмешаться (остановить, поправить, продолжить вручную).

Важный нюанс: сам факт, что раннтайм по умолчанию упакован в контейнер, ещё не значит, что настройка безопасна «из коробки». Дефолтная конфигурация многих подобных инструментов рассчитана на удобство разработчика на его собственной машине, а не на безопасный запуск на сервере с реальными данными.

Почему реальное выполнение кода — это реальный риск

Здесь стоит остановиться подробно, потому что это самая важная часть темы, а не второстепенное примечание.

Когда агент предлагает код, худшее, что может случиться — вы прочитаете неудачное решение и отклоните его. Когда агент выполняет код, каждая сгенерированная команда действует на реальную файловую систему, реальные процессы, реальную сеть — ровно так же, как если бы её ввёл человек за терминалом. ИИ-модель при этом не обладает пониманием последствий на уровне «это удалит продакшн-базу» — она статистически генерирует правдоподобное следующее действие, и в подавляющем большинстве случаев оно безобидно, но не гарантированно.

Практические сценарии, которые не требуют экзотики, а вытекают просто из ошибок логики:

  • Агент решает, что для «чистого теста» нужно удалить временные файлы, и неверно определяет границу «временного» — под удаление попадает то, что временным не было.
  • При рефакторинге агент переписывает конфиг и по ошибке указывает путь на уровень выше нужной директории.
  • Скрипт миграции данных содержит логическую ошибку в условии WHERE, и вместо тестовой выборки затрагивает всю таблицу.
  • Цикл «попробовать снова» на неверном шаге превращается в бесконечный: агент раз за разом выполняет ресурсоёмкую команду, не замечая, что причина ошибки не в этом, и исчерпывает диск, память или процессорное время.
  • Агент с доступом к сети «для проверки» по своей инициативе обращается к внешним хостам — не по злому умыслу, а потому что это показалось ему логичным шагом решения задачи.

Ни один из этих сценариев не требует «взлома» или злонамеренного кода — это обычные ошибки логики, на которые способен любой начинающий разработчик, только у агента нет интуитивного «стоп, а если я ошибаюсь» перед нажатием Enter. Почему контейнер сам по себе не гарантирует полную изоляцию, мы подробно разбираем в статье про миф контейнерной изоляции: он ограничивает поверхность атаки, но не заменяет продуманную конфигурацию.

Обязательная практика: строгая изоляция среды выполнения

Из предыдущего раздела следует простое практическое правило: автономный агент, который реально исполняет сгенерированный код, должен запускаться только в изолированной песочнице — без исключений, даже для «простых» задач. Ниже — конкретные пункты, из которых должна состоять такая изоляция.

1. Отдельная рабочая директория, а не весь сервер. Runtime агента должен видеть только специально выделенную директорию проекта (workspace), примонтированную в контейнер, а не корень файловой системы хоста и не домашнюю директорию с другими проектами. В терминах Docker это означает точечный volume-маунт, а не -v /:/host и не запуск процесса агента напрямую на хосте вне контейнера:

docker run --rm -it \
  -v /srv/agent-workspace/project-x:/workspace \
  -v /srv/agent-workspace/project-x/.openhands-state:/.openhands \
  -e SANDBOX_VOLUMES=/srv/agent-workspace/project-x:/workspace:rw \
  --network agent-net \
  docker.all-hands.dev/all-hands-ai/openhands:latest

Здесь агент физически не может «дотянуться» до файлов вне /workspace, даже если ошибётся в пути — операционная система просто не даст доступа.

2. Никакого доступа к продакшн-данным и продакшн-системам. Если задача агента — «почини баг в скрипте обработки заказов», это не повод давать ему прямое подключение к боевой базе данных или продакшн-API с реальными пользователями. Правильная схема — копия данных (или анонимизированная выборка) в изолированной среде, где ошибка агента максимум испортит копию, которую легко восстановить. Прямой доступ к продакшену через агента — это то же самое, что дать джуниору первого дня рут-доступ к боевому серверу, только без паузы на «подумать».

3. Явные лимиты на ресурсы и время. Циклическая природа агента («попробовал → не вышло → попробовал ещё раз») означает, что зацикливание — не гипотетический, а регулярно встречающийся сценарий на практике (мы разбирали конкретный такой случай в статье про агента, который зациклился ночью и сжёг лимиты). Обязательно ограничивайте:

# ограничение ресурсов контейнера с раннтаймом агента
docker run --rm -it \
  --cpus="2" \
  --memory="4g" \
  --pids-limit=256 \
  -e MAX_ITERATIONS=30 \
  -v /srv/agent-workspace/project-x:/workspace \
  docker.all-hands.dev/all-hands-ai/openhands:latest

Параметр числа итераций (в OpenHands это настраивается через конфигурацию агента, max_iterations в config.toml или переменную окружения) не даёт агенту молотить один и тот же неверный подход десятки раз подряд, сжигая бюджет на вызовы модели. Ограничение CPU/памяти и pids-limit защищает хост от того, что сгенерированный код случайно запустит fork-бомбу или бесконечный процесс.

4. Сетевая изоляция по умолчанию закрыта, открывается точечно. Если задаче не требуется исходящий доступ в интернет — не давайте его. Если требуется (например, установка пакетов) — ограничьте список хостов через отдельную docker-сеть с правилами, а не оставляйте агента с полным доступом «на всякий случай». Подробный разбор конкретных механизмов — сетевых неймспейсов, seccomp-профилей, безопасного проброса Docker-сокета — мы делаем отдельно в материале про изоляцию сервисов через Docker, а для задач с повышенными требованиями к изоляции стоит рассмотреть runtime уровня VM — их мы разбираем в статье про gVisor и Kata Containers, где контейнерный API сочетается с изоляцией, близкой к полноценной виртуальной машине.

5. Снимки состояния перед запуском. Раз агент может неожиданно затронуть файлы workspace, привычка делать git commit перед каждым запуском — не паранойя, а минимальная страховка: откат к рабочему состоянию должен занимать секунды, а не требовать восстановления из бэкапа.

Пошаговый запуск в безопасной конфигурации

Ниже — минимальный практический чек-лист для разворачивания OpenHands на своём сервере с уже применёнными выше принципами:

  1. Подготовьте отдельную директорию под проект и убедитесь, что в ней нет ничего, кроме нужных для задачи файлов:
mkdir -p /srv/agent-workspace/project-x
cd /srv/agent-workspace/project-x
git init && git add -A && git commit -m "baseline before agent run"
  1. Создайте отдельную Docker-сеть без прямого доступа к остальной инфраструктуре сервера:
docker network create --internal agent-net

(флаг --internal отключает выход в интернет из этой сети; если пакеты ставить всё же нужно — вместо --internal используйте сеть с явным egress-фильтром на конкретные хосты).

  1. Запустите контейнер с ограничениями ресурсов и точечным маунтом, как показано в примерах выше, задав ключ API модели через переменную окружения, а не хардкодом в конфиге.
  1. В веб-интерфейсе OpenHands сформулируйте задачу максимально конкретно — не «улучши проект», а «в файле parser.py функция parse_line падает на пустых строках, добавь обработку и покрой тест-кейсом» — и укажите разумный лимит итераций именно под эту задачу.
  1. Наблюдайте за логом действий в реальном времени, не оставляя агента без присмотра на длительный запуск, особенно на первых прогонах, пока не появится доверие к тому, как он ведёт себя на ваших задачах.
  1. По завершении обязательно проверьте diff перед тем, как переносить результат в основную ветку или тем более в продакшн:
git diff --stat
git diff

Реалистичные ожидания: для чего годится, а для чего — нет

Автономный цикл «пиши-запускай-чини» реально экономит время, но полезность жёстко привязана к масштабу задачи.

Тип задачиПодходит ли автономный агентПочему
Написать конкретную функцию по чёткому ТЗДаУзкая, проверяемая цель — тест либо проходит, либо нет
Исправить баг с понятным описанием и репродукциейДаЕсть чёткий критерий успеха, ошибка воспроизводима
«Улучшить производительность приложения»ОсторожноРазмытая цель, агент может оптимизировать не то, что важно вам
Миграция схемы боевой базы данныхНет без ручного ревьюОшибка необратима или дорого обратима, нужен человеческий контроль каждого шага
Полный рефакторинг незнакомой кодовой базы за один запускОсторожноСлишком широкий контекст, кумулятивная ошибка на раннем шаге портит всё, что после
Задача с доступом к реальным пользовательским даннымНетВозможная порча данных не тестовая, а реальная

Практический вывод: доверяйте циклу для ограниченных, чётко очерченных задач — там, где легко сформулировать и легко проверить критерий «готово». Для всего, что затрагивает что-то важное — продакшн, реальные данные, необратимые операции — human-in-the-loop не опция, а обязательное условие: смотрите diff, читайте, что реально изменилось, и только потом принимаете результат, вместо того чтобы доверять автономному циклу вслепую. Автономность агента экономит вам время на написание черновика решения, но не снимает с вас ответственность за то, что в итоге попадёт в рабочий код.

Если хочется быстрее разобраться, чем автономный агент вообще отличается от привычного чат-бота с подсказками кода, стоит взглянуть на разбор в статье про агентов и чат-ботов на практике — там показано, где заканчивается автодополнение и начинается настоящая автономность с её рисками и выгодами.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть ИИ на сервере

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

OpenHands может работать с локальной моделью, а не только с облачным API?

Да, проект поддерживает подключение локально развёрнутых моделей через совместимые с OpenAI API эндпоинты — это снижает риск утечки кода наружу, но требует сервера с достаточными ресурсами под саму модель, отдельно от ресурсов под раннтайм агента.

Достаточно ли просто запустить агента в Docker, чтобы считать это безопасным?

Нет — контейнер снижает поверхность атаки, но без точечного маунта, ограничения ресурсов и сетевой изоляции сам факт «это в Docker» не защищает от порчи данных внутри примонтированной директории или от исчерпания ресурсов хоста.

Что делать, если агент зациклился и продолжает повторять неудачное действие?

Останавливайте запуск вручную через интерфейс и снижайте max_iterations для повторного запуска; если зацикливание регулярное — это обычно сигнал, что задача сформулирована слишком широко или без чёткого критерия завершения.

Нужно ли давать агенту доступ в интернет?

Только если задача явно этого требует (например, установка зависимостей) — и тогда лучше ограничить исходящие соединения списком конкретных хостов, а не оставлять сеть полностью открытой.

Можно ли доверить агенту сразу продакшн-задачу, если очень нужен быстрый результат?

Не стоит — риск необратимой ошибки в продакшене не компенсируется экономией времени; для боевых систем такой агент годится максимум как черновик решения, который проверяет и применяет человек.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →