Quick answer
An AI NPC should not remember everything the player has ever said.
A better memory architecture separates information by purpose:
recent conversation → current-session state → structured long-term facts → retrieved relevant memories → current game state
Then, before the AI generates a response, the game provides only the memories relevant to the current situation.
A useful architecture looks like:
player interaction → identify memory candidates → score importance → store selected facts → retrieve relevant memories later → combine with current game state → generate response
This approach keeps prompts smaller, reduces inference cost, makes characters easier to debug, and prevents years of accumulated dialogue from overwhelming the model.
Real game systems are already moving toward this pattern. KRAFTON’s 2026 PUBG Ally implementation uses short-term memory for the current match and structured long-term memory across matches, storing information such as player preferences, shared personal details and prior match history.
The lesson is simple:
Good NPC memory is selective memory.
What does “memory” actually mean for an AI NPC?
Suppose the player meets our fictional merchant from the previous Blinkcade guide:
Mara Venn
During the first conversation, the player says:
“I’m Alex. I usually carry a pulse rifle.”
Ten minutes later:
“Have you found anything I’d like?”
Tomorrow, after starting the game again:
“Do you remember me?”
Those three interactions require several different kinds of memory.
The NPC needs to remember that:
the player’s name is Alex
and:
Alex prefers pulse rifles.
But it probably does not need to permanently remember:
Player said “thanks” at 8:42 PM.
That distinction is the foundation of a useful AI memory system.
The four memory layers I recommend
For most games, divide NPC memory into four layers:
1. WORKING MEMORY
Recent conversation
2. SESSION MEMORY
Important current-session events
3. LONG-TERM MEMORY
Persistent structured facts
4. WORLD STATE
Canonical facts owned by the game
They are not interchangeable.
1. Working memory: what just happened
Working memory gives the NPC enough recent context to understand the current conversation.
For example:
Player:
Who owns the refinery?
Mara:
Voss Industries.
Player:
Do you trust them?
The phrase:
“them”
only makes sense if Mara remembers the previous turn.
You might send the last:
4–12 dialogue turns
depending on your game.
Conceptually:
{
"recentConversation": [
{
"speaker": "player",
"text": "Who owns the refinery?"
},
{
"speaker": "mara",
"text": "Voss Industries."
},
{
"speaker": "player",
"text": "Do you trust them?"
}
]
}
This memory should usually be temporary.
Once that conversation is no longer active, there is little reason to keep every sentence in the model context forever.
Current model APIs can support persistent conversational state if you want it. OpenAI’s Conversations API, for example, allows applications to maintain durable conversation objects across sessions, devices or jobs.
But persistent conversation storage and good game memory design are different problems.
Just because you can save every turn doesn’t mean you should feed every turn back into the NPC forever.
2. Session memory: what matters right now
Session memory stores significant things that happened during the current game session.
Example:
The player:
- rescued Mara from raiders
- told her they work for the resistance
- purchased a thermal cloak
- threatened one of her friends.
A session-memory record could be:
{
"sessionMemories": [
{
"type": "event",
"key": "rescued_mara",
"value": true
},
{
"type": "affiliation",
"key": "player_claimed_faction",
"value": "resistance"
},
{
"type": "purchase",
"item": "thermal_cloak"
}
]
}
These facts may affect Mara’s behavior immediately.
For example:
“You already bought the cloak. Don’t tell me you lost it.”
That feels like memory.
But we’re not replaying an entire transcript.
We’re storing meaningful state.
3. Long-term memory: what survives between sessions
Long-term memory should contain information that remains useful tomorrow, next week or 30 hours later.
Examples:
{
"playerName": "Alex",
"preferredWeapon": "pulse_rifle",
"relationship": 0.73,
"helpedMara": true,
"betrayedSmuggler": false,
"favoriteDropLocation": "Old Harbor"
}
This closely resembles the approach NVIDIA describes for PUBG Ally: structured long-term memory stores player profile information, preferences and prior match history, while short-term memory tracks the current match.
Notice that these aren’t full transcripts.
They’re facts.
That’s usually the right design.
4. World state is not NPC memory
This distinction is critical.
Suppose:
The bridge was destroyed.
The mayor is dead.
Quest 14 is complete.
Player has 82 credits.
Those are not memories the language model should own.
They are canonical game state.
The game database should supply those facts when they’re relevant.
Why?
Because game state needs to be:
deterministic
authoritative
debuggable
consistent across systems.
If the mayor dies, the game knows the mayor is dead.
You don’t want Mara “remembering” that the mayor is alive because an old dialogue chunk was retrieved.
So the prompt may include:
{
"currentWorldState": {
"mayorAlive": false,
"northBridge": "destroyed"
}
}
The current game state always outranks an old memory.
Step 1: Extract memory candidates
Suppose the player says:
“My name’s Alex. I can’t stand plasma rifles. Give me a pulse rifle whenever you see one.”
The NPC system can extract possible memories:
[
{
"type": "identity",
"key": "player_name",
"value": "Alex"
},
{
"type": "preference",
"key": "weapon_dislike",
"value": "plasma_rifle"
},
{
"type": "preference",
"key": "weapon_preference",
"value": "pulse_rifle"
}
]
Now evaluate whether they deserve storage.
Don’t blindly persist every sentence.
Step 2: Score memory importance
Give each candidate a usefulness score.
For example:
0.0 = irrelevant
1.0 = extremely important
Possible criteria:
Identity
Player name:
0.95
Preference
Favorite weapon:
0.75
Major relationship event
Player saved NPC:
0.95
Ordinary dialogue
Player said hello:
0.05
Temporary observation
Player is standing near a door:
0.01
Then:
if (memory.importance >= 0.6) {
longTermMemory.store(memory);
}
The threshold can vary by memory type.
This gives your system a mechanism for forgetting by default.
That is desirable.
Step 3: Store structured facts when possible
Compare two approaches.
Transcript memory
"Yesterday Alex told Mara that he prefers pulse rifles because
plasma weapons remind him of an accident at Ceres Station..."
versus:
Structured memory
{
"subject": "player",
"type": "weapon_preference",
"value": "pulse_rifle",
"confidence": 0.92,
"source": "player_statement"
}
The second representation is:
- easier to query
- cheaper to store in context
- easier to update
- easier to invalidate
- easier to test.
You can still keep original text as provenance if useful.
But the game’s operational memory should usually be structured.
Step 4: Store episodic memories separately
Some experiences don’t fit neatly into a key/value pair.
For example:
Alex and Mara escaped the refinery together while Mara was injured.
That’s a narrative event.
You might store:
{
"id": "memory_0182",
"type": "episodic",
"summary": "Alex helped Mara escape the refinery after she was wounded.",
"participants": ["player", "mara"],
"location": "voss_refinery",
"emotionalWeight": 0.88,
"timestamp": 184382,
"importance": 0.91
}
Later Mara might say:
“After what happened at the refinery, I know I can trust you.”
That’s far more convincing than random generated nostalgia because it points to an actual game event.
Step 5: Retrieve memories instead of dumping them all into the prompt
Suppose Mara has accumulated:
1,500 memories.
The player says:
“What weapon do you think suits me?”
Don’t send all 1,500.
Retrieve memories related to:
player + weapons + preferences.
A semantic retrieval system can help here.
Semantic search uses embeddings to find information that is conceptually relevant even if it doesn’t use the same keywords.
Your game doesn’t have to use OpenAI’s retrieval implementation specifically.
The architecture is what matters:
Player message
↓
Create memory query
↓
Retrieve top relevant memories
↓
Filter by validity
↓
Add only selected memories to context
For example:
{
"retrievedMemories": [
{
"type": "weapon_preference",
"value": "pulse_rifle"
},
{
"type": "episodic",
"summary": "Alex disliked the recoil of a heavy railgun during training."
}
]
}
Now Mara has just enough memory to answer.
Step 6: Filter retrieval using metadata
Semantic similarity alone isn’t enough.
Imagine the game contains memory for:
Mara
Kai
Juno
three different players
multiple campaign saves.
You need filters.
A memory record might include:
{
"npcId": "mara",
"playerId": "player_481",
"campaignId": "campaign_12",
"type": "preference",
"createdAt": 184382
}
Then retrieve only memories where:
npc = mara
AND
player = player_481
AND
campaign = campaign_12
The principle is useful even if you use your own database.
Semantic relevance + deterministic filters is safer than semantic similarity alone.
Step 7: Handle contradictory memories
Players change.
Suppose Alex says early in the game:
“I love pulse rifles.”
Later:
“I’ve switched to shotguns. Pulse rifles feel weak now.”
Do not keep both as equally current facts.
Possible record:
{
"type": "weapon_preference",
"value": "shotgun",
"supersedes": "memory_102",
"updatedAt": 293840
}
Or maintain:
{
"weaponPreference": {
"value": "shotgun",
"confidence": 0.91,
"updatedAt": 293840
}
}
Memories require lifecycle rules.
Otherwise your NPC becomes a database of contradictions.
Step 8: Add confidence
Not every statement is trustworthy.
Player says:
“I’m the emperor.”
Should Mara permanently believe:
{
"player_is_emperor": true
}
Probably not.
Record source and confidence:
{
"claim": "player_is_emperor",
"value": true,
"source": "player_statement",
"confidence": 0.2
}
Compare:
{
"claim": "player_is_resistance_member",
"value": true,
"source": "verified_quest_event",
"confidence": 1.0
}
The game can distinguish:
what the player claimed
from:
what the game knows.
That’s extremely useful for roleplaying characters.
Mara might say:
“You say you’re the emperor. Sure.”
rather than treating the statement as canon.
Step 9: Give memories emotional weight
Not all experiences matter equally.
Imagine:
Event A
Player bought a health potion.
Event B
Player rescued Mara’s daughter.
Both are technically events.
They should not carry equal weight.
Store something like:
{
"importance": 0.97,
"emotionalValence": 0.92,
"relationshipImpact": 0.85
}
Now retrieval can prioritize:
importance
alongside:
semantic similarity
and:
recency.
A useful conceptual score might be:
memory score =
semantic relevance
× importance
× validity
× recency modifier
You don’t need that exact formula.
But you need an explicit policy for why one memory appears and another does not.
Step 10: Forget things
Perfect memory is not necessarily believable.
Humans forget.
Characters can too.
You might define:
Permanent memories
major story events
identity
important relationships.
Slow-decay memories
preferences
ordinary interactions.
Session-only memories
temporary objectives.
Immediate-only memories
conversation wording.
For example:
player_name
→ permanent
saved_maras_daughter
→ permanent
favorite_drink
→ slow decay
player_said_good_morning
→ discard
Forgetting also saves money and reduces retrieval noise.
Step 11: Summarize old episodes
Suppose Mara and Alex have interacted 47 times.
Instead of storing:
47 verbose scenes,
you might periodically summarize:
Alex and Mara have developed a strong working relationship.
Alex has repeatedly helped Mara with smuggling problems.
Mara trusts Alex but remains uncomfortable discussing her family.
Keep the major episodic events separately.
This gives the model a high-level relationship picture without needing the entire history.
Step 12: Never let memory override authoritative game state
Suppose memory says:
Mara believes Alex owns a thermal cloak.
But the player sold it.
Current inventory says:
{
"thermal_cloak": false
}
Current state wins.
The model prompt should separate:
CURRENT VERIFIED STATE
Player does not own Thermal Cloak.
NPC MEMORY
Mara remembers selling Alex a Thermal Cloak previously.
Now she can naturally say:
“Didn’t I sell you a cloak already?”
without incorrectly claiming:
“You’re wearing the cloak I sold you.”
Memory is perspective.
Game state is reality.
That distinction produces better characters.
Step 13: Build memory as a game mechanic
Memory shouldn’t exist merely to impress players technically.
Use it to create gameplay.
Examples:
Merchant
Remembers what you buy.
Companion
Learns preferred tactics.
Rival
Remembers defeats.
Guard
Remembers suspicious behavior.
Villager
Remembers whether you helped their family.
Quest giver
References previous solutions.
The PUBG Ally example is particularly interesting because memory affects practical cooperation: NVIDIA describes the companion remembering preferred weapons and favorite landing locations across matches and then acting on those preferences without needing to be reminded.
That’s more valuable than:
“Remember when we talked yesterday?”
The memory changes behavior.
Step 14: Keep memory explainable
When Mara says something surprising, developers need to know:
Why did she say that?
Log:
{
"interaction": "mara_992",
"retrievedMemoryIds": [
"memory_103",
"memory_188"
],
"currentStateVersion": 42,
"generatedResponse": "I saved a pulse rifle for you."
}
Then, during QA, you can inspect:
Memory 103:
Alex prefers pulse rifles.
Memory 188:
Mara promised to watch for one.
Now the behavior is explainable.
Without this, debugging AI character behavior becomes guesswork.
A practical memory schema
Here’s a reasonable starting point:
interface NPCMemory {
id: string;
npcId: string;
playerId: string;
campaignId: string;
type:
| "identity"
| "preference"
| "relationship"
| "event"
| "claim"
| "promise";
summary: string;
structuredData?: Record<string, unknown>;
importance: number;
confidence: number;
emotionalWeight?: number;
relationshipImpact?: number;
createdAt: number;
updatedAt: number;
expiresAt?: number;
supersedes?: string;
source:
| "player_statement"
| "npc_observation"
| "verified_game_event";
}
That’s far better than a table containing:
NPC CHAT LOG
and nothing else.
The complete NPC memory request
Before model inference:
{
"character": {
"name": "Mara",
"role": "merchant"
},
"currentState": {
"location": "Blackwater Market",
"playerCredits": 83
},
"recentConversation": [
"..."
],
"sessionMemory": [
"Player visited the Frozen Relay."
],
"retrievedLongTermMemory": [
"Player prefers pulse rifles.",
"Mara promised to save one for the player."
]
}
Then the AI has:
who it is
what is happening
what just happened
what matters from the past.
That’s enough.
Memory and cost
Memory increases context.
Context increases processing.
So the naive architecture:
send complete player history every turn
will scale poorly.
Imagine:
100 NPC conversations
×
5,000 tokens of history
versus:
100 NPC conversations
×
500 tokens of retrieved memory
The exact costs depend on your chosen provider/model.
But the direction is obvious.
Selective memory reduces:
- latency
- token usage
- irrelevant context
- contradictions.
This is one reason retrieval architectures are useful.
Memory and latency
Retrieval itself also costs time.
Your pipeline may become:
player speaks
↓
extract intent
↓
query memory database
↓
retrieve records
↓
build context
↓
model inference
↓
response
So measure each stage.
For example:
{
"memoryRetrievalMs": 28,
"contextBuildMs": 3,
"modelLatencyMs": 410,
"totalLatencyMs": 441
}
If memory retrieval takes:
800 ms
you have a problem.
Don’t optimize blindly.
Instrument the pipeline.
What real games are doing
PUBG Ally provides an unusually useful public example.
According to KRAFTON’s discussion with NVIDIA, the AI teammate uses structured memory across two timescales:
Short-term memory
recent speech and events inside the current match.
Long-term memory
player profile information and cross-match history, including:
- player name
- preferred weapons
- favorite drop locations
- personal details
- match outcomes
- notable shared moments.
That’s remarkably close to the architecture I’d recommend.
It also reinforces an important design lesson:
Memory becomes compelling when it changes future behavior.
What RAG is—and what it isn’t
You will often hear:
RAG
or:
retrieval-augmented generation
discussed alongside memory.
RAG means retrieving relevant information from an external knowledge source before generating an answer.
But remember:
world knowledge retrieval
and:
personal NPC memory
are related but different.
Mara retrieving:
the history of Blackwater Market
is world knowledge.
Mara retrieving:
Alex prefers pulse rifles
is personal memory.
They may use similar retrieval technology.
They should live in different logical systems.
The Blinkcade NPC memory architecture
Put everything together:
PLAYER MESSAGE
↓
RECENT CONVERSATION
↓
CURRENT GAME STATE
↓
MEMORY QUERY
↓
┌──────────────────────────┐
│ SESSION MEMORY │
│ STRUCTURED FACTS │
│ EPISODIC MEMORY │
│ RELATIONSHIP STATE │
└──────────────────────────┘
↓
FILTER + RANK
↓
SELECT TOP RELEVANT MEMORIES
↓
NPC AI MODEL
↓
DIALOGUE / INTENT
↓
VALIDATED GAME ACTION
↓
MEMORY CANDIDATE EXTRACTION
↓
STORE / UPDATE / DISCARD
Memory is a cycle.
Characters:
remember
and:
form new memories.
AI NPC memory QA checklist
Before shipping, test:
Identity
Does the NPC remember the player’s name?
Preference
Does a changed preference supersede the old one?
Session boundary
Does persistent memory survive restart?
Forgetting
Do trivial memories disappear?
Contradiction
Does current game state override stale memory?
Retrieval
Does the right memory appear when relevant?
Isolation
Can one player’s memory leak into another player’s account?
NPC isolation
Can Mara accidentally retrieve Kai’s memories?
Campaign isolation
Do New Game saves remain separate?
False claims
Does player dialogue become “truth” automatically?
Cost
How much additional context does memory add?
Latency
How long does retrieval take?
Explainability
Can developers see which memories influenced a response?
If you cannot answer those questions, the memory system isn’t finished.
Common AI NPC memory failures
NPC forgets everything between conversations
Cause: only recent chat context exists.
Fix: structured persistent memory.
NPC remembers too much
Cause: full chat history is continually replayed.
Fix: extraction + relevance retrieval.
NPC contradicts itself
Cause: old facts aren’t superseded.
Fix: version/update memory.
NPC believes player lies
Cause: player statements become verified facts.
Fix: source + confidence tracking.
NPC remembers something that no longer exists
Cause: memory overrides world state.
Fix: current game state remains authoritative.
NPC feels creepy
Cause: trivial personal details are stored and surfaced unnecessarily.
Fix: deliberately define what your game should remember.
More memory does not automatically equal a better character.
Blinkcade verdict
The right way to give an AI NPC memory is not:
Save every conversation forever.
It’s:
Turn important experiences into structured, retrievable game knowledge.
For Mara:
Player says something
↓
Memory system identifies useful facts
↓
Important memories are stored
↓
Old or contradictory memories are updated
↓
Later conversation triggers retrieval
↓
Only relevant memories enter the AI context
↓
Mara responds using past experience + current reality
The best NPC memory architecture has three qualities.
Selective
It remembers what matters.
Grounded
Current game state always remains authoritative.
Behavioral
Memories influence what the NPC does—not merely what it says.
That’s where AI NPC memory becomes more than a novelty.
A companion that remembers your favorite weapon and brings it to you later feels meaningfully different from a chatbot that merely says:
“I remember you.”
The first creates gameplay.
The second creates a demo.
If you’re building AI-driven characters, design memory as a game system first and an LLM context system second.
That’s the difference between a character that stores history and a character that actually seems to have lived through it.
Sources & verification
- NVIDIA — How KRAFTON Built PUBG Ally: https://developer.nvidia.com/blog/how-krafton-built-pubg-ally-a-co-playable-character-powered-by-nvidia-ace/
- NVIDIA — ACE Game Agent SDK and RAG: https://developer.nvidia.com/blog/build-on-device-ai-companions-with-the-nvidia-ace-game-agent-sdk-and-unreal-engine-5-plugins/
- OpenAI — Retrieval guide: https://platform.openai.com/docs/guides/retrieval
- OpenAI — Conversation state: https://platform.openai.com/docs/guides/conversation-state
Last verified: September 3, 2026
Blinkcade original contribution: four-layer NPC memory architecture, structured memory schema, memory-candidate and importance model, fact/episode separation, confidence and supersession rules, memory-versus-world-state boundary, retrieval pipeline, memory QA checklist and Mara worked example.
