~/satyajit

Hy Memory: a 3B-active memory writer that ties Opus 5, and four launch numbers that belong to the engine

mdjsonmcp

2026-10-16 · 18 min · agent-memory · agents · reinforcement-learning · grpo · mixture-of-experts · benchmarks

A 1:51 narrated explainer, drawn in code. Every number and picture in it is this article's own; the sources are below.

› transcript

Hi, I'm Plinth! Let's follow one turn through Tencent's Hy Memory, and a model trained only to write memories. A reader cannot recover a fact that was never stored. The writer decides what later answers can use. A new turn arrives. The first model call extracts durable facts and drops the small talk. Each fact is searched against stored facts. Only matches above a fused score of zero point four go forward. The second call reconciles them: add, merge, or supersede a fact that is no longer true. The bank applies the operations. Recall needs no model, just an embedding and a search. Three moves. Add, for something new. Update, to merge a detail into the same fact. Supersede, when both cannot be true. The old fact stays as history. In the engine's own diagram, the write row is embed, extraction, then reconcile. The search row is recall, fusion, and a response in three channels. One extraction call read about two and a half thousand tokens to write about a hundred. Training scores each chunk of writes by what the bank can answer. Probes check that facts survived, and traps check that filler stayed out. Outcome credit comes from later questions, traced back to this chunk. A growth penalty stops it storing everything. It leads Claude Opus 5 everywhere, but two margins are hundredths of a point. Without travel planning, Opus leads. The writer can only reconcile what retrieval hands it. A contradiction the search misses stays. Extract, search, reconcile, store. And read the tie as a tie. Every source is in the full article. I'm Plinth. Bye!

Why read this

Essentialtop 10%

Traces one memory write through the engine's code and a real run, and shows the 'beats Opus 5' and launch numbers come from different systems.

  • Checked against the source
  • Interactive explanations
  • Widely used

Agents & harnessesNeeds a workstation GPUApache-2.0Practitioner model

How this was scored
Is it new?
2 of 3: A real new idea, method or capability
Can I trust it?
3 of 3: Reproduces the headline result, or shows from primary files it is wrong
Can I run it?
2 of 3: Open code or weights with real limits
Will I understand it?
3 of 3: Mechanism carried by interactives built from real code or data
Can I act on it?
2 of 3: A concrete recipe, numbers or comparison
Will it last?
2 of 3: A reference for a year or more
Does it affect many?
2 of 3: A widely used model, tool or lab release
Only here?
2 of 3: A teardown or measurement few others did

Score 81 of 100, ranked 17 of 577 rated articles. Each question is answered 0–3 by hand, and a 3 is rare. How articles are scored

On 16 October Tencent Hunyuan posted that "a 3B active model beats Opus 5 at memory", and open-sourced three things under the name Hy Memory. MemHub is a desktop and CLI app that pulls conversation history out of Claude Code, Cursor, Codex and seven other tools into one local store. Hy Memory is the engine and Python SDK underneath it. Hy-Memory-30B-A3B is a model trained for one job: deciding what goes into that store.

The post makes six claims. The model is first on all four benchmarks run, leads MemoryArena by 10.2 points, and cuts memory volume by 51.8% and recall tokens by 39.3%. It still wins when dropped into Mem0, MemOS or EverMemOS, "even on the one system it never trained on". And in Tencent's products one assistant's multi-hop recall went from 50% to 90%.

I cloned the repo, read every safetensors header of the weights by range request, read the technical report and the project's website, installed the engine in a scratch venv, ran its test suite, and drove it through two conversation turns with a stub model on localhost. I did not run the 30B model. Numbers below are labelled measured (I computed it from a file or a run), reported (Tencent's figure, not re-run) or reasoned (my arithmetic on the other two).

The short version: the model is real and the training idea is good. The headline is thinner than the post says, and four of its numbers come from a different system.

What a memory model does that a chat model doesn't

An external memory system has three parts. A writer turns an interaction into changes to a persistent store. A retriever picks records for a later question. A reader answers from what was retrieved. The report's point is that the writer is the hard one: "a powerful downstream reader cannot reliably infer a fact that was never stored" (reported, paper §1). Store everything instead and you pay for it in tokens and in retrieval noise.

So a memory writer is a policy acting on external state. At chunk tt it sees the bank MtM_t (or the slice the framework shows it) and the raw chunk xtx_t, emits operations ata_t, and the framework applies them to make Mt+1M_{t+1}. Each call may start from a fresh prompt, but the decisions are sequential because the bank carries their consequences. In practice that is three jobs a chat model is not trained for:

Mem0, MemOS, EverMemOS and Hy Memory all put an ordinary LLM behind a long prompt to do this. Hy-Memory-30B-A3B is trained to be that LLM.

One write, traced through the engine

The engine is a large Python package: 75,578 lines under hy_memory/ at commit fba347a (measured). Its own diagram is a fair map.

Diagram titled HY Memory Architecture. add() or search() enters a scene router that sends chat to a left panel and working or coding to a right panel. The chat panel has a write row (Embed plus raw L1_RAW, LLM extraction of facts summaries and intentions, Reconcile with a supersedes chain), a store row (vector store for L0 to L4 and L7, optional graph store for L6 schemas), a search row (recall by vector BM25 and graph, fusion with chain expansion, response with profile normal and proactive channels) and a System 2 row (evolve, schema induction, cross-domain sweeper). The working and coding panel has extraction of fact plus experiences, reconcile with ADD UPDATE SUPERSEDE, diff capture with zero LLM, stores for facts and experiences and a version chain, and a search row that attaches revisions to recalled facts.
The engine: a scene router in front of a chat pipeline with a layered memory and a working/coding pipeline with facts, reusable experiences and, for code, a chain of real diffs. Model calls happen only on the write side (Hy Memory repository, docs/images/architecture.svg).

In pro mode a chat write goes like this, and the steps map onto files I could read:

  1. Store the raw turn. pipelines/writer.py embeds the messages and stores them verbatim as layer L1_RAW. Once extraction succeeds, that node is demoted to SHADOW, kept but never recalled.
  2. Extract. agent/extractor.py sends a system prompt that lists what to keep (preferences, projects, plans, decisions, constraints) and what to drop (small talk, generic emotions, "assistant reminders of old memories"), plus the last few messages for resolving "her" and "that project". The reply is JSON with three buckets: memory, intentions with a valid_until, and basic_info.
  3. Find candidates. agent/reconciler.py searches each new fact against stored facts with vector and BM25 search, fuses the scores, and keeps candidates at min_score=0.4 or above. If nothing passes, every fact is written as ADD and the reconcile call is skipped.
  4. Reconcile. One more model call lists the candidates with their ids and the new facts, and asks for operations. The prompt defines three: ADD for new information, UPDATE to merge a compatible fact on the same topic, and SUPERSEDE only when "both cannot be true at the same time". Each superseded chain is shown by its head only, so the model cannot supersede a record that is already history.
  5. Apply. In the code (not the docstring at the top of the file, which still describes an older ADD and DELETE scheme), UPDATE rewrites the old node in place and keeps its original date. SUPERSEDE marks the old node superseded, sets is_latest false, links it with superseded_by, and writes the new fact as the head of an evolution chain.
  6. Recall. search() with the default mode makes no model call at all: one embedding, vector and keyword search, and a response in three channels (profile, normal, proactive). A chain comes back as its current state plus its history.

Chat memory sits in layers L0 to L7, from basic info through raw turns, facts and summaries to schemas and expiring intentions. Working and coding scenes use two layers instead, one fact per session plus reusable "experiences", and coding also keeps every revision's real diff.

What happened when I ran it

The task allowed installing the engine and running it offline. hy-memory 2.0.1 installed from the clone into a fresh venv of 872 MB (measured). For the model and the embedder I wrote a stub OpenAI-compatible server on localhost: hashed bag-of-words embeddings, and rule-based replies to the extraction and reconcile prompts. The engine talks to its model only through MEMORY_LLM_BASE_URL, the slot you would point at a vLLM server running Hy-Memory-30B-A3B. Below, the decisions are my stub's. The calls, the prompts, the candidate search, the store and the recall are the engine's own (measured, shared 4-core cloud VM, CPU only).

Turn one ("I live in Pune. Black coffee every morning, and I'm training for a half marathon in December.") cost one model call. Extraction produced three facts, the store was empty, so all three went in as ADD with no reconcile call. Turn two ("I moved to Bengaluru last week, and I've switched from coffee to green tea.") cost two. Extraction produced two facts; the Bengaluru fact found the Pune fact as a candidate; reconcile returned SUPERSEDE for it and ADD for the tea.

Measured with the model's own tokenizer.json, the extraction prompts were 2,453 and 2,480 tokens and the reconcile prompt 1,620, against replies of 106, 90 and 133 tokens. That is about 20 tokens read for every token written (reasoned, from those six counts). A memory writer is mostly a reader of long fixed prompts, which is why the cost of the model in that slot matters, and why a 3B-active one is attractive.

The interesting part is what did not happen. The tea fact's best candidate fused to 0.19, under the 0.4 gate, so the coffee fact was never shown to the model. Afterwards the store held "drinks black coffee every morning" as active next to "switched from coffee to green tea", and the query "coffee tea morning" returned both, the stale one first (0.516 against 0.486, measured). The Pune fact, which did reach the reconciler, came back as a 62-token block reading "Current: … Bengaluru … History: … Pune".

My hashed embedder is far cruder than a real one, so a real deployment would pair these more often. The mechanism holds: the writer can only reconcile what retrieval hands it, and that gate is in the engine, not the model. A reply under the launch post asked what happens "when two stored memories contradict each other". The answer from the code is: they are superseded if the candidate search pairs them, and both stay active if it doesn't.

The model: a Hy3 30B-A3B with 128 experts

The model card names no base, but the paper does: the student is the "Hy3-30B-A3B instruction-tuned checkpoint", taught by the flagship Hy3. The files agree. config.json says model_type: hy_v3, the same family as the 295B flagship and the same 120,832-row vocabulary.

Summing all 18,673 tensors in the 51 shard headers gives 30,064,725,888 parameters, all BF16 except 6,016 F32 router biases (measured). That is exactly the parameter count of Hy-MT2-30B-A3B, Tencent's translation model from May, and the two configs differ only in cosmetic fields (measured). So both are fine-tunes of the same unreleased Hy3 30B-A3B base (reasoned).

The layout, from the config and the tensor shapes (measured):

One config field is off: moe_intermediate_size says 1,536, but the expert tensors are 768 wide, which is what expert_hidden_dim says and what Hy-MT2's config says (measured). Loaders that read the wrong field would mis-size the experts.

The launch thread says "24GB+ VRAM recommended". The only weights published are BF16, 60.13 GB on disk (measured). They do not fit in 24 GB. You would need to quantize them yourself, roughly 15 GB at 4 bits before KV cache (reasoned), or offload experts to CPU memory. Tencent publishes FP8 and GGUF builds of Hy-MT2 but none of this model, as of today.

How it was trained: rewards for what the bank can answer

Two-panel diagram. Top strip: deployed harnesses Mem0, MemOS, Hy-Memory Chat, Working and Coding, unmodified and shared by both stages. Stage 1, Memory on-policy distillation: a parent bank feeds the harness write path where the student Hy3-30B-A3B samples every LLM call; a frozen Hy3 flagship teacher supplies top-50 reverse KL on the sampled tokens; the candidate bank is promoted as parent of the next chunk. Stage 2, Attributed memory RL, initialised at step 375: eight rollouts from a parent bank write chunks 1 to 5, shown as a grid of cells shaded by chunk score, with a dashed column marking one chunk-level group; each bank is examined by retrieving a memory block, a frozen answer model and a rubric judge; score equals PRM plus 2 ORM minus 0.3 Penalty; the best final bank is carried to the next window.
Both stages run inside the unmodified frameworks. Distillation teaches each framework's write protocol on the student's own states; RL scores each chunk's writes by what the resulting bank can answer, and carries the best bank forward (Hy-Memory-30B-A3B technical report, Figure 1).

Training has two stages, both inside the real frameworks with every framework LLM call routed to the student (reported, paper §4).

On-policy distillation teaches protocol. The student writes, and the frozen Hy3 flagship scores the student's own tokens (a top-50 reverse KL). Later prompts therefore contain the student's own earlier mistakes, as in deployment.

Memory RL teaches usefulness. A window is up to five chunks of about ten turns. Eight rollouts write the window from copies of the same parent bank, then each bank is examined: retrieve, answer with a frozen answer model, grade with a frozen rubric judge. Each chunk tt of rollout ii gets a score

si[t]=prm[t]+2 orm[t]−0.3 pen[t]s_i[t] = \mathrm{prm}[t] + 2\,\mathrm{orm}[t] - 0.3\,\mathrm{pen}[t]

where prm\mathrm{prm} is the mean credit on probes written for that chunk (did an exact name, number or version survive the write?) and on traps (did the assistant's generic encouragement stay out?), orm\mathrm{orm} is credit from cross-chunk questions attributed back to the chunks whose gold facts the answer recovered, and pen\mathrm{pen} rises steeply once bank-token growth per input token passes a per-framework threshold. Advantages are normalised per chunk position across the eight rollouts, not per trajectory, so a rollout can be rewarded at chunk 2 and penalised at chunk 4. The best final bank seeds the next window.

The reward set has 164,576 probes, 8,599 traps and about 60.8k outcome questions over 57,616 chunks, and RL ran on 128 H20 GPUs (reported, §5 and §7). There is no ablation: chunk-level GRPO, traps, the growth penalty and the distillation start are all listed as "future work" (reported, §8.4). The method is well argued, and no single part of it is shown to matter.

Checking the claims

"Beats Opus 5": 55.49 to 54.62, carried by one metric

The evaluation swaps only the writer. Framework, prompts, retrieval, answer model and judge stay fixed, each writer builds its bank from empty, and each framework's score is the mean of six metrics: LoCoMo, LongMemEval, PersonaMem-v2, Travel SPS, Shopping PS and CMB, Tencent's own coding-memory benchmark. Every benchmark is cut to a fixed 20% subsample (reported, §8.1).

Grouped bar chart of macro-average score in percent for Hy-Memory-30B-A3B, Claude Opus 5, DeepSeek V4.1 Flash and Qwen3.6-35B-A3B. Overall 55.49, 54.62, 53.64, 50.37. Hy-Memory harness 60.55, 60.53, 60.20, 55.87. Mem0 54.02, 53.43, 49.73, 47.51. MemOS 50.51, 50.50, 49.17, 47.36. EverMemOS, marked held out, 56.89, 54.04, 55.47, 50.75. The y axis is broken and starts at 30.
The headline chart. Note the y axis starts at 30, which makes 0.01-point gaps look like bars of equal height and 2.86-point gaps look large (Hy-Memory-30B-A3B technical report, Figure 3).

Across the four frameworks it averages 55.49 against Opus 5's 54.62 (reported, Table 6), and I recompute both from the per-metric tables to rounding (measured). The per-framework margins over Opus 5 are 0.60 on Mem0, 0.02 on Hy Memory, 0.01 on MemOS and 2.86 on EverMemOS. The paper says it itself: the 0.01 to 0.02 margins "indicate parity with Opus 5 … not a statistically resolved difference", and there are no repeated seeds (reported, §8.2 and §10).

Go one level down and it is closer still. Of the 24 framework-metric cells, Hy-Memory-30B-A3B beats Opus 5 in 11, loses 12 and ties 1 (reasoned, from Tables 7 to 10). Opus 5 leads on LoCoMo in every framework where they are not tied. The lead comes from Travel SPS, where the model averages 48.22 against 40.59 across frameworks (reasoned). Remove Travel and recompute, and Opus 5 leads, 57.43 to 56.95 (reasoned). Try it:

The report never says which Opus 5 setting was used (thinking or not, at what effort), does not name the answer model or the judge, and ran every baseline itself. None of that makes the numbers wrong. It does mean "beats Opus 5" is a self-run tie on a 20% sample, decided by one metric, which is still a remarkable result for a model with 3.45B active parameters. The fairer headline is the one in the same table: memory training lifted the base checkpoint from 47.66 to 55.49 (reported).

"Even on the one system it never trained on": yes, EverMemOS

The paper trains on five configurations from three frameworks (Mem0, MemOS, and Hy Memory's chat, working and coding scenes) and holds EverMemOS out entirely (reported, Table 2 and §8.3). On EverMemOS it scores 56.89 against 55.47 for DeepSeek V4.1 Flash and 54.04 for Opus 5. That is the cleanest evidence in the report that the model learned memory writing rather than three prompt formats. It is also one held-out framework, and the gain there is mostly Travel (+10.65) and CMB (+13.66) against Opus 5 (reported).

The four benchmarks, MemoryArena, 51.8% and 39.3% belong to the engine

None of "MemoryArena", "10.2", "51.8%", "39.3%" or "50% to 90%" appears in the paper or the model card. They are on the project website, and its own fine print says what they measure: the Hy Memory framework against Mem0, MemOS, EverOS, OpenViking, RepoMemory and a plain RAG baseline, with DeepSeek V4.1 Flash as the memory model and GPT-5.6-sol as answer model and judge (reported). The "four benchmarks" there are LoCoMo for chat, MemoryArena for working memory, and CodeMemoryBench and SWE-ContextBench for code. The paper's "first on all four" is about four frameworks for the model. The post folded the two into one sentence.

Taking the engine numbers on their own terms:

For the model alone, the paper's matrix does contain MemoryArena's two tasks. Averaged across frameworks, Hy-Memory-30B-A3B leads Opus 5 there by 3.21 points (reasoned, from the site's per-metric averages 48.22 and 19.90 against 40.59 and 21.11).

"Multi-hop recall went from 50% to 90%": unverifiable, and not this model

The website attributes this to the AI assistant in Tencent's stock app: an internal evaluation of A-share research memory, where multi-hop recall rose from 50 to 90 after switching from the previous memory system to Hy Memory. Its footnote says the memory model was DeepSeek V4 Flash (reported). So it is an engine result, from a private evaluation nobody outside Tencent can run. I cannot verify it, and it says nothing about Hy-Memory-30B-A3B.

What I ran, exactly

WhatResult
pip install from the clone, plus faiss-cpu and qdrant-client for the optional backends872 MB venv
pytest tests (unit tests; integration deselected by the repo's own config)1,273 passed, 1 failed, 26 skipped, 19 deselected in 60 s; peak RSS 1.69 GB
The one failuretest_reader_selection.py compares a class __dict__ against a fixed set, and Python 3.13 adds __static_attributes__ and __firstlineno__. A test artefact, not an engine bug
Two-turn drive of HyMemoryClient(mode="pro") against my localhost stub3 model calls, 1 SUPERSEDE, 4 ADD, one stale fact left active, as traced above
Hy-Memory-30B-A3BNot run. 60.13 GB of BF16 does not fit this machine

All measured on a shared 4-core cloud VM, CPU only, with no API keys and no hosted endpoints.

Where it breaks

What I like is the reward design: probes and traps per chunk, outcome credit traced to the chunks that supplied the evidence, and a growth penalty are a careful answer to the question every memory system ducks, which is whether a particular write was useful. The engine is real software with a passing test suite and a clean model slot. Point MEMORY_LLM_BASE_URL at a vLLM server running this model and you have the whole stack on your own hardware, once you have the 60 GB for it.

tencent/Hy-Memory-30B-A3B@64a460a · snapshot 2026-10-16
parameters
30.06B
repo size
60.13 GB
architecture
HYV3ForCausalLM
task
text-generation
library
transformers
license
apache-2.0
safetensors
51 shards
largest file
1.21 GB
files
66
downloads
0
likes
31
languages
en, zh
parameters by dtype
BF1630.06BF326.0K

repo last modified 2026-10-16

Tencent-Hunyuan/Hy-Memory@fba347a · snapshot 2026-10-16
tracked files
1,769
license
Apache-2.0
branch
main
tests
896 files
source
20.3 MB
commit date
2026-10-16
source by language
Python12.7 MB(920)TypeScript6.8 MB(624)JavaScript482.8 kB(55)CSS322.5 kB(32)SQL20.9 kB(1)Shell9.4 kB(4)Objective-C1.9 kB(1)

by size of tracked source at this commit, file counts in brackets; docs, data and vendored trees excluded

local clone, 2026-10-16 at fba347a — branch, commit, commitDate, fileCount, hasTests, languages, license, licenseFile, shallow, testFileCount

shallow clone: counts describe the pinned tree, not the history

Cite this article

For attribution, please use the following reference or BibTeX:

Satyajit Ghana, "Hy Memory: a 3B-active memory writer that ties Opus 5, and four launch numbers that belong to the engine", ai.thesatyajit.com, October 2026.

bibtex
@misc{ghana2026hymemory,
  author = {Satyajit Ghana},
  title  = {Hy Memory: a 3B-active memory writer that ties Opus 5, and four launch numbers that belong to the engine},
  url    = {https://ai.thesatyajit.com/articles/hy-memory},
  year   = {2026}
}
share