TL;DR
Memory Echo is a finding about long-term agent memory: when an agent retrieves a note and writes a recap of it back, a single old record multiplies into several. The fix, FPA (Family–Provenance–Authority), adds three steps between retrieval and answering. It keeps one representative per source in the context, switches off stale records once a verified correction arrives, and forces the answer to rest on confirmed facts.
You know the pain. You told your agent: “I'm looking for low-carb vegetables.” It still recommends the keto bars you talked about a month ago. The reason: the old recommendation got recapped and saved over and over. Now it holds three to five slots in search results, while your correction holds one. To the model that looks like “five independent confirmations versus one,” even though all five come from the same source. Crucially, plain reading without writing doesn't cause this. The echo grows specifically from the “retrieve → recap → write” loop. Even after the correction, the old record's descendants stay in the results and keep leaning on the answer.
The method fixes this in three steps. Step 1: records are grouped by origin (by “parent,” not by wording), and at most one per family gets into the context. Step 2: if a verified correction has arrived, the whole old family stays in the archive but is not allowed to take part in the current answer. Step 3: the answer is built from confirmed data, and the draft is checked against it.
Want this for your own case? Apply this study to your task: AI adapts its method to what you are working on and writes the prompt.
Method Blueprint
STEP 1 (Family): group retrieved records by source/parent
→ at most 1 record per family goes into the context
STEP 2 (Provenance): check records against the verified correction
→ the old family stays in the archive but is barred from the answer
STEP 3 (Authority): answer from verified, current facts
→ the draft is checked against the admitted data
The store is never deleted: history is kept for auditing.
Only what enters the answer's context changes.
In the paper, FPA runs as code between memory retrieval and answer generation. The steps are not executed by a single prompt.
Example in Practice
Task: You run a small coffee shop in Austin. A purchasing agent keeps notes on suppliers. In those notes, the bean price from “Southfield Farms” ($16.50/kg) is recorded three times: the supplier's email, a recap in the meeting notes, and a line in the weekly summary. All three descend from one email. Then an invoice arrives with the price now at $20/kg. You ask the agent to calculate the month's purchase.
Prompt:
You are the coffee shop's purchasing agent. Before answering, go through three stages.
<Records>
M1 | source: supplier email (March 12) | parent: — | status: active
“Arabica Blend beans, $16.50/kg”
M2 | source: meeting notes (March 14) | parent: M1 | status: active
“Southfield Farms is holding the price at $16.50/kg”
M3 | source: weekly summary (March 21) | parent: M2 | status: active
“Main bean supplier: Southfield Farms, ~$16.50/kg”
M4 | source: supplier invoice #188 (April 2) | parent: — | status: verified
“Arabica Blend, $20/kg, effective April 1”
M5 | source: coffee shop operating schedule | parent: — | status: active
“Bean usage: 60 kg per month”
</Records>
<Stage_1_Family>
Group the records into families by parent and source, not by wording.
Keep no more than one representative record from each family.
Output the list of families and the chosen representatives.
</Stage_1_Family>
<Stage_2_Provenance>
Check the families against the verified records.
If a verified record replaces a fact, the whole old family is marked
“archived, not for answering.”
Output which records are admitted to the answer, which are switched off, and why.
</Stage_2_Provenance>
<Stage_3_Authority>
Answer the question using only the admitted records.
If there is no verified source, say so plainly.
Check the draft against the admitted records and fix any mismatches.
</Stage_3_Authority>
Question: how much will we spend on beans in April?
Result: The model will show three blocks. In the first, records M1–M3 are merged into one family with a single representative, while M4 and M5 stand on their own. In the second, the old family is marked as switched off because of invoice M4. In the third, the calculation uses the invoice price and the usage from the schedule, and the old price stays out of the math. The model does the actual arithmetic itself.
Why It Works
The weakness. The model doesn't know that three records are the same email. To it, three similar notes look like three independent confirmations. The more repeats, the heavier the old version weighs, and a single fresh correction loses to the choir. Stopping the writes doesn't kill this inertia: the descendants are already sitting in the store.
The strength. If each record carries metadata (where it came from, whose descendant it is, whether it's verified), deduplicating by origin and checking against verified facts is an easy job. The researchers showed you need to group by lineage, not by word similarity. Two independent sources can say the same thing, while two recaps of the same retrieval remain one family.
How the method exploits this. It steps in between retrieval and answering. The store stays untouched, so nothing is lost and everything can be audited. What changes is what gets admitted into the context.
Levers:
- Per-family limit (one record in the paper) → you can raise it to two for complex tasks, but the echo will come back.
- Order of checks → families first, then corrections, then the answer: in this order each step cleans the input for the next.
- Record status (active / verified / archived) → the key to the whole method. Without it, step 2 doesn't work.
- Rule for when there's no verified source → swap in your own: “ask the user,” “flag as unverified.”
Prompt Template
The paper has no ready-made prompts; FPA is implemented there as code. Below is a translation of the three-step logic into text instructions you can run in a chat or an agent. This is not the authors' prompt.
You are an agent with long-term memory. Before every answer, go through three stages.
<Records>
{id} | source: {source} | parent: {parent id or —} | status: {active / verified / archived}
{record text}
...
</Records>
<Stage_1_Family>
Group the records into families by parent and source, not by wording.
Two records with different words but a shared parent are one family.
Admit no more than {per_family_limit} record(s) from each family.
Output: the families and the chosen representatives.
</Stage_1_Family>
<Stage_2_Provenance>
Check the families against the verified records.
If a verified record replaces or refutes a fact, the whole old family
gets the status “archived” and is not admitted to the answer.
Do not delete or modify archived records.
Output: admitted records, switched-off records, the reason.
</Stage_2_Provenance>
<Stage_3_Authority>
Answer the question using only the admitted records.
If there is no verified source, say so and {action_without_source}.
Check the draft against the admitted records and fix any mismatches.
</Stage_3_Authority>
<Rule>
Do not write your recap of a retrieved note as a new fact.
If you need to save a recap, name its parent and mark it as derived.
</Rule>
Question: {question}
What to fill in:
- {id}, {source}, {parent}, {status} — data from your notes. You can reconstruct the parent like this: “this record is a recap of that one.”
- {per_family_limit} — 1 by default.
- {action_without_source} — “ask me a clarifying question” or “flag the answer as unverified.”
- {question} — the current task.
🚀 Quick start — paste into the chat:
Here is a template with three stages for cleaning up memory (families → admission based on verified corrections → answer from confirmed facts). Adapt it to my task: [your task].
Ask me questions to fill in the fields.
[paste the template above]
The LLM will ask where your records come from, what counts as a verified source for you, and what to do without verification. That's because the method rests on three things: record origin, the “verified” status, and a rule for the unconfirmed case. The model will take the structure from the template and fit it to your note-keeping system.
Limitations
⚠️ Metadata required: the method works when records have a source, a parent, and a status. If your notes are flat text with no origin, step 1 can't tell “five recaps of one thing” from “five independent sources.”
⚠️ A verified source is required: steps 2 and 3 rely on a confirmed “ground truth” (an invoice, a document, your direct correction). What to do when there isn't one, the authors did not test. The recovery branch in the diagram is labeled illustrative.
⚠️ In the paper it's code, not a prompt: FPA is built into memory retrieval for four existing systems. Moving it into a chat prompt is our translation of the logic. The authors did not measure the effect of that translation.
⚠️ Reading without writing doesn't feed the echo: the problem comes from the “retrieve → recap → write” loop. If your agent writes nothing back to memory, the main part of the risk doesn't apply to you.
⚠️ The effect is uneven: in two of the four systems the accuracy gain is more modest. There the final retrieval results often stay “clogged” with old records, yet the answer still improves. A single snapshot of the results doesn't show what happens to the answer.
⚠️ The test is artificial: the “old claim” was taken from another real answer in the same dataset. Real-world scenarios (shopping, medicine, travel) were checked on an early pilot protocol and aren't part of the headline numbers. Some appendices aren't visible in the text.
How They Studied It
The researchers built a benchmark called MEchoBench. They took 50 questions each from four well-known memory evaluation sets (LoCoMo, LongMemEval, HotpotQA, BEAM). That left 190 questions, with ten set aside for development. Into each question they mixed an “old” claim taken from another real answer, while the correct answer served as the verified correction. For each question they created three memory histories. In the first, the old claim appears once; in the second, it's read six times without writing; in the third, a recap is written after every read. Then the same correction was introduced in all histories, followed by 30 more memory reads with no writes.
The picture came out clear. Reading without writing barely changes anything, while writing recaps sharply increases the old family's share in all four memory systems (A-MEM, Mem0, CoM, LangMem). The takeaway: the culprit is the “retrieve → write” loop itself, not any particular ranking algorithm. After the correction, the old descendants kept occupying slots: the old family's presence score in the results held at around 0.65–0.70 across all 30 no-write queries. The echo lives on without new writes, as an inherited advantage.
To compare methods fairly, the candidates and the history were frozen. Four retrieval approaches were run on the same set of records with two models (DeepSeek V4 Flash and Kimi K2.6). Answers were graded by GPT-5.6. Baseline accuracy was 0.825 (DeepSeek) and 0.782 (Kimi); with FPA it rose to 0.920 and 0.916. “Decision contamination” (how much closer the answer is to the old claim than to the correct one) dropped from 0.106 to 0.030 and from 0.109 to 0.038. Three standard alternatives (a repetition penalty, record quality scoring, learned ranking) also raised accuracy but barely removed the persistent presence of the old family. FPA cut persistent presence the most: the index fell from 0.427 to 0.057. The practical lessons: a useful write can help the answer while old descendants still creep into the results, and cleanup has to go by lineage and by correction status.
Adaptations and Extrapolations
💡 Adaptation for an agent instructions file (CLAUDE.md, AGENTS.md, assistant memory): the principle carries over into note-keeping rules. This is our extrapolation: the authors did not test such rules in prompts.
## Memory rules
- Every note record: what, where from (source), whose recap (parent),
status (active / verified / replaced).
- Do not write a recap of a retrieved note as a new fact. Write: “derived from {id}”.
- When I correct a fact or a confirming document arrives: mark the old record
and all its derivatives as “replaced”, do not delete them.
- When answering, rely on records with the status “verified”; from each chain
of recaps take no more than one record.
- No verified source — say so, don't silently fall back on the old version.
🔧 Technique: add a memory audit → catch the echo before it sways the answer
Here are my notes on {topic}. Find records that are recaps of each other
(shared source, different words). Group them into families and show how many
“votes” each version of a fact really has. Flag versions that contradict
more recent verified records.
This way you can see that “five confirmations” are really one source.
Resources
- Paper title: Memory Echo in Single-Agent Long-Term Memory: Lifecycle Evaluation and Provenance-Guided Mitigation
- Code and benchmark: https://github.com/OrcasSam/memory-echo-benchmark
- Authors: Yufeng Li, Sheng Yao, Peng Zeng, Dezhang Kong, Shi Lin, Changting Lin, Xun Wang, Meng Han
- Affiliations: East China Normal University, University of Southern California, Zhejiang University, Zhejiang Gongshang University
- Memory systems in the paper: A-MEM, Mem0, CoM, LangMem
- Datasets: LoCoMo, LongMemEval, HotpotQA, BEAM