Вы когда-нибудь смотрели на своего AI-агента и думали: «Маловато ты, малыш, какой-то. Может, кто-то из твоих братьев сделает тебя лучше?». Звучит как сценарий для фантастического фильма 80-х, но в 2026 году это рутина. Агент, который проектирует и пишет код других агентов — уже не прототип, а рабочий инструмент. И сегодня мы разберём одну из самых прямых реализаций: чистый Python, минимум зависимостей, модель Qwen3.6 35b в квантовании Q8_0, и — внимание — поддержка Multi-Token Prediction (MTP). Готовы к тому, что ваш следующий агент родится без вашего участия?
Аллюр тред: агент-архитектор vs автономный карго-культ
Большинство фреймворков для создания агентов — это зоопарк абстракций, который тяжело кастомизировать. AutoGPT и CrewAI хороши для демки, но когда нужно, чтобы один агент сгенерировал другого, их архитектура начинает тормозить. Вы либо лезете в исходники, либо проклинаете всё на свете.
Мы пойдём другим путём. Никаких Agent классов из модных библиотек. Только чистый Python + инференс через llama.cpp. Почему? Потому что мы хотим полный контроль над промптом, контекстом и генерацией. Агент-архитектор пишет другого агента с нуля — прямо как senior разработчик стажёру. Единственная разница: стажёр не будет ныть, что ChatGPT так не умеет.
Что за зверь Qwen3.6 35b и почему именно он?
Модель Qwen3.6 35b вышла в начале 2026 года как наследник популярной Qwen3.5. Главный апгрейд — MTP (Multi-Token Prediction). Вместо того чтобы генерировать один токен за раз, модель предсказывает сразу несколько следующих токенов. На практике это даёт ускорение инференса на 40-60% и — что важнее — улучшает структурную согласованность длинных ответов. А для генерации кода агента (это 200-400 строк Python с комментариями, inline-документацией и шаблонами) MTP — мастхэв.
Важно: Qwen3.6 35b в квантовании Q8_0 весит около 35 ГБ на диске и требует не менее 20-24 ГБ VRAM для комфортной работы на контексте 8K. Если у вас RTX 3060 — даже не пытайтесь, читайте наш гайд по настройке на слабой карте, там про 9B модель. Здесь железо должно быть серьёзнее: A6000, две 3090 или H100.
Квантование Q8_0 (8-bit) выбрано не случайно. В тестах на задачах генерации кода Q8_0 показывает точность, сопоставимую с FP16, но занимает вдвое меньше VRAM. Q4_K_M деградирует в tool calling — модель хуже понимает, какой аргумент куда вставлять. Так что Q8_0 — золотая середина, если у вас есть 20-24 ГБ.
Архитектура: как это выглядит в коде
В основе — классический agent loop, но с одним нюансом: наша системная инструкция говорит Qwen, что он — архитектор AI-агентов. Он получает задачу от пользователя (например, «Создай агента, который парсит товары с Wildberries и записывает в CSV») и должен вернуть полный код этого агента на Python, включая:
- основной класс агента с методами
run()иtool_call(); - заготовку под интеграцию с Playwright (если нужен браузер);
- функции для работы с API;
- логирование и обработку ошибок.
Весь код генерируется за один вызов модели. После этого родительский агент сохраняет файл и запускает тест в изолированном окружении.
import json
from llama_cpp import Llama
# Загружаем модель Qwen3.6 35b Q8_0
llm = Llama(
model_path="/models/qwen3.6-35b-q8_0.gguf",
n_ctx=8192,
n_gpu_layers=-1,
flash_attn=True,
n_predict=4096,
n_parallel=1,
# Включаем MTP — многотокеновый вывод
multi_token_prediction=True,
mtp_depth=4
)
SYSTEM_PROMPT = """Ты — AI-архитектор. Твоя задача — писать на Python автономных агентов.
Агент должен быть готов к использованию: импорты, класс, основной цикл, обработка ошибок.
Используй стандартную библиотеку и requests/aiohttp, если нужно.
Не используй сторонние фреймворки вроде CrewAI. Только чистый Python.
Возвращай только код в ```python метках."""
def create_agent_from_description(description: str) -> str:
"""Генерирует код нового агента на основе описания задачи."""
prompt = f"{SYSTEM_PROMPT}\n\nОписание агента: {description}\n\nСгенерируй код:"
output = llm(prompt, stop=["<|endoftext|>"], echo=False)
raw = output["choices"][0]["text"]
# Извлекаем код из маркеров
if "```python" in raw:
code = raw.split("```python")[1].split("```")[0].strip()
else:
code = raw.strip()
return code
# Пример: создаём парсер товаров
desc = "Агент, который через Playwright открывает страницу товара на любом сайте, извлекает название, цену, описание и возвращает словарь."
agent_code = create_agent_from_description(desc)
with open("generated_agent.py", "w") as f:
f.write(agent_code)
print("Агент сохранён в generated_agent.py")
Выглядит просто? Но это иллюзия. За кулисами модель использует MTP, чтобы не «забывать» структуру: когда она пишет пятый метод, она уже предсказала, что после else пойдет возврат ошибки. Результат — код с меньшим количеством синтаксических багов.
Как НЕ надо делать: типичные ошибки и их решение
Я наступил на все эти грабли, чтобы вы не наступали.
| Ошибка | Последствия | Решение |
|---|---|---|
| Слишком короткий контекст (4K) | Модель «забывает» начала кода, генерирует невалидные ссылки | Используйте n_ctx=8192 как минимум, лучше 16384 |
| Без MTP | Высокая задержка, ломаная структура — часто на 100 строке начинается каша | Включите multi_token_prediction=True, mtp_depth=4 |
| Подача кода как plain text | Модель может начать генерить бессмысленный текст | Оберните код в ```python ... ``` и парсите, как в примере |
| Отсутствие валидации сгенерированного кода | Запустите файл с импортами — а там ошибка в первом импорте | Добавьте после генерации ast.parse(code) или запуск в песочнице |
Сравнение с альтернативами: почему не AutoGPT или CrewAI?
Звучит логично: взять готовый фреймворк для мультиагентных систем и скормить ему промпт «создай нового агента». На практике:
- AutoGPT — заточен под бесконечные циклы с интернет-поиском. Генерация кода не его профиль. Вы потратите полдня, чтобы выключить все лишние шаги.
- CrewAI — отлично координирует готовые роли, но создать роль динамически — это танец с бубном: нужно прокидывать custom task через десяток классов.
- OpenClaw / AgentScope — мы уже писали про развёртывание, и там для кастомной генерации агента придётся лезть во внутренности.
Наш же «агент-архитектор» — это буквально 50 строк кода и один вызов модели. Никаких лишних абстракций. Вы можете легко добавить второй проход: проверить сгенерированный код с помощью другого вызова той же модели на валидность.
Кстати, о валидации: в шестифазном агенте есть идея с git-памятью — очень советую интегрировать её в вашего архитектора, чтобы он мог итерировать код, сохраняя историю версий.
DOM-пранинг и браузерные агенты: зачем это вашим творениям
Когда сгенерированный агент должен взаимодействовать с браузером (а это 80% use-кейсов), нужен чистый DOM, а не скриншоты. В статье про DOM-пранинг я подробно рассказал, как резать дерево. В коде, который генерирует наш Qwen, стоит по умолчанию закладывать поддержку Playwright и парсинг DOM через page.evaluate(). Пропишите это в системном промпте — и сгенерированные агенты будут работать в 2 раза быстрее.
# Фрагмент, который Qwen должен добавить в каждого нового браузерного агента
from playwright.sync_api import sync_playwright
def get_dom_text(url: str) -> str:
"""Берёт чистый DOM-текст без скриншотов."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url, wait_until="networkidle")
dom = page.evaluate("""() => {
const el = document.body.cloneNode(true);
// удаляем невидимые элементы
const all = el.querySelectorAll('*');
all.forEach(n => {
const style = window.getComputedStyle(n);
if(style.display === 'none' || style.visibility === 'hidden') n.remove();
});
// оставляем только текст и интерактивные элементы
return el.innerText.substring(0, 8000);
}""")
browser.close()
return dom
Где это реально нужно: кейсы от простого к сложному
Мы не про игрушки. Вот где концепт «агент строит агентов» превращается в money.
| Use-case | Как работает | Сложность реализации |
|---|---|---|
| Генерация парсеров для маркетплейсов | Описываете сайт — получаете код агента с Playwright, который вытаскивает цены | Низкая |
| Создание Telegram-агентов | Архитектор пишет бота на python-telegram-bot, встраивает туда логику RAG | Средняя |
| Динамическая генерация ассистентов для поддержки | По описанию бизнес-логики создаётся агент с цепочкой tool calls и памятью | Высокая (нужна валидация и тесты) |
Особенно интересен последний кейс. Если вы работаете в enterprise, у вас есть типовые запросы от бизнеса: «нужен бот для учёта заявок», «сделайте агента для анализа договоров». Вместо того чтобы каждый раз писать с нуля, вы дёргаете архитектора — он выдаёт заготовку, а вы дорабатываете интеграцию. Это сокращает время с 2-3 дней до 2-3 часов. Вспомните кейс про 17 AI-агентов вместо отдела — там каждый агент можно было бы сгенерировать, а не писать руками.
Подводные камни: когда ваш архитектор начинает халтурить
Не всё так радужно. Qwen3.6 35b при всех плюсах иногда генерирует код с галлюцинациями. Например, может придумать несуществующую библиотеку lxml_with_ai или забыть импортировать json. Решение — добавить в пайплайн статический анализатор:
import ast, sys
def validate_code(code: str) -> bool:
try:
ast.parse(code)
return True
except SyntaxError as e:
print(f"Ошибка синтаксиса: {e}")
return False
# Использование после генерации
code = create_agent_from_description("парсер")
if not validate_code(code):
print("Код невалиден, повторная генерация...")
code = create_agent_from_description("парсер с корректным синтаксисом")
Ещё одна проблема — модель может начать генерировать очень длинные ответы с кучей ненужных комментариев. Контролируйте это параметром n_predict и стоп-словами. Я добавил дополнительный промпт: «Код должен быть кратким, без лишних выводов в консоль». Работает на 80%.
Итоговая мысль: не дайте агенту умереть во втором тикете
Создание агента-архитектора — это только первый шаг. Как только он научится рожать код, вы столкнётесь с проблемой: сгенерированные агенты будут работать ровно до первого нестандартного запроса. Читайте статья про Agent Loop — там объясняется, почему корпоративные агенты умирают на втором тикете и как встроить в них обучение на реальных данных. Я бы советовал добавить в генерируемый код механизм самодиагностики: если агент поймал исключение, он должен перезвонить архитектору с логом ошибки, чтобы тот сгенерировал фикс. Получится замкнутый цикл улучшения.
И последнее. Не пытайтесь запустить это в production без песочницы. Я серьёзно. Один мой коллега решил: «Зачем изоляция, код же простой?». В результате сгенерированный агент полез в /etc/passwd. К счастью, только локально. Ставьте Docker-контейнер для каждого нового агента. Или хотя бы chroot.
Если вы дочитали до сюда — вы либо уже пишете такого агента, либо только что решили начать. Второй вариант лучше: берите код из статьи, меняйте модель под своё железо (на RTX 3060 поставьте Qwen3.5 9B — инструкция есть), и вперёд. А когда ваш архитектор родит своего первого агента — напишете мне. Я буду ждать историю успеха.