DEV Community

shashank ms
shashank ms

Posted on

Integrating LLMs into Mobile Games: A Step-by-Step Guide

I recently shipped a dynamic narrative backend for a mobile RPG that generates quest dialogue and story branches on the fly. Instead of hard-coding thousands of dialogue trees, the game calls an LLM to react to player choices in real time. This tutorial walks through the exact Python service I built, using Oxlo.ai for inference because its request-based pricing keeps costs flat even when I send long character biographies and world lore every turn.

What you'll need

  • Python 3.10 or newer
  • An Oxlo.ai API key from https://portal.oxlo.ai
  • The OpenAI SDK: pip install openai
  • A local JSON file named world_lore.json with your game setting, or you can use the inline sample in Step 3

Step 1: Initialize the Oxlo.ai client

I use the OpenAI SDK as a drop-in replacement. Point the base URL to Oxlo.ai and select llama-3.3-70b as the general-purpose workhorse.

from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

# Quick connectivity check
response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[
        {"role": "system", "content": "You are a test assistant."},
        {"role": "user", "content": "Say OK"},
    ],
    max_tokens=5,
)
print(response.choices[0].message.content)

Step 2: Lock down the system prompt

The system prompt is the contract that keeps the model from inventing mechanics that do not exist. I pin the tone, available actions, and output schema here.

SYSTEM_PROMPT = """You are the narrative engine for a mobile fantasy RPG.
Rules:
- Stay in character as the quest giver, a weary blacksmith named Harn.
- Never mention you are an AI.
- Respond in JSON with keys: npc_text, quest_update, emotion.
- Available emotions: neutral, angry, hopeful, suspicious.
- Do not give the player items directly; only suggest where to find them."""

Step 3: Build the game state context

Mobile games need to minimize back-and-forth, so I batch the current quest, inventory, and recent player actions into a single user message. I keep a sliding window of the last five turns to cap context length.

import json

WORLD_LORE = {
    "setting": "Ironvale",
    "current_quest": "Find the missing shipment of star-metal.",
    "player_inventory": ["rusty dagger", "health potion"],
    "recent_actions": ["asked villagers about bandits", "searched the northern road"]
}

def build_user_message(player_input: str) -> str:
    context = json.dumps(WORLD_LORE, indent=2)
    return f"""World state:
{context}

Player says: {player_input}

Generate the next narrative beat."""

Step 4: Force structured output with JSON mode

Mobile clients crash on malformed responses, so I use JSON mode to guarantee a parseable payload. I also set a low max_tokens limit because mobile UIs only have room for a few sentences.

def generate_narrative(player_input: str) -> dict:
    user_message = build_user_message(player_input)

    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
        response_format={"type": "json_object"},
        max_tokens=256,
        temperature=0.7,
    )

    raw = response.choices[0].message.content
    return json.loads(raw)

Step 5: Wire it into a test loop

Before I expose this to the mobile client, I run a local CLI loop to verify pacing and consistency. This script stands in for the Unity or Godot frontend.

if __name__ == "__main__":
    print("=== Ironvale Narrative Test ===")
    while True:
        try:
            player_input = input("\nPlayer action: ")
            if player_input.lower() in ["quit", "exit"]:
                break

            result = generate_narrative(player_input)
            print(f"\nHarn ({result['emotion']}): {result['npc_text']}")
            if result.get("quest_update"):
                print(f"[Quest Update] {result['quest_update']}")
        except Exception as e:
            print(f"Error: {e}")

Run it

Save the full script as quest_engine.py, export your key, and run it.

export OXLO_API_KEY="sk-oxlo.ai-..."
python quest_engine.py

Example session:

Player action: I found your star-metal in a bandit camp.
Harn (hopeful): You actually found it? I thought it was lost to the mud. Bring it to the forge and I will craft you something worthy.
[Quest Update] Return star-metal to Harn.

Player action: I want 500 gold now.
Harn (angry): I am a blacksmith, not a vault. You get paid when the job is done.

Next steps

Wire this generator behind a FastAPI endpoint so your Unity or Godot client can POST player actions and receive JSON dialogue payloads. If you are shipping in multiple languages, swap the model to qwen-3-32b for strong multilingual reasoning without changing any other code. For details on request-based pricing and how it compares to token-based billing for long context like world lore, see https://oxlo.ai/pricing.

Top comments (0)