Зачем агенту выполнять код

LLM рассуждает текстом, но многие задачи нельзя решить «в уме»: посчитать статистику по данным, построить график, обратиться к API, преобразовать файл. Модель напишет для этого код — но без запуска она не узнает, работает ли он. А значит, и не исправит ошибку.

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

ℹ️ Кто пишет и кто выполняет — разные агенты

Важно из прошлых уроков: код пишет один агент (AssistantAgent, «мозг»), а выполняет другой (UserProxyAgent или любой агент с включённым исполнением). Это разделение неслучайно — оно даёт точку контроля: между «предложено» и «выполнено» можно вставить проверку или подтверждение человека.

Как это работает

Механика проста и проходит через сообщения. Ассистент оформляет код в markdown-блок (```python ... ```). Агент-исполнитель, получив такое сообщение, извлекает блоки кода, запускает их и возвращает результат (stdout/stderr или код ошибки) обратным сообщением. Автор видит вывод и реагирует.

100%
колёсико — масштаб  ·  зажать и тянуть — перемещение
assistant пишет ```python``` executor 1. извлекает блоки кода 2. запускает 3. собирает вывод/ошибку песочница local / Docker work_dir код run stdout / stderr результат → assistant правит код от LLM выполняется в песочнице; вывод возвращается автору сообщением

Всё это — обычный обмен сообщениями из уроков про ConversableAgent: «код» и «результат выполнения» — просто разные сообщения в той же истории. Никакого скрытого канала; выполнение встроено в разговор как ещё один тип реплики.

code_execution_config: где и как

Выполнение включается параметром code_execution_config у агента-исполнителя. Он же говорит, где запускать код. Главное решение — local или Docker:

Local (use_docker=False)
  • код бежит прямо на твоей машине
  • быстро и без настройки
  • ❗ полный доступ к ФС и сети
  • только для учёбы / доверенного кода
Docker (use_docker=True)
  • код бежит в изолированном контейнере
  • нет доступа к хост-системе
  • последствия ограничены контейнером
  • ✅ рекомендуется для прода
Конфигурация выполнения кода
python
from autogen import UserProxyAgent

# Вариант 1: Docker — изолированно (для прода)
executor = UserProxyAgent(
    name="executor",
    human_input_mode="NEVER",
    code_execution_config={
        "work_dir": "coding",     # папка для файлов кода и артефактов
        "use_docker": True,       # запуск в контейнере
    },
    llm_config=False,
)

# Вариант 2: local — на хосте (только учёба/доверенное)
executor_local = UserProxyAgent(
    name="executor",
    code_execution_config={"work_dir": "coding", "use_docker": False},
    llm_config=False,
)

# Выключить выполнение совсем (агент станет просто собеседником):
# code_execution_config=False

Параметр work_dir — рабочая папка, куда складываются файлы с кодом и созданные артефакты (например, сохранённый график). Изоляция через use_docker=True ограничивает «радиус поражения»: что бы код ни натворил, он заперт в контейнере, а не в твоей системе.

ℹ️ Современный API: исполнители как объекты

В свежих версиях AutoGen выполнение оформляют отдельными классами-исполнителями — LocalCommandLineCodeExecutor и DockerCommandLineCodeExecutor — и передают их как {"executor": ...}. Идея та же (local vs Docker, рабочая папка), просто конфиг стал явным объектом. Принципы из этого урока переносятся напрямую; смотри документацию своей версии для точного синтаксиса.

Безопасность — это не опция

Запомни главное: ты выполняешь код, который написала языковая модель. Не человек-эксперт, а вероятностная модель, способная галлюцинировать. Она может — без злого умысла — сгенерировать rm -rf, бесконечный цикл, утечку переменных окружения или запрос к внешнему серверу. И всё это выполнится автоматически, если ты не поставил барьеров.

Local execution без изоляции на проде — недопустимо

use_docker=False даёт коду от LLM полный доступ к твоей файловой системе, сети и переменным окружения (включая секреты). Для прода это неприемлемо. Минимум — Docker; лучше — Docker + ограничения ресурсов, без сети, без чувствительных монтирований, отдельные временные ключи.

Слои защиты, которые стоит применять (от обязательного к желательному):

  • Изоляция (Docker). Базовый барьер — выполнять в контейнере, а не на хосте.
  • Человек в цикле. human_input_mode="ALWAYS" или "TERMINATE" — подтверждать код перед запуском (привет approval workflows и interrupt_before из модуля 03).
  • Ограничение окружения. Без доступа к сети, без секретов в окружении, лимиты CPU/памяти/времени, отдельная одноразовая папка.
  • Минимум прав. Контейнер с непривилегированным пользователем, только нужные пакеты.
Правило по уровню риска

Чем «боевее» окружение, тем строже барьеры. Учёба/демо на личной машине — допустим local (осознавая риск). Прод — Docker + изоляция как минимум, для опасных операций добавляй подтверждение человеком. Никогда не давай агенту-исполнителю доступ к production-данным и боевым ключам напрямую.

Полный пример: пара пишет и выполняет

Assistant пишет код → executor выполняет в Docker
python
from autogen import AssistantAgent, UserProxyAgent

llm_config = {"model": "gpt-4o-mini", "api_key": "sk-..."}

assistant = AssistantAgent(name="assistant", llm_config=llm_config)

executor = UserProxyAgent(
    name="executor",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=5,
    is_termination_msg=lambda m: "TERMINATE" in (m.get("content") or ""),
    code_execution_config={"work_dir": "coding", "use_docker": True},  # ИЗОЛЯЦИЯ
    llm_config=False,
)

executor.initiate_chat(
    assistant,
    message="Сгенерируй 100 случайных чисел, посчитай среднее и медиану. "
            "Напиши и запусти код, выведи результат.",
)

# Цикл: assistant пишет код → executor запускает в контейнере →
#       возвращает stdout → assistant видит числа, подтверждает, TERMINATE.
# Артефакты (если код сохранял файлы) останутся в папке coding/

Тот же паттерн «мозг + руки» из прошлого урока, но теперь мы явно видим, что «руки» исполняют код в изолированной песочнице. Если код упадёт — executor вернёт текст ошибки, и assistant починит его, не выходя из разговора.

Типичные ошибки

Ошибка 1: local execution на проде

Выполнять код от LLM на хосте без изоляции — прямой путь к инциденту. На проде — Docker (или другая песочница) обязательно.

Ошибка 2: доступ к секретам и сети «по умолчанию»

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

Ошибка 3: нет лимита итераций

Без max_consecutive_auto_reply пара может бесконечно «чинить» код, который в принципе не запускается, сжигая токены. Ставь предел и условие завершения.

Ошибка 4: исполнитель с llm_config

Агенту-исполнителю модель не нужна — он запускает код, а не генерирует текст. Лишний llm_config добавит ненужные вызовы LLM. Ставь llm_config=False.

Шпаргалка

Code execution — всё в одном месте
python
# ИДЕЯ: агент извлекает код из ```блоков``` сообщения, запускает, шлёт вывод назад
#   пишет код — ассистент (мозг); выполняет — executor (руки)

code_execution_config = {
    "work_dir": "coding",     # папка для кода и артефактов
    "use_docker": True,       # ИЗОЛЯЦИЯ (прод). False — local (только учёба!)
}
# отключить выполнение совсем:  code_execution_config = False

# Современный API: явные исполнители
#   LocalCommandLineCodeExecutor / DockerCommandLineCodeExecutor
#   → {"executor": }

# БЕЗОПАСНОСТЬ (код пишет LLM — он может галлюцинировать опасное):
#   1. Docker — базовый барьер (не хост!)
#   2. human_input_mode = ALWAYS/TERMINATE — подтверждение перед запуском
#   3. без секретов и сети в окружении; лимиты CPU/RAM/time
#   4. непривилегированный пользователь, минимум пакетов

# Правила:
#  • прод → НИКОГДА local без изоляции
#  • исполнителю → llm_config=False
#  • max_consecutive_auto_reply + is_termination_msg
#  • учёба → local ок (осознанно); прод → Docker + изоляция (+ человек для опасного)

Практическое задание

Запусти выполнение кода — и подумай о безопасности:

Задание: агент, который пишет и выполняет код

  1. Собери пару assistant + executor с code_execution_config. Дай задачу с реальным вычислением: «посчитай статистику списка» или «построй и сохрани график в png».
  2. Проследи по логу полный цикл: код → выполнение → вывод → подтверждение/правка. Где executor вернул реальный результат интерпретатора?
  3. Намеренно дай задачу, где первый код упадёт (например, опечатка в импорте), и убедись, что assistant чинит его по тексту ошибки.
  4. Загляни в папку work_dir — что там появилось после выполнения?
  5. Сравни use_docker=True и False: что меняется в поведении и какие риски снимает контейнер. Перечисли, что опасного мог бы сделать код без изоляции.
  6. Со звёздочкой: добавь human_input_mode="ALWAYS" и реализуй ручное подтверждение перед каждым запуском — это твой минимальный approval-контур для опасных действий.

Что дальше

Ты прошёл код-ядро AutoGen: агенты-собеседники, пара мозг+руки, групповой чат и безопасное выполнение кода. Завершает раздел инструмент для тех, кто предпочитает собирать агентов мышкой, — AutoGen Studio, визуальный билдер.