I'm building EverQuill, an AI-powered tabletop RPG platform — a game where an AI acts as your dungeon master, narrating the story and reacting to what you do. Every turn of that story is a message to a language model, and every message costs money.
That cost isn't a problem you get to solve later, once you're big. It's a set of choices you make before anyone shows up, because the defaults you pick decide whether a bad day costs you a few cents or a few hundred dollars. Here are three decisions I made before I opened the alpha, and why.
1. When the tier is unclear, I reach for the stronger model
This is tier-based routing: which model serves a request depends on who's asking. Better models write better stories and cost more; cheaper ones are faster and rougher. So free players get Claude Haiku (cheaper, ~$0.80 per million input tokens) and paying players get Claude Sonnet (stronger, ~$3.00 per million) — plus, because the platform is designed to route across providers, the same decision could hand a turn to a local model running through Ollama instead of a hosted one. That part is straightforward.
The interesting case is the ambiguous one. My routing hands over the cheaper model only when a request is clearly free-tier; everything else — paid, alpha testers, admin, anything the system can't cleanly place as free — gets the stronger model. The instinct most people have is the reverse: default to cheap, protect the margin, don't spend money you don't have to.
The reasoning: a rough, disappointing experience for someone who should have gotten a good one is a real cost — it just doesn't show up on the bill. It shows up as someone deciding the product isn't worth paying for. Meanwhile the money risk is capped elsewhere (more on that below), so biasing toward quality can't run away from me. Given a bounded downside on money and an unbounded downside on reputation, I'd rather err toward quality than toward cheap.
2. I stopped paying full price for the part that never changes
Every turn, a big chunk of what I send the model is identical: the rules of the game, the world, the setup. Only the newest part — what the player just did — is actually new.
The tool for this is prompt caching — most providers let you mark a stable chunk of the prompt so it isn't charged at full rate every time it's re-sent. I placed the cache breakpoint deliberately: everything that stays constant across a session sits on the cached side of the line, and only the genuinely new text is processed fresh each turn.
The part I want to highlight isn't the trick — it's that I didn't trust it blindly. On every call I log the split between cached and uncached input tokens, so I can see the saving actually happening instead of assuming it. If I'd drawn the breakpoint in the wrong place, the numbers would show it immediately. Measured, not hoped for.
3. I decided what happens on the worst day first
Three safeguards, all in place before I opened the alpha:
A spending cap — a hard ceiling of $30/month at this stage, which the account can't exceed, so there's no version of events where I wake up to a bill I didn't authorize.
A kill switch — a single control that stops all AI calls instantly, for the case where something is clearly wrong and I need it to stop now, not after I've finished investigating.
Usage logging — every call's token cost is recorded as it happens, so a runaway is visible in real time rather than as a surprise at the end of the month.
The honest part
None of this came from surviving a horror-story bill. I decided all of it before real usage, on purpose. That's the whole point: cost control isn't something you bolt on after a scary invoice teaches you a lesson. It's a set of defaults you choose up front, so that if something does go wrong, it goes wrong cheaply — and visibly. I'd rather build the seatbelt before the drive than after the crash.
One piece of EverQuill's code — the part that separates the AI's narration from the structured instructions the game acts on — is extracted and public here: llm-structured-output. The application itself is in closed alpha.
Top comments (0)