tksluangrath/lol-matchbook
LoL Matchbook LoRA adapter (Qwen3-4B-Instruct, qualitative-dedicated-v2)
A LoRA adapter for Qwen/Qwen3-4B-Instruct-2507, fine-tuned to answer free-form League of Legends matchup follow-up questions in a fixed early/mid/late-game format. It's the /ask model behind LoL Matchbook, a local champ-select assistant. A precomputed lookup answers the time-critical pick/ban question; this adapter handles the conversational follow-ups after that.
This is an unofficial fan project, not endorsed by or affiliated with Riot Games.
Model details
- Base model: Qwen/Qwen3-4B-Instruct-2507
- Method: QLoRA (4-bit NF4 base, LoRA on
q/k/v/o_proj+gate/up/down_proj, r=8, alpha=16, dropout=0.05) - Training data: 76 matchup rows (40 original + 36 expanded pairs). Win rates come from BoostedJonP/league_of_legends_match_data (Riot API match exports), aggregated per champion pair/role. The early/mid/late advice text for each row was generated by the base model (Qwen3-4B-Instruct-2507, before fine-tuning) from a prompt containing the real win rate and each champion's real kit/ability text pulled from Data Dragon, then kept only if a grounding check found no invented ability names and no win-rate mismatch.
- Training: 10 epochs / 380 steps, on CPU (no CUDA on the training machine; see
train.pyfor the compute-gate rationale) - System prompt used at train and inference time:
You are a League of Legends coach. Give concise, rank-aware matchup advice for the game phase asked about. If you do not have reliable data for this matchup at this rank, say so plainly instead of inventing specifics.
Also published in this repo: merged-qualitative-v2/ (adapter merged into the base model, fp16 safetensors) and gguf-qualitative-v2/ (f16 and Q4_K_M GGUF quantizations for llama.cpp serving).
Intended use
Conversational matchup Q&A as a follow-up to a precomputed lookup answer. It is not the source of truth for win rates or patch-specific numbers; verify any cited percentages or kit details against a real source before acting on them.
Limitations
- 76 training rows. Final training loss on this run dropped to ~0.02 with ~99.5% mean token accuracy, which means the adapter is memorizing its training set, not generalizing broadly. Expect it to do best on champions/matchups resembling the training data, and to fall back on the base model's general LoL knowledge (with the usual hallucination risk) elsewhere.
- Held-out eval is small. The qualitative fact-ledger eval passed 10/10 on 10 held-out matchups (all three phases present, no invented-fact flags tripped), which is a sanity check, not a statistically meaningful accuracy number. Raw results: `eval/eval_results.json`; full loss/accuracy curve: `eval/training_log_history.json`.
- Self-distilled training targets. The training labels came from the base model's own (filtered) generations, not an independent expert source, so this adapter mostly teaches the base model to commit to the three-section format and phrasing style more consistently rather than adding new matchup knowledge.
- Not grounded in live match data at inference time — it doesn't know the current patch's actual win rates unless retrieval context is supplied by the calling application.
Usage
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-4B-Instruct-2507")
tok = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B-Instruct-2507")
model = PeftModel.from_pretrained(base, "tksluangrath/lol-matchbook")
messages = [
{"role": "system", "content": "You are a League of Legends coach. Give concise, rank-aware matchup advice for the game phase asked about. If you do not have reliable data for this matchup at this rank, say so plainly instead of inventing specifics."},
{"role": "user", "content": "How does Camille beat Urgot in the early game?"},
]
inputs = tok.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")
out = model.generate(inputs, max_new_tokens=256)
print(tok.decode(out[0][inputs.shape[-1]:], skip_special_tokens=True))For the GGUF files, load gguf-qualitative-v2/merged-qualitative-v2-Q4_K_M.gguf (or -f16.gguf) with llama.cpp / llama-cpp-python.
Framework versions
- PEFT 0.19.1 · TRL 1.9.2 · Transformers 5.3.0 · PyTorch 2.11.0 · Datasets 4.8.5
License
MIT, matching the LoL Matchbook repo. Base model license (Qwen3, Apache 2.0) applies to the base weights this adapter is applied to. This project uses Riot Games IP under Riot's Developer API terms; it is not licensed, sponsored, or endorsed by Riot Games.
