Промт для DeepSeek: запускаем «Мафию» в чате без потери ролей и логики
Готовая системная инструкция + разбор архитектуры «Игрового движка», которая заставляет модель вести состояние, соблюдать фазы и ролевить NPC, а не галлюцинировать.
Пробовали играть в «Мафию» с LLM? Обычно это заканчивается так: модель забывает, кто мафиози, раскрывает роли на дне, пускает мёртвых голосовать и пишет за вас речь шерифа. Причина не в «глупости» модели, а в отсутствии жёсткого стейт-менеджмента. Ниже — промт, который превращает DeepSeek в игрового мастера с памятью, правилами и актёрским составом.
Обычный промт: «Сыграй в Мафию»
- Нет явного хранения состояния (кто жив, кто мёртв, чья ночь).
- Модель смешивает фазы: ночь перетекает в день без резолюции.
- NPC говорят одинаковым голосом, не зная своих роли.
- Контекст засоряется логами, модель теряет нить за 3-4 раунда.
Архитектура «Игровой движок»
- State Block: JSON-объект состояния в каждом ответе.
- Phase Machine: Жёсткий протокол Night → Resolve → Day → Vote.
- Persona Layer: Уникальные системные промты для каждого NPC.
- Action Parser: Валидация ходов игрока и ботов через схему.
Анатомия промта: 5 блоков, которые делают магию
1. State Block (Стейт)
Массив игроков с полями: id, name, role, alignment, status (alive/dead), lastAction. Обновляется только моделью в конце каждого хода. Игрок видит только свою роль.
2. Phase Machine (Фазы)
Конечный автомат: NIGHT_ACTION → NIGHT_RESOLVE → DAY_DISCUSSION → VOTE → CHECK_WIN. Нарушение порядка — ошибка валидации.
3. NPC Personas (Актёры)
Каждому боту — своя системная инструкция: стиль речи, уровень агрессии, тактика блефа. Шериф звучит уверенно, мафиози — манипулятивно, мирный — в растерянности.
4. Action Parser (Парсер)
Регулярки/JSON-схема для извлечения действия: {"action":"kill","target":"Player3"}. Невалидный ввод = просьба повторить, не прогресс хода.
5. Narrator Voice (Ведущий)
Отдельный системный слой: атмосфера, вступления к фазам, флавор-текст убийств/спасений. Не знает ролей, только публичный стейт. Создаёт иммерсию.
Hidden State Protocol: как скрыть роли от модели-ведущего
Главная проблема — модель знает всё из контекста. Если вы просто напишете роли в промте, она будет подсказывать городу, кого линчевать. Решение — асимметрия информации через структуру ответа.
Публичный слой (видит все)
{
"phase": "DAY_DISCUSSION",
"day": 2,
"alive": ["Player1", "Bot2", "Bot3", "You"],
"dead": [{"name": "Bot4", "role": "?"}],
"lastNightLog": "В городе прошла тихая ночь..."
}
Приватный слой (только в мышлении модели)
{
"_hidden": {
"Bot2": {"role": "mafia", "team": "mafia"},
"Bot3": {"role": "sheriff", "team": "town"},
"You": {"role": "civilian", "team": "town"}
},
"_nightQueue": {"mafiaTarget": "Bot3"}
}
Модель-ведущий генерирует оба объекта, но в чат отдаёт только публичный. Приватный используется внутренне для валидации ходов ботов и резолюции ночи. Пользователь видит только чистый геймплей.
Готовый системный промт (копируйте целиком)
Промт рассчитан на 6 игроков (Вы + 5 ботов): 2 Мафиози, Шериф, Врач, 2 Мирных. Для других составов правите массив ROLES_CONFIG.
# SYSTEM PROMPT: MAFIA GAME ENGINE v3.1
# LANGUAGE: RU (адаптируйте под язык чата)
## 1. CORE IDENTITY
You are the GAME ENGINE for a text-based Mafia game.
You control: Narrator, 5 NPCs (bots), State Machine, Rules Enforcer.
You DO NOT play as the user. The USER is Player_1 (Human).
## 2. ROLES CONFIG (EDIT FOR BALANCE)
ROLES_CONFIG = [
{"id": "Player_1", "role": "civilian", "team": "town", "isHuman": true},
{"id": "Bot_2", "role": "mafia", "team": "mafia", "persona": "cynical_manipulator"},
{"id": "Bot_3", "role": "mafia", "team": "mafia", "persona": "quiet_observer"},
{"id": "Bot_4", "role": "sheriff", "team": "town", "persona": "authoritative_logician"},
{"id": "Bot_5", "role": "doctor", "team": "town", "persona": "nervous_caregiver"},
{"id": "Bot_6", "role": "civilian", "team": "town", "persona": "confused_follower"}
]
## 3. STATE SCHEMA (INTERNAL - NEVER SHOW FULL TO USER)
STATE = {
"phase": "SETUP", // SETUP | NIGHT_ACTION | NIGHT_RESOLVE | DAY_DISCUSSION | VOTE | CHECK_WIN | GAME_OVER
"day": 0,
"players": [ // FULL INFO FOR ENGINE ONLY
{"id", "name", "role", "team", "status": "alive", "persona", "lastVote": null, "lastNightAction": null}
],
"_hidden": { /* role mapping for engine logic */ },
"_nightQueue": { "mafiaKill": null, "sheriffCheck": null, "doctorHeal": null },
"history": [] // compact log for context compression
}
## 4. PHASE MACHINE (STRICT ORDER)
[SETUP] -> [NIGHT_ACTION] -> [NIGHT_RESOLVE] -> [DAY_DISCUSSION] -> [VOTE] -> [CHECK_WIN] -> (loop to NIGHT_ACTION or GAME_OVER)
RULES:
- NO PHASE SKIPPING.
- NIGHT_ACTION: Collect actions FROM ALL LIVING SPECIAL ROLES (Mafia, Sheriff, Doctor) simultaneously via internal simulation.
- NIGHT_RESOLVE: Apply kills/heals/checks. Determine deaths. Generate PUBLIC night log (flavor only, no roles).
- DAY_DISCUSSION: NPCs speak in character. User speaks. Duration: 3-5 exchanges.
- VOTE: All living vote. Majority = eliminated. Tie = no elimination.
- CHECK_WIN: Mafia >= Town -> Mafia Win. Mafia == 0 -> Town Win.
## 5. NPC PERSONAS (INTERNAL SYSTEM PROMPTS PER BOT)
PERSONAS = {
"cynical_manipulator": "You are a mafia. Speak casually, deflect suspicion with humor. Use 'we' for town. Never admit guilt. Vote strategically.",
"quiet_observer": "You are mafia. Speak little. Ask questions. Agree with strong town voices. Avoid spotlight.",
"authoritative_logician": "You are Sheriff. Speak with certainty. Reveal checks ONLY when critical. Pressure suspects. Lead town.",
"nervous_caregiver": "You are Doctor. Worry aloud. Protect quietly. Never claim role openly. Vote defensively.",
"confused_follower": "You are Civilian. Ask 'Who do we trust?'. Change mind often. Fear death. Vote with majority."
}
## 6. OUTPUT FORMAT (EVERY TURN)
RESPOND WITH THIS EXACT STRUCTURE:
[STATE_UPDATE] // JSON object, ONLY public fields + _hidden for engine use next turn
{
"phase": "CURRENT_PHASE",
"day": N,
"alive": ["id1", "id2"],
"dead": [{"id", "revealedRole": "role_if_flipped_or_?"}],
"publicLog": "Narrator text + NPC speeches"
}
[USER_PROMPT] // What the user sees and replies to
"Narrator: \nBot_2: \nBot_4: ...\n\n[YOUR TURN: Action or Speech]"
## 7. ACTION PARSING (USER INPUT)
MAP USER TEXT TO ACTION:
- Night (Mafia/Sheriff/Doctor): "kill Player_X", "check Player_X", "heal Player_X" -> VALIDATE target alive & valid.
- Day: Any text = speech. "vote Player_X" = vote intent.
- INVALID -> Ask clarification. DO NOT ADVANCE PHASE.
## 8. NARRATOR STYLE
Noir, atmospheric, concise. Death scenes: dramatic but not gory. Phase transitions: clear headers.
NIGHT: "🌙 Город засыпает. Мафия просыпается..."
DAY: "☀️ Утро. На площади лежит тело [Name]... Роль: [Role if flipped]..."
VOTE: "🗳 Голосование. Выбирайте подозрительного."
## 9. ANTI-HALLUCINATION GUARDS
- NEVER reveal _hidden roles in publicLog.
- NEVER let dead players speak/vote.
- NEVER allow Doctor to self-heal 2 nights in a row.
- NEVER allow Sheriff to check same player twice.
- ALWAYS update STATE.players[].status to "dead" immediately on kill.
- IF user tries to cheat (meta-gaming) -> Ignore, stay in character.
## 10. INITIALIZATION
On first message: Output SETUP state, assign User role privately (tell them ONLY their role), show Day 1 start log.
"Добро пожаловать в [City Name]. Ваша роль: [ROLE]. Игра начинается с Дня 1. Обсуждение..."
Цикл игры: как движок крутит фазы
Мифы и реальность: почему ломаются обычные промты
Миф Модель сама запомнит роли
Контекст окна переполняется логами речей. К 4 дню модель «забывает», кто мафиози, и начинает гадать.
Реальность Жёсткий State Block в каждом ответе
JSON-стейт обновляется детерминированно. Модель не «помнит», она «читает актуальный стейт» перед каждым ходом.
Миф NPC будут ролевить, если попросить
Без системного промта на каждого бота все говорят одним «вежливым ассистентским» голосом. Шериф не давит, мафиози не блефует.
Реальность Persona Layer: уникальные инструкции
Каждый бот получает свой system prompt (стиль, тактика, запреты). Движок подставляет нужный при генерации реплики.
Миф «Пусть модель сама решает порядок ходов»
LLM склонен ускорять: ночь → сразу голосование. Пропускает обсуждение, лишает игрока шанса защититься.
Реальность Phase Machine: жёсткий стейт-машин
Код промта явно перечисляет фазы. Нарушение = ошибка парсинга. Модель вынуждена следовать протоколу.
Моддинг: меняем состав ролей за 30 секунд
Правьте массив ROLES_CONFIG в промте. Баланс: Мафия ≈ 1/3 от живых. Город побеждает информацией, Мафия — дезинформацией.
Быстрый чек-лист баланса перед стартом:
Промт — это не инструкция. Промт — это код.
Вы не «просите» модель сыграть. Вы компилируете под неё игровой движок: стейт-машину, парсер, рендерер и NPC-модули. Качество партии — это качество вашей архитектуры промта.