Cloud & Databases

Building TencentDB Agent Memory Layers: L0 to L3 Explained

TencentDB Agent Memory retrieval is more than vector search. Learn how layered memory, hybrid retrieval, confidence, freshness, provenance, scope filtering, and context construction work together to build reliable AI Agent memory systems.

43 min read
Building TencentDB Agent Memory Layers: L0 to L3 Explained
Advertisement
What You Will Learn
Why AI Agent Memory Needs Layers
L0: Conversation Is the Ground Truth
L0 Is Detailed but Expensive
L1: Atom Turns Conversations Into Facts
⚡ Quick Answer
TencentDB Agent Memory layers enhance AI Agent performance by structuring knowledge, converting raw conversation data into reusable facts and high-level user context. This layered approach, from L0 Conversation to L3 Persona/Core, efficiently manages vast information, preventing noise and ensuring traceability for critical development and automation decisions.

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:

Code
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:

Code
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:

Code
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:

Code
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:

JSON
{
  "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:

Code
"The team uses Playwright."

a developer may eventually need to know:

Code
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)

Image

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:

Code
L3:
Team prefers Playwright for browser automation.

If the Agent needs evidence:

Code
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:

Code
User:
We are moving checkout automation from Selenium to Playwright.
Keep the existing Page Object naming conventions.

the system might produce:

JSON
[
  {
    "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:

Code
Thousands of conversation messages

the system can search:

Code
Relevant facts

This dramatically changes the retrieval problem.

Why Atomic Memory Matters

Consider these three records.

Raw conversation

Code
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

Code
Fact:
Checkout automation uses Playwright.

Constraint:
Existing Page Object names must remain unchanged.

Dependency:
Another team depends on the existing Page Objects.

Search query

Code
"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:

JSON
{
  "id": "atom_204",
  "layer": "L1",
  "content": "Checkout automation uses Playwright.",
  "source": {
    "layer": "L0",
    "id": "conversation_102"
  }
}

Now the Agent can answer:

Code
What is the fact?

and an engineer can also answer:

Code
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:

Code
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:

Code
Checkout Automation Strategy

L2 can organize those related memories into a coherent scenario.

For example:

Shell
# 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:

Code
Retrieve 30 individual facts
↓
Rank them
↓
Reconstruct the project context

With L2:

Code
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:

Code
Scenario 1:
Checkout automation

Scenario 2:
Payments automation

Scenario 3:
Authentication automation

Across those scenarios, the system may identify:

Code
The team prefers Playwright for browser automation.

That becomes higher-level knowledge.

A conceptual L3 record could look like:

JSON
{
  "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:

Code
The user always uses Playwright.

is dangerous.

This is better:

Code
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

CharacteristicFlat Vector MemoryLayered Memory
Raw conversationsUsually mixed with other recordsPreserved at L0
Atomic factsMay be independent chunksExplicit L1 layer
ScenariosOften implicitExplicit L2 layer
Persona/contextUsually inferred during retrievalExplicit L3 layer
RetrievalPrimarily similarity-drivenHierarchical + semantic
TraceabilityCan be difficultDesigned into relationships
Context efficiencyVariableProgressive disclosure
DebuggingOften opaqueCan inspect each layer
Long-term organizationWeakStrong

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:

Code
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:

Code
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:

Code
"OAuth configuration for checkout"

A keyword search might find:

Code
OAuth
checkout
authentication

A vector search might find semantically related content:

Code
authorization setup
token configuration
identity provider

Each has strengths.

Retrieval MethodBest At
BM25Exact terms and keywords
Vector searchSemantic similarity
Metadata filtersScope and authorization
RRFCombining ranking signals

A production memory system can combine them.

Python
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:

Code
L0 → L1 → L2 → L3

It is:

Code
Start high
↓
Drill down only when necessary

For a simple request:

Code
"What framework do we use?"

L3 may be enough.

For:

Code
"Why did we move from Selenium to Playwright?"

the system may need:

Code
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:

Python
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:

Code
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:

Code
"The team uses Cypress."

But the actual project uses Playwright.

With flat vector memory, you may see:

Code
Result #1
Result #2
Result #3

and a set of similarity scores.

Finding the problem can be difficult.

With layered memory, you can investigate:

Code
L3 Persona
      ↓
L2 Scenario
      ↓
L1 Atom
      ↓
L0 Conversation

Perhaps the problem is:

Code
L1 Atom was extracted incorrectly.

Or:

Code
L2 Scenario was not updated.

Or:

Code
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)

TencentDB memory layers L0 conversation L1 atom L2 scenario and L3 persona architecture
TencentDB memory layers L0 conversation L1 atom L2 scenario and L3 persona architecture

Build a Layered Memory Schema

A practical implementation can define a common memory structure:

Advertisement
Code
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.

Code
conversation = Memory(
    layer="L0",
    content=raw_message,
    source_ids=[],
    confidence=1.0,
    scope="project-alpha"
)

An extracted atom:

Code
atom = Memory(
    layer="L1",
    content="Checkout automation uses Playwright.",
    source_ids=[conversation.id],
    confidence=0.94,
    scope="project-alpha"
)

A scenario:

Code
scenario = Memory(
    layer="L2",
    content="Checkout automation strategy",
    source_ids=[atom.id],
    confidence=0.91,
    scope="project-alpha"
)

A persona/core record:

Code
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:

Code
Project Alpha:
Playwright

Project Beta:
Cypress

A global search for:

Code
"What browser framework do we use?"

could retrieve both.

The memory system should understand:

Code
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:

Code
Conversation
↓
One giant summary

This is easy but dangerous.

Suppose the summary says:

Code
"The team uses Playwright and API-based test data."

What happens when you need to know:

Code
Why?
When?
Who decided?
What exception exists?
Which project?

The summary may not contain the answer.

A layered architecture instead provides:

Code
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:

Code
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:

InformationLayer
Raw user messageL0
“Checkout uses Playwright”L1
“Checkout automation strategy”L2
“Team prefers Playwright”L3
Temporary debugging outputL0
Stable project constraintL1/L2
Repeated long-term preferenceL3

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:

Code
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:

Code
"What framework do we prefer?"
→ L3
Code
"How does checkout automation work?"
→ L2
Code
"What API creates the test user?"
→ L1
Code
"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:

Code
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:

Code
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:

Code
What browser automation framework does our team prefer?

If the system already has a validated L3 memory:

Code
Team preference:
Playwright is preferred for browser automation.

there is little reason to retrieve hundreds of historical conversations.

The retrieval path can remain:

Code
User Query
    ↓
L3 Persona/Core
    ↓
Confidence Check
    ↓
Answer

But consider a different question:

Code
Why did we move checkout automation from Selenium to Playwright?

A high-level preference is insufficient.

The system should progressively investigate:

Code
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.

Python
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:

Code
Query Type → Retrieval Depth

rather than:

Code
Every Query → Search Everything

Why Searching Everything Is a Bad Strategy

Imagine a memory database containing:

Code
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:

Code
L3
 ↓
If insufficient
 ↓
L2
 ↓
If insufficient
 ↓
L1
 ↓
If evidence required
 ↓
L0

This produces a much more controlled retrieval process.

StrategySearch ScopeContext NoiseComplexity
Full historyVery largeHighLow initially
Flat vector memoryLargeMediumMedium
Metadata-filtered vector memoryReducedLowerMedium
Layered retrievalAdaptiveLowHigher
Layered + hybrid retrievalAdaptive + preciseVery lowHigher

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:

JSON
{
  "content": "The team prefers Playwright.",
  "confidence": 0.91
}

That may be sufficient for:

Code
Which browser framework does the team prefer?

But if the result is:

JSON
{
  "content": "The team may prefer Playwright.",
  "confidence": 0.51
}

the Agent should probably investigate further.

A conceptual controller:

Python
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:

Code
enough_evidence()

because the Agent needs a measurable stopping condition.

Define an Evidence Threshold

You can start with a simple scoring model:

Python
def evidence_score(memory):
    return (
        memory.confidence * 0.45 +
        memory.relevance * 0.35 +
        memory.freshness * 0.20
    )

Then:

Python
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:

Code
How should we create checkout test users?

The vector search might return:

Code
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.

Code
results = vector_search(
    query=query,
    filters={
        "project_id": "checkout",
        "memory_status": "active"
    }
)

A production retrieval request might conceptually include:

Code
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:

Code
Query
 ↓
Authorization
 ↓
Metadata Filtering
 ↓
Semantic Search
 ↓
Ranking

rather than:

Code
Query
 ↓
Semantic Search
 ↓
Authorization
 ↓
Filtering

The second design can create both performance and security problems.

A conceptual implementation:

Python
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:

Code
"Playwright"

Exact lexical matching is valuable.

Now consider:

Code
"What framework do we use for browser automation?"

Semantic retrieval becomes much more valuable.

A hybrid approach combines them:

Python
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:

Code
A
B
C

while vector search produces:

Code
C
A
D

Neither ranking is necessarily correct by itself.

Reciprocal Rank Fusion can combine them:

Python
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:

Code
L3:
Team prefers Playwright.

linked to:

Code
L2:
Checkout automation strategy.

linked to:

Code
L1:
Checkout tests use Playwright.

linked to:

Code
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:

Code
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:

Diagram
             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.

Image
Image

Retrieval Should Return a Context Package

Do not simply pass raw database rows to the LLM.

Instead, create a structured context package:

Python
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:

Advertisement
Code
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:

SQL
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:

Code
Retrieval:
20 relevant memories

does not mean:

Code
Prompt:
20 raw database records

Context construction can:

Code
deduplicate
compress
group
rank
summarize
attach provenance
remove irrelevant fields

A useful pipeline is:

Code
Search
 ↓
Rank
 ↓
Deduplicate
 ↓
Group
 ↓
Compress
 ↓
Attach Provenance
 ↓
Build Context

Deduplication Prevents Context Inflation

Suppose retrieval returns:

Code
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:

Python
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:

Code
semantic relevance
keyword relevance
confidence
freshness
importance
scope
layer
source quality

For example:

Python
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:

Code
Similarity ≠ Truth

A highly similar memory can still be:

Code
old
wrong
out of scope
low confidence
superseded

Freshness Needs to Be Explicit

Consider:

Code
2025:
Team uses Selenium.

and:

Code
2026:
Team uses Playwright.

A similarity search may find both.

A freshness signal can help:

Python
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:

Code
freshness
+
explicit superseding
+
confidence
+
scope

Supersession Is Better Than Silent Replacement

Instead of deleting:

Code
Selenium is used for checkout.

when Playwright becomes the new standard, represent the relationship:

JSON
{
  "old_memory": "memory_101",
  "new_memory": "memory_207",
  "relationship": "superseded_by"
}

Now the system knows:

Code
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:

FeatureTraditional RAGLayered Agent Memory
Main sourceDocumentsConversations + extracted knowledge
Primary goalRetrieve external knowledgePreserve agent/user/project knowledge
HierarchyOptionalCore architectural concept
User preferencesUsually secondaryImportant
Temporal evolutionOften limitedCentral
Memory lifecycleBasicImportant
Evidence tracingDocument-basedMemory lineage
PersonalizationLimitedStrong

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.

Code
External Knowledge
       ↓
RAG
       ↓
+
Persistent Agent Memory
       ↓
Agent Context

That combination is particularly powerful for enterprise systems.

Memory Layers vs Simple Conversation Summaries

CapabilityConversation SummaryLayered Memory
Compresses historyYesYes
Preserves atomic factsSometimesExplicitly
Scenario organizationLimitedExplicit
Long-term preferencesWeakStrong
Evidence traceabilityLimitedStrong
Selective retrievalLimitedStrong
Conflict managementBasicCan be explicit
Progressive disclosureNoYes

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:

Python
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:

Diagram
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.

JSON
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:

Code
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:

Code
L3 retrieval = 10 ms
L2 retrieval = 20 ms
L1 retrieval = 40 ms
L0 retrieval = 100 ms

You could conceptually optimize:

Python
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:

Diagram
                   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:

Code
L0 → evidence
L1 → facts
L2 → scenarios
L3 → stable understanding

while retrieval determines:

Code
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:

Code
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:

Code
How do we create checkout test users?

A vector search might return:

Code
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:

Code
similarity_score

It needs:

Code
similarity
+
scope
+
freshness
+
confidence
+
status
+
provenance

A useful conceptual ranking function is:

Python
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:

Code
Project A
Browser automation → Playwright

Project B
Browser automation → Cypress

Now ask:

Code
What browser automation framework do we use?

A global semantic search could return both.

The system needs to know:

Code
Which project?
Which team?
Which user?
Which tenant?
Which Agent?

A memory record can therefore contain explicit scope:

JSON
{
  "id": "memory_204",
  "layer": "L1",
  "content": "Checkout tests use Playwright.",
  "scope": {
    "tenant": "company-a",
    "project": "checkout",
    "team": "qa"
  },
  "status": "active"
}

Then retrieval becomes:

Code
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:

Code
Tenant
  ↓
Organization
  ↓
Team
  ↓
Project
  ↓
Agent
  ↓
User
  ↓
Session

Not every memory belongs to every level.

For example:

Code
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.

Image
Image

Freshness Changes the Meaning of Memory

Memory is not always timeless.

Consider:

Code
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:

JSON
{
  "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:

Code
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:

Code
Selenium is used for browser automation.

Instead of deleting it, create a relationship:

JSON
{
  "source": "memory_101",
  "target": "memory_207",
  "relationship": "superseded_by"
}

The resulting knowledge chain becomes:

Code
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:

Code
User explicitly stated:
"We use Playwright."

with:

Code
Agent inferred:
"The team probably uses Playwright."

They should not receive identical confidence.

A conceptual memory model:

Code
memory = {
    "content": "Team uses Playwright",
    "confidence": 0.95,
    "source_type": "explicit_user_statement"
}

versus:

Code
memory = {
    "content": "Team uses Playwright",
    "confidence": 0.62,
    "source_type": "agent_inference"
}

Possible source categories include:

SourceTypical Trust
Explicit user statementVery high
Verified tool outputVery high
Project configurationHigh
Repeated observed behaviorMedium-high
Agent-generated inferenceMedium
Weak semantic inferenceLow

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:

SQL
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:

Advertisement
Code
confidence = base_confidence + repetition_bonus

Conceptually:

Code
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:

Code
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:

Python
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:

Code
timestamp
source
scope
status
supersession
explicit confirmation

This is where provenance becomes extremely valuable.

Provenance Makes Memory Auditable

A high-quality memory should answer:

Code
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:

JSON
{
  "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:

Code
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:

Code
L3 → ??? 

With provenance:

Code
L3
 ↓
L2
 ↓
L1
 ↓
L0

This creates a traceable chain.

Image
Image
Image

Hybrid Search Should Be Combined With Layer Selection

Hybrid search and layered memory solve different problems.

Think of them like this:

Code
Layer Selection
=
Where should I search?

Hybrid Search
=
How should I find relevant records there?

For example:

Code
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:

Code
vector.search(query)

across the entire database.

Compare Flat RAG, Vector Memory, and Layered Retrieval

CapabilityFlat RAGVector MemoryLayered + Hybrid Memory
Semantic retrieval
Keyword retrievalOptionalOptional
Raw conversation preservationLimitedPossibleExplicit
Memory hierarchyNoUsually noYes
Scope awarenessDepends on implementationDepends on implementationExplicitly designed
ProvenanceDocument-orientedVariableStrong lineage model
Temporal lifecycleLimitedVariableImportant
Progressive disclosureNoLimitedYes
Contradiction handlingBasicBasicCan be explicit
Long-term personalizationModerateGoodStrong

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:

Code
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:

Code
content
+
evidence
+
metadata
+
lifecycle

That makes downstream reasoning more reliable.

Use Structured Memory Instead of Prompt Fragments

Avoid storing memories like:

Code
"User likes Playwright. Maybe prefers API testing too. Probably dislikes Selenium."

This is difficult to query and difficult to verify.

Prefer:

JSON
{
  "preference": {
    "subject": "browser automation",
    "value": "Playwright",
    "confidence": 0.94,
    "status": "active"
  }
}

And:

JSON
{
  "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:

Code
Fact:
The checkout service exposes /users/test.

and:

Code
Preference:
The team prefers API-based test data generation.

One describes the system.

The other describes a choice.

Your schema should distinguish them:

JSON
{
  "type": "fact",
  "content": "Checkout exposes /users/test."
}

versus:

JSON
{
  "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:

Code
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:

Code
Payment API is always slow.

for months.

Instead:

Code
Session State
→ temporary

Persistent Memory
→ validated knowledge

A useful lifecycle is:

Code
Observation
   ↓
Candidate Memory
   ↓
Validation
   ↓
Persistent Memory

This reduces memory pollution.

Think in Terms of Memory Lifecycle

A practical lifecycle could look like:

Code
Captured
   ↓
Extracted
   ↓
Validated
   ↓
Active
   ↓
Updated
   ↓
Superseded
   ↓
Archived

For example:

Code
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:

Code
active

and exclude:

Code
archived

unless historical evidence is requested.

For example:

Code
results = search(
    query=query,
    filters={
        "status": "active"
    }
)

For a historical question:

Code
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 QuestionPrimary LayerAdditional Evidence
What do I prefer?L3L2/L1 if uncertain
What does this project use?L2L1
What is the exact API?L1L0 if ambiguous
Why was this decision made?L1L0
What happened previously?L0L1/L2
What changed over time?L2/L1L0
Is this memory still valid?L1/L2Provenance

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.

JSON
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:

Code
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

Code
Given a known query,
retrieve the correct memory.

Scope tests

Code
Given Project A,
do not return Project B memories.

Freshness tests

Code
Given an updated decision,
prefer the active memory.

Provenance tests

Code
Given a high-level memory,
trace it back to source evidence.

Example:

Python
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:

Code
Retrieved = Correct

Instead:

Code
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:

Code
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:

Code
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:

Python
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:

Code
"What framework do we prefer?"

with:

Code
"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:

Python
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:

Code
classification = llm.classify(
    query,
    categories=[
        "preference",
        "scenario",
        "fact",
        "history",
        "general"
    ]
)

Then:

Code
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:

Code
L3 → "Team prefers Playwright."

That may completely answer:

Code
Which browser framework do we prefer?

But:

Code
Why did we choose Playwright?

requires deeper investigation.

A useful controller:

Python
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:

Code
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:

Code
L3
 ↓
Enough?
 ↓ yes
Answer

For a difficult historical question:

Code
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:

Code
"Playwright checkout fixture"

Keyword retrieval can strongly identify exact matches.

Now consider:

Code
"How does the team prepare browser tests?"

A semantic search may discover:

Code
browser fixtures
test setup
Playwright initialization
automation bootstrap

A hybrid system combines both signals.

Advertisement
Python
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:

Code
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:

Python
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:

Code
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:

JSON
{
  "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:

Code
active
superseded
expired
archived

Never Silently Delete Important Historical Memory

Suppose:

Code
Selenium

was replaced by:

Code
Playwright

Do not necessarily delete Selenium from the memory system.

Instead:

JSON
{
  "old_memory": "selenium_memory",
  "new_memory": "playwright_memory",
  "relationship": "superseded_by"
}

The memory graph becomes:

Code
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:

Diagram
Company A
 ├── Project Checkout
 └── Project Payments

Company B
 └── Project Checkout

A query such as:

Code
"How do we test checkout?"

must not accidentally retrieve information from another tenant.

A retrieval request should carry scope:

Code
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.

Image

Provenance Should Follow Every Important Memory

Suppose the Agent retrieves:

Code
"The checkout team uses Playwright."

The system should ideally know:

Code
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:

JSON
{
  "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:

Code
Fast retrieval
+
Auditable evidence

Provenance is Especially Important for L3

High-level memory is usually several transformations away from the original conversation.

Consider:

Code
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:

Code
L3
 ↓
L2
 ↓
L1
 ↓
L0

should remain traceable.

Image

Deduplicate Before Sending Context to the Agent

Hybrid retrieval can produce duplicate or near-duplicate memories:

Code
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:

Python
def deduplicate(memories):
    groups = cluster_similar(memories)

    return [
        select_best(group)
        for group in groups
    ]

The resulting context could be:

Code
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:

Code
Which memories are relevant?

Context construction asks:

Code
How should those memories be presented?

A retrieval engine might return:

Code
20 records

but the LLM should not necessarily receive all 20.

Instead:

Code
Retrieve
 ↓
Rank
 ↓
Deduplicate
 ↓
Compress
 ↓
Group
 ↓
Attach provenance
 ↓
Build context

For example:

Python
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:

Code
content: string

Instead distinguish:

Code
fact
preference
decision
constraint
scenario
observation
temporary_state
inference

For example:

JSON
{
  "type": "fact",
  "content": "The checkout API exposes /users/test."
}

versus:

JSON
{
  "type": "preference",
  "content": "The team prefers API-based test data."
}

versus:

JSON
{
  "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:

Code
Observation
    ↓
Candidate
    ↓
Validation
    ↓
Active Memory
    ↓
Updated / Superseded
    ↓
Archived

For example:

Code
candidate = {
    "content": "Team prefers Playwright",
    "status": "candidate",
    "confidence": 0.61
}

After repeated confirmation:

Code
candidate["status"] = "active"
candidate["confidence"] = 0.94

This reduces memory pollution.

Contradiction Detection Should Be Automatic

Long-lived memory eventually develops conflicts.

Example:

Code
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:

Python
def detect_conflicts(memories):
    grouped = group_by_subject(memories)

    return [
        group
        for group in grouped
        if contains_conflicting_values(group)
    ]

Then investigate:

Code
timestamp
+
scope
+
status
+
source
+
supersession

A conflict can then become:

Code
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

CapabilitySimple Vector SearchProduction Memory Pipeline
Vector similarity
Keyword retrievalSometimes
Layer selection
Scope filteringOptionalRequired
FreshnessUsually limitedExplicit
ConfidenceUsually limitedExplicit
ProvenanceOptionalStrong
DeduplicationOptional
Conflict detectionRare
LifecycleBasicExplicit
Context constructionBasicStructured
EvaluationOften manualMeasurable

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:

Diagram
                  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:

Code
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

Python
def test_checkout_framework():
    result = retrieve(
        "What framework does checkout use?"
    )

    assert "Playwright" in result.text

Scope isolation

Python
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

Python
def test_current_framework():
    result = retrieve(
        "What framework do we currently use?"
    )

    assert result.current_value == "Playwright"

Provenance

Python
def test_memory_has_source():
    result = retrieve(
        "Why did we migrate frameworks?"
    )

    assert result.evidence

Conflict handling

Python
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:

Code
Retrieval Recall
Precision@K
MRR
Correct Layer Selection
Scope Accuracy
Freshness Accuracy
Conflict Resolution
Evidence Coverage
Latency
Token Consumption

You might discover:

Code
Accuracy: 94%
Latency: 180 ms
Token reduction: 63%
Evidence coverage: 91%

Those measurements tell you much more than:

Code
"The Agent seems better."

An Interactive Challenge for Your Own Agent

Take five historical conversations and classify every useful memory into:

Code
L0
L1
L2
L3

Then ask:

Code
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:

Code
"What do I already know?"

to:

Code
"What exactly do I know?"

to:

Code
"Where did I learn it?"

to:

Code
"Is it still valid?"

to:

Code
"Is it relevant to this project and this user?"

and finally:

Code
"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

Internal Series Links

External Links

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?

Code
Query
→ Scope
→ Layer
→ Hybrid Search
→ Ranking
→ Validation
→ Context
→ Agent

Is 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:

Code
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.

Frequently Asked Questions

What problem do TencentDB Agent Memory Layers aim to solve for AI agents working with large datasets, especially relevant in a QA context?
TencentDB Agent Memory Layers solve the problem of information overload for AI agents, which otherwise face issues like increased noise, higher token usage, and lower signal quality when managing thousands of messages, tool calls, and test results. By organizing memory by abstraction, it transforms raw data into reusable knowledge.
Can you explain the hierarchical structure of TencentDB Agent Memory Layers?
TencentDB Agent Memory utilizes a layered architecture progressing from L0 Conversation, L1 Atom, L2 Scenario, to L3 Persona/Core. This structure, conceptualized as a semantic pyramid, ensures lower layers preserve detailed evidence while higher layers provide compact context for efficient retrieval.
Why is the L0 Conversation layer critical for maintaining accuracy and traceability within the TencentDB Agent Memory system?
The L0 Conversation layer is critical because it preserves the raw, original interaction as the 'ground truth.' This allows for traceability, enabling verification of higher-level memories and providing detailed evidence to answer questions about past decisions, even if summarized information is incorrect.
Advertisement
Found this helpful? Clap to let Shahnawaz know — you can clap up to 50 times.