Why Agent Memory Is Not Learning
Remembering facts about a user is useful. Getting better at the work is a different problem.
When teams say they want an AI agent that learns, they usually reach for a memory layer.
That instinct makes sense. Out of the box, a language model starts every task from zero. If you have to remind it every Monday which repositories belong to your billing service, or that your finance lead prefers tables over prose, it feels less like a coworker and more like a temp who had their badge wiped overnight.
Over the last two years, a rich ecosystem of agent memory projects such as Mem0, Supermemory, Zep, Letta, and LangMem has taken shape. They give agents ways to persist facts, track how entities change over time, edit their own notes, or rewrite their system prompts after a conversation.
Those systems solve a real problem. But recall is not competence.
A coworker who remembers your job title, your timezone, and last week's thread, yet still wastes twenty minutes looking in the wrong place and makes the same calculation mistake on this week's billing question, has remembered plenty, but learned nothing about how to do the work.
To get better at the job, an agent needs more than a bigger notebook of past conversations. It needs a way to turn experience and feedback into explicit working methods, check those methods against real evidence, and reuse only what passes.
A mistake that memory alone does not fix
Suppose a support teammate asks an agent in Slack to handle a billing handoff: "Acme is asking in Intercom why their November invoice jumped by $480. Check Stripe and leave an internal billing note on their contact explaining the increase."
On its first attempt, the agent stumbles in two ways:
-
It wastes effort figuring out how to find the account: Instead of
reading the Stripe customer ID already stored on the Intercom contact, the
agent searches Stripe by company name (
"Acme"). It gets back three records (Acme Inc,Acme Sandbox, andAcme EU) and pulls invoice histories for all three before finding the live subscription. -
It misreads the numbers: Comparing October's
$1,200total with November's$1,680total, the agent inspects the first line ininvoice.linesand reports that "Acme added 4 seats at $120/seat."
A teammate checks the Stripe invoice—or Nine's own review of the run catches
the discrepancy—and sees that the explanation is wrong. In Stripe's API, seat
renewals and mid-cycle proration adjustments (proration: true) sit in
invoice.lines, while coupon discounts (total_discount_amounts) and applied
account credits (starting_balance) live on the top-level invoice object. Acme
only added 2 seats mid-month:
- +$240 for the 2 new seats on the November renewal.
- +$120 in mid-October seat proration billed on the same invoice.
- +$120 because a startup discount coupon on the invoice expired at the end of October.
By looking only at the headline totals and the first seat line instead of
reconciling the full invoice object, the agent attributed the entire $480
jump to new seats.
How do you stop the agent from wasting those searches and making that reconciliation mistake on the next billing question?
How today's agent memory systems approach the problem
"Agent memory" has become an umbrella term for four distinct approaches. If you apply this billing correction with each one, you get different behavior, and each approach hits a ceiling:
-
Extract facts and preferences: Systems like Mem0 and Supermemory run an extraction model on new messages and documents to pull out atomic facts, consolidate or link related facts, and index them across vectors, keywords, and entity links for future search. That works well for remembering user preferences or project names. Here, however, the extracted fact is just an observation about Acme's November bill:
Fact: Acme's November invoice increased by $480 because 2 seats were added mid-cycle (+$360 with proration) and a $120 discount coupon expired.Tomorrow, when Harbor asks why their invoice changed—or a teammate asks "Can you check the billing discrepancy in this thread?"—a note about Acme's expired coupon does not tell the agent how to look up Harbor's Stripe ID or how to reconcile Harbor's line items. A fact can inform; it cannot verify.
-
Track entity state in a temporal graph: Zep, through its Graphiti engine, extracts entities and relationship facts into a bi-temporal knowledge graph, tracking both when a fact became true in the world and when the system learned it. That is ideal for point-in-time questions like "What plan was Acme on in Q3?" or "When did Acme's discount expire?" But a graph edge recording
Acme → discount_expired → 2026-10-31models what was true about Acme, not how to reconcile a Stripe invoice. -
Let the agent edit its own notes: Frameworks like Letta give the agent tools to rewrite in-context memory blocks or commit Markdown notes to a Git-backed filesystem, often paired with background reflection jobs that consolidate files between sessions. The catch is that memory quality depends on unverified self-edits. If the model misreads a noisy thread or overgeneralizes from a single comment, it writes a flawed rule into its own context, and later tasks that load it inherit the mistake.
-
Rewrite the system prompt: LangMem's prompt optimizer targets behavior directly by taking a conversation trajectory and user feedback and rewriting the agent's system prompt. After a correction like this one, an illustrative single-pass update can look like:
System prompt diff: + Compare invoice line items first, + and explain increases using mid-month seat proration and expired discounts.Even when part of the new instruction sounds reasonable ("Compare invoice line items first"), a single-pass rewrite appends it to a shared prompt alongside the specifics of Acme's case, without checking whether the revised prompt actually reconciles the numbers or stops the wasted Stripe searches.
Memory can hold a rule; holding it is not the same as checking it. In short, the first two approaches stop at recall, while the latter two treat writing a rule as proving it. Any of these systems can be wrapped in evaluation; the memory mechanism itself does not define the checks or tie them to the work.
Real work spans multiple steps: resolving account identifiers across tools, fetching the right records, computing exact differences, and drafting a handoff note. Stuffing every correction into a global prompt or scratchpad turns instructions into an ever-growing list of rules. Rules meant for billing support leak into sales prep or bug investigations, and a log of prompt edits only tells you when the agent changed its mind, not whether the change produced accurate numbers.
Learning means improving and checking the method
Nine treats learning at work as method improvement, not memory accumulation.
When Nine works on a task, learning follows a closed loop: work → observe → improve → check → reuse.
Each stage does a job that recall alone skips:
-
Observe from both execution and feedback: Lessons do not come only from a human typing "remember that..." in chat. Nine also inspects its own runs, spotting where it wasted turns searching Stripe by company name instead of reading the Intercom contact's
stripe_customer_id, and where the line items disagreed with the headline summary. It also takes in teammate corrections. -
Scope the improvement to the right part of the work: A lesson about matching Intercom contacts to Stripe customers and reconciling invoice lines belongs in the billing-support method, within the team and access boundaries authorized for that work, not in a global prompt that gets injected into every unrelated question.
-
Capture reusable steps and code, not just prose advice: A working method can include the exact tool sequence, field mappings, and durable agent-written JavaScript for the job. Instead of hoping a language model does mental arithmetic across raw JSON on every run, the revised method includes a small script that buckets
invoice.lines,total_discount_amounts, and balance adjustments across both invoices and verifies that the parts explain the total change:const delta = currentInvoice.amount_due - previousInvoice.amount_due; const breakdown = reconcileInvoices(previousInvoice, currentInvoice); const explained = breakdown.seats + breakdown.proration + breakdown.discounts + breakdown.credits; if (explained !== delta) { throw new Error(`Unexplained invoice delta: ${delta - explained}`); } -
Check the change against real evidence before reuse: An observation is a hypothesis until it is tested. Before a revised method becomes the default, Nine checks it against the records that exposed the flaw and the cases the method already handles:
-
Does it read
stripe_customer_iddirectly from the Intercom contact before querying Stripe? -
Do the bucketed line items (
+$240seats,+$120proration,+$120expired discount) reconcile to the exact+$480invoice delta with$0unexplained variance? - Does the Intercom note attach the invoice references and keep confirmed charges separate from open questions?
-
Does it read
The checks are part of the method, so the team can inspect them. If a proposed change fails them, it is not reused.
When the next billing question arrives—say Harbor asks why their invoice
changed by $225 after a plan upgrade and a service credit—the verified method
pays off in both accuracy and efficiency. Nine does not waste turns searching
Stripe for matching company names or rewriting invoice-parsing logic from
scratch. It reads Harbor's Stripe ID from Intercom in one step, runs the
checked reconciliation code (+$300 upgrade, -$75 credit, $0 unexplained
variance), and leaves a sourced billing note ready for the support team.
A coworker that gets better at the job
Memory layers and knowledge graphs have a real place in the stack. An agent should know who is on your team and what changed in an account last week.
But knowing facts about your company is only the starting line. What turns an agent into a useful coworker is whether it can take a piece of work, learn from what happened, verify that a better method holds up against the evidence, and bring that improved method to the next task. That is how Nine improves its working methods without training models on your data.