Access to memory-resoner

Released for research, evaluation, internal validation and education. Tell us who you are and we will grant access.

By requesting access you agree to the Elda Community License 1.0: no commercial use, no redistribution of the weights or derivatives, and attribution as "Built with Elda". Commercial licensing is available on request.

Log in or Sign Up to review the conditions and access this model content.

memory-resoner β€” the reference step of conversational memory

A conversation can only be stored if you know what γ€Œκ·Έ 동넀」 meant. memory-resoner reads the turns of a conversation and says, for each mention, which earlier mention it refers to β€” so the layer above can write a memory entry that points at the right words.

"합정동에 κ°€κ²Œλ₯Ό μ—΄μ–΄μš” . κ·Έ λ™λ„€λŠ” μœ λ™μΈκ΅¬κ°€ λ§Žλ‚˜μš” ?"

  mentions   합정동에   (s0, w0–0)
             κ·Έ λ™λ„€λŠ”  (s1, w0–1)
  chains     [합정동에 Β· κ·Έ λ™λ„€λŠ”]

version 0.1.4 Β· 149M parameters Β· fp32 Β· 35 ms per sentence on CPU.


Where it sits

memory-resoner is one stage of a Korean conversational stack. Each stage answers one question and hands the next stage a span, never prose.

utterance
   β”‚
   β”œβ”€ Elda-AI/intenter              what was said, and what kind of thing it is  ── spans come from here
   β”œβ”€ slot extraction               which of those the user said about themselves
   β”‚
   β–Ό
β˜… memory-resoner                    β˜… which earlier mention does this one refer to
   β”‚
   β–Ό
memory write                        a pointer into the user's own words β€” checkable, not generated

Where the spans come from. In the Elda stack, mention spans are produced upstream by Elda-AI/intenter and this model consumes them; its card is the reference for how a span is drawn, which types exist, and what the channels mean. Used standalone, memory-resoner will find its own mentions instead β€” the linking answer is the same either way.

⚠ The two sides count spans in different units, and the conversion is yours to make. Upstream spans are character offsets with the particle left outside (γ€Œν•©μ •λ™γ€). This model works in μ–΄μ ˆ (word) indices, and a μ–΄μ ˆ contains its particle, so the same mention is γ€Œν•©μ •λ™μ—γ€ here. Neither is wrong; they are different units. Align on the μ–΄μ ˆ that contains the upstream span.

What it returns. Span indices and chains. Not a rewritten sentence, not a summary β€” an index into the words you sent, which the layer above can verify before storing anything.

What it does not decide. Whether a fact is true, whether it is worth keeping, how long it lives. Those belong to the system around it. This stage answers one question and stops.


Why a small encoder

this model LLM prompting
Parameters 149M 7B – 70B
Latency per sentence, CPU p50 35 ms seconds
Output span index β€” checkable byte-for-byte free text to be parsed
Determinism same input, same chains sampling

Memory is written on every turn. A stage that runs that often has to be cheap, and its answer has to be something the next stage can check rather than trust. A span index is both.


Output contract

input        sentences, in order β€” a string per sentence, or a list of μ–΄μ ˆ
output       mentions Β· antecedents Β· chains (links closed transitively)
spans        inclusive word (μ–΄μ ˆ) indices β€” Korean particles stay attached (see the note above)
window       6 previous sentences of context Β· 40 previous mentions as candidates

A mention with no antecedent opens a chain of its own β€” that is how the next stage learns it has seen a new entity, so singleton chains are kept rather than dropped.


Usage

from transformers import AutoModel, AutoTokenizer

m   = AutoModel.from_pretrained("Elda-AI/memory-resoner", trust_remote_code=True).eval()
tok = AutoTokenizer.from_pretrained("Elda-AI/memory-resoner", trust_remote_code=True)

out = m.coref(["합정동에 κ°€κ²Œλ₯Ό μ—΄μ–΄μš” .",
               "κ·Έ λ™λ„€λŠ” μœ λ™μΈκ΅¬κ°€ λ§Žλ‚˜μš” ?"], tok)

out["mentions"]     # [{'sent': 0, 'words': [0, 0], 'text': '합정동에'}, ...]
out["antecedents"]  # [None, 0]   ← per mention: what it points back at
out["chains"]       # [[0, 1]]
call does
m.coref(sentences, tok) finds the mentions and links them
m.mentions(sentences, tok) finds mentions only β€” a span provider for another linker
m.resolve(units, mentions, tok) links only β€” you supply the mentions

Notes that matter in practice:

  • fp32. The config pins it. In bf16 near-ties flip and chains change.
  • Pass sentences, not a paragraph. The sentence boundary is what the window is counted in.
  • Send the resolved span downstream, not the reference. The output is an index into the words you sent, so whatever consumes it can verify what it was handed.
  • Strip the particle at display time, not at span time. Keeping it inside the μ–΄μ ˆ is what makes the span a plain index into your own input; trimming belongs to whatever renders the value.

Measurements

Public Korean coreference, held out from training; document overlap with the training split is 0 and the benchmark script asserts it. Both scripts ship in this repository.

pip install torch transformers datasets
python bench_corefud_ko.py --model Elda-AI/memory-resoner

Mention detection β€” boundaries must match exactly

precision recall F1
0.811 0.7874 0.799

Linking, mentions given

scored mentions 10263
accuracy 0.8568
non-NULL accuracy 0.5744 (n=2721)
deictic, non-NULL 0.5277 (n=271)
reference β€” always NULL 0.7349
reference β€” always most-recent 0.0448

Read the non-NULL rows. Most mentions open a chain, so answering NULL every time already scores 0.7349; the rows that require actually linking are the ones in bold.

End-to-end β€” (mention, antecedent) pairs, the model finding its own mentions

precision recall F1
0.6387 0.6534 0.646

Every run first pushes the gold answers back through the scorer and asserts they survive intact (1.0000). A scorer that cannot return its own gold is not grading anything.

On dialogue

The numbers above are prose. On dialogue β€” references mined from a public multi-turn Korean corpus, with the antecedent taken from that corpus's own annotation rather than chosen by us β€” this version resolves γ€Œκ·Έ 식당」-style references at 0.2091, against 0.1077 for 0.1.1, and locates the referring mention in 483/483 cases.

python bench_wos_references.py --model Elda-AI/memory-resoner

That gain was paid for: on prose, deictic non-NULL moved from .524 (0.1.1) to 0.5277. If your text is prose rather than conversation, 0.1.1 is the stronger checkpoint and it remains in this repository's history.


What comes next

Conversational memory here is built in three layers. They are not future versions of this model β€” they are different kinds of component, and saying so is the point.

what it is for how it is built
Layer 1 Β· conversation memory what was said in this conversation, and what refers to what β˜… this model + deterministic assembly
Layer 2 blackbox β€” how a memory is addressed and kept apart from every other conversation not described here
Layer 3 Β· authority and persona whether something holds and on what grounds, and what an agent is like across conversations a deterministic VM, and a decoder used off the request path

Layer 1 is the only one this model sits in. Layer 2 is deliberately not described: it is where memories are separated from one another, and it is the part of the system we keep closed. Layer 3 is where facts acquire grounds and where a persona is formed, and it is built from two very different machines β€” one that must be exact, and one that must be fluent.

The VM β€” the exact one. Memory is written in a small closed language and executed by a deterministic machine, so a write is either accepted, a duplicate, a replacement, or refused, and the same inputs always produce the same store. Reads are queries against that store, not recollection. This is what makes memory auditable rather than merely plausible, and it is why the per-turn path carries no generation at all.

The decoder β€” the fluent one. Never on the request path. Writing and reading memory happen on every turn and stay on the encoder-and-machine side. Generation is for prose a person will read, and for periodic passes that look across many conversations at once to form a persona β€” a pass that can fail without the conversation stopping.


Versioning

v<major>.<minor>.<patch>, three digits. Minor moves when the task, the inputs or the heads change β€” when your code has to change. Patch moves when the same job is done better. The version lives in config.json and is cross-checked against this card at publish time.

Current: 0.1.4. Earlier weights remain in this repository's history.

This repository previously hosted a different model, a Korean slot tagger. It is not an earlier version of this one.


License & access

Released under the Elda Community License 1.0 (see LICENSE). Provenance of the training data is recorded in LINEAGE.md; no user conversations were used.

  • βœ… Research, evaluation, internal validation, education β€” free of charge
  • ✳ Attribution: "Built with Elda"
  • β›” Commercial use and redistribution require a separate agreement

Access is gated: tell us who you are and access is granted automatically.

Citation

@software{memoryresoner2026,
  title  = {memory-resoner: reference resolution for Korean conversational memory},
  author = {Elda AI},
  year   = {2026},
  url    = {https://huggingface.co/Elda-AI/memory-resoner}
}
Downloads last month
4
Safetensors
Model size
0.1B params
Tensor type
F32
Β·
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support