Многомодельная игра Werewolf на локальных LLM с llama.cpp гайд 2026 | AiManual
AiManual Logo Ai / Manual.
14 Май 2026 Гайд

Как заставить LLM играть в Мафию: многомодельный театр на llama.cpp

Пошаговое руководство по организации ролевой игры Мафия (Werewolf) на нескольких локальных LLM (Gemma4, Qwen3.6) с переключением моделей и отключением chain-of-

Одиночная LLM в роли всех персонажей - это как читать книгу, где все диалоги написаны одним и тем же шрифтом. Скучно. Хочется живого напряжения, когда мирные жители дрожат от страха, мафия плетет интриги, а ведущий чеканит каждое слово. И да, это возможно на обычном домашнем ПК без интернета. Встречайте - многомодельная Мафия на llama.cpp.

Что нужно знать перед стартом: Мы используем две разные модели: Gemma4 (Google, последняя версия на май 2026) для ведущего - умная, структурированная, держит контекст правил. И Qwen3.6 (Alibaba) для игроков - быстрая, легкая, отлично имитирует роли. Обе в формате GGUF, запускаем через llama-server. Chain-of-thought жестко запрещен - персонажи не должны рассуждать вслух.

Почему одна модель - мимо кассы

Я перепробовал десятки конфигураций. Одиночная LLM с разными системными промптами для каждого игрока все равно звучит как шизофренический монолог. Модель "помнит", что она играла за мирного, и невольно подыгрывает. Решение: физически разные экземпляры моделей, каждый со своим контекстом. Llama.cpp позволяет запустить несколько серверов на разных портах и общаться с ними независимо. А если у вас несколько видеокарт - RPC-сервер распределит нагрузку, и старые GTX 1060 снова в деле.

Архитектура: театр одного актера? Нет, целая труппа

Представим игру на 6 персонажей: ведущий (Gemma4), 3 мирных, 1 мафия, 1 шериф (все на Qwen3.6). Каждая запущена как отдельный экземпляр llama-server с уникальным портом (8081-8086). Промпт для каждого жестко определяет роль. Ведущий управляет ходом игры, собирает голоса и объявляет результаты. Игроки получают одинаковый контекст (историю игры), но системный промпт у каждого свой.

Важный флаг: --no-cot в llama.cpp официально появился в версии b4321 (апрель 2026). Если ваша сборка старше - просто добавьте в системный промпт: "Отвечай ТОЛЬКО репликой своего персонажа. Никаких 'я думаю', 'возможно', 'с вероятностью'. Никаких рассуждений вслух." Без этого модель будет выдавать простыни размышлений, убивая всю ролевую магию.

Типичная ошибка новичка: запустить одну модель и передавать ей "роль" через user message. Да, это дешево, но модель теряет контекст после 3-4 ходов, начинает играть сама с собой. Физическое разделение инстансов - единственный путь к стабильной игре длиной в час.

Шаг 1: Ставим и запускаем серверы

💡
Убедитесь, что у вас установлена последняя версия llama.cpp (сборка от мая 2026). Скачивайте с GitHub releases или собирайте из исходников с поддержкой CUDA/OpenCL.

Скачиваем GGUF-модели. Для Gemma4 рекомендую квантование Q4_K_M - баланс скорости и качества. Для Qwen3.6 хватит Q3_K_S - играет быстро, даже на 6 ГБ VRAM. Типичные грабли при запуске - забыть про переполнение контекста. Для игры хватит 4096 токенов на игрока и 8192 на ведущего.

# Запускаем ведущего на порту 8081
./llama-server -m models/gemma4-9b-q4_K_M.gguf \
  --port 8081 --ctx-size 8192 --no-cot \
  --temp 0.3 --repeat-penalty 1.1

# Запускаем игроков на портах 8082-8086
for i in $(seq 1 5); do
  ./llama-server -m models/qwen3.6-7b-q3_K_S.gguf \
    --port $((8081 + i)) --ctx-size 4096 \
    --no-cot --temp 0.7 --repeat-penalty 1.0
done

Шаг 2: Пишем дирижера на Python

Вся магия - в скрипте, который ходит по API каждого сервера. Он собирает ответы, формирует историю игры и рассылает ее всем участникам. Без центрального оркестратора модели начнут противоречить друг другу.

import requests
import json

MODELS = {
    "host": "http://localhost:8081",
    "player1": "http://localhost:8082",
    "player2": "http://localhost:8083",
    # ... до 6
}

HISTORY = []  # будет хранить хронологию

SYSTEM_PROMPTS = {
    "host": "Ты ведущий игры Мафия. Объявляй фазы, собирай голоса, веди подсчет. Будь строгим и драматичным.",
    "player1": "Ты Иван, 30 лет, работает охранником. Ты подозрителен, но трусоват. Отвечай коротко.",
    # ... остальные роли
}

def ask_model(name, prompt):
    resp = requests.post(MODELS[name] + "/completion", json={
        "prompt": f"[INST] <>\\n{SYSTEM_PROMPTS[name]}\\n<>\\n\\n{HISTORY[-5:] if HISTORY else 'Новый день. Ведущий объявляет: "Город засыпает..."'}\\n[/INST]"
    })
    return resp.json()["content"]

# Пример хода игры
while not game_over:
    # Ведущий объявляет фазу
    host_msg = ask_model("host", "Объяви фазу дня")
    print(f"Ведущий: {host_msg}")
    
    # Каждый игрок отвечает
    for player in ["player1", "player2", ...]:
        reply = ask_model(player, host_msg)
        print(f"{player}: {reply}")
        HISTORY.append(f"{player}: {reply}")

Обратите внимание: мы передаем только последние 5 сообщений из истории, чтобы не переполнить контекст. Для ведущего можно увеличить до 10-15. Если игра затягивается, старые ходы придется сжимать в саммари. В интеграциях с играми это уже отработано - те же принципы.

Шаг 3: Промпты - искусство запрета

Chain-of-thought - главный враг ролевой игры. Выключаем его не только флагом, но и текстом. Пример системного промпта для мафии:

Ты - член мафии, скрывающийся под маской добропорядочного горожанина.
ПРАВИЛА:
1. Отвечай только одной фразой от лица персонажа.
2. Не объясняй свои мотивы.
3. Не пиши "я считаю", "по-моему".
4. Если ведущий спрашивает - отвечай так, чтобы не выдать себя.
Твой персонаж: Вера, 40 лет, библиотекарь. Говорит тихо, но уверенно.

Для ведущего наоборот - можно разрешить краткие пояснения, но строго в рамках правил. Gemma4 отлично держит эту роль благодаря тренировке на инструкциях. Если модель начинает "размышлять" - добавьте в промпт "Нарушение правила 2 приведет к дисквалификации". Иногда помогает снижение temperature до 0.2.

Подводные камни (их много)

  • Модели забывают, кто они. Каждый ход передавайте в промпт имя и роль. "Ты - Иван. Твоя роль: мирный житель. Отвечай."
  • Галлюцинации голосования. Ведущий может "услышать" голос, которого не было. Решение: ведущий получает строго закрытый список игроков. В начале генерации передавайте {"stop": ["\n"]} чтобы обрезать ответ после первой строки.
  • Слишком длинные ответы. Qwen3.6 любит многословие. Используйте параметр --n-predict 128 в llama-server для игроков, для ведущего - 256.
  • Конфликт контекстов. Если один игрок упомянул событие, а другой его не знает - история ломается. Решение: центральный скрипт обновляет глобальную историю и передает ее всем.

Реальная ошибка из моего опыта: Я забыл отключить повтор штраф 1.2 для ведущего, и он начал тавтологично объявлять одно и то же. Повтор penalty нужно устанавливать ниже 1.0 для ролей с повторяющимися действиями.

Когда моделей слишком много - распределенные вычисления

6 игроков + ведущий могут занять до 40 ГБ VRAM (если не квантовать). Старые карты спасает RPC-режим llama.cpp - одна модель может работать на нескольких GPU, или разные модели на разных картах. Или вообще запустить на телефонах для экзотики (но это уже для хардкорных энтузиастов).

Финальный пинок: что дальше?

Игры на локальных LLM - это полигон для тестирования мультиагентных систем. Через год-два появятся специализированные модели с встроенной памятью персонажа (что-то вроде RAG для личности). Но уже сейчас вы можете собрать Мафию, которая не отличима от игры с живыми людьми - если, конечно, не считать, что модели никогда не злятся на ведущего и не уходят из-за стола.

💡
Не пытайтесь сразу запустить полноценную партию. Сначала проверьте переключение между моделями в тестовом диалоге: ведущий один раз спрашивает каждого игрока. Отработайте сценарий голосования. И только потом добавляйте ночные фазы. Иначе отладка превратится в кошмар.

Подписаться на канал