Я хотел оживить голема, но получил галлюцинирующего идиота

от автора

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

Я захотел такого же, но в коде.

Телом пусть будет Telegram-бот. А мозгом — нейросеть. Не просто очередной «чат с ИИ», а настоящий кодинг-агент. Чтобы кидаешь ему проект, а он: «Тут у тебя SQL-инъекция, тут гонка данных, тут ты импорт забыл, и вообще у тебя в зависимостях дыра». Идея казалась простой: берём aiogram, прикручиваем DeepSeek, пишем промпт «ты senior-разработчик, разбери этот код» — и готово.

Первая версия была готова за вечер.

Я кинул Голему свой проект. Он задумался на пару секунд и выдал:

«Твой код обрывается. Похоже, ты прислал неполный файл. Я не могу его проанализировать».

Я перепроверил. Файл был полный.

Кинул другой проект. Ответ:

«Интересный фрагмент, но он заканчивается на середине функции. Пришли весь код».

Чёрт подери!!!!

Я сидел и смотрел на этот ответ минут пять. Нейросеть буквально говорила мне, что я идиот, который не умеет копировать файлы. Хотя проблема была в ней самой.

LLM не умеют читать большие объёмы кода. У них есть контекстное окно — как короткая память у рыбки. Они дочитывают до какого-то момента, теряют нить, и им кажется, что текст оборвался. А на самом деле они просто не дошли до конца.

И вот тут я понял: просто «мозг» в «теле» — это не голем. Это говорящая голова на палке. Она не видит проект целиком, не понимает его структуру, не знает, где реальные проблемы, а где просто странный нейминг.

Чтобы оживить голема по-настоящему, ему нужны были глаза.

Тогда и родилась идея «гибрида».

Сначала я попробовал запускать линтеры последовательно:

# Первая версия гибрида — тупая и медленнаяbandit_result = await run_bandit(project_dir)  # безопасностьruff_result = await run_ruff(project_dir)      # стиль и багиpip_audit_result = await run_pip_audit(project_dir)  # уязвимости в зависимостях# Собираем всё в одну кучу и шлём в LLMcontext = f"""Bandit нашёл: {bandit_result}Ruff нашёл: {ruff_result}pip-audit нашёл: {pip_audit_result}"""response = llm.ask(context)

Работало. Но медленно. Каждый линтер ждал предыдущего, а проект мог быть большим. Я сидел и смотрел на экран как дебил, пока Bandit копался в коде.

Переписал:

# Параллельный запуск — глаза открываются одновременноbandit_result, ruff_result, pip_audit_result = await asyncio.gather(    run_bandit(project_dir),    run_ruff(project_dir),    run_pip_audit(project_dir))

Все три тулзы отрабатывают одновременно.  Но и это было не идеально. Линтеры выдают портянку — сотни строк в своём формате. Если скормить всё это LLM, она снова начинает тупить. Тогда я добавил фильтр:

# Оставляем только проблемные строки с контекстомdef extract_issues(bandit_result, ruff_result, pip_audit_result):    issues = []        for issue in bandit_result.get("results", []):        issues.append({            "file": issue["filename"],            "line": issue["line_number"],            "severity": issue["issue_severity"],            "problem": issue["issue_text"],            "code": issue.get("code", "")        })        for issue in ruff_result.get("results", []):        issues.append({            "file": issue["filename"],            "line": issue["line"],            "severity": "medium",            "problem": issue["message"],            "code": issue.get("rule", "")        })        return issues[:30]  # Не больше 30 проблем — остальное мусор

И только эти выжимки летят в LLM:

main.py:42 — Bandit HIGH — Possible SQL injectionauth/login.py:15 — Ruff medium — Unused import 'os'requirements.txt — pip-audit CRITICAL — CVE-2024-1234 in package xyz==1.2.3

Нейросеть получает сжатый набор фактов, а не гору кода. И выдаёт читаемый отчёт: где проблема, почему критично, как исправить.

Вот так Голем обрёл зрение. А потом я захотел, чтобы он ещё и действовал.

Когда Голем начал выдавать вменяемые отчёты, я выдохнул. Но радость была недолгой. Потому что я смотрел на эти отчёты и думал: «Ок, он нашёл 15 проблем. А исправлять кто будет? Я?»

Ну уж нет.

Ruff — он не только находит проблемы, но и умеет их автоматически исправлять. Правда, не все. Но то, что умеет — делает молча и быстро. Осталось только научить Голема запускать эту магию по команде.

Так появился /fix.

# /fix — запуск автоисправления через Ruffasync def fix_project(project_dir: str):    proc = await asyncio.create_subprocess_exec(        "ruff", "check", project_dir, "--fix",        stdout=asyncio.subprocess.PIPE,        stderr=asyncio.subprocess.PIPE    )    stdout, stderr = await proc.communicate()        if proc.returncode == 0:        # Показываем, что изменилось        diff = await get_diff(project_dir)        return diff    else:        return f"Ошибка: {stderr.decode()}"

Юзер жмёт /fix — Ruff проходится по проекту и молча правит что может: неиспользуемые импорты, кривой синтаксис, нарушение стиля. А Голем показывает дифф:

Минус одна проблема. Минус одна строчка в отчёте. Красота.

Но не всё так радужно. Ruff чинит только свои замечания. Уязвимости безопасности от Bandit он не трогает. Дыры в зависимостях от pip-audit — тоже. Поэтому /fix — это не панацея, а первый шаг. Дальше — руками или головой.

И вот когда база для Python устаканилась, я подумал: «А почему только Python?»

Голем учит Go

В моём канале как раз прошло голосование. Народ хотел Go.

Для Go свой набор инструментов:

# Go-линтеры: gosec (безопасность) и staticcheck (стиль и баги)gosec_result, staticcheck_result = await asyncio.gather(    run_gosec(project_dir),    run_staticcheck(project_dir))

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

Архитектура та же: параллельный запуск → сбор проблемных строк → фильтр → LLM → читаемый отчёт.

И когда я первый раз прогнал через Голема urfave/cli — библиотеку с 22 тысячами звёзд на GitHub — он нашёл 14 проблем безопасности и 2 косяка в стиле за пару минут. 

Но знаете что? Это всё ещё не «крутой кодинг-агент», о котором я думал в начале. Это полезный инструмент, да. Но до настоящего голема — автономного, помнящего, самообучающегося — ещё далеко.

Голем 1.0 — это только начало

То, что работает сейчас — это набор разрозненных инструментов, собранных в одного бота:

  • /analyze — гибридный разбор Python и Go

  • /fix — автоисправление части проблем через Ruff

  • /github_push — заливка на GitHub

  • Общение — ответы на вопросы про код

Выглядит неплохо. Но технически это просто разные функции и голем сам не видит картину в целом.

Текущая версия — это инструмент. Полезный, но с ограниченной памятью. Он реагирует на команды, но не запоминает ни свой опыт, ни пользователей, ни результаты своей работы. Для v2 я перепроектирую ядро так, чтобы у Голема появилась настоящая архитектура агента.

Память и самосознание. Появятся две таблицы в SQLite — agent_memory (что Голем знает о себе и своих возможностях) и agent_actions (журнал всех действий и решений). Это даст ему контекст. Он будет помнить, что делал минуту, час или неделю назад, и сможет использовать этот опыт.

Восприятие. Через Telegram API Голем начнёт собирать объективные данные о своей работе: какие возможности востребованы, как часто к нему обращаются и с какими задачами, какие его ответы вызывают реакцию, а какие — нет.

Мотив. Вся эта информация будет собираться не ради отчётов, а чтобы дать Голему возможность действовать осознанно. Его главная внутренняя цель — становиться полезнее и совершеннее. Имея данные, он сможет сам определять: «Вот здесь я справляюсь плохо, надо усилить это направление», или «Этой фичей пользуются чаще всего, значит, её нужно развивать в первую очередь». Или в чат ему юзеры пишут типо » А вот круто было если бы ты умел деплоить проекты сразу на сервер..» И Голем задумается над этим и возможно перепишет свой код)))

Замкнутый цикл. Так мы приходим к замкнутому циклу эволюции. Голем видит результат своих действий, анализирует его и предлагает конкретные технические улучшения в своей архитектуре и коде. Он уже сейчас анализирует Python и Go. v2 будет способен анализировать и улучшать самого себя.

Вот так задумывался настоящий Голем. Не просто ещё один бот с командами, а автономная единица, способная к саморазвитию.

Бот @Golem666bot работает прямо сейчас. Кидайте ссылки на репозитории, тестируйте анализ.

ссылка на оригинал статьи https://habr.com/ru/articles/1027038/