Проблема, которая всех бесит: игры без API
Хочешь сделать бота для Civilization 6 или любой другой игры. Открываешь документацию — нет API. Вообще. Нулевой доступ к внутреннему состоянию. Только экран. Только пиксели.
Классические боты работают через инъекции памяти, патчинг исполняемых файлов или перехват сетевых пакетов. Все это нарушает лицензионные соглашения, требует обратной разработки и ломается с каждым патчем. В 2026 году есть другой путь — Vision-Language Models. Они смотрят на экран как человек и понимают, что там происходит.
Важно: Этот метод работает с любой игрой, которая запускается в окне. Не нужен доступ к исходному коду, не нужны инжекты. Но нужна видеокарта с 8+ ГБ VRAM для современных VLM.
Архитектура civStation: три слоя вместо одного монолита
Большинство пытается запихнуть всю логику в одну модель: "посмотри на скриншот и нажми куда надо". Результат предсказуем — агент тупит, путает интерфейсы, не помнит контекст прошлых действий.
civStation делит задачу на три независимых слоя, каждый со своей ответственностью:
| Слой | Что делает | Модель (актуально на март 2026) | Частота вызовов |
|---|---|---|---|
| Strategy | Анализирует общую ситуацию, ставит долгосрочные цели | Llama 3.2 11B Vision или Qwen2.5-VL-7B | Каждые 30-60 секунд |
| Action | Преобразует цель в конкретные клики и нажатия | LLaVA-NeXT-2025 (специально обучена на UI элементах) | Каждые 2-5 секунд |
| HITL (Human-in-the-Loop) | Перехватывает контроль при низкой уверенности модели | Человек + простая эвристика | Только при ошибках |
Разделение стратегии и действий — ключевая идея. Strategy слой работает с низкой частотой, но использует более мощную модель, которая видит "общую картину". Action слой — быстрый, легкий, но предельно конкретный.
1 Strategy слой: мозг, который строит планы
Strategy получает скриншот всего экрана и историю последних 10 действий. Его задача — сформулировать цель на следующие 30 секунд. Не "нажать кнопку X", а "увеличить производство в городе Санкт-Петербург".
Промпт для стратегического слоя выглядит так:
Ты — стратегический планировщик для игры Civilization VI.
Анализируй текущий скриншот и историю действий.
Контекст игры:
- Текущий раунд: {{turn}}
- Наши ресурсы: {{resources}}
- Последние 5 действий: {{last_actions}}
Задача: определи ОДНУ главную цель на следующие 30 секунд игры.
Формат ответа:
ЦЕЛЬ: [одно предложение]
ОБОСНОВАНИЕ: [2-3 предложения]
ПРИОРИТЕТ: [HIGH/MEDIUM/LOW]
Strategy слой не знает ничего про координаты экрана. Только семантика. Если тебе интересно, как управлять таким контекстом без деградации, у меня есть отдельная статья про вайб-кодинг.
2 Action слой: руки, которые кликают
Action слой получает от Strategy цель и текущий скриншот. Его работа — преобразовать "увеличить производство" в последовательность: 1) найти город Санкт-Петербург на карте, 2) кликнуть по нему, 3) найти кнопку управления производством, 4) выбрать юнит "Рабочий".
Здесь нужна VLM, которая умеет локализовывать объекты на изображении. LLaVA-NeXT-2025 (выпущена в январе 2026) поддерживает bounding boxes в ответах. Промпт:
На скриншоте интерфейс Civilization VI.
Текущая цель: {{goal_from_strategy}}
Инструкции:
1. Найди все интерактивные элементы, относящиеся к цели
2. Для каждого элемента укажи координаты bounding box и действие
3. Действия могут быть: CLICK, RIGHT_CLICK, DRAG, PRESS_KEY
Формат ответа JSON:
{
"actions": [
{
"element": "название элемента",
"bbox": [x1, y1, x2, y2],
"action": "тип действия",
"confidence": 0.95
}
]
}
3 HITL слой: страховочная сетка
Human-in-the-Loop — это не "человек сидит и смотрит 8 часов". Это система, которая:
- Отслеживает confidence score от Action слоя
- При confidence ниже 0.7 делает паузу и показывает предложенное действие человеку
- Позволяет человеку скорректировать действие одним кликом
- Запоминает корректировки для будущих аналогичных ситуаций
На практике HITL срабатывает в 3-5% случаев, но эти 3-5% предотвращают катастрофические ошибки (вроде объявления войны вместо торгового соглашения). Для локального запуска таких агентов рекомендую Tauri + llama.cpp комбинацию — она экономит оперативку.
Пошаговая сборка: от нуля до работающего агента
Шаг 1: Установка и настройка моделей
Сначала ставим две разные модели. Для Strategy слоя — что-то с хорошим reasoning, для Action — что-то с точной визуальной локализацией.
# Устанавливаем Ollama (актуальная версия на март 2026)
curl -fsSL https://ollama.ai/install.sh | sh
# Качаем модель для Strategy слоя
ollama pull qwen2.5:7b-vision
# Для Action слоя нужна LLaVA-NeXT с поддержкой bounding boxes
# Она есть в репозитории llama.cpp, но не в Ollama по умолчанию
# Качаем вручную с Hugging Face:
git clone https://huggingface.co/llava-hf/LLaVA-NeXT-2025-7B-vision
Если хочешь сэкономить на API и сохранить приватность, читай мой гайд про локальные Claude-совместимые модели.
Шаг 2: Модуль захвата экрана
НЕ используй стандартный PIL.ImageGrab на Windows. Он медленный и не работает с GPU-ускоренным рендерингом. Вместо этого — библиотека DXcam или mss с копированием в текстуру CUDA.
import dxcam
import torch
from PIL import Image
class GameCapture:
def __init__(self):
self.camera = dxcam.create()
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
def get_screenshot(self):
# Захват в numpy array, сразу на GPU
frame = self.camera.grab()
if frame is None:
return None
# Конвертация в тензор, нормализация для VLM
tensor = torch.from_numpy(frame).to(self.device).float() / 255.0
return tensor
Шаг 3: Strategy слой — реализация
Подключаем модель через llama.cpp с GGUF-квантованием до 4-bit (экономит VRAM). Для контекстного менеджмента используем технику sliding window.
from llama_cpp import Llama
class StrategyLayer:
def __init__(self, model_path):
self.model = Llama(
model_path=model_path,
n_ctx=4096, # Хватит на историю 10 действий + скриншот
n_gpu_layers=35, # Все слои на GPU
verbose=False
)
self.action_history = []
def analyze(self, screenshot_tensor, game_state):
# Конвертируем тензор в base64 для VLM
screenshot_base64 = tensor_to_base64(screenshot_tensor)
prompt = f"""[SYSTEM] Ты стратегический планировщик...
Скриншот: {screenshot_base64}
История: {self.action_history[-10:]}
Состояние: {game_state}"""
response = self.model.create_chat_completion(
messages=[{"role": "user", "content": prompt}],
temperature=0.1, # Низкая температура для консистентности
max_tokens=256
)
return self._parse_strategy(response['choices'][0]['message']['content'])
Предупреждение: Не храни полную историю действий в контексте модели. После 50-60 действий производительность падает. Вместо этого делай суммаризацию каждые 10 действий. Как это правильно делать — в статье про Agent Skills.
Шаг 4: Action слой — от плана к кликам
Для Action слоя используем LLaVA-NeXT через трансформеры напрямую, потому что нужен доступ к выходным logits для bounding boxes.
from transformers import LlavaNextForConditionalGeneration, LlavaNextProcessor
import torch
class ActionLayer:
def __init__(self):
self.model_id = "llava-hf/LLaVA-NeXT-2025-7B-vision"
self.processor = LlavaNextProcessor.from_pretrained(self.model_id)
self.model = LlavaNextForConditionalGeneration.from_pretrained(
self.model_id,
torch_dtype=torch.float16,
device_map="auto"
)
def generate_actions(self, screenshot, strategy_goal):
prompt = f"""На скриншоте интерфейс игры. Цель: {strategy_goal}
Определи элементы для взаимодействия..."""
inputs = self.processor(images=screenshot, text=prompt, return_tensors="pt").to("cuda")
# Генерация с constrained decoding для JSON
output = self.model.generate(
**inputs,
max_new_tokens=500,
do_sample=False, # Детерминировано для точности координат
output_bboxes=True # Новая фича LLaVA-NeXT-2025
)
return self.processor.decode(output[0], skip_special_tokens=True)
Шаг 5: HITL слой — минимальная реализация
HITL — это простой веб-интерфейс на FastAPI, который показывает скриншот и предложенные действия. Человек может кликнуть по экрану для корректировки.
from fastapi import FastAPI, WebSocket
from pydantic import BaseModel
import asyncio
app = FastAPI()
class ActionRequest(BaseModel):
screenshot: str # base64
proposed_actions: list
confidence: float
@app.post("/review_action")
async def review_action(request: ActionRequest):
if request.confidence < 0.7:
# Отправляем в очередь на человеческую проверку
await human_review_queue.put(request)
return {"status": "pending_human"}
return {"status": "approved"}
Для сложных диалоговых сценариев, где нужен многошаговый диалог с агентом, изучи архитектуру целеустремленных агентов.
Где архитектура ломается (и как чинить)
Реальный мир игр сложнее лабораторных условий. Вот что пойдет не так:
- Динамические интерфейсы: В том же Civilization VI панели меняют размер, появляются модальные окна. Решение — детектировать изменения интерфейса через diff скриншотов и переключать "контекстные профили".
- Время загрузки: Между ходами игра грузится 3-5 секунд. Action слой будет пытаться кликать по черному экрану. Добавь детектор "загрузочного экрана" по цветовым паттернам.
- Разрешения экрана: Игра в 4K, модель обучена на 1080p. Решение — даунсэмплинг областей интереса, но с сохранением пропорций UI элементов.
| Проблема | Симптом | Фикс |
|---|---|---|
| VLM не видит мелкие элементы | Пропускает кнопки размером меньше 32x32 пикселей | Предобработка: увеличивай контрастность UI-элементов перед подачей в модель |
| Ложные срабатывания | Кликает по декоративным элементам как по интерактивным | Добавь whitelist допустимых элементов через RAG-систему |
| Задержки между слоями | Strategy думает 3 секунды, игра уже изменилась | Кэшируй результаты Strategy на похожих скриншотах |
А если мне нужен агент для другого софта?
Архитектура civStation универсальна. Замени промпты и обучение — получишь агента для:
- Автоматизации веб-приложений (вместо Selenium)
- Ботов для мобильных игр через эмулятор
- Ассистентов в профессиональном ПО (Photoshop, Blender)
Для настольных игр с физическими компонентами тебе пригодится мой опыт по созданию RAG-агентов — там похожие проблемы с контекстом.
Код из статьи — упрощенный. В реальном проекте нужно добавить обработку ошибок, логирование, механизм пауз при обнаружении капчи (да, некоторые игры добавляют капчу при подозрении на бота). Полную реализацию смотри в репозитории на GitHub.
Что будет дальше с VLM-агентами?
До конца 2026 года появится три ключевых улучшения:
- Мультимодальные RAG — агенты будут запрашивать документацию по игре прямо во время выполнения, как в LM Studio MCP.
- Самодостаточное обучение — агент сможет создавать датасеты из своих ошибок и дообучать Action слой без человека.
- Стандартизация интерфейсов — что-то вроде OpenAPI для VLM, где игры будут предоставлять "визуальную схему" своего UI.
Мой прогноз: к 2027 году screen-based automation вытеснит 80% традиционных ботов, работающих через инжекты. Не потому что они точнее, а потому что они легальны и переносимы между играми.
Начни с простого прототипа на одной игре. Через месяц у тебя будет фреймворк, который адаптируется под любую игру за пару дней тренировки. Только не забудь поставить HITL — первые версии будут ошибаться в самых неожиданных местах.