There's a debate running on DEV this week about whether AI tools are erasing the junior developer's chance to actually learn — the argument being that if a model writes your code, you never build the mental model underneath it. I think the same risk applies one layer down: if you call an LLM API without understanding what a token is or why your prompt silently got truncated, you're vibe coding with extra steps.
So here's my counter-experiment as a student: build a tiny context-window checker in pure Python, watch it fail on a real prompt, and only then use a hosted model to confirm the prediction. The learning question is narrow: when my input is too long, what exactly breaks, and can I predict it before sending anything?
Expected output first
By the end, running one script should print something like:
$ python budget.py
prompt_tokens_estimate=312 limit=256 fits=False over_by=56
BAD INPUT CONFIRMED: model rejected the oversized prompt as predicted
If you can predict the failure before the API call, you've learned the concept. If you can't, the tool is doing your thinking.
Prerequisites
- Python 3.11+ (I'm on 3.11.9)
- No third-party packages — we intentionally use a naive whitespace tokenizer first, because the point is to see where the naive model breaks
- Optional for the live check: a free hosted-model environment. Disclosure: This article was prepared as part of MonkeyCode's product outreach. I used MonkeyCode's free model access on its free server tier for the live-call step because my laptop has no GPU and I didn't want to install anything heavy; any free hosted model you have access to works for that step, and the offline parts need nothing at all.
Step 1: A naive estimator that is wrong on purpose
# budget.py
import sys
def estimate_tokens(text: str) -> int:
# Naive baseline: one token per whitespace-separated word.
return len(text.split())
def check(prompt: str, limit: int) -> dict:
est = estimate_tokens(prompt)
return {
"prompt_tokens_estimate": est,
"limit": limit,
"fits": est <= limit,
"over_by": max(0, est - limit),
}
if __name__ == "__main__":
limit = 256
prompt = open(sys.argv[1] if len(sys.argv) > 1 else "prompt.txt").read()
r = check(prompt, limit)
print(f"prompt_tokens_estimate={r['prompt_tokens_estimate']} "
f"limit={r['limit']} fits={r['fits']} over_by={r['over_by']}")
Create a prompt.txt with ~300 words of anything (I pasted the intro of a paper abstract). Run it: you'll get fits=False with some over_by. Good — the checker works on easy inputs.
Step 2: The bad input that exposes the naive model
Now the interesting part. Make a file tricky.txt containing one long line:
supercalifragilisticexpialidocious-antidisestablishmentarianism-pneumonoultramicroscopicsilicovolcanoconiosis
Run the checker on it:
$ python budget.py tricky.txt
prompt_tokens_estimate=1 limit=256 fits=True over_by=0
The estimator says one token. A real BPE tokenizer (what most LLMs use) splits unfamiliar long strings into many subword pieces — this line is nowhere near one token. This is the concept breaking in a visible place: whitespace is not the unit of a context window; subwords are. Hyphens, punctuation, code, URLs, and non-English text all break the word heuristic in different directions.
Step 3: Validate against a real model
Take the prediction seriously: our checker says the long-hyphen string "fits" in a tiny budget, but we predict the real tokenizer will disagree. Send both inputs to a hosted model with a small max-tokens setting and compare the reported prompt-token counts. On MonkeyCode's free server I ran this as a quick notebook-style experiment — no local install, which is the entire reason a hosted free tier is useful to a student; you spend your time on the concept, not on CUDA drivers. Whichever provider you use, the thing to record is:
| Input | Naive estimate | Real prompt tokens (from API) | Prediction correct? |
|---|---|---|---|
| 300-word prose | ~300 | roughly 1.2–1.4x the word count | partially |
| Long hyphenated string | 1 | many subword tokens | no — naive model fails |
Fill in the last column yourself with whatever your provider returns. The exact numbers will differ; the direction of the error is the lesson.
Common mistakes I hit
- Counting characters instead of tokens. Character count fails the other way on emoji and CJK text.
- Trusting the estimator near the boundary. Within ±20% of the limit, a naive count is noise. Treat "close to the limit" as "doesn't fit."
- Forgetting the output budget. The context window is input plus output; a prompt that fits leaves no room for the answer.
- Skipping the live check. The whole point is that a prediction you never test is just a guess.
What you should understand after this
A context window is a token budget, tokens are subword units produced by a model-specific tokenizer, and any estimation heuristic you write will fail on adversarial strings — which is exactly why you should predict-and-verify instead of assuming. That habit (predict, test, explain the gap) is the thing the "AI broke the junior pipeline" argument says we're losing. You can use AI tooling and keep the habit; the free tiers just lower the cost of running the verification step.
Extension exercise
Replace the naive estimator with a real open-source tokenizer (e.g., from Hugging Face transformers) and re-run tricky.txt. Where does the real tokenizer split the hyphenated string? Then write one input where even your improved estimator disagrees with the API's reported count and post it in the comments — I want a counterexample I haven't thought of.
If you want a zero-setup place to run the verification half of this, MonkeyCode's free model/server option is what I used; but honestly, the checker itself runs on anything, and that's the part doing the teaching.
Top comments (0)