A purpose-built fine-tuned embedding model for emotion-aware memory retrieval in AI companions. Based on all-MiniLM-L6-v2, fine-tuned with 10 specialised objectives to natively encode emotion, importance, narrative arcs, and emotional transitions into the embedding space.
Standard sentence embedding models produce vectors that capture what was said but nothing about how it felt. This model learns to differentiate memories by emotional context, not just semantic content.
It does this through 58 special tokens added during fine-tuning:
[EMO:happy] [IMP:8] [ARC:climax] [FROM:anxious] I finally got the promotion!
Token Type
Examples
Purpose
[EMO:x]
[EMO:happy], [EMO:anxious]
Encode the emotion of the memory
[IMP:x]
[IMP:1] through [IMP:10]
Encode importance (1-10 scale)
[ARC:x]
[ARC:setup], [ARC:climax]
Encode narrative arc position
[FROM:x]
[FROM:calm], [FROM:sad]
Encode emotional transition (previous state)
[MOOD:x]
[MOOD:happy]
Encode query-time mood for retrieval
[QUERY]
[QUERY]
Query-mode flag
This means a memory about "I got the promotion" encoded with [EMO:happy] produces a different vector than the same text encoded with [EMO:anxious] — and the model has learned what that emotional difference means geometrically.
How It Compares to Standard Embeddings
On the MemGPT/Letta EmbedBench benchmark (500 evaluations, 5 seeds):
Metric
Standard all-MiniLM-L6-v2
all-MiniLLM-VividTuned
Leading Memory System
Tool Accuracy
0.4320
0.4400 (+1.9%)
0.4300
F1 Score
0.5148
0.5151 (+0.1%)
0.4945
BLEU-1
0.6338
0.6660 (+5.1%)
0.6310
The fine-tuned model outperforms both the base model it was built on and leading memory systems — with the same 22M parameters and no cloud APIs.
What the Numbers Mean
Tool Accuracy: How often the system uses the right memory tool for the task
F1 Score: Precision-recall balance on memory retrieval relevance
BLEU-1: How well retrieved memories match expected content (unigram overlap)
Unlike the base model which L2-normalises everything, this model preserves vector magnitude. High-importance memories ([IMP:9]) produce longer vectors than low-importance ones ([IMP:2]). The VividEmbed scoring function uses this:
1from vividembed import VividEmbed
23# Automatically uses VividTuned if found, falls back to base model4ve = VividEmbed(model_name="Kronic90/all-MiniLLM-VividTuned")56ve.add("I finally got the job offer!", emotion="excited", importance=9)7ve.add("The rejection letter was devastating", emotion="sad", importance=8)89# Mood-congruent retrieval10results = ve.query("career milestones", mood="happy", top_k=3)
With sentence-transformers Directly
python
1from sentence_transformers import SentenceTransformer
23model = SentenceTransformer("Kronic90/all-MiniLLM-VividTuned")45# Encode with emotion tokens6vec1 = model.encode("[EMO:happy] [IMP:8] I got the promotion!")7vec2 = model.encode("[EMO:sad] [IMP:8] I got the promotion!")89# These produce DIFFERENT vectors — the model understands emotional context10import numpy as np
11cos_sim = np.dot(vec1, vec2)/(np.linalg.norm(vec1)* np.linalg.norm(vec2))12print(f"Same text, different emotion: similarity = {cos_sim:.3f}")13# Expect < 1.0 — emotion shifts the embedding