Transaction Decider

A bank record goes in, a budget category comes out. The model never writes a sentence: it runs one forward pass and the answer is read straight from the logits at the 17 candidate letters. That makes an invalid category impossible and keeps response time flat no matter how many categories you offer.

Input

Prompt template

{state} is replaced by the record above, {options} by the lettered category list. Edit freely, both are yours.

Answer

Pick an example, or write your own.

    What is running

    Base model
    Qwen3-4B, bf16
    Adaptation
    LoRA, rank 16, alpha 32, 7 projections
    Training data
    64.6k US rows, 8k synthetic Dutch, 452 real Dutch
    Curriculum
    Three stages, decaying rate, real data last
    Accuracy
    69.2% balanced on a merchant-disjoint Dutch holdout, 94.8% on US
    Decoding
    One forward pass, softmax over 17 letter logits
    Serving
    Apple M4 Max, MLX, 214 ms median locally
    Calibration
    0.08 expected calibration error, untuned
    Categories
    17

    Balanced accuracy is the mean of the per-category accuracies, so a rare category counts as much as a common one. The Dutch holdout shares no merchant with any training row, so a familiar name cannot carry the score. Ablations showed the merchant string does nearly all the work: blank it and accuracy falls to roughly chance, while blanking the account or the date changes nothing.