Spaces:
Sleeping
Sleeping
| title: Micro RPG Engine | |
| emoji: π | |
| colorFrom: purple | |
| colorTo: indigo | |
| sdk: gradio | |
| sdk_version: 5.50.0 | |
| app_file: app.py | |
| pinned: true | |
| license: apache-2.0 | |
| short_description: A whole RPG world generated live by a small 1B-4B model. | |
| tags: | |
| - small-models-hackathon | |
| - track:wood | |
| - thousand-token-wood | |
| - achievement:offbrand | |
| - off-brand | |
| - rpg | |
| - text-adventure | |
| - qwen | |
| - minicpm | |
| <!-- SUBMISSΓO: | |
| Demo video: https://youtu.be/-XfaAcRHH28 | |
| Social post: https://www.linkedin.com/posts/luiz-felipe-barbedo-94188215a_buildsmall-smallmodels-llm-share-7472417718395301889-ZSKJ/ | |
| Track: Thousand Token Wood (entretenimento/whimsical) | |
| β οΈ Confirme o slug exato da tag de track no template da org build-small-hackathon. | |
| --> | |
| > **π₯ Demo video:** https://youtu.be/-XfaAcRHH28 β’ **π£ Social post:** https://www.linkedin.com/posts/luiz-felipe-barbedo-94188215a_buildsmall-smallmodels-llm-share-7472417718395301889-ZSKJ/ | |
| # π Micro RPG Engine | |
| A text RPG where a **small language model (1Bβ4B)** generates *everything* in real | |
| time β the world, NPCs, dialogue, combat, the shop, random events. There is no | |
| pre-written content. **No AI, no game.** Every playthrough is unique. | |
| > Hugging Face Small Models Hackathon β **Track 2** | |
| ## The technical bet | |
| The hard part with small models isn't writing pretty prose β it's **narrative | |
| consistency**: not forgetting your HP, your inventory, that you already killed the | |
| goblin. A generic "RPG-themed chatbot" loses the plot in three turns. | |
| Our approach makes the **Python engine the source of truth**, not the model: | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββ | |
| player input β GameEngine (turn loop) β | |
| ββββββββββββββββΆ β | |
| β 1. build context from GameState ββββββββΌβββΆ System prompt | |
| β 2. call the 1B-4B model β + authoritative | |
| β 3. parse output ββββββββββββββββββββββββΌβββββ state snapshot | |
| β ββ <narrative> β shown to player β | |
| β ββ <state> tags β VALIDATED & applied β | |
| β 4. GameState mutates (HP, gold, items) β | |
| βββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| The model never *remembers* the numbers β it receives them, fresh, every turn, and | |
| may only *propose* deltas (`HP: -10`, `ITEM_ADD: Rusty Sword`) through a strict tag | |
| protocol. The parser clamps and validates every change against the real state. The | |
| model handles imagination; Python handles bookkeeping. That's what keeps a 1.5B | |
| model coherent across a long dungeon crawl. | |
| ## Run locally | |
| ```bash | |
| pip install -r requirements.txt | |
| python app.py | |
| ``` | |
| By default it loads the model with `transformers`. To run with no local GPU, set a | |
| Hugging Face token and it falls back to the serverless Inference API: | |
| ```bash | |
| # Windows PowerShell | |
| $env:HF_TOKEN = "hf_..." | |
| $env:MICRORPG_BACKEND = "inference_api" | |
| python app.py | |
| ``` | |
| ## Configuration (env vars) | |
| | Variable | Default | Meaning | | |
| |----------------------|-------------------------------|------------------------------------------| | |
| | `MICRORPG_MODEL` | `Qwen/Qwen3-4B-Instruct-2507` | Model repo id | | |
| | `MICRORPG_BACKEND` | `transformers` | `transformers` \| `inference_api` \| `mock` | | |
| | `HF_TOKEN` | β | Token for the Inference API backend | | |
| | `MICRORPG_MAX_TOKENS`| `512` | Max new tokens per turn | | |
| Set `MICRORPG_BACKEND=mock` to run the full engine with a deterministic fake model | |
| (no weights, no network) β handy for testing the parser and UI. | |
| ## Fine-tuning (the "Well-Tuned" quest) | |
| The hard skill for a small model here is emitting the strict three-block tag format | |
| with valid mechanics, every turn. We teach it with a **parser-validated synthetic | |
| dataset**: `build_dataset.py` generates RPG turns in the exact protocol, then runs | |
| **every single one through the real engine parser** and keeps only those that parse | |
| and apply cleanly. 100% of the training data is guaranteed well-formed. | |
| ```bash | |
| pip install -r requirements-train.txt # GPU / Colab | |
| python -m finetune.build_dataset --n 1200 # offline, no model needed | |
| python -m finetune.train \ | |
| --model Qwen/Qwen3-4B-Instruct-2507 \ | |
| --out finetune/out/qwen3-4b-microrpg # LoRA, ~few MB adapter | |
| ``` | |
| Play with your fine-tuned model by pointing the engine at the adapter: | |
| ```bash | |
| # Windows PowerShell | |
| $env:MICRORPG_ADAPTER = "finetune/out/qwen3-4b-microrpg" | |
| python app.py | |
| ``` | |
| The dataset is model-agnostic β swap `--model` for MiniCPM, or a Llama for the | |
| **Llama Champion** quest. Add `--load-4bit` for QLoRA on a small GPU. | |
| ## Project layout | |
| ``` | |
| app.py Gradio UI + glue | |
| style.css Custom theme (parchment / arcane) | |
| engine/ | |
| game_state.py GameState: HP, gold, inventory, location, NPCs, quest log | |
| prompts.py System prompt + the tag protocol the model must follow | |
| llm.py Model backends (transformers / inference API / mock) | |
| parser.py Splits narrative from mechanics, validates deltas | |
| engine.py GameEngine: the turn loop | |
| finetune/ | |
| build_dataset.py Parser-validated synthetic turns β train.jsonl / eval.jsonl | |
| train.py LoRA SFT (TRL/PEFT); produces a small adapter | |
| tests/ | |
| test_parser.py Parser/engine smoke tests (run with mock backend) | |
| ``` | |
| ## License | |
| Apache-2.0. | |