Зачем нейросети играть в карты? (Нет, это не безумие)
Вы смотрите на экран, где LLM принимает решение: продать редкий аркан или усилить бубнового валета. Это не симуляция и не теория. Это BalatroBot в действии — проект, превращающий локальную языковую модель в автономного игрока. Зачем? Потому что тестировать LLM на абстрактных бенчмарках скучно. А вот наблюдать, как она строит стратегию в сложной, стохастичной игре с десятками механик — это и есть настоящий stress-тест для "интеллекта".
В основе лежат два компонента: BalatroBot (Python-бот, управляющий игрой через компьютерное зрение и эмуляцию ввода) и BalatroLLM (слой, который через промпты и шаблоны Jinja2 заставляет модель понимать игровое состояние и принимать решения). Вместе они создают замкнутую петлю: игра → скриншот/парсинг → промпт для LLM → действие → игра.
На момент февраля 2026 года актуальная версия BalatroBot поддерживает как Ollama, так и vLLM эндпоинты, что позволяет использовать модели вплоть до Mixtral 8x22B или свежих ревизий Llama 3.1, если у вас хватит VRAM.
Под капотом безумия: как это вообще работает?
Представьте цепочку: бот делает скриншот экрана с игрой. Не нужно парсить память процесса (это сложно и ненадежно) — используется комбинация OpenCV для поиска UI-элементов и Tesseract для OCR текста (номиналы карт, чипы, деньги). Полученные данные структурируются в JSON.
Далее в дело вступает BalatroLLM. Этот модуль — не просто обертка для API. Это система промпт-инжиниринга, где состояние игры через Jinja2-шаблон превращается в инструкцию для модели. Шаблон объясняет модели правила, возможные действия ("купить карту", "продать джокера", "завершить раунд") и главное — контекст текущей игры.
LLM, получив этот мега-промпт, должна вернуть строго структурированный ответ, обычно в JSON, который бот может интерпретировать как действие: {'action': 'buy', 'target': 'tarot_card', 'position': 3}. И вот уже курсор мыши движется к нужной карте, а нейросеть, по сути, играет.
1 Подготовка поля боя: ставим BalatroBot
Клонируем репозиторий. Никаких волшебных установщиков тут нет, только чистый Python.
git clone https://github.com/username/BalatroBot.git
cd BalatroBot
pip install -r requirements.txt
Требования стандартные: opencv-python, pytesseract, pynput, requests. Главная загвоздка — Tesseract OCR. Его нужно поставить отдельно в систему. На Ubuntu это просто, на Windows придется скачать установщик с официального сайта и не забыть добавить в PATH.
Проверь разрешение экрана! Бот заточен под 1920x1080. Если у тебя 4K или ультраширокий монитор, придется лезть в конфиги и пересчитывать координаты UI-элементов. Это самая частая причина, почему бот "не видит" кнопки.
2 Запускаем движок: настраиваем LLM эндпоинт
BalatroBot по умолчанию настроен на локальный Ollama. Если у тебя ее еще нет — самое время поставить. Наш гид по Ollama подробно разбирает все тонкости.
Запускаем сервер и нужную модель. Для Balatro я рекомендую не гигантов, а что-то среднее, но с хорошим логическим мышлением. По состоянию на 2026 год отлично показывают себя Qwen2.5-7B-Instruct или свежая ревизия Mistral 7B.
# Запускаем Ollama сервер (обычно он уже работает как служба)
ollama serve &
# Скачиваем и запускаем модель
ollama run qwen2.5:7b-instruct
Проверяем, что API доступен:
curl http://localhost:11434/api/generate -d '{"model": "qwen2.5:7b-instruct", "prompt": "Hello"}'
Если хочешь больше скорости и есть GPU с 16+ GB VRAM, можно использовать vLLM. Это сложнее в настройке, но latency будет в разы меньше. Конфиг бота позволяет указать любой эндпоинт, совместимый с OpenAI API.
3 Магия промптов: кастомизируем BalatroLLM
Сердце системы — папка prompt_templates. Внутри лежат .jinja2 файлы. Открываем decision_step.jinja2 и видим примерно это:
Ты — опытный игрок в Balatro. Текущее состояние игры:
Деньги: {{ money }}
Анте: {{ ante }}
Раунд: {{ round }}
Твои джокеры:
{% for joker in jokers %}
- {{ joker.name }} ({{ joker.effect }})
{% endfor %}
Доступные действия: купить карту (buy_card), продать джокера (sell_joker), сыграть руку (play_hand), закончить раунд (end_round).
Проанализируй ситуацию и верни JSON: {"action": "выбранное_действие", "reason": "краткое_объяснение"}.
Это твоя игровая логика. Можно усложнять, добавлять стратегические указания: "Если денег больше 20 и есть слабый джокер — продай его", "Всегда покупай таро карты, если они улучшают руку". Именно здесь происходит "обучение" модели. Ты не fine-tun'ишь веса, ты fine-tun'ишь промпт.
4 Первая игра: запуск и отладка
Запускаем Balatro (обязательно в оконном режиме, без полноэкранного). Затем запускаем бота:
python main.py --model-endpoint http://localhost:11434/api/generate --model-name qwen2.5:7b-instruct
Первые несколько ходов будут медленными (модель думает). Следи за логами. Если видишь ошибку типа "Cannot parse model response", значит, LLM нарушила формат вывода. Это частая проблема. Нужно усиливать инструкции в шаблоне: "Ты должен вернуть ТОЛЬКО JSON, без каких-либо дополнительных текстов, комментариев или markdown".
Бот делает скриншоты, отправляет промпт, получает ответ, выполняет действие. Цикл. Если что-то пошло не так — он ждет 5 секунд и пробует снова. Не оставляй его без присмотра в первый раз: он может зациклиться на попытке купить карту, которой нет.
Ошибки, которые съедят твое время (и как их избежать)
- "Бот кликает мимо кнопок". Причина: разрешение экрана или масштабирование Windows (125% вместо 100%). Решение: установить масштаб 100% или перекалибровать координаты в файле
ui_positions.py. - "OCR не распознает цифры". Tesseract плохо работает с пиксельными шрифтами. Решение: улучшить скриншот через cv2 (увеличить контраст, применить threshold) или обучить кастомный tesseract model (это боль, честно).
- "LLM возвращает бред вместо JSON". Ты используешь базовую модель, не инструктивную. Переходи на instruct-версии (с суффиксом -Instruct, -Chat). Или, как вариант, используй модели с поддержкой Tool Calling — они лучше следуют структуре.
- "Игра зависает из-за долгого ответа модели". Установи timeout в конфиге бота (например, 30 секунд). Если модель не ответила — бот должен пропустить ход или выполнить действие по умолчанию.
От простого бота к стратегическому игроку
Когда базовая связка работает, начинается самое интересное — тонкая настройка стратегии. Можно пойти двумя путями.
Первый: Усложнение промптов. Добавляй в шаблон историю ходов: "В прошлом магазине ты купил 'Сатира', что увеличило множитель червей. Сейчас у тебя много червей на руке, поэтому...". Это заставляет модель учитывать контекст, но и увеличивает расход токенов.
Второй: Внедрение RAG (Retrieval-Augmented Generation). Звучит сложно, но суть проста. У тебя есть файл с wiki по Balatro (все карты, арканы, синергии). Когда бот видит новую карту, он ищет в этой базе связанную информацию и подкладывает в промпт. Так модель "знает", что 'Планирование' совместимо с 'Астрономом'. Технически, это похоже на подход из нашего гайда по RAG для PDF, только вместо поваренной книги — гайд по игре.
| Стратегия | Сложность | Эффективность |
|---|---|---|
| Агрессивная покупка джокеров | Низкая | Средняя (часто не хватает денег) |
| Фокус на одну масть + усиление | Средняя | Высокая (но требует точных промптов) |
| Комбо-построение (синергии) | Высокая | Очень высокая (если модель уловит связи) |
А что, если...? (Ответы на вопросы, которые ты боялся задать)
Можно ли использовать это для других игр? Да, если игра имеет детерминированный UI и доступные действия можно описать текстом. Принцип тот же: скриншот → парсинг → промпт → действие. Например, похожий подход можно применить к Slay the Spire или даже к некоторым аспектам автономного исследования в S.T.A.L.K.E.R. Anomaly, хотя там задачи сложнее.
Нужна ли мощная видеокарта? Для самой игры Balatro — нет. Для LLM — зависит от модели. 7B-параметровые модели работают на CPU (медленно) или на GPU с 8GB VRAM. Для 13B-моделей уже нужно 16GB+. Если нет мощной карты, используй квантованные версии (q4, q5) через llama.cpp — они экономят память.
Это читерство? С точки зрения игры — да, это бот. С точки зрения исследования ИИ — нет, это эксперимент по оценке стратегического планирования в среде с неполной информацией. Не используй это в онлайн-соревнованиях (если такие вдруг есть).
Почему Balatro, а не шахматы? Потому что шахматы детерминированы. В Balatro есть случайность (распределение карт), экономика (деньги), синергии и долгосрочное планирование. Это гораздо ближе к реальным задачам, где нужно принимать решения в условиях неопределенности.
Главный секрет не в том, чтобы заставить LLM играть идеально. Идеальная игра потребует тысяч симуляций и fine-tuning'а, что убивает всю магию. Секрет в том, чтобы наблюдать, как модель, обученная на текстах из интернета, пытается выстроить логическую цепочку в карточной игре. Она будет делать глупые ошибки, упускать очевидные комбо, но иногда выдаст ход, который тебе и в голову не пришел. И в этот момент понимаешь: это не просто бот. Это что-то странное, несовершенное, но думающее. И это чертовски интересно.