TencentDB Agent Memory Retrieval provide a practical way to understand how an AI Agent can move from raw conversation data to structured, reusable knowledge. Instead of treating every message as an equally important memory, a layered architecture progressively transforms information into facts, scenarios, and higher-level user or project context.
TencentDB Agent Memory’s current architecture describes this progression as L0 Conversation → L1 Atom → L2 Scenario → L3 Persona/Core, while also applying layered symbolic memory to short-term task context. (GitHub)
Why AI Agent Memory Needs Layers
Imagine an AI coding Agent working with a developer for several months.
During that period, it may encounter:
10,000+ conversation messages
5,000+ tool calls
hundreds of files
thousands of test results
dozens of architectural decisions
many user preferences
temporary debugging states
If every piece of information is stored and retrieved in exactly the same way, the Agent eventually faces a serious problem:
More Memory
↓
More Search Results
↓
More Noise
↓
More Context
↓
Higher Token Usage
↓
Lower Signal
The solution is not simply to store less.
The solution is to organize memory according to its level of abstraction.
That is where TencentDB memory layers become strategically important.
A useful mental model is:
L3 — Persona / Core
↑
L2 — Scenario
↑
L1 — Atom
↑
L0 — Conversation
The lower layers preserve detailed evidence.
The higher layers provide compact context.
Tencent’s project describes this as a semantic pyramid rather than a flat collection of vector records. (GitHub)
L0: Conversation Is the Ground Truth
The first layer is the raw conversation.
Consider:
User:
We are moving checkout automation from Selenium to Playwright.
Agent:
Understood. Should I update the existing Page Objects?
User:
Yes. Keep the current naming conventions.
L0 preserves this interaction with its context.
Conceptually:
{
"layer": "L0",
"session_id": "session_102",
"timestamp": "2026-08-16T10:30:00Z",
"messages": [
{
"role": "user",
"content": "We are moving checkout automation from Selenium to Playwright."
},
{
"role": "user",
"content": "Keep the current naming conventions."
}
]
}
Why preserve this raw information?
Because higher-level memories can be wrong.
If an L3 profile says:
"The team uses Playwright."
a developer may eventually need to know:
When did that decision happen?
Why was Selenium replaced?
Was it permanent?
Who made the decision?
What naming conventions were retained?
The answer may exist only in the original conversation.
This is why raw memory should not simply be destroyed after summarization.
TencentDB Agent Memory’s architecture explicitly emphasizes traceability from higher-level abstractions back to lower-level evidence. (GitHub)
L0 Is Detailed but Expensive
Raw conversation is excellent for evidence but poor as the primary context.
Suppose the Agent needs to answer:
What automation framework does this team currently prefer?
Injecting 200 previous conversations into the prompt would be wasteful.
Instead, the system can use higher-level memory:
L3:
Team prefers Playwright for browser automation.
If the Agent needs evidence:
L3
↓
L2
↓
L1
↓
L0
The system can progressively drill down.
This is the core idea behind progressive disclosure.
The Agent does not need everything.
It needs the smallest useful layer first.
L1: Atom Turns Conversations Into Facts
The next layer extracts individual pieces of actionable information.
From:
User:
We are moving checkout automation from Selenium to Playwright.
Keep the existing Page Object naming conventions.
the system might produce:
[
{
"layer": "L1",
"type": "decision",
"content": "Checkout automation is moving from Selenium to Playwright."
},
{
"layer": "L1",
"type": "constraint",
"content": "Existing Page Object naming conventions should be preserved."
}
]
These are atomic memories.
They are much easier to retrieve than entire conversations.
Instead of searching:
Thousands of conversation messages
the system can search:
Relevant facts
This dramatically changes the retrieval problem.
Why Atomic Memory Matters
Consider these three records.
Raw conversation
User:
Remember that our checkout automation is moving from
Selenium to Playwright, but don't rename the existing
Page Objects because another team depends on them.
Atomic memories
Fact:
Checkout automation uses Playwright.
Constraint:
Existing Page Object names must remain unchanged.
Dependency:
Another team depends on the existing Page Objects.
Search query
"How should I modify checkout automation?"
The Agent can retrieve the relevant atoms without loading the entire conversation.
This is a much more efficient memory strategy.
Atomic Memory Should Remain Traceable
A common mistake is creating a summary without preserving its source.
Instead, use relationships:
{
"id": "atom_204",
"layer": "L1",
"content": "Checkout automation uses Playwright.",
"source": {
"layer": "L0",
"id": "conversation_102"
}
}
Now the Agent can answer:
What is the fact?
and an engineer can also answer:
Where did this fact come from?
That distinction becomes critical when memory quality is questioned.
L2: Scenario Memory Restores Context
Individual facts are useful, but facts alone do not always provide enough context.
Suppose the system has:
Atom 1:
Checkout uses Playwright.
Atom 2:
Users are generated through API calls.
Atom 3:
Existing Page Object names are preserved.
Atom 4:
UI registration makes tests slower.
Atom 5:
Checkout tests run in CI.
Individually, these are useful.
Together, they describe a larger scenario:
Checkout Automation Strategy
L2 can organize those related memories into a coherent scenario.
For example:
# Checkout Automation Scenario
## Framework
Playwright
## Test Data
Generate users through API endpoints.
## Page Objects
Preserve existing naming conventions.
## Performance Strategy
Avoid UI registration during test setup.
## Execution
Tests run in CI.
This is far more useful for an Agent that needs to understand the project quickly.
TencentDB Agent Memory describes L2 Scenario as a middle layer that organizes knowledge around projects or scenarios. (GitHub)
Scenario Memory Is a Context Accelerator
Imagine asking:
How does our checkout automation work?
Without L2:
Retrieve 30 individual facts
↓
Rank them
↓
Reconstruct the project context
With L2:
Retrieve Checkout Automation Scenario
↓
Load structured context
↓
Answer
This reduces the amount of reasoning required before the Agent can act.
That makes L2 particularly valuable for long-running projects.
L3: Persona or Core Memory
At the highest level, multiple scenarios can be synthesized into stable patterns.
For example:
Scenario 1:
Checkout automation
Scenario 2:
Payments automation
Scenario 3:
Authentication automation
Across those scenarios, the system may identify:
The team prefers Playwright for browser automation.
That becomes higher-level knowledge.
A conceptual L3 record could look like:
{
"layer": "L3",
"type": "team_preference",
"content": "The team prefers Playwright for browser automation.",
"derived_from": [
"scenario_checkout",
"scenario_payments",
"scenario_authentication"
]
}
Tencent’s current project documentation describes L3 as Persona/Core-level knowledge representing stable profiles, patterns, and higher-level cognition. (GitHub)
L3 Should Be Stable, Not Overconfident
There is an important engineering distinction.
This:
The user always uses Playwright.
is dangerous.
This is better:
The user generally prefers Playwright for browser automation.
The second statement leaves room for exceptions.
A high-level memory should represent a stable pattern, not transform every historical observation into an absolute rule.
This is one reason the lower layers remain important.
Comparing Flat Memory With Layered Memory
| Characteristic | Flat Vector Memory | Layered Memory |
|---|---|---|
| Raw conversations | Usually mixed with other records | Preserved at L0 |
| Atomic facts | May be independent chunks | Explicit L1 layer |
| Scenarios | Often implicit | Explicit L2 layer |
| Persona/context | Usually inferred during retrieval | Explicit L3 layer |
| Retrieval | Primarily similarity-driven | Hierarchical + semantic |
| Traceability | Can be difficult | Designed into relationships |
| Context efficiency | Variable | Progressive disclosure |
| Debugging | Often opaque | Can inspect each layer |
| Long-term organization | Weak | Strong |
The key difference is not that one uses vectors and the other does not.
The difference is how information is organized before retrieval.
Layering Does Not Replace Vector Search
This is an important misconception.
A layered architecture can still use:
BM25
+
Vector Search
+
RRF
+
Metadata Filtering
TencentDB Agent Memory’s current implementation describes hybrid retrieval using BM25, vector retrieval, and Reciprocal Rank Fusion (RRF). (GitHub)
Conceptually:
keyword_results = bm25.search(query)
semantic_results = vector_search(query)
ranked = reciprocal_rank_fusion(
keyword_results,
semantic_results
)
The layered architecture determines where and how memory is organized.
Hybrid retrieval determines how relevant information is found.
These are complementary ideas.
Why BM25 and Vector Search Work Better Together
Consider the query:
"OAuth configuration for checkout"
A keyword search might find:
OAuth
checkout
authentication
A vector search might find semantically related content:
authorization setup
token configuration
identity provider
Each has strengths.
| Retrieval Method | Best At |
|---|---|
| BM25 | Exact terms and keywords |
| Vector search | Semantic similarity |
| Metadata filters | Scope and authorization |
| RRF | Combining ranking signals |
A production memory system can combine them.
def retrieve_memory(query, filters):
lexical = bm25.search(
query=query,
filters=filters
)
semantic = vector.search(
query=query,
filters=filters
)
return rrf(lexical, semantic)
Progressive Disclosure Is the Strategic Advantage
The most important idea is not merely:
L0 → L1 → L2 → L3
It is:
Start high
↓
Drill down only when necessary
For a simple request:
"What framework do we use?"
L3 may be enough.
For:
"Why did we move from Selenium to Playwright?"
the system may need:
L3
↓
L2
↓
L1
↓
L0
The Agent can retrieve progressively deeper evidence.
This is much more efficient than dumping every historical record into the context window.
A Simple Retrieval Controller
You can model the decision process like this:
def retrieve_with_depth(query):
result = search_layer("L3", query)
if is_sufficient(result):
return result
result += search_layer("L2", query)
if is_sufficient(result):
return result
result += search_layer("L1", query)
if is_sufficient(result):
return result
return result + search_layer("L0", query)
The important function is:
is_sufficient()
because the system should stop retrieving when it has enough reliable evidence.
More context is not automatically better context.
Memory Layers Also Improve Debugging
Imagine an Agent suddenly claims:
"The team uses Cypress."
But the actual project uses Playwright.
With flat vector memory, you may see:
Result #1
Result #2
Result #3
and a set of similarity scores.
Finding the problem can be difficult.
With layered memory, you can investigate:
L3 Persona
↓
L2 Scenario
↓
L1 Atom
↓
L0 Conversation
Perhaps the problem is:
L1 Atom was extracted incorrectly.
Or:
L2 Scenario was not updated.
Or:
L3 Persona retained an outdated preference.
Now debugging becomes a data-lineage problem rather than a mysterious LLM problem.
Tencent’s project explicitly emphasizes white-box debugging and readable intermediate memory artifacts for this reason. (GitHub)

Build a Layered Memory Schema
A practical implementation can define a common memory structure:
class Memory:
id: str
layer: str
content: str
source_ids: list[str]
confidence: float
created_at: str
updated_at: str
scope: str
Then create specialized records.
conversation = Memory(
layer="L0",
content=raw_message,
source_ids=[],
confidence=1.0,
scope="project-alpha"
)
An extracted atom:
atom = Memory(
layer="L1",
content="Checkout automation uses Playwright.",
source_ids=[conversation.id],
confidence=0.94,
scope="project-alpha"
)
A scenario:
scenario = Memory(
layer="L2",
content="Checkout automation strategy",
source_ids=[atom.id],
confidence=0.91,
scope="project-alpha"
)
A persona/core record:
persona = Memory(
layer="L3",
content="Team prefers Playwright for browser automation.",
source_ids=[scenario.id],
confidence=0.88,
scope="team-alpha"
)
This is conceptual code rather than a claim that these exact classes are required by TencentDB Agent Memory.
Keep Scope Attached to Every Layer
Memory without scope can become dangerous.
Imagine:
Project Alpha:
Playwright
Project Beta:
Cypress
A global search for:
"What browser framework do we use?"
could retrieve both.
The memory system should understand:
tenant
team
project
agent
user
session
and apply appropriate authorization and filtering.
TencentDB Agent Memory’s current architecture also includes explicit visibility and access-control concepts for memory assets in its broader Memory Hub design. (GitHub)
Layered Memory vs Conversation Summaries
A conventional approach might be:
Conversation
↓
One giant summary
This is easy but dangerous.
Suppose the summary says:
"The team uses Playwright and API-based test data."
What happens when you need to know:
Why?
When?
Who decided?
What exception exists?
Which project?
The summary may not contain the answer.
A layered architecture instead provides:
L3 → stable understanding
L2 → scenario context
L1 → precise facts
L0 → original evidence
This provides both compression and recoverability.
An Interactive Design Exercise
Take one real Agent conversation and manually classify five statements.
For each statement, ask:
Is this raw evidence?
Is this an atomic fact?
Does it belong to a scenario?
Is it a stable preference?
Could I need the original evidence later?
For example:
| Information | Layer |
|---|---|
| Raw user message | L0 |
| “Checkout uses Playwright” | L1 |
| “Checkout automation strategy” | L2 |
| “Team prefers Playwright” | L3 |
| Temporary debugging output | L0 |
| Stable project constraint | L1/L2 |
| Repeated long-term preference | L3 |
This exercise exposes an important insight:
Memory hierarchy is fundamentally a knowledge-organization problem.
The database is only the infrastructure supporting that organization.
When Should the Agent Drill Down?
Use a simple rule:
Question is simple?
→ Use higher-level memory.
Question needs project context?
→ Retrieve scenario memory.
Question needs exact facts?
→ Retrieve atomic memory.
Question requires evidence or history?
→ Retrieve conversation memory.
For example:
"What framework do we prefer?"
→ L3
"How does checkout automation work?"
→ L2
"What API creates the test user?"
→ L1
"Why did we stop using UI registration?"
→ L1 → L0
This is the kind of reasoning that makes a memory system efficient instead of merely large.
The Architecture You Should Remember
Think of TencentDB memory layers as four different jobs:
L0
Preserve what happened.
L1
Extract what matters.
L2
Organize why it matters in a scenario.
L3
Understand what remains consistently true.
That gives the Agent a powerful combination:
Evidence
+
Facts
+
Context
+
Long-term understanding
The result is not simply a bigger memory.
It is a more structured memory system that can reveal the right amount of information at the right time.
Turning Layered TencentDB Memory Into a Retrieval Strategy
TencentDB memory layers become genuinely useful when the Agent knows which layer to search, when to stop, and when to drill deeper. A layered memory architecture is not simply a four-level database structure; it is a retrieval strategy that controls relevance, context size, latency, and the quality of the evidence presented to the model.
The practical question is therefore not:
“How do I retrieve memory?”
It is:
“How much memory does the Agent actually need to answer this particular question?”
Start Retrieval With the Highest Useful Abstraction
Consider a user asking:
What browser automation framework does our team prefer?
If the system already has a validated L3 memory:
Team preference:
Playwright is preferred for browser automation.
there is little reason to retrieve hundreds of historical conversations.
The retrieval path can remain:
User Query
↓
L3 Persona/Core
↓
Confidence Check
↓
Answer
But consider a different question:
Why did we move checkout automation from Selenium to Playwright?
A high-level preference is insufficient.
The system should progressively investigate:
L3
↓
L2
↓
L1
↓
L0
This is the foundation of efficient hierarchical retrieval.
Retrieval Depth Should Depend on the Question
A useful controller can classify queries before searching.
def determine_depth(query):
if asks_for_preference(query):
return "L3"
if asks_for_project_context(query):
return "L2"
if asks_for_specific_fact(query):
return "L1"
if asks_for_history_or_reason(query):
return "L0"
return "L2"
This is intentionally simple.
In a production system, query classification could use an LLM, rules, metadata, or a hybrid approach.
The important architectural principle is:
Query Type → Retrieval Depth
rather than:
Every Query → Search Everything
Why Searching Everything Is a Bad Strategy
Imagine a memory database containing:
100 L3 records
2,000 L2 records
50,000 L1 records
1,000,000 L0 records
A flat retrieval system might search across all available representations.
Even with good ranking, it creates unnecessary work.
A hierarchical strategy can reduce the search space:
L3
↓
If insufficient
↓
L2
↓
If insufficient
↓
L1
↓
If evidence required
↓
L0
This produces a much more controlled retrieval process.
| Strategy | Search Scope | Context Noise | Complexity |
|---|---|---|---|
| Full history | Very large | High | Low initially |
| Flat vector memory | Large | Medium | Medium |
| Metadata-filtered vector memory | Reduced | Lower | Medium |
| Layered retrieval | Adaptive | Low | Higher |
| Layered + hybrid retrieval | Adaptive + precise | Very low | Higher |
The goal is not to minimize retrieval complexity at all costs.
The goal is to minimize unnecessary retrieval while preserving answer quality.
Use Confidence to Decide Whether to Stop
Finding a memory does not necessarily mean retrieval should stop.
Suppose L3 returns:
{
"content": "The team prefers Playwright.",
"confidence": 0.91
}
That may be sufficient for:
Which browser framework does the team prefer?
But if the result is:
{
"content": "The team may prefer Playwright.",
"confidence": 0.51
}
the Agent should probably investigate further.
A conceptual controller:
def retrieve_hierarchically(query):
for layer in ["L3", "L2", "L1", "L0"]:
results = search_layer(layer, query)
if enough_evidence(results):
return results
return []
The important function is not search_layer().
It is:
enough_evidence()
because the Agent needs a measurable stopping condition.
Define an Evidence Threshold
You can start with a simple scoring model:
def evidence_score(memory):
return (
memory.confidence * 0.45 +
memory.relevance * 0.35 +
memory.freshness * 0.20
)
Then:
def enough_evidence(results):
if not results:
return False
best = max(
evidence_score(item)
for item in results
)
return best >= 0.80
This is not a universal formula.
Your production weights should be determined through evaluation.
The strategic lesson is more important:
Retrieval should have a reason to stop.
Combine Semantic Relevance With Memory Metadata
Semantic similarity alone is not enough.
Suppose a query is:
How should we create checkout test users?
The vector search might return:
Memory A:
Checkout users should be created through the API.
Memory B:
The user created a personal account through the UI.
Memory C:
A different project uses UI registration.
All three may have reasonable semantic similarity.
But metadata can eliminate irrelevant results.
results = vector_search(
query=query,
filters={
"project_id": "checkout",
"memory_status": "active"
}
)
A production retrieval request might conceptually include:
tenant
project
user
agent
memory layer
memory type
status
timestamp
confidence
This creates a much stronger retrieval boundary.
Metadata Filtering Should Happen Early
Do not retrieve 500 records and then discover that 400 belong to another project.
Prefer:
Query
↓
Authorization
↓
Metadata Filtering
↓
Semantic Search
↓
Ranking
rather than:
Query
↓
Semantic Search
↓
Authorization
↓
Filtering
The second design can create both performance and security problems.
A conceptual implementation:
def retrieve(query, user, project):
authorize(user, project)
filters = {
"project_id": project.id,
"status": "active"
}
return hybrid_search(
query=query,
filters=filters
)
Hybrid Retrieval Gives the Agent More Signals
TencentDB Agent Memory’s documented architecture uses hybrid retrieval approaches involving keyword/BM25 retrieval, vector retrieval, and Reciprocal Rank Fusion.
Why does that matter?
Because different queries need different retrieval signals.
Consider:
"Playwright"
Exact lexical matching is valuable.
Now consider:
"What framework do we use for browser automation?"
Semantic retrieval becomes much more valuable.
A hybrid approach combines them:
def hybrid_retrieve(query):
lexical = bm25.search(query)
semantic = vector.search(query)
return reciprocal_rank_fusion(
lexical,
semantic
)
The result is not simply “more search.”
It is multiple evidence signals combined into one ranking.
RRF Helps Combine Different Rankings
Suppose BM25 produces:
A
B
C
while vector search produces:
C
A
D
Neither ranking is necessarily correct by itself.
Reciprocal Rank Fusion can combine them:
def rrf(rankings, k=60):
scores = {}
for ranking in rankings:
for rank, document in enumerate(ranking, start=1):
scores[document] = scores.get(
document,
0
) + 1 / (k + rank)
return sorted(
scores,
key=scores.get,
reverse=True
)
This is a conceptual implementation, but it demonstrates the idea.
A memory can become highly ranked because multiple retrieval strategies independently consider it relevant.
Retrieval Should Understand Memory Relationships
Imagine:
L3:
Team prefers Playwright.
linked to:
L2:
Checkout automation strategy.
linked to:
L1:
Checkout tests use Playwright.
linked to:
L0:
"We're moving checkout automation from Selenium to Playwright."
These relationships are useful retrieval signals.
Instead of returning an isolated record, the system can return a chain:
High-Level Memory
↓
Scenario
↓
Supporting Fact
↓
Original Evidence
This makes the answer easier to ground.
Think of Retrieval as a Graph
A useful conceptual model is:
L3
│
┌──────┴──────┐
↓ ↓
L2 L2
│ │
┌──┴──┐ ┌──┴──┐
↓ ↓ ↓ ↓
L1 L1 L1 L1
│ │
↓ ↓
L0 L0
The Agent does not necessarily need to traverse the entire structure.
It can traverse only the branches relevant to the question.
That creates selective memory traversal.
Retrieval Should Return a Context Package
Do not simply pass raw database rows to the LLM.
Instead, create a structured context package:
def build_agent_context(results):
return {
"facts": [
r.content
for r in results
if r.layer == "L1"
],
"scenarios": [
r.content
for r in results
if r.layer == "L2"
],
"preferences": [
r.content
for r in results
if r.layer == "L3"
],
"evidence": [
r.source_ids
for r in results
]
}
Then provide the model with:
Relevant persistent knowledge:
- Team preference: Playwright
- Checkout scenario: API-generated test users
- Constraint: Existing Page Object names remain unchanged
Evidence available:
- Conversation session_102
- Conversation session_118
This is far better than:
SELECT * FROM memories;
followed by dumping everything into the prompt.
Retrieval and Context Construction Are Different Problems
This distinction is easy to miss.
Retrieval
Answers:
Which memories are relevant?
Context construction
Answers:
How should those memories be presented to the Agent?
For example:
Retrieval:
20 relevant memories
does not mean:
Prompt:
20 raw database records
Context construction can:
deduplicate
compress
group
rank
summarize
attach provenance
remove irrelevant fields
A useful pipeline is:
Search
↓
Rank
↓
Deduplicate
↓
Group
↓
Compress
↓
Attach Provenance
↓
Build Context
Deduplication Prevents Context Inflation
Suppose retrieval returns:
Playwright is preferred.
The team prefers Playwright.
Browser automation uses Playwright.
Playwright is the preferred browser framework.
These may represent the same underlying fact.
Before sending them to the LLM:
def deduplicate(memories):
groups = cluster_semantically_similar(memories)
return [
select_best_memory(group)
for group in groups
]
This reduces context duplication.
Ranking Should Consider More Than Similarity
A useful ranking model can combine:
semantic relevance
keyword relevance
confidence
freshness
importance
scope
layer
source quality
For example:
def final_score(memory):
return (
memory.semantic_score * 0.30 +
memory.keyword_score * 0.15 +
memory.confidence * 0.20 +
memory.freshness * 0.10 +
memory.importance * 0.10 +
memory.source_quality * 0.10 +
memory.scope_match * 0.05
)
Again, the numbers are illustrative.
The important concept is that:
Similarity ≠ Truth
A highly similar memory can still be:
old
wrong
out of scope
low confidence
superseded
Freshness Needs to Be Explicit
Consider:
2025:
Team uses Selenium.
and:
2026:
Team uses Playwright.
A similarity search may find both.
A freshness signal can help:
def freshness(memory, now):
age_days = (
now - memory.updated_at
).days
return max(
0,
1 - age_days / 365
)
But freshness alone is not enough.
An old architectural decision may still be valid.
A better system considers:
freshness
+
explicit superseding
+
confidence
+
scope
Supersession Is Better Than Silent Replacement
Instead of deleting:
Selenium is used for checkout.
when Playwright becomes the new standard, represent the relationship:
{
"old_memory": "memory_101",
"new_memory": "memory_207",
"relationship": "superseded_by"
}
Now the system knows:
Current:
Playwright
Historical:
Selenium
That is much more useful than pretending the historical fact never existed.
Memory Layers and RAG Are Not the Same Thing
A common comparison is:
| Feature | Traditional RAG | Layered Agent Memory |
|---|---|---|
| Main source | Documents | Conversations + extracted knowledge |
| Primary goal | Retrieve external knowledge | Preserve agent/user/project knowledge |
| Hierarchy | Optional | Core architectural concept |
| User preferences | Usually secondary | Important |
| Temporal evolution | Often limited | Central |
| Memory lifecycle | Basic | Important |
| Evidence tracing | Document-based | Memory lineage |
| Personalization | Limited | Strong |
Traditional RAG typically answers:
What does the knowledge base say?
Agent memory answers:
What has this user, project, or Agent learned over time?
They can also work together.
External Knowledge
↓
RAG
↓
+
Persistent Agent Memory
↓
Agent Context
That combination is particularly powerful for enterprise systems.
Memory Layers vs Simple Conversation Summaries
| Capability | Conversation Summary | Layered Memory |
|---|---|---|
| Compresses history | Yes | Yes |
| Preserves atomic facts | Sometimes | Explicitly |
| Scenario organization | Limited | Explicit |
| Long-term preferences | Weak | Strong |
| Evidence traceability | Limited | Strong |
| Selective retrieval | Limited | Strong |
| Conflict management | Basic | Can be explicit |
| Progressive disclosure | No | Yes |
A summary is useful.
But a summary should not be mistaken for a complete memory architecture.
Make Retrieval Interactive
A strong Agent can decide whether it needs more information.
For example:
def answer(query):
memory = retrieve(query)
if confidence(memory) >= 0.85:
return generate(query, memory)
deeper_memory = retrieve_deeper(query)
return generate(
query,
memory + deeper_memory
)
This creates an adaptive loop:
Question
↓
Retrieve
↓
Evaluate
↓
Enough?
├── Yes → Answer
└── No → Retrieve Deeper
That is much closer to how an intelligent memory system should behave.
Measure Retrieval Instead of Assuming It Works
Create a benchmark.
test_cases = [
{
"query": "What browser framework does Alpha use?",
"expected_layer": "L3"
},
{
"query": "How does checkout automation work?",
"expected_layer": "L2"
},
{
"query": "Which endpoint creates test users?",
"expected_layer": "L1"
},
{
"query": "Why did the team switch frameworks?",
"expected_layer": "L0"
}
]
Measure:
Layer Selection Accuracy
Retrieval Recall
Precision@K
MRR
Answer Accuracy
Latency
Token Consumption
Evidence Coverage
This gives you an engineering feedback loop.
A Useful Cost Model
Suppose:
L3 retrieval = 10 ms
L2 retrieval = 20 ms
L1 retrieval = 40 ms
L0 retrieval = 100 ms
You could conceptually optimize:
def retrieve_efficiently(query):
result = search("L3", query)
if confidence(result) > 0.85:
return result
result += search("L2", query)
if confidence(result) > 0.85:
return result
result += search("L1", query)
if confidence(result) > 0.85:
return result
return result + search("L0", query)
The actual production values should come from benchmarking.
But the strategy is clear:
Don’t pay the cost of deep retrieval when shallow memory already answers the question.
A Practical Retrieval Architecture
Put everything together:
User Query
│
▼
Query Understanding
│
▼
Authorization
│
▼
Scope Filtering
│
▼
┌─────────────────┐
│ Layer Selection │
└────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
L3 L2 L1
│ │ │
└────────────┼────────────┘
▼
Hybrid Retrieval
│
▼
Ranking
│
▼
Deduplication
│
▼
Evidence Check
│
┌─────────┴─────────┐
▼ ▼
Enough? Not Enough
│ │
▼ ▼
Context Drill Down
│ │
└─────────┬─────────┘
▼
Context Builder
│
▼
LLM Agent
This architecture transforms memory retrieval from a simple search operation into a controlled reasoning-support system.
The Strategic Principle
The strongest implementation does not ask:
“How can I give the Agent more memory?”
It asks:
“How can I give the Agent the smallest amount of trustworthy memory that is sufficient for this decision?”
That distinction changes everything.
A well-designed layered system can preserve:
L0 → evidence
L1 → facts
L2 → scenarios
L3 → stable understanding
while retrieval determines:
what
when
how much
how deep
and with what confidence
The result is an Agent that does not merely remember more.
It remembers in a way that is searchable, explainable, scoped, efficient, and useful for reasoning.
Designing Reliable TencentDB Memory Retrieval With Hybrid Search, Scope, and Provenance
TencentDB memory architecture becomes significantly more reliable when retrieval is treated as an evidence-selection problem rather than a simple similarity search. An Agent needs to distinguish current information from historical information, project facts from personal preferences, and strong evidence from weak signals.
The practical goal is simple:
Find relevant memory
↓
Verify its scope
↓
Check its freshness
↓
Check confidence
↓
Trace its source
↓
Build minimal context
↓
Let the Agent reason
This approach is especially important for long-running Agents where memory can accumulate for months or years.
Relevance Alone Is Not Enough
Imagine an Agent receives this question:
How do we create checkout test users?
A vector search might return:
Result 1:
Checkout users are created through the API.
Result 2:
Users can register through the web interface.
Result 3:
A previous project used database fixtures.
Result 4:
The mobile application creates test accounts through an admin panel.
All four records could be semantically related to “creating users.”
But only one may actually answer the question.
The Agent therefore needs more than:
similarity_score
It needs:
similarity
+
scope
+
freshness
+
confidence
+
status
+
provenance
A useful conceptual ranking function is:
def memory_score(memory):
return (
memory.semantic_score * 0.30 +
memory.keyword_score * 0.15 +
memory.scope_score * 0.20 +
memory.confidence * 0.15 +
memory.freshness * 0.10 +
memory.source_quality * 0.10
)
The exact weights should be evaluated against your own workload.
The important principle is that semantic similarity should be one signal, not the entire decision.
Scope Prevents Cross-Project Memory Pollution
One of the most dangerous problems in persistent Agent memory is mixing information from different scopes.
Consider:
Project A
Browser automation → Playwright
Project B
Browser automation → Cypress
Now ask:
What browser automation framework do we use?
A global semantic search could return both.
The system needs to know:
Which project?
Which team?
Which user?
Which tenant?
Which Agent?
A memory record can therefore contain explicit scope:
{
"id": "memory_204",
"layer": "L1",
"content": "Checkout tests use Playwright.",
"scope": {
"tenant": "company-a",
"project": "checkout",
"team": "qa"
},
"status": "active"
}
Then retrieval becomes:
results = search(
query="browser automation framework",
filters={
"tenant": "company-a",
"project": "checkout",
"team": "qa",
"status": "active"
}
)
This is considerably safer than searching the entire memory store.
Scope Should Be Hierarchical
Enterprise Agents often operate across multiple levels.
A useful model is:
Tenant
↓
Organization
↓
Team
↓
Project
↓
Agent
↓
User
↓
Session
Not every memory belongs to every level.
For example:
Company coding standard
→ Organization
Checkout API convention
→ Project
User prefers concise answers
→ User
Temporary debugging state
→ Session
This distinction prevents a local preference from accidentally becoming a global rule.
Freshness Changes the Meaning of Memory
Memory is not always timeless.
Consider:
January:
The project uses Selenium.
March:
The project migrates to Playwright.
August:
The project standardizes on Playwright.
If the Agent retrieves all three records without considering time, it may produce an incorrect answer.
A memory record should therefore carry lifecycle metadata:
{
"created_at": "2026-03-12T09:00:00Z",
"updated_at": "2026-03-15T14:00:00Z",
"valid_from": "2026-03-15T00:00:00Z",
"valid_until": null,
"status": "active"
}
Now the retrieval engine can distinguish:
Historical
Superseded
Active
Expired
This is much safer than simply sorting by insertion date.
Use Supersession Instead of Deleting History
Suppose the old memory is:
Selenium is used for browser automation.
Instead of deleting it, create a relationship:
{
"source": "memory_101",
"target": "memory_207",
"relationship": "superseded_by"
}
The resulting knowledge chain becomes:
Selenium
↓
Superseded by
↓
Playwright
↓
Current
Now the Agent can answer both:
What do we use now?
and:
What did we use previously?
This distinction is critical for debugging historical decisions.
Confidence Should Be Treated as Evidence Quality
Not every memory originates from the same source.
Compare:
User explicitly stated:
"We use Playwright."
with:
Agent inferred:
"The team probably uses Playwright."
They should not receive identical confidence.
A conceptual memory model:
memory = {
"content": "Team uses Playwright",
"confidence": 0.95,
"source_type": "explicit_user_statement"
}
versus:
memory = {
"content": "Team uses Playwright",
"confidence": 0.62,
"source_type": "agent_inference"
}
Possible source categories include:
| Source | Typical Trust |
|---|---|
| Explicit user statement | Very high |
| Verified tool output | Very high |
| Project configuration | High |
| Repeated observed behavior | Medium-high |
| Agent-generated inference | Medium |
| Weak semantic inference | Low |
These values should not be blindly hard-coded.
Instead, evaluate how each source type performs in your application.
Repetition Can Strengthen a Memory
Suppose an Agent observes:
Conversation 1:
We use Playwright.
Conversation 2:
Update the Playwright configuration.
Conversation 3:
Our Playwright tests failed in CI.
Conversation 4:
Add another Playwright fixture.
The same concept repeatedly appears.
That may strengthen confidence:
confidence = base_confidence + repetition_bonus
Conceptually:
One observation
↓
Candidate memory
Repeated observations
↓
Higher confidence
Explicit confirmation
↓
Strong memory
But repetition should not blindly create certainty.
Five copies of the same incorrect inference are still incorrect.
Contradictions Need Their Own Strategy
Persistent memory eventually encounters contradictions.
For example:
Memory A:
Checkout uses Selenium.
Memory B:
Checkout uses Playwright.
Memory C:
Checkout is being migrated from Selenium to Playwright.
A simple system may retrieve all three and confuse the Agent.
A stronger system detects the contradiction:
def detect_conflict(memories):
groups = group_by_subject(memories)
conflicts = []
for group in groups:
if has_incompatible_values(group):
conflicts.append(group)
return conflicts
Then the system can investigate:
timestamp
source
scope
status
supersession
explicit confirmation
This is where provenance becomes extremely valuable.
Provenance Makes Memory Auditable
A high-quality memory should answer:
What is the memory?
Where did it come from?
When was it created?
Who provided it?
What transformed it?
What does it supersede?
For example:
{
"id": "atom_207",
"content": "Checkout automation uses Playwright.",
"layer": "L1",
"confidence": 0.94,
"source": {
"layer": "L0",
"conversation_id": "conv_102",
"message_id": "msg_17"
},
"created_at": "2026-08-01T10:30:00Z",
"status": "active"
}
Now the Agent can use the memory while engineers can investigate its origin.
This is one of the most important differences between memory as data and memory as an auditable knowledge system.
Provenance Should Survive Summarization
Imagine:
L0:
"We are moving checkout automation from Selenium to Playwright."
↓
L1:
"Checkout automation uses Playwright."
↓
L2:
"Checkout automation strategy."
↓
L3:
"Team prefers Playwright."
The final L3 statement is several transformations away from the original message.
Without provenance:
L3 → ???
With provenance:
L3
↓
L2
↓
L1
↓
L0
This creates a traceable chain.
Hybrid Search Should Be Combined With Layer Selection
Hybrid search and layered memory solve different problems.
Think of them like this:
Layer Selection
=
Where should I search?
Hybrid Search
=
How should I find relevant records there?
For example:
layer = select_layer(query)
lexical = bm25.search(
query,
layer=layer
)
semantic = vector.search(
query,
layer=layer
)
results = rrf(
lexical,
semantic
)
This is more targeted than:
vector.search(query)
across the entire database.
Compare Flat RAG, Vector Memory, and Layered Retrieval
| Capability | Flat RAG | Vector Memory | Layered + Hybrid Memory |
|---|---|---|---|
| Semantic retrieval | ✓ | ✓ | ✓ |
| Keyword retrieval | Optional | Optional | ✓ |
| Raw conversation preservation | Limited | Possible | Explicit |
| Memory hierarchy | No | Usually no | Yes |
| Scope awareness | Depends on implementation | Depends on implementation | Explicitly designed |
| Provenance | Document-oriented | Variable | Strong lineage model |
| Temporal lifecycle | Limited | Variable | Important |
| Progressive disclosure | No | Limited | Yes |
| Contradiction handling | Basic | Basic | Can be explicit |
| Long-term personalization | Moderate | Good | Strong |
The layered approach is not necessarily a replacement for RAG.
It is an architectural extension for situations where memory evolves over time.
Build a Memory Retrieval Contract
A useful engineering practice is defining what every retrieval operation must return.
For example:
class RetrievalResult:
memory_id: str
layer: str
content: str
relevance: float
confidence: float
scope: str
status: str
source_ids: list[str]
created_at: str
updated_at: str
Now the Agent runtime knows that memory results are not just text.
They are:
content
+
evidence
+
metadata
+
lifecycle
That makes downstream reasoning more reliable.
Use Structured Memory Instead of Prompt Fragments
Avoid storing memories like:
"User likes Playwright. Maybe prefers API testing too. Probably dislikes Selenium."
This is difficult to query and difficult to verify.
Prefer:
{
"preference": {
"subject": "browser automation",
"value": "Playwright",
"confidence": 0.94,
"status": "active"
}
}
And:
{
"preference": {
"subject": "Selenium",
"value": "not preferred",
"confidence": 0.72,
"status": "active"
}
}
Structured memories make filtering, conflict detection, and updates easier.
Separate Facts From Preferences
This is another subtle but important design decision.
These are not equivalent:
Fact:
The checkout service exposes /users/test.
and:
Preference:
The team prefers API-based test data generation.
One describes the system.
The other describes a choice.
Your schema should distinguish them:
{
"type": "fact",
"content": "Checkout exposes /users/test."
}
versus:
{
"type": "preference",
"content": "The team prefers API-based test data generation."
}
This prevents the Agent from treating preferences as immutable technical facts.
Separate Temporary State From Persistent Knowledge
Suppose an Agent is debugging:
Current test:
checkout.spec.ts
Temporary hypothesis:
Payment timeout may be caused by slow API setup.
That should not automatically become long-term memory.
Otherwise the Agent might remember:
Payment API is always slow.
for months.
Instead:
Session State
→ temporary
Persistent Memory
→ validated knowledge
A useful lifecycle is:
Observation
↓
Candidate Memory
↓
Validation
↓
Persistent Memory
This reduces memory pollution.
Think in Terms of Memory Lifecycle
A practical lifecycle could look like:
Captured
↓
Extracted
↓
Validated
↓
Active
↓
Updated
↓
Superseded
↓
Archived
For example:
VALID_STATES = [
"candidate",
"active",
"superseded",
"archived"
]
This is far safer than a database where every record is permanently “active.”
Retrieval Should Respect Memory State
A query should normally prioritize:
active
and exclude:
archived
unless historical evidence is requested.
For example:
results = search(
query=query,
filters={
"status": "active"
}
)
For a historical question:
results = search(
query=query,
filters={
"status": [
"active",
"superseded",
"archived"
]
}
)
This makes the retrieval behavior match the user’s intent.
A Practical Decision Matrix
When designing your Agent, use this mental model:
| User Question | Primary Layer | Additional Evidence |
|---|---|---|
| What do I prefer? | L3 | L2/L1 if uncertain |
| What does this project use? | L2 | L1 |
| What is the exact API? | L1 | L0 if ambiguous |
| Why was this decision made? | L1 | L0 |
| What happened previously? | L0 | L1/L2 |
| What changed over time? | L2/L1 | L0 |
| Is this memory still valid? | L1/L2 | Provenance |
This gives your retrieval controller an actionable starting point.
Test Memory Retrieval Like a Production System
Do not evaluate memory only by asking:
“Does the Agent sound intelligent?”
Create explicit test cases.
evaluation_cases = [
{
"query": "What browser framework does checkout use?",
"expected": "Playwright",
"layer": "L2"
},
{
"query": "Why did checkout move away from Selenium?",
"expected_source": "conversation",
"layer": "L0"
},
{
"query": "Which endpoint creates test users?",
"expected": "/users/test",
"layer": "L1"
}
]
Then measure:
Retrieval Precision
Retrieval Recall
Correct Layer Selection
Evidence Accuracy
Conflict Detection
Freshness Accuracy
Latency
Token Consumption
A memory architecture should be measurable.
An SDET-Friendly Memory Test Strategy
If you approach Agent memory like a testing engineer, you can create four test categories.
Retrieval tests
Given a known query,
retrieve the correct memory.
Scope tests
Given Project A,
do not return Project B memories.
Freshness tests
Given an updated decision,
prefer the active memory.
Provenance tests
Given a high-level memory,
trace it back to source evidence.
Example:
def test_project_scope():
result = retrieve(
query="browser framework",
project="checkout"
)
assert all(
item.project == "checkout"
for item in result
)
This transforms memory from an abstract AI feature into something that can actually be tested.
The Most Important Engineering Rule
Never assume:
Retrieved = Correct
Instead:
Retrieved
↓
Relevant?
↓
Correct scope?
↓
Current?
↓
Trusted?
↓
Supported by evidence?
↓
Safe to use
This is the mindset required for reliable persistent Agent memory.
The database can store millions of records.
The Agent should still receive only the smallest defensible set of memories required for the task.
That is where layered architecture, hybrid retrieval, lifecycle metadata, scope control, and provenance work together.
Building a Production-Ready TencentDB Agent Memory Retrieval Pipeline
TencentDB Agent Memory retrieval becomes valuable in production when memory is treated as an engineered system rather than a collection of stored conversations. A reliable Agent must know what to remember, what to retrieve, which memories are current, which belong to the correct project, and when the retrieved evidence is strong enough to influence an answer.
The architecture can be summarized as:
User Query
↓
Query Understanding
↓
Access + Scope Validation
↓
Memory Layer Selection
↓
Hybrid Retrieval
↓
Ranking + Deduplication
↓
Conflict + Freshness Checks
↓
Provenance Validation
↓
Context Construction
↓
Agent Response
The interesting part is that retrieval is only one stage of the pipeline.
The real engineering challenge is deciding which memory deserves to become context.
Memory Retrieval Should Be a Decision System
A weak implementation looks like this:
results = vector_search(user_query)
prompt += results
It works for a demo.
It becomes problematic when the memory store grows.
A production-oriented implementation should look more like:
def retrieve_memory(query, user_context):
authorize(user_context)
scope = resolve_scope(user_context)
layer = select_memory_layer(query)
candidates = hybrid_search(
query=query,
layer=layer,
scope=scope
)
ranked = rank_memories(candidates)
valid = validate_memories(ranked)
return build_context(valid)
Notice the difference.
The second implementation asks several questions before giving memory to the model.
That is the difference between searching memory and operating a memory system.
Query Understanding Comes Before Retrieval
The same words can require completely different memory depths.
Compare:
"What framework do we prefer?"
with:
"Why did we migrate from Selenium?"
The first is likely asking for stable preference.
The second requires historical evidence.
A query router could classify them:
def classify_query(query):
if "prefer" in query.lower():
return "preference"
if "why" in query.lower():
return "historical"
if "how" in query.lower():
return "scenario"
return "general"
A more advanced system could use an LLM classifier:
classification = llm.classify(
query,
categories=[
"preference",
"scenario",
"fact",
"history",
"general"
]
)
Then:
Preference → L3
Scenario → L2
Fact → L1
History → L0
This gives retrieval a purpose before it touches the database.
Retrieval Depth Should Be Adaptive
Never assume every question requires the deepest memory layer.
Consider:
L3 → "Team prefers Playwright."
That may completely answer:
Which browser framework do we prefer?
But:
Why did we choose Playwright?
requires deeper investigation.
A useful controller:
def adaptive_retrieval(query):
for layer in ["L3", "L2", "L1", "L0"]:
memories = search_layer(layer, query)
if sufficient_evidence(memories):
return memories
return []
The important idea is progressive disclosure.
The Agent starts with compact knowledge and drills into evidence only when necessary.
Why This Saves Context
Suppose the database contains:
L3 → 500 memories
L2 → 10,000 memories
L1 → 100,000 memories
L0 → 2,000,000 messages
A flat retrieval system potentially searches a massive pool.
An adaptive architecture can begin with:
L3
↓
Enough?
↓ yes
Answer
For a difficult historical question:
L3
↓
Insufficient
↓
L2
↓
Insufficient
↓
L1
↓
Need evidence
↓
L0
This is particularly important for Agents with expensive context windows.
Hybrid Retrieval Should Be the Default Strategy
Semantic vector search is powerful, but it should not be the only retrieval mechanism.
Imagine the query:
"Playwright checkout fixture"
Keyword retrieval can strongly identify exact matches.
Now consider:
"How does the team prepare browser tests?"
A semantic search may discover:
browser fixtures
test setup
Playwright initialization
automation bootstrap
A hybrid system combines both signals.
def hybrid_search(query):
lexical = bm25_search(query)
semantic = vector_search(query)
return reciprocal_rank_fusion(
lexical,
semantic
)
TencentDB Agent Memory’s documented architecture includes hybrid retrieval using BM25, vector retrieval, and Reciprocal Rank Fusion.
The strategic lesson is simple:
Use lexical search when words matter, semantic search when meaning matters, and combine both when you cannot predict which signal will dominate.
Ranking Should Understand Memory Quality
Imagine two results:
Memory A
Similarity: 0.91
Confidence: 0.55
Status: outdated
Memory B
Similarity: 0.87
Confidence: 0.96
Status: active
A pure vector ranking might select A.
A production memory system should probably prefer B.
A conceptual scoring model:
def score(memory):
return (
0.30 * memory.semantic_score +
0.15 * memory.keyword_score +
0.20 * memory.confidence +
0.15 * memory.scope_match +
0.10 * memory.freshness +
0.10 * memory.source_quality
)
The numbers are examples, not universal production values.
You should tune them against evaluation data.
Freshness Is a First-Class Signal
Long-term Agent memory creates a unique problem:
old information can remain highly relevant semantically while being factually wrong today.
For example:
2025:
Team uses Selenium.
2026:
Team migrated to Playwright.
Both records contain the same conceptual subject.
But only one represents the current state.
Memory records should therefore include lifecycle information:
{
"status": "active",
"created_at": "2026-03-15T10:00:00Z",
"updated_at": "2026-03-15T10:00:00Z",
"valid_from": "2026-03-15T00:00:00Z",
"valid_until": null
}
Now retrieval can distinguish:
active
superseded
expired
archived
Never Silently Delete Important Historical Memory
Suppose:
Selenium
was replaced by:
Playwright
Do not necessarily delete Selenium from the memory system.
Instead:
{
"old_memory": "selenium_memory",
"new_memory": "playwright_memory",
"relationship": "superseded_by"
}
The memory graph becomes:
Selenium
↓
Superseded by
↓
Playwright
Now the Agent can answer both:
What do we use now?
and:
What did we use before?
That is much more useful for debugging and historical analysis.
Scope Filtering Is a Security Boundary
Memory should never be treated as universally accessible text.
Consider:
Company A
├── Project Checkout
└── Project Payments
Company B
└── Project Checkout
A query such as:
"How do we test checkout?"
must not accidentally retrieve information from another tenant.
A retrieval request should carry scope:
filters = {
"tenant_id": tenant_id,
"project_id": project_id,
"team_id": team_id,
"status": "active"
}
results = hybrid_search(
query=query,
filters=filters
)
This is not just an optimization.
It is part of the security model.
Provenance Should Follow Every Important Memory
Suppose the Agent retrieves:
"The checkout team uses Playwright."
The system should ideally know:
Where did this come from?
When was it created?
Who stated it?
Was it inferred?
Which scenario produced it?
Is it still active?
A useful structure:
{
"memory_id": "atom_204",
"layer": "L1",
"content": "Checkout tests use Playwright.",
"confidence": 0.94,
"source": {
"layer": "L0",
"conversation_id": "conv_102",
"message_id": "msg_17"
},
"status": "active"
}
Now the Agent can use the concise memory while engineers can inspect its origin.
That gives you two properties:
Fast retrieval
+
Auditable evidence
Provenance is Especially Important for L3
High-level memory is usually several transformations away from the original conversation.
Consider:
L0
"We are moving checkout automation to Playwright."
↓
L1
"Checkout automation uses Playwright."
↓
L2
"Checkout automation follows a Playwright-based strategy."
↓
L3
"Team prefers Playwright."
The L3 statement is more abstract.
It is also more dangerous if incorrect.
Therefore:
L3
↓
L2
↓
L1
↓
L0
should remain traceable.
Deduplicate Before Sending Context to the Agent
Hybrid retrieval can produce duplicate or near-duplicate memories:
Playwright is preferred.
The team prefers Playwright.
Browser automation uses Playwright.
Playwright is the team's browser framework.
Sending all four to the model wastes context.
A deduplication stage can consolidate them:
def deduplicate(memories):
groups = cluster_similar(memories)
return [
select_best(group)
for group in groups
]
The resulting context could be:
Team browser automation preference:
Playwright.
Evidence:
3 independent observations.
Confidence:
0.94.
This is significantly cleaner.
Separate Retrieval From Context Construction
This distinction deserves attention.
Retrieval asks:
Which memories are relevant?
Context construction asks:
How should those memories be presented?
A retrieval engine might return:
20 records
but the LLM should not necessarily receive all 20.
Instead:
Retrieve
↓
Rank
↓
Deduplicate
↓
Compress
↓
Group
↓
Attach provenance
↓
Build context
For example:
def build_context(memories):
memories = deduplicate(memories)
memories = rank(memories)
return {
"current_facts": extract_facts(memories),
"scenarios": extract_scenarios(memories),
"preferences": extract_preferences(memories),
"evidence": extract_sources(memories)
}
Now the Agent receives structured context rather than database noise.
Facts, Preferences, and Temporary State Need Different Types
Do not store everything as:
content: string
Instead distinguish:
fact
preference
decision
constraint
scenario
observation
temporary_state
inference
For example:
{
"type": "fact",
"content": "The checkout API exposes /users/test."
}
versus:
{
"type": "preference",
"content": "The team prefers API-based test data."
}
versus:
{
"type": "temporary_state",
"content": "Payment test is currently timing out."
}
This prevents temporary debugging information from becoming permanent organizational knowledge.
Use a Candidate Memory Stage
Not every extracted observation should immediately become permanent.
A safer lifecycle is:
Observation
↓
Candidate
↓
Validation
↓
Active Memory
↓
Updated / Superseded
↓
Archived
For example:
candidate = {
"content": "Team prefers Playwright",
"status": "candidate",
"confidence": 0.61
}
After repeated confirmation:
candidate["status"] = "active"
candidate["confidence"] = 0.94
This reduces memory pollution.
Contradiction Detection Should Be Automatic
Long-lived memory eventually develops conflicts.
Example:
Memory A:
Checkout uses Selenium.
Memory B:
Checkout uses Playwright.
Memory C:
Checkout is migrating to Playwright.
Rather than blindly retrieving all three, identify the conflict:
def detect_conflicts(memories):
grouped = group_by_subject(memories)
return [
group
for group in grouped
if contains_conflicting_values(group)
]
Then investigate:
timestamp
+
scope
+
status
+
source
+
supersession
A conflict can then become:
Historical:
Selenium
Transition:
Migration to Playwright
Current:
Playwright
That is much more useful than deleting one record.
Compare Simple Vector Search With a Production Pipeline
| Capability | Simple Vector Search | Production Memory Pipeline |
|---|---|---|
| Vector similarity | ✓ | ✓ |
| Keyword retrieval | Sometimes | ✓ |
| Layer selection | ✗ | ✓ |
| Scope filtering | Optional | Required |
| Freshness | Usually limited | Explicit |
| Confidence | Usually limited | Explicit |
| Provenance | Optional | Strong |
| Deduplication | Optional | ✓ |
| Conflict detection | Rare | ✓ |
| Lifecycle | Basic | Explicit |
| Context construction | Basic | Structured |
| Evaluation | Often manual | Measurable |
This is why simply adding a vector database does not automatically create good Agent memory.
A Production-Oriented Pipeline
You can model the complete system as:
USER QUERY
│
▼
Query Understanding
│
▼
Authentication
│
▼
Scope Resolution
│
▼
Layer Selection
│
▼
┌───────────────────────┐
│ Hybrid Retrieval │
│ │
│ BM25 + Vector Search │
└───────────┬───────────┘
▼
Ranking
│
▼
Deduplication
│
▼
Freshness Check
│
▼
Conflict Detection
│
▼
Provenance Check
│
▼
Evidence Threshold
│ │
Enough? Not enough
│ │
▼ ▼
Context Deeper Layer
│ │
└────┬─────┘
▼
Context Builder
│
▼
AGENT
This architecture is far more robust than:
query → vector search → LLM
Test the Memory System Like an SDET
Persistent Agent memory should be tested just like an API or distributed system.
Create tests for:
Retrieval accuracy
def test_checkout_framework():
result = retrieve(
"What framework does checkout use?"
)
assert "Playwright" in result.text
Scope isolation
def test_project_isolation():
result = retrieve(
"What browser framework do we use?",
project="checkout"
)
assert all(
item.project == "checkout"
for item in result.memories
)
Freshness
def test_current_framework():
result = retrieve(
"What framework do we currently use?"
)
assert result.current_value == "Playwright"
Provenance
def test_memory_has_source():
result = retrieve(
"Why did we migrate frameworks?"
)
assert result.evidence
Conflict handling
def test_old_memory_does_not_override_new():
result = retrieve(
"What framework do we use now?"
)
assert result.answer != "Selenium"
This makes memory behavior observable and regression-testable.
Measure More Than Answer Accuracy
A sophisticated evaluation suite should measure:
Retrieval Recall
Precision@K
MRR
Correct Layer Selection
Scope Accuracy
Freshness Accuracy
Conflict Resolution
Evidence Coverage
Latency
Token Consumption
You might discover:
Accuracy: 94%
Latency: 180 ms
Token reduction: 63%
Evidence coverage: 91%
Those measurements tell you much more than:
"The Agent seems better."
An Interactive Challenge for Your Own Agent
Take five historical conversations and classify every useful memory into:
L0
L1
L2
L3
Then ask:
1. Which memories are temporary?
2. Which facts have expired?
3. Which memories conflict?
4. Which memories have no provenance?
5. Which memories belong to a different project?
6. Which L3 memories are actually supported by multiple L1/L2 records?
7. Which queries can be answered without touching L0?
If you cannot answer those questions, your memory architecture probably needs stronger metadata and lineage.
The Key Architectural Insight
The real power of TencentDB Agent Memory is not simply storing more information.
It is organizing information so that the Agent can progressively move from:
"What do I already know?"
to:
"What exactly do I know?"
to:
"Where did I learn it?"
to:
"Is it still valid?"
to:
"Is it relevant to this project and this user?"
and finally:
"Is there enough evidence for me to act?"
That is the difference between a memory store and a reliable Agent memory architecture.
Internal Blog Links
- 50 Playwright Commands Every QA Engineer Should Know
- How to Build a More Reliable Test Automation Architecture
- Test Automation Framework vs Test Suite: The Critical Difference Every Engineer Should Understand
- Test Automation Framework Health: 9 Signs Your Tests Are Lying to You
- RAG Powered Performance Testing: Make k6 Tests Smarter With Real API Behavior
Internal Series Links
- Learn MCP – Zero to Hero
- Learn AI Agents for QA – Zero to Hero
- Playwright Automation – Zero to Hero
- TencentDB Agent Memory: Complete Zero to Hero
- LangGraph: Complete Zero to Hero
- Learn Python – Zero to Hero
- OpenAI Codex: Complete Zero to Hero
- Cursor AI: Complete Zero to Hero
- Claude Code Tutorial: Complete Zero to Hero
- AutoGen: Complete Zero to Hero Guide
- Free QA Resources Built From Real Experience
- QA Glossary: Test Automation Terms Every Engineer Should Know
External Links
- Tencent Cloud Agent Memory product page
- Tencent Cloud Agent Memory introduction
- Tencent Cloud self-developed Agent integration guide
- TencentDB Agent Memory GitHub repository
- Tencent Cloud Agent Memory documentation
- Tencent Cloud Agent Memory API documentation
AI Answer-Engine Optimization
What is hybrid Agent memory retrieval?
Hybrid Agent memory retrieval combines lexical keyword search with semantic vector search to find memories based on both exact terminology and contextual meaning.
And:
What is layered Agent memory?
Layered Agent memory organizes information at different abstraction levels, allowing an Agent to retrieve concise knowledge first and deeper evidence only when necessary.
AI Overview Optimization
TencentDB Agent Memory retrieval is a process of finding, ranking, validating, and assembling relevant persistent memories for an AI Agent. A reliable implementation can combine layered memory, hybrid lexical and semantic retrieval, scope filtering, freshness checks, provenance, and context construction rather than relying only on vector similarity.
People Asked Questions
What is TencentDB Agent Memory retrieval?
Explain that it refers to retrieving relevant persistent Agent memories from stored information using mechanisms such as layered retrieval, semantic/lexical search, ranking, and validation.
How does TencentDB Agent Memory retrieval work?
Query
→ Scope
→ Layer
→ Hybrid Search
→ Ranking
→ Validation
→ Context
→ AgentIs TencentDB Agent Memory retrieval the same as vector search?
Explain that vector search is only one retrieval mechanism; production memory retrieval can combine semantic search with lexical search, metadata filtering, ranking, freshness, and provenance.
Why does Agent memory need multiple layers?
Explain the difference between high-level knowledge, scenarios, atomic facts, and raw evidence.
What is hybrid retrieval for AI Agents?
Explain the combination of lexical and semantic retrieval.
Why is provenance important in Agent memory?
Explain how provenance allows a high-level memory to be traced back to supporting evidence.
How do you prevent outdated Agent memories?
Discuss timestamps, validity, status, supersession, and freshness-aware ranking.
How do you test Agent memory retrieval?
Discuss retrieval accuracy, scope isolation, freshness, provenance, contradiction detection, latency, and token consumption.
Conclusion
A production-grade memory system should never treat retrieval as a single vector-search operation. The strongest architecture combines layered memory, hybrid retrieval, scope filtering, freshness, confidence, lifecycle management, provenance, conflict detection, and structured context construction.
The practical pipeline is:
Understand
→ Scope
→ Select Layer
→ Retrieve
→ Rank
→ Validate
→ Trace
→ Compress
→ Build Context
→ Reason
When these mechanisms work together, the Agent can maintain long-term knowledge without turning every interaction into an enormous context dump.
The ultimate objective is not maximum memory.
It is maximum useful memory with minimum unnecessary context.
Final Key Takeaways
- TencentDB Agent Memory retrieval should be adaptive rather than flat.
- Start with the highest useful abstraction and drill down only when evidence is insufficient.
- Combine BM25, vector search, and ranking techniques instead of depending on semantic similarity alone.
- Treat scope filtering as a security boundary, not merely a performance optimization.
- Give memories explicit confidence, freshness, status, and provenance.
- Preserve historical information through supersession rather than blindly deleting it.
- Separate facts, preferences, decisions, inferences, and temporary state.
- Deduplicate retrieved memories before sending them to the LLM.
- Keep retrieval separate from context construction.
- Test memory like a production system: retrieval accuracy, isolation, freshness, conflicts, provenance, latency, and token usage all matter.
- The strongest Agent does not remember everything equally; it retrieves the smallest trustworthy evidence set needed for the current decision.
Continue Learning
Explore more expert articles on Mobile Testing, Backend & API, AI & Agentic, AI Tools, n8n, LangChain, CrewAI, MCP Servers, AI Agents, LlamaIndex, Docker, FastAPI, Playwright, Cypress, Test Automation, DevOps, and Software Engineering at www.skakarh.com.
QAPulse by SK delivers expert release analysis, AI engineering insights, enterprise automation strategies, migration guidance, DevOps best practices, and practical testing knowledge to help software professionals build scalable, intelligent, and production-ready software systems.



