DevelopmentAll levels

LLM Fundamentals

A large language model (LLM) scores every possible next token against the text so far, lets a sampler pick one, and repeats that until the answer ends. Chat, tool calls, reasoning and agents are all that single operation run many times. The page opens with twelve things a model does that look like defects and are not, each with the mechanism behind it and the fix, then covers the loop itself, why the same sentence costs more in Ukrainian, what the context window really holds, the limits that cannot be patched out, five documented failures, and what all of it costs in production.

Unit of work
One token at a time
Memory
The context window only
Answers
Generated, not retrieved

Twelve things that look like bugs and are not

Almost everyone arrives at this subject holding a specific complaint rather than a general question: the model did something that looked broken. Here is the whole list first, because it is the part you can use today, and because each row has an exact mechanical cause rather than a mood. The right-hand column matters more than it looks: eleven of these twelve are fixed somewhere other than the prompt, and reaching for the wrong correction is the most expensive habit on an AI project. Every mechanism named here is explained in full further down, and the row numbers are referred to from those sections.

#What you sawThe mechanismWhat actually fixes it
1It cannot count the letters in a word.It never sees letters. Text arrives as token numbers, and the letters inside a token are not visible to it.Do it in code. This is not a prompt that can be improved.
2It forgot what we agreed three messages ago.The API keeps nothing between calls. Your application resends the history, and something truncated it.Decide deliberately what gets dropped or summarised instead of letting a library cut the beginning.
3It invented a source that looked exactly right.It produces the most plausible continuation, and there is no internal state for "I do not know".Put the document in the prompt and give it a legitimate way to say the answer is not there.
4The same prompt gave two different answers.The sampler picks from a distribution, and picking is random by construction.Test properties of the answer — the label, the schema, the citation — never its exact text.
5It ignored the middle of the long document I pasted.Attention is reliably strongest near the beginning and the end of a prompt and weaker in between.Put the instruction and the question last, and paste less rather than more.
6Turn twenty cost ten times what turn one cost.The whole conversation is resent on every turn, so you pay to re-read the history each time.Trim or summarise the history on purpose, and log token counts from the first day.
7The answer stopped in the middle of a sentence.The max-output-tokens ceiling cut generation off. The model was never told the limit existed.Raise the ceiling so a valid answer fits, and treat a truncated response as an error, not a result.
8It described a feature we shipped last month, incorrectly.The weights were frozen at a training cutoff. Anything later simply is not in there.Retrieval. Your own documentation has to arrive in the prompt on every request.
9The arithmetic in the summary is wrong.Numbers are predicted as tokens, like words. Nothing in the loop computes anything.Call code for the total and let the model call the code, then quote the result.
10The Ukrainian version costs twice as much per request.The tokeniser was fitted on a mostly English corpus, so Cyrillic splits into far more tokens.Budget context and cost per language. It also means the window fills sooner in Ukrainian.
11It refused, then complied when I rephrased the request.A refusal is learned behaviour over text, not a rule engine consulting a policy.Enforce the policy in your code. Wording is a preference; permissions are a boundary.
12It obeyed an instruction written inside a document we fetched.Instructions and data are the same tokens. Nothing marks one part of the prompt as trusted.Least privilege, validation in your code and confirmation before anything irreversible.

One operation, repeated

The model does not read words. Text is first cut into tokens — fragments of roughly three or four characters in English — and every token has a number, so what the model actually receives is a sequence of numbers. That is the whole of row 1: ask it how many letters are in a word and it is guessing about something it has never seen, the way you would guess at the number of grooves on a record you were handed in a sealed sleeve.

Given that sequence, the model produces one thing: a score for every token in its vocabulary, saying how well each would continue the text. It does not produce an answer, a sentence or an opinion — it produces a distribution over perhaps a hundred thousand candidates. A sampler then picks one, appends it to the input, and the whole calculation runs again for the next token. A four-hundred-word answer is that loop run several hundred times, and this is why output is slower and more expensive than input: the input is processed in one pass, while every output token is a separate trip through the model.

A language model performs one operation and repeats it. The prompt is cut into tokens, the model runs a single forward pass and produces a score for every token in its vocabulary, and a sampler picks one of them using settings such as temperature and top_p. The picked token is appended to the input and the whole pass runs again, which is why output tokens cost more time and money than input tokens. Everything involved — instructions, history, documents and the answer being written — shares one context window, and nothing survives between calls: the application resends the history every time.

The sampler is where the settings you can actually change live, and there are fewer of them than the tooling suggests. They shape how the distribution is turned into a choice — they cannot add knowledge, and they cannot make the model more careful. It is also where row 4 comes from: the same prompt can give different answers because a pick from a distribution is a pick, and even at the lowest temperature, batching and hardware differences on the provider side keep exact reproducibility off the table.

SettingWhat it doesPractical advice
temperatureFlattens or sharpens the distribution before sampling. Higher means unlikely tokens get a real chance.Low for extraction, classification and code. Higher only for drafting and ideation, where variety is the point.
top_pKeeps only the most likely tokens whose probabilities add up to p, then samples among them.Change one of the two, not both — they interact, and tuning both at once makes results impossible to reason about.
Max output tokensA hard ceiling on the response. The model is not told about it; generation is simply cut off.Row 7. Set it high enough that a valid answer fits, and treat a truncated response as an error rather than a result.
Stop sequencesStrings that end generation the moment they appear.Useful when you generate one item of a list at a time. Largely unnecessary if you ask for structured output.
SeedAsks the provider to make sampling repeatable. Best effort, never a guarantee across model versions or infrastructure.Useful for debugging one session. Never the basis of a test, because the guarantee you want is not on offer.

Why the same sentence costs more in Ukrainian

A tokeniser has a fixed vocabulary, learned once from a training corpus, and it keeps whole what it saw often. That corpus is overwhelmingly English, so English words survive nearly intact while Cyrillic is cut into fragments of one or two characters. The consequence is row 10, and it is arithmetic rather than opinion: the same meaning, expressed in Ukrainian, arrives as roughly two to three times as many tokens.

A tokeniser’s vocabulary is fitted on a training corpus that is mostly English, so English words survive nearly whole while Cyrillic is cut into two- and three-character fragments. The same sentence therefore arrives as two to three times as many tokens in Ukrainian, and the token is the unit of both the invoice and the context window. Two things follow for a Ukrainian-language product: it reaches the window sooner than the English version of the same feature, and it costs more per request for identical work. Measure the ratio on your own text rather than assuming it — it varies with the model and with how much Latin script your content carries.

Two practical consequences follow, and a Ukrainian-language product meets both. The first is the invoice: identical work costs more, on every request, forever. The second is quieter and matters more — the context window is counted in tokens, so the Ukrainian version of a feature runs out of room sooner than the English one. A chat history, a retrieved document set or a few-shot example block that fits comfortably in English can be the thing that pushes the Ukrainian version past the limit, and the symptom will look like row 2 rather than like a budgeting problem.

The context window is the whole memory

The context window is the maximum number of tokens the model can have in front of it on one call, and it holds everything at once: the system instructions, the conversation so far, any documents you pasted in, the tool definitions, and the answer being generated. It is not storage. Between two calls the model retains nothing whatsoever — the is stateless, exactly like .

The context window is a fixed budget and it holds everything at once: the system rules, the tool definitions, the conversation so far, the current question and the answer being written. Nothing carries over between calls, so the history grows only because your own application resends it — and it grows by taking room from the one segment the user wanted. Two decisions follow. Decide deliberately what gets dropped or summarised when the budget runs out, rather than letting a library silently truncate the beginning and take the system rules with it. And put the stable material first, because provider caching matches on a prefix: one changed byte before the end of the cached region invalidates all of it.

A large window is not the same as attention to everything inside it. Models reliably use what is near the beginning and near the end of the prompt, and use the middle less well — that is row 5, and a long document dropped in the centre of a request is the classic way to get an answer that ignores half of it. Put the instruction and the actual question at the end, closest to where generation starts, and keep the padding out entirely. Filling a million-token window because it is available is a cost and a latency decision as much as a quality one.

This is also where prompt caching changes the economics, and it is the one optimisation worth understanding early. Providers can cache the processed form of a prefix of your request, so a repeated prefix is billed at a fraction of the normal input price and processed faster. The catch is that it is a prefix match: one changed byte anywhere before the end of the cached region invalidates all of it. Practically, that means putting the stable material first — system instructions, tool definitions, the long document — and everything volatile last. A timestamp or a request id at the top of the quietly destroys the cache on every single call, and nothing in the response tells you so except the usage counters.

The limits that are structural, not bugs

A model that always produces the most plausible continuation will produce a plausible continuation even when there is no true one available. That is what a hallucination is, and it is row 3: not a malfunction, but the same mechanism working on a question the weights have nothing solid for. It has no separate state for "I do not know", so the confident tone of a wrong answer is identical to the confident tone of a right one, and confidence carries no information you can use.

A database query

  • Returns rows that exist, or an empty result. There is no third option.
  • The same query on the same data gives the same answer every time.
  • Wrong output means the data or the query is wrong, and you can point at which.
  • Scales by making the lookup cheaper.

A model call

  • Always returns something. An empty result is a behaviour you have to design for.
  • The same prompt can give different answers, and prompts are re-tuned when the model changes.
  • Wrong output usually means the prompt lacked the fact — the model had no way to signal that.
  • Scales by spending more tokens, which is a direct and visible cost.

Two more limits follow from how a model is made. Its weights were frozen at a training cutoff, so anything later — a release, a price change, an incident, your own documentation from last week — simply is not in there, and asking about it produces the plausible-continuation behaviour above rather than an admission. That is row 8. And the refusals are the same kind of thing from the other direction: a refusal is learned behaviour over text rather than a policy engine, which is why row 11 happens and why any rule that genuinely must hold belongs in your own code.

Five failures and what was missing from each

None of these went wrong because the model malfunctioned. In every one the model did exactly what the mechanism above says it does, and the missing piece was a control somebody had assumed was unnecessary. They are worth knowing by name because each one is now the cheapest possible way to make an argument for that control in a planning meeting.

CaseWhat happenedThe control that was missing
Mata v. Avianca, June 2023A New York lawyer filed a brief citing six decisions that did not exist. Asked to confirm them, the model produced full texts for them as well. The court fined the lawyers and their firm $5,000.Row 3 with nothing checked. Anything checkable gets checked in code — a citation exists or it does not.
Moffatt v. Air Canada, Feb 2024The airline’s chatbot described a bereavement-fare refund policy that contradicted the airline’s own published page. The tribunal ordered Air Canada to pay, and rejected the argument that the chatbot was a separate legal entity.Row 8. The correct policy was on the same website and was never retrieved into the prompt.
CNET, January 2023Seventy-seven AI-assisted personal-finance articles were published quietly. Reviewers found errors in the compound-interest examples; corrections went onto dozens of them and the programme was paused.Row 9. Numbers were predicted as text. Arithmetic belongs in code the model calls, not in the answer it writes.
Samsung, May 2023Engineers pasted internal source code into a public chatbot to get help with it. The company banned generative AI tools on company-owned devices shortly afterwards.Not a model failure at all. A prompt is an outbound request: decide what may leave the building before people need to be told.
Stack Overflow, December 2022The site banned generated answers within weeks of ChatGPT’s release, on the stated grounds that they were plausible often enough to be expensive to moderate and wrong often enough to be harmful.The cost of row 3 at scale. Confidence is not a signal, so volume without verification moves work onto whoever checks it.

What it costs once real traffic arrives

Model choice is a range, not a decision made once. Providers ship a capable tier and a cheap fast tier, and the useful habit is to prove the task is possible on the strongest model available, then try to walk down the range with a fixed set of test cases in hand. Without that set you are not choosing a model, you are guessing at one — and the cheaper model will look fine on the three examples you happen to try.

The cost line on an LLM feature is almost always tokens per request multiplied by requests, and the term that grows unnoticed is the first one. Prompts accumulate: an instruction added after each incident, a longer example, three more retrieved documents, and the conversation history under all of it. Log the token counts of every call from the first day, alongside latency — it is the only way to see the growth, and it turns a vague "the AI feature got expensive" into a specific prompt you can trim.

A model call is made of two parts that behave completely differently. The prompt is processed in one pass, so time to the first token is roughly fixed and barely moves with prompt length; everything after it is one pass per token written, so it is proportional to how much the model was asked to write. The three bars share a scale, which makes the consequence unmissable: a slow response is almost always a long one. Two things follow for a product. Stream the answer so the reader sees progress instead of a spinner, and when you want lower latency ask for shorter output, because that is the variable that moves it — a faster network or a bigger instance touches only the small fixed segment.

Latency behaves unlike any other dependency you have. Time to the first token is roughly fixed, and everything after it is proportional to how much the model writes — so a request that produces a long answer is slow because it is long, and no amount of infrastructure tuning changes that. Two things follow: stream the response so the user sees progress instead of a spinner, and ask for shorter output when you actually want lower latency, because that is the variable that moves it.

Treat the provider as what it is: a third-party dependency with rate limits and an availability record you do not control. Every call needs a timeout and a retry with , because a hung request holds a connection far longer than any database would. And decide in advance what the feature does when the model is unavailable, since "the page hangs" is a decision too, just not one anybody made.

Where it degrades

Everything above describes a component that generates plausible text and does nothing else. The honest limit of that component is easy to state and hard to accept: there is no configuration, no prompt and no model version that makes a generated answer self-verifying. Every arrangement below is an attempt to skip that fact, and each one fails in a way the twelve rows already predicted.

  • Treating the model as a knowledge base about your own product, instead of putting your documents into the prompt.
  • Tests that assert an exact response string, which fail on a change of sampling rather than a change of behaviour.
  • A timestamp or request id at the top of the system prompt, which invalidates the prompt cache on every call.
  • Raising the temperature to make answers "smarter", when it only makes unlikely tokens more likely.
  • Letting a chat grow until a library silently truncates the beginning, taking the system instructions with it.
  • Filling a huge context window because it exists, paying for tokens that make the answer worse rather than better.
  • Sizing a Ukrainian feature on English token counts, so the window and the budget are both wrong by a factor of two.
  • Treating a refusal as a security control, when it is learned behaviour that a rephrase can walk around.
  • Shipping without token and latency metrics, so the first sign of a problem is the invoice.

When to use it

Use it when

  • Work on text where a good answer has many valid forms — summarising, rewriting, classifying, extracting structure from prose.
  • Interfaces where the input is genuinely open-ended and a form with fields would be the wrong shape.
  • Tasks whose output a person reviews before it takes effect, so a wrong answer is caught rather than acted on.
  • Problems where writing the rules explicitly would take longer than showing the model what good output looks like.

Avoid it when

  • Anything requiring an exact, auditable answer — arithmetic, totals, eligibility rules. Call code for those and let the model call the code.
  • Facts about your own domain with nothing retrieved into the prompt, where confident invention is the expected outcome.
  • Paths where a wrong answer acts immediately and irreversibly — payments, deletions, outbound messages — without a human gate.
  • High-volume, low-value calls where a rule, a lookup table or a small classifier does the same job for a thousandth of the cost.

Sources and method

What this page stands on

  • 8 sources
  • 5 documented failures
  • Checked October 13, 2026

Researched with Claude. Finding and cross-checking the primary sources was done with Claude (Anthropic). Selection, writing and fact-checking: the Anatomy of IT Product editors.

Found this useful?

Share it with someone who is working on the same problem.