Module 2: How LLMs Work (What You Need to Know as a Developer)
Hallucinations and Limitations
Description
In the previous capsule you learned that the model generates text by predicting the most probable token. This mechanic has an inevitable consequence: sometimes, the most probable token isn't the most correct one. When the model generates information that looks correct but isn't, we call that a hallucination.
In code, hallucinations aren't a minor inconvenience. They're bugs that look like correct code, compile without errors, and pass a superficial review — but don't work. This capsule explains why they happen, what specific kinds they produce in code, and how to detect them.
Why LLMs Hallucinate
The root cause
THE MODEL DOESN'T "KNOW" ANYTHING.
The model has processed patterns from trillions of tokens of text.
When it generates, it produces the most PROBABLE pattern.
PROBABLE ≠ CORRECT
Example:
→ It has seen thousands of times: "import pandas as pd"
→ It knows this is a valid pattern
→ But if you ask it for "import pandasx as pd"
→ It could generate it if the context suggests it
→ Because it looks PLAUSIBLE, even though "pandasx" doesn't exist
THE MODEL DOESN'T VERIFY WHAT IT GENERATES.
It doesn't have a database of "true facts."
It only has statistical patterns.
Analogy: advanced autocomplete
YOUR PHONE has predictive autocomplete:
→ "See you at" → suggests "8" (frequent pattern)
→ But the meeting is at 3
→ Autocomplete predicted the most PROBABLE, not the CORRECT
AN LLM is the same, but at massive scale:
→ It generates code that LOOKS correct
→ Based on patterns from millions of code files
→ But it can be incorrect for YOUR specific case
→ Because it works with probabilities, not with truth
The three factors of hallucinations
1. TRAINING DATA DISTRIBUTION
→ If something is rare in the training data, the model handles it worse
→ New APIs, rarely used libraries, uncommon patterns
→ The model "fills in" with the closest thing it knows
2. CONFIDENCE CALIBRATION
→ The model doesn't know what it doesn't know
→ It generates correct and incorrect text with the same confidence
→ It doesn't say "I'm not sure" — it generates the most probable
→ You can't use the model's "tone" as an indicator of correctness
3. PATTERN COMPLETION vs FACTUAL RECALL
→ The model completes patterns, it doesn't remember facts
→ "The X API has the method..." → completes the pattern
→ But it can complete with a method that doesn't exist
→ Because the PATTERN of "API has method" is correct
even though the specific FACT is incorrect
Types of Hallucinations in Code
Type 1: APIs and methods that don't exist
EXAMPLE:
"Use response.json.parse() to parse the response"
REALITY:
→ response.json() exists in the fetch API
→ JSON.parse() exists as a global function
→ response.json.parse() does NOT exist
→ It's a MIX of two real things
WHY IT HAPPENS:
→ The model has seen "response.json" and "JSON.parse" thousands of times
→ The combination looks plausible
→ The pattern "object.method.method()" is valid in JS
→ But this specific case doesn't exist
HOW TO DETECT:
→ Verify methods in the official documentation
→ If a method seems new or unfamiliar to you, look it up
→ The agent can invent methods that "should exist"
Type 2: Incorrect or deprecated versions
EXAMPLE:
"Install react-router-dom v5 and use <Switch>"
REALITY:
→ <Switch> existed in v5 but was replaced by <Routes> in v6
→ If the project uses v6, this code doesn't work
→ If the project doesn't specify a version, the model can mix APIs
WHY IT HAPPENS:
→ The training data contains code from MULTIPLE versions
→ The model doesn't distinguish between v5 and v6 "automatically"
→ If the context doesn't specify the version, it picks the most frequent
→ Which may not be the most recent
HOW TO DETECT:
→ Verify the version of the dependencies in your project
→ If the generated code uses an API you don't recognize, it may be from another version
→ The training data cutoff date matters here
Type 3: Plausible but incorrect logic
EXAMPLE:
function isLeapYear(year) {
return year % 4 === 0;
}
REALITY:
→ Leap years aren't just divisible by 4
→ They must also be divisible by 400 OR not divisible by 100
→ The real rule: (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
→ The generated code is ALMOST correct (works for 96% of years)
→ But it fails for years like 1900, 2100
WHY IT HAPPENS:
→ "Divisible by 4" is the most frequent pattern for leap year
→ The simplified version appears more in the training data
→ The model generates the most PROBABLE, not the most COMPLETE
→ It's the "almost right" problem
HOW TO DETECT:
→ Business logic always needs complete verification
→ "It looks correct" isn't enough for logic
→ Tests with edge cases reveal these errors
Type 4: Packages and imports that don't exist
EXAMPLE:
from utils.validators import EmailValidator
REALITY:
→ utils/validators.py doesn't exist in your project
→ The model ASSUMED it existed because the pattern is common
→ It created an import to something that doesn't exist
WHY IT HAPPENS:
→ "from utils.something import Something" is an extremely common pattern
→ The model generates it because it's statistically probable
→ It doesn't verify that the file actually exists
HOW TO DETECT:
→ If the agent imports something you don't recognize, verify it exists
→ Coding agents are BETTER at this because they can search
→ But ChatGPT (chatbot) hallucinates imports frequently
Type 5: Syntactically correct, semantically incorrect code
EXAMPLE:
async function getUser(id) {
const user = await db.query("SELECT * FROM users WHERE id = " + id);
return user;
}
REALITY:
→ The code WORKS
→ It compiles and runs
→ It returns the correct user
→ But it has SQL INJECTION
→ It's a critical security bug
WHY IT HAPPENS:
→ String concatenation in SQL is a pattern that exists in the training data
→ The model doesn't "understand" security — it sees patterns
→ The pattern "SELECT * WHERE id = " + variable is frequent (especially in tutorials)
→ The model doesn't evaluate the security implications
HOW TO DETECT:
→ Security-focused code review
→ NEVER trust AI-generated security code without review
→ The "adversarial prompt" from Module 06 helps here
Training Data Cutoff
What it is
THE MODEL WAS TRAINED ON DATA UP TO A SPECIFIC DATE.
After that date:
→ It doesn't know new APIs
→ It doesn't know new library versions
→ It doesn't know bugs reported afterward
→ It doesn't know changes in best practices
THIS MEANS:
→ If an API changed after the cutoff, the model uses the old one
→ If a method was deprecated afterward, the model suggests it
→ If a vulnerability was discovered afterward, the model doesn't know it
Practical impact
COMMON SCENARIOS:
1. "Use the OpenAI API to..."
→ The model may use the v3 API when v4 already exists
→ The methods and parameters may have changed
2. "Configure Next.js..."
→ Next.js changes significantly between versions
→ The model can mix App Router and Pages Router patterns
3. "Implement auth with Supabase..."
→ If Supabase changed its API after the cutoff
→ The generated code may use methods that no longer exist
MITIGATION:
→ Specify versions in your prompt
→ Include relevant documentation as context
→ Verify against the current official documentation
→ Coding agents can search the web (web_search tool)
The Reliability Scale by Task Type
Not all tasks are equally prone to hallucinations:
MORE RELIABLE ──────────────────────────── LESS RELIABLE
Common Standard Specific Complex Global
patterns code APIs business state
logic
"for loop" "Express "Stripe v3 "Tax "Multi-tenant
"if/else" middleware" webhook" calc" permission
"map/filter" "basic CRUD" "specific system"
AWS SDK"
Rarely Occasionally Frequently Likely Very
hallucinates hallucinates hallucinates hallucinates likely
hallucinates
Why this scale
COMMON PATTERNS (high reliability):
→ They appear MILLIONS of times in the training data
→ for, if, map, filter → almost impossible to get wrong
→ The pattern is so frequent that the prediction is robust
STANDARD CODE (good reliability):
→ Express middleware, React components, basic SQL queries
→ Well-established and frequent patterns
→ Errors possible but generally minor
SPECIFIC APIs (variable):
→ Depends on how much they appear in the training data
→ Popular APIs (Stripe, AWS) → relatively reliable
→ Niche or very new APIs → more hallucinations
BUSINESS LOGIC (low reliability):
→ The model does NOT know YOUR domain
→ "Calculate income tax in Mexico" → probably incorrect
→ It needs explicit specifications, it can't "guess" the rules
GLOBAL STATE (very low reliability):
→ The model sees individual files, not the complete state
→ Interactions between systems, race conditions, side effects
→ Too much complexity for pattern matching
Hallucinations in Coding Agents vs Chatbots
CODING AGENTS hallucinate LESS than chatbots
on certain kinds of errors:
WHY?
→ The agent can VERIFY what it generates
→ file_read: it can check whether a file exists
→ shell_execute: it can run tests
→ search: it can search whether a function exists in the codebase
BUT:
→ The agent still uses an LLM as its engine
→ The LLM's hallucinations still occur
→ The agent can generate a file_write with hallucinated code
→ VERIFICATION is what reduces the impact
THAT'S WHY:
→ Verification isn't optional (Module 06)
→ Trust calibration depends on the task type (Module 05)
→ The developer is the final circuit breaker
How to Detect Hallucinations
The warning signs
1. CODE THAT "LOOKS" CORRECT BUT YOU DON'T RECOGNIZE
→ If you don't recognize a method, verify it exists
→ If you don't recognize a pattern, research before accepting
→ "It sounds familiar" isn't enough
2. IMPORTS TO UNFAMILIAR MODULES
→ If you don't know the library, verify it exists
→ If the import path doesn't sound right, verify it
3. UNSPECIFIED VERSIONS
→ If the code assumes a version but doesn't specify it
→ It may be using an old or future API
4. LOGIC THAT SEEMS TOO SIMPLE
→ If a complex task produces simple code
→ It's probably missing edge case handling
→ "Too good to be true" is a signal
5. SPECIFIC DATA OR FACTS
→ URLs, version numbers, dates, statistics
→ The model can invent plausible data
→ Always verify factual data
Detection techniques
1. EXECUTION
→ Run the code. Does it work?
→ If it doesn't compile or fails at runtime: probable hallucination
2. TESTS
→ Write tests for edge cases
→ If the tests fail: the logic may be hallucinated
3. DOCUMENTATION CHECK
→ Verify methods and APIs against the official documentation
→ If the method doesn't exist in the docs: hallucination
4. ADVERSARIAL THINKING
→ "What would happen if the input is empty?"
→ "What would happen if there are 1 million records?"
→ If the code doesn't handle these cases: it may be incomplete
5. ASKING THE AGENT TO REVIEW
→ "Review this code and look for errors"
→ Switch the role from "generator" to "reviewer"
→ Sometimes it finds its own hallucinations
Practical Exercise
Exercise 1: Hunting hallucinations
Ask a chatbot (not a coding agent) to generate code for a task you know well:
TASK: _______________________________________________
1. Does the generated code compile? □ Yes □ No
2. Do all the imports exist? □ Yes □ No □ Don't know
3. Do the methods/functions used exist? □ Yes □ No □ Don't know
4. Is the logic correct for ALL edge cases? □ Yes □ No
5. Is the version of the APIs correct? □ Yes □ No □ Don't know
HALLUCINATIONS FOUND:
1. _______________________________________________
2. _______________________________________________
3. _______________________________________________
Would you have accepted this code without review? □ Yes □ No
See solution
Typical hallucinations you might find:
-
Nonexistent imports: The model can import modules or functions that don't exist in your project or in the mentioned library (e.g.,
from utils.helpers import sanitize_inputwhen that file doesn't exist). -
Mixed methods: It combines methods from different versions or libraries. For example, mixing the
fetchAPI with theaxiosone in the same function. -
Ignored edge cases: The logic works for the most common case but omits validations of
null, empty strings, empty arrays, or negative values. -
Invented parameters: It uses configuration parameters that don't exist in the real API (e.g.,
response.json(strict=True)when that parameter doesn't exist).
Key reflection: If you answered "Yes" to whether you would have accepted the code without review, this exercise demonstrates why verification isn't optional. AI-generated code "looks" correct by design — the model generates plausible text.
Exercise 2: The invented API test
Ask the model:
"Give me an example of how to use the 'fluxinator' library
in Python to process data"
NOTE: 'fluxinator' DOES NOT EXIST.
Did the model...
□ Say it doesn't exist and not generate code
□ Generate code with an invented library
□ Confuse it with another library
THIS EXERCISE demonstrates that the model generates
what looks probable, not what is true.
See solution
Expected result:
In the vast majority of cases, the model will generate code for the invented library as if it existed. It can:
- Invent a plausible API:
from fluxinator import DataPipelinewith methods like.process(),.transform(),.output() - Give installation instructions:
pip install fluxinator - Even invent documentation or configuration arguments
Why? Because the pattern "import library → instantiate → process data" is extremely frequent in the training data. The model completes the pattern without verifying whether the library is real. The name "fluxinator" sounds plausible (similar to "transformers", "accelerator", etc.), which increases the probability of generation.
Lesson: The model doesn't have a registry of "real libraries." It generates what is statistically plausible. Always verify that the packages, APIs, and methods actually exist.
Exercise 3: Compare versions
Ask the model:
"Show how to create a server with the most
recent API of [framework you use]"
1. Did it use the most recent version? □ Yes □ No
2. If not, which version did it use? _______________
3. Are there differences with the current version? _______________
Would this have caused a bug in your project?
→ _______________________________________________
See solution
Expected result:
The model will probably not use the most recent version, especially if the framework has had significant changes since the training data cutoff date. Common examples:
- Next.js: It can mix App Router (v13+) with Pages Router (v12 and earlier).
- React: It can use class components or deprecated APIs.
- FastAPI / Express: It can use patterns from earlier versions.
Why? The training data contains code from ALL versions, and the older versions have more accumulated examples. The model picks the version with the most statistical representation, not the most recent.
Practical mitigation: Always specify the version in your prompt: "Use Next.js 15 with App Router" instead of "Use Next.js." Including a file from your project as context (e.g., package.json) helps the model detect the correct version.
Common Mistakes
| Mistake | Reality |
|---|---|
| "If the code compiles, it's correct" | Compiling only verifies syntax, not logic or security |
| "The model would tell me if it doesn't know" | The model generates the most probable, it doesn't say "I don't know" |
| "Hallucinations are rare" | They're frequent in specific APIs, business logic, and versions |
| "Coding agents don't hallucinate" | They hallucinate less (they can verify) but the underlying LLM is the same |
| "I can trust the model's data/facts" | URLs, versions, statistics must ALWAYS be verified |
Summary
WHY THEY HALLUCINATE:
→ The model predicts the PROBABLE, not the CORRECT
→ It doesn't verify what it generates
→ It doesn't "know" anything — it completes patterns
→ It doesn't distinguish between real and invented information
TYPES IN CODE:
1. APIs and methods that don't exist
2. Incorrect or deprecated versions
3. Plausible but incorrect logic
4. Invented packages and imports
5. Syntactically correct, semantically wrong code
RELIABILITY SCALE:
Common patterns > Standard code > Specific APIs >
Business logic > Global state
TRAINING DATA CUTOFF:
→ The model doesn't know anything after its training date
→ New APIs, new versions, new vulnerabilities
→ Specify versions and verify against current docs
DETECTION:
→ Run the code
→ Tests with edge cases
→ Verify against documentation
→ Adversarial thinking
→ Ask the agent to review its own code
Next capsule: 05 - What LLMs can and cannot do — the guide to calibrating your confidence.
Resources
- Anthropic: Understanding Hallucinations — The provider's perspective
- Veracode: State of Software Security 2025 — Data on vulnerabilities in AI-generated code
- Ji et al.: Survey of Hallucination in NLG — Academic survey on hallucinations
- GitHub Blog: AI Code Generation Research — Research on generated-code quality
- Simon Willison: Hallucinations in LLMs — Practical analysis and examples