AI-RPG — Text RPG with an LLM Game Master
Version: 1.0.0
Stack: Python 3.12 · FastAPI · SQLAlchemy 2.x async · PostgreSQL 15 · Qdrant 1.9 · React 18 · Vite 5 · TypeScript 5 · Tailwind CSS 3 · zustand 4 · react-i18next 14
AI-RPG — это веб-приложение, в котором игрок ведёт текстовую ролевую игру с ИИ-мастером (GM). Игрок создаёт мир (или выбирает готовый пресет), настраивает персонажа, и далее вступает в пошаговое взаимодействие: каждое действие игрока обрабатывается трёхфазным orchestrator-ом, который генерирует нарратив, обновляет состояние мира через tool calls, и предлагает 1-3 следующих действия.
Полное ТЗ — в docs/AI-RPG_TZ_TDD.md.
Возможности (v1.0.0)
- ✅ JWT-аутентификация — регистрация обычных пользователей и первого админа по токену.
- ✅ Админ-панель — настройки (LLM, embeddings, Qdrant, UI, game), логи LLM-вызовов с фильтрами, список пользователей, статистика, диагностические кнопки (test LLM / test LLM tools / test embeddings / probe dimension / recreate collections), загрузка favicon/logo/OG-image.
- ✅ Пресеты миров — 2 встроенных (Classic Fantasy, Deep Space Outpost) + создание/редактирование своих.
- ✅ World Builder — генерация нового мира из пресета или формы через SSE-стрим: schemas → environment → entities → intro scene.
- ✅ World Editor — чат-инструция для LLM,
propose_changesс diff,ask_userдля уточнений, optimistic locking. - ✅ Orchestrator (3 фазы):
- Phase 1: planner+executor — цикл tool-calls до
submit_plan. - Phase 2: writer — single LLM call с
submit_step, стримингscene_chunk. - Phase 3: persist + deferred triggers + summary (если история длинная) + suggest actions.
- Phase 1: planner+executor — цикл tool-calls до
- ✅ RAG через Qdrant —
rag_query/rag_add, двухстадийный retrieval (Qdrant → PostgreSQL), изоляция миров через payload-фильтр, фоновая индексация (черезembedding_status). - ✅ Embeddings —
HashEmbedder(offline, для dev) иOpenAIEmbedder(OpenAI-compatible API), авто-fallbackembeddings.api_url→llm.api_url. - ✅ Игровые инструменты (17 шт.):
entity_create/get/list/update/delete,env_update/get,update_plot_rails,advance_time,schedule_trigger,calc(с кубиками),random_choice(детерминированный),rag_query/add,run_subagent,submit_plan/step,suggest_actions. - ✅ Schema tools —
schema_add_type/add_field/remove_field/modify_fieldдля world_editor. - ✅ Контекстный менеджер — последние N сообщений + summary при превышении порога, деградация recent → rag → summary.
- ✅ SSE-стриминг — все долгие операции (world_builder, world_editor, orchestrator) отдают прогресс через SSE с
event:/data:/id:, heartbeat, reconnect черезLast-Event-ID. - ✅ Фронтенд — React+TS+Vite+Tailwind, тёмная тема, i18n (en/ru), мобильный responsive, SSE-клиент с автопереподключением.
Архитектура
┌──────────────────────────────────────────────────────────────┐
│ Браузер (React 18 + Vite + TS + Tailwind + zustand) │
└──────────────────────────┬───────────────────────────────────┘
│ HTTP / SSE
┌──────────────────────────▼───────────────────────────────────┐
│ FastAPI Backend (uvicorn) │
│ ├─ app/api/ — роутеры (auth, worlds, sessions, ...) │
│ ├─ app/engine/ — game_master, world_builder, editor │
│ │ └─ tools/ — ToolRegistry + 17 game tools │
│ ├─ app/core/ — llm, rag, embeddings, security, ... │
│ ├─ app/models/ — SQLAlchemy ORM │
│ ├─ app/prompts/ — системные промпты (en) │
│ └─ app/schemas/ — Pydantic request/response │
└──────┬─────────────────────────────────┬─────────────────────┘
│ async SQLAlchemy │ httpx + qdrant-client
┌──────▼──────────────┐ ┌───────▼──────────────────────┐
│ PostgreSQL 15 │ │ Qdrant 1.9 (векторный индекс)│
│ (users, worlds, │ │ collections: entities, │
│ entities, steps, │ │ story_entries │
│ logs, ...) │ └──────────────────────────────┘
└─────────────────────┘ ▲
│ httpx (embeddings API)
┌────────┴─────────────┐
│ LLM Provider (any │
│ OpenAI-compatible) │
└──────────────────────┘
Быстрый старт
Опция 1: docker-compose (рекомендуется)
# 1. Скопировать .env.example в .env и отредактировать
cp .env.example .env
# Отредактируйте SECRET_KEY, ADMIN_SETUP_TOKEN, LLM_API_URL, LLM_API_KEY
# 2. Поднять всё
docker compose up -d
# 3. Зайти на http://localhost (frontend через nginx)
# Или http://localhost:5173 (frontend dev) / http://localhost:8000/api/docs (backend)
При первом старте сервер напечатает в лог:
=== AI-RPG Admin Setup ===
No admin user yet. Open this URL in your browser:
/register/admin?token=<ADMIN_SETUP_TOKEN>
===========================
Откройте http://localhost/register/admin?token=<...> и создайте первого админа.
Опция 2: локальный dev (backend + frontend раздельно)
# Backend
cd /path/to/ai-rpg
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Запустить PostgreSQL и Qdrant (через docker compose up db qdrant)
docker compose up -d db qdrant
# Применить миграции (создаёт все таблицы)
python -c "import asyncio; from app.db import get_engine; from app.migrations.versions.001_initial_schema import create_all_tables; asyncio.run(create_all_tables(get_engine()))"
# Запустить backend
uvicorn app.main:app --reload --port 8000
# В другом терминале — frontend
cd frontend
npm install
npm run dev
# Откроется http://localhost:5173
Конфигурация LLM
AI-RPG работает с любым OpenAI-compatible API:
| Provider | LLM_API_URL |
Пример LLM_MODEL |
|---|---|---|
| OpenAI | https://api.openai.com/v1 |
gpt-4o-mini |
| Ollama (local) | http://localhost:11434/v1 |
qwen2.5:7b-instruct |
| LM Studio | http://localhost:1234/v1 |
local-model |
| vLLM | http://localhost:8000/v1 |
Qwen/Qwen2.5-7B-Instruct |
| OpenRouter | https://openrouter.ai/api/v1 |
qwen/qwen-2.5-7b-instruct |
Если LLM_API_URL пуст — backend использует MockLlmClient (возвращает записанные replay-ответы). Это удобно для dev и тестов.
Embeddings
Два провайдера:
offline_hash(по умолчанию) —HashEmbedder, детерминированный bag-of-words + hash projection. Не делает HTTP-запросов, работает offline. Размерность 256.openai— OpenAI-compatible embeddings API. URL/key fallback наllm.api_url/llm.api_key, еслиembeddings.api_url/embeddings.api_keyпустые.
Кнопка «Авто-проба размерности» в админке (POST /api/admin/test/embeddings/probe-dimension) определяет реальную размерность модели и предлагает сохранить её в embeddings.dimension.
Структура проекта
ai-rpg/
├── app/ # Backend (Python 3.12)
│ ├── api/ # FastAPI роутеры
│ │ ├── auth.py # /api/register, /api/auth/*
│ │ ├── worlds.py # /api/worlds
│ │ ├── sessions.py # /api/sessions/* (SSE streams)
│ │ ├── presets.py # /api/presets
│ │ ├── admin.py # /api/admin/* (settings, logs, test, upload)
│ │ └── misc.py # /api/health, /api/i18n
│ ├── core/ # Сквозные сервисы
│ │ ├── llm.py # LlmClient + MockLlmClient
│ │ ├── rag.py # RAG через Qdrant + PostgreSQL
│ │ ├── embeddings.py # HashEmbedder, OpenAIEmbedder
│ │ ├── qdrant_client.py # singleton AsyncQdrantClient
│ │ ├── security.py # JWT + bcrypt
│ │ ├── settings_service.py # settings table CRUD + seed
│ │ ├── state_validator.py # validate_state, apply_patch
│ │ ├── time_utils.py # GameTime, parse_delta, advance_time
│ │ └── logging.py # structlog setup
│ ├── engine/ # Игровой движок
│ │ ├── game_master.py # orchestrator (3 фазы)
│ │ ├── world_builder.py # flow создания мира
│ │ ├── world_editor.py # flow редактирования мира
│ │ ├── context.py # контекстный менеджер
│ │ ├── sse.py # SseEmitter
│ │ └── tools/
│ │ ├── base.py # Tool, ToolRegistry, ToolContext, ToolResult
│ │ ├── game.py # 17 игровых инструментов
│ │ ├── schema_tools.py # 4 schema-инструмента
│ │ └── register_all.py # build_default_registry()
│ ├── models/ # SQLAlchemy ORM (10 таблиц)
│ ├── prompts/
│ │ ├── registry.py # get_prompt(stage, language)
│ │ └── stages/ # 11 stage-промптов (en)
│ ├── schemas/ # Pydantic request/response
│ ├── migrations/
│ │ ├── init_db.py # init_db(session)
│ │ ├── init_qdrant.py # re-export init_qdrant_collections
│ │ ├── seed.py # builtin presets (fantasy, sci-fi)
│ │ └── versions/001_initial_schema.py
│ ├── config.py # Settings (pydantic-settings)
│ ├── db.py # async engine + session factory
│ └── main.py # FastAPI app + lifespan
├── frontend/ # Frontend (React 18 + Vite + TS)
│ ├── src/
│ │ ├── pages/ # 8 pages
│ │ ├── components/
│ │ │ ├── ui/ # 9 primitives (Button, Card, Modal, ...)
│ │ │ ├── sessions/ # Chat, ToolCallBubble, ActionInput, ...
│ │ │ ├── worlds/ # WorldCard, WorldBuilder, WorldEditor
│ │ │ └── admin/ # SettingsPanel, LlmLogsTable, ...
│ │ ├── stores/ # zustand (auth, ui, worlds, session, toast)
│ │ ├── lib/ # api.ts, sse.ts, cn.ts
│ │ ├── i18n/ # en.json, ru.json
│ │ └── types/index.ts
│ ├── package.json
│ ├── vite.config.ts
│ ├── tsconfig.json
│ └── tailwind.config.js
├── tests/ # pytest
│ ├── unit/ # 65+ unit-тестов
│ └── integration/ # (placeholder)
├── deploy/
│ ├── Dockerfile.backend
│ ├── Dockerfile.frontend
│ └── nginx.conf
├── docs/
│ └── AI-RPG_TZ_TDD.md # оригинальное ТЗ
├── docker-compose.yml
├── requirements.txt
├── pytest.ini
├── .env.example
└── README.md
API обзор
Полная OpenAPI-схема — на http://localhost:8000/api/docs (Swagger UI).
Ключевые эндпоинты
| Метод | Путь | Назначение |
|---|---|---|
POST |
/api/register |
Регистрация пользователя |
POST |
/api/register/admin?token= |
Регистрация первого админа |
POST |
/api/auth/login |
Логин по email/username → JWT |
GET |
/api/auth/me |
Текущий профиль |
GET |
/api/worlds |
Список миров пользователя |
POST |
/api/worlds |
Создать мир → SSE URL для world_builder |
GET |
/api/sessions/worlds/{id}/state |
Текущее состояние для play-страницы |
POST |
/api/sessions/worlds/{id}/iterate |
Запустить orchestrator → SSE URL |
GET |
/api/sessions/worlds/{id}/iterate/stream |
SSE-стрим итерации |
POST |
/api/sessions/worlds/{id}/retry |
Повторить последний шаг |
POST |
/api/sessions/worlds/{id}/rollback |
Откатить последний шаг |
GET |
/api/admin/settings |
Все настройки (секреты замаскированы) |
PATCH |
/api/admin/settings |
Обновить настройки |
GET |
/api/admin/llm-logs?stage=&status_filter=&... |
Логи LLM-вызовов с фильтрами |
POST |
/api/admin/test/llm?api_url=&api_key=&model= |
Проверка связности LLM |
POST |
/api/admin/test/embeddings/probe-dimension |
Авто-проба размерности эмбеддингов |
POST |
/api/admin/upload-icon |
Загрузить favicon/logo/og_image |
GET |
/api/health |
Health-check (db, qdrant, llm, emb) |
SSE-события (orchestrator)
| Event | Когда |
|---|---|
phase_start |
Начало Phase 1/2/3 |
phase_end |
Конец фазы |
tool_call |
LLM вызвала инструмент |
llm_call_start/end |
Начало/конец LLM-вызова |
scene_chunk |
Streaming-чанк текста из Phase 2 |
scene_complete |
Полный текст сцены + delta_time |
suggested_actions |
1-3 следующих действия |
trigger_fired |
Сработал отложенный триггер |
summary_generated |
Сгенерирован summary |
iteration_complete |
Полное завершение итерации |
done |
Успешное завершение стрима |
error |
Фатальная ошибка, стрим закрывается |
Тестирование
# Backend unit-тесты
pytest tests/unit/ -v
# С покрытием
pytest --cov=app --cov-report=term-missing tests/
# Frontend
cd frontend
npm run typecheck # tsc --noEmit
npm run lint # ESLint
npm run test # vitest
npm run build # production build
Покрытие unit-тестами:
app.core.time_utils— парсинг/advance времени, дельтыapp.core.security— JWT, bcrypt, валидация пароляapp.core.state_validator— валидация state/world, apply_patch (set/inc/dec/append/remove)app.core.embeddings.HashEmbedder— детерминизм, нормализация, размерностьapp.core.llm.MockLlmClient— replay, исчерпание, запись вызовов, стримингapp.engine.tools.base.ToolRegistry— регистрация, диспетч, unknown tool, исключенияapp.engine.tools.game.CalcTool— арифметика, кубики, переменные, ошибкиapp.engine.tools.game.RandomChoiceTool— детерминизм, весаapp.engine.sse.SseEmitter— emit/done/error, ID, сериализацияapp.prompts.registry— все 11 stage-промптов валидны
Production-деплой
См. docs/AI-RPG_TZ_TDD.md §13 (DevOps / Deployment) и §18.3 (Pre-deploy checklist).
Ключевые моменты:
- SECRET_KEY — сгенерировать через
python -c "import secrets; print(secrets.token_urlsafe(48))". - ADMIN_SETUP_TOKEN — задать в
.envИЛИ оставить пустым (тогда сгенерируется случайно при первом старте, напечатается в логах). - HTTPS — terminate TLS на nginx или на внешнем reverse-proxy.
- Backups — ежедневно
pg_dump+ Qdrant snapshot в S3. - Health-check —
GET /api/healthдолжен вернуть 200 сdb:true, qdrant:true. - Мониторинг — structlog пишет JSON в stdout, забирается любой log-агрегатор.
Лицензия
MIT — см. LICENSE (если отсутствует, предполагается MIT).
Changelog
v1.0.0 (2026-06-20)
- Первый release. Реализованы все 8 спринтов из ТЗ:
- Sprint 1: Foundation (docker-compose, БД, Qdrant, миграции, seed, health-check)
- Sprint 2: Auth + Admin (JWT, регистрация, админ-панель настроек, тесты LLM/embeddings)
- Sprint 3: World Builder (LLM-клиент, промпты, SSE-стрим генерации мира)
- Sprint 4: World Editor (чат-редактор, propose_changes, ask_user, optimistic lock)
- Sprint 5: Orchestrator (3 фазы, retry/rollback)
- Sprint 6: Frontend polish (i18n en/ru, тёмная тема, responsive, SSE reconnect)
- Sprint 7: RAG + Triggers + Summary + Context Manager
- Sprint 8: Production (README, метрики, тесты, сборка ZIP)