LoRA adapters for tencent/WeMM-Embedding-4B that answer
jul's typed questions — pick an option (Choice), yes or no (Noul), a
score (Score) — reading the question and the text together. jul's default model on PyTorch.
from jul import TypeSafeClient, Choice, Noul
client = TypeSafeClient() # jul-decision-wemm-4b: tencent/WeMM-Embedding-4B + these adapters
response = client.system_one(
state={"ticket": "I was charged twice for my subscription this month."},
questions={
"team": Choice(instructions="Which team should handle this ticket?",
criteria={"billing": "payments, invoices, refunds",
"technical": "bugs, errors, crashes",
"sales": "pricing, plans, demos"}),
"is_bug": Noul(instructions="Does the message report a software bug?"),
},
)
Needs jul after 0.3.0 (today main, then the next release), with the PyTorch backend (jul[torch]).
On a Mac with MLX, jul's default model reads with vectors only until these adapters are measured in 4-bit.
adapter.npz: rank-16 LoRA adapters (A and B, float16) on the 248 Linear layers of the decoder, 32.5M
parameters, 65 MB. Switched off, the model is WeMM-Embedding-4B unchanged; jul switches them on only
for the reading below, so the vector reading of the same model is untouched.cross_heads.npz: one head per question type — noul (3 classes), score (1), choice_q and
choice_k (a bilinear head, 2560 → 256).cross.json: the prompts and the heads, read by jul.Text: "<text>", Question: <question> (and Candidate answer: <level> for a Score),
Verdict:, read on the last token of the last layer after the final norm.Answer:, scored by the bilinear head. jul mixes it with the vector reading of
the same model: log p = log p_vector + 3 · log p_listwise.Text: "<text>"
Question: <question>
Options:
- <option 1>
- <option 2>
Answer:
Decision bench: 2,108 typed questions over 12 task families, English and French, with texts written for the bench and never seen in training. PyTorch bf16 on one A10G GPU, one question per call; Jev (TypeSafe's hosted decision model) through its API, network included in its latency.
| Family | n | Jev | jul-decision-wemm-4b |
|---|---|---|---|
| emotion | 60 | 0.933 | 0.817 |
| finance | 180 | 0.756 | 0.850 |
| hard negatives | 226 | 0.823 | 0.836 |
| intent | 234 | 0.842 | 0.868 |
| legal | 158 | 0.911 | 0.873 |
| moderation | 179 | 0.877 | 0.804 |
| inference (NLI) | 208 | 0.817 | 0.731 |
| relational | 101 | 0.941 | 0.921 |
| routing | 118 | 0.898 | 0.831 |
| sentiment | 120 | 0.983 | 0.925 |
| support | 294 | 0.898 | 0.864 |
| topic | 230 | 0.917 | 0.891 |
| Choice | 917 | 0.924 | 0.883 |
| Noul (yes/no) | 895 | 0.878 | 0.872 |
| Score | 296 | 0.699 | 0.672 |
| English | 1,254 | 0.871 | 0.862 |
| French | 854 | 0.876 | 0.829 |
| All | 2,108 | 0.873 | 0.849 |
| p50 latency | 655 ms | 97 ms |
WeMM-Embedding-4B read as vectors, with the earlier adapters for Noul and Score only
(usejul/jul-decision-wemm-4b-4bit-mlx),
scores 0.757 on the same bench (Choice 0.700).
A family has 60 to 300 questions, so one row moves by ±4 to ±12 points. The bench shares its task families and label sets with the training data, not its texts. On four label sets never trained on (Yahoo topics, EmpatheticDialogues, MASSIVE, Financial PhraseBank; 1,453 texts), Choice goes from 0.707 with the vectors to 0.730. Emotion on real conversations barely moves: it learnt the traps of written sarcasm more than it reads emotion.
WeMM-Embedding-4B frozen (bf16); adapters and heads trained on public English and French datasets under commercial-use licenses, with no text of the bench nor of the dev sets:
Apache-2.0, as WeMM-Embedding-4B (Tencent), which these adapters are built on.
LoRA adapters for tencent/WeMM-Embedding-4B that answer
jul's typed questions — pick an option (Choice), yes or no (Noul), a
score (Score) — reading the question and the text together. jul's default model on PyTorch.
from jul import TypeSafeClient, Choice, Noul
client = TypeSafeClient() # jul-decision-wemm-4b: tencent/WeMM-Embedding-4B + these adapters
response = client.system_one(
state={"ticket": "I was charged twice for my subscription this month."},
questions={
"team": Choice(instructions="Which team should handle this ticket?",
criteria={"billing": "payments, invoices, refunds",
"technical": "bugs, errors, crashes",
"sales": "pricing, plans, demos"}),
"is_bug": Noul(instructions="Does the message report a software bug?"),
},
)
Needs jul after 0.3.0 (today main, then the next release), with the PyTorch backend (jul[torch]).
On a Mac with MLX, jul's default model reads with vectors only until these adapters are measured in 4-bit.
adapter.npz: rank-16 LoRA adapters (A and B, float16) on the 248 Linear layers of the decoder, 32.5M
parameters, 65 MB. Switched off, the model is WeMM-Embedding-4B unchanged; jul switches them on only
for the reading below, so the vector reading of the same model is untouched.cross_heads.npz: one head per question type — noul (3 classes), score (1), choice_q and
choice_k (a bilinear head, 2560 → 256).cross.json: the prompts and the heads, read by jul.Text: "<text>", Question: <question> (and Candidate answer: <level> for a Score),
Verdict:, read on the last token of the last layer after the final norm.Answer:, scored by the bilinear head. jul mixes it with the vector reading of
the same model: log p = log p_vector + 3 · log p_listwise.Text: "<text>"
Question: <question>
Options:
- <option 1>
- <option 2>
Answer:
Decision bench: 2,108 typed questions over 12 task families, English and French, with texts written for the bench and never seen in training. PyTorch bf16 on one A10G GPU, one question per call; Jev (TypeSafe's hosted decision model) through its API, network included in its latency.
| Family | n | Jev | jul-decision-wemm-4b |
|---|---|---|---|
| emotion | 60 | 0.933 | 0.817 |
| finance | 180 | 0.756 | 0.850 |
| hard negatives | 226 | 0.823 | 0.836 |
| intent | 234 | 0.842 | 0.868 |
| legal | 158 | 0.911 | 0.873 |
| moderation | 179 | 0.877 | 0.804 |
| inference (NLI) | 208 | 0.817 | 0.731 |
| relational | 101 | 0.941 | 0.921 |
| routing | 118 | 0.898 | 0.831 |
| sentiment | 120 | 0.983 | 0.925 |
| support | 294 | 0.898 | 0.864 |
| topic | 230 | 0.917 | 0.891 |
| Choice | 917 | 0.924 | 0.883 |
| Noul (yes/no) | 895 | 0.878 | 0.872 |
| Score | 296 | 0.699 | 0.672 |
| English | 1,254 | 0.871 | 0.862 |
| French | 854 | 0.876 | 0.829 |
| All | 2,108 | 0.873 | 0.849 |
| p50 latency | 655 ms | 97 ms |
WeMM-Embedding-4B read as vectors, with the earlier adapters for Noul and Score only
(usejul/jul-decision-wemm-4b-4bit-mlx),
scores 0.757 on the same bench (Choice 0.700).
A family has 60 to 300 questions, so one row moves by ±4 to ±12 points. The bench shares its task families and label sets with the training data, not its texts. On four label sets never trained on (Yahoo topics, EmpatheticDialogues, MASSIVE, Financial PhraseBank; 1,453 texts), Choice goes from 0.707 with the vectors to 0.730. Emotion on real conversations barely moves: it learnt the traps of written sarcasm more than it reads emotion.
WeMM-Embedding-4B frozen (bf16); adapters and heads trained on public English and French datasets under commercial-use licenses, with no text of the bench nor of the dev sets:
Apache-2.0, as WeMM-Embedding-4B (Tencent), which these adapters are built on.