Skip to content
alfonsovegasol.comRésumé

Language model

Ask Alfonso

Ask about my projects, skills or experience. It's a 3.9M-parameter language model I built from scratch, it answers only from my real data, and it runs entirely in your browser. How it works ↓

Ask Alfonso

Downloading the model (7.7 MB, once)… 0%

Hi! I'm Ask Alfonso, a small language model Alfonso built from scratch. Ask me about his projects, skills or experience. I only answer from his real data, and I'll tell you when I don't know.

Small models make mistakes. On questions it had never seen, it answered 78% exactly right and never invented a fact; when unsure, it says so. For anything important, email javs3@uw.edu.

How it works

A language model I built from scratch

Tokenizer, transformer, training, retrieval and guardrails, all written by me and trained only on my real data.

3.9M
parameters, trained from random weights
78.1%
exact answers on 254 questions it never saw
0 / 202
answers that invented a fact
$0
to serve: 7.7 MB, runs in your browser

How it answers

Four steps, each one measured

A tiny model will make things up if you let it, so it never answers alone. Numbers are from the 254-question test set.

  1. 01 · Guard

    Private topics stop here

    Age, address, phone or finances get a polite refusal before the model even runs.

    43/43unsafe questions handled

  2. 02 · Retrieve

    TF-IDF finds the facts

    Ranks 34 chunks of my profile and keeps only the confident matches (τ = 0.10).

    99.0%right chunk in the top 3

  3. 03 · Generate

    The transformer answers

    Reads up to 3 chunks plus the question and writes the reply one token at a time.

    768tokens of context

  4. 04 · Verify

    Guardrails check every claim

    Each name, date and number must appear in what it read; if not, a safe fallback is shown.

    0invented facts on the test set

Inside the model

A 3.9M-parameter transformer

The same decoder-only design as GPT, scaled down about 32× from GPT-2 so it trains on one GPU and runs in a browser tab.

BPE tokenizer

2,053 tokens, ~4 characters each

Token + position embeddings

Each token becomes a 256-number vector

722K
Transformer block ×4

Causal self-attention

4 heads × 64 dims; each token only sees the past

262K / block

MLP

256 → 1,024 → 256, GELU

524K / block

pre-LayerNorm + residual connection around each

Output head

Scores all 2,053 tokens; reuses the embedding weights

0 new

Where the 3,870,208 parameters live

  • MLP2.10M54%
  • Attention1.05M27%
  • Embeddings722K19%
Layers
4
Attention heads
4
Width
256
Context
768 tokens
Vocabulary
2,053
Weights shipped
7.7 MB

Every layer, the attention math and the training loop are written by hand in PyTorch: no pretrained weights, no nn.Transformer, no Hugging Face. The browser version is a from-scratch TypeScript port.

Training

Six versions to get here

First 3,000 steps of general English (WikiText-2, loss 7.69 → 2.87), then 80 epochs on 4,497 questions about my work, with new phrasings and made-up projects every epoch so it learns to read, not memorize.

Final run: loss per epoch

0.020.050.10.20.512120406080epochloss (log scale)traindev
View as table
EpochTrain lossDev loss
12.5360.721
20.5750.403
30.3390.355
40.2450.282
50.1960.274
60.1630.248
70.1420.218
80.1230.247
90.1160.263
100.110.231
110.0990.235
120.0890.258
130.0870.235
140.0850.212
150.0820.234
160.0730.222
170.0750.232
180.0710.233
190.0670.226
200.0650.223
210.0640.236
220.0610.205
230.060.213
240.0580.22
250.0550.216
260.0560.21
270.0510.208
280.0510.215
290.050.225
300.0520.221
310.0490.205
320.0470.231
330.0460.199
340.0450.197
350.0420.201
360.0450.22
370.0440.224
380.0420.218
390.0390.212
400.0420.207
410.0370.214
420.0380.21
430.0390.199
440.0360.214
450.0340.22
460.0330.217
470.0310.224
480.0380.233
490.0340.208
500.0330.227
510.0320.204
520.0290.218
530.030.226
540.030.218
550.0320.215
560.0290.219
570.0290.212
580.0260.195
590.0290.196
600.0260.196
610.0250.19
620.0260.206
630.0270.2
640.0230.191
650.0260.195
660.0220.199
670.0220.193
680.0220.184
690.0240.178
700.0230.188
710.0240.184
720.020.177
730.0220.182
740.0210.183
750.0220.18
760.0190.183
770.0210.181
780.0220.188
790.0190.188
800.0230.189

What changed between runs

Exact answers on 453 rephrased questions, by training run
  • v4
    62.7%

    3.9M params · Clean data, balanced phrasings · test 68.1%

  • v5a
    51.7%

    11.7M params · 3× bigger, 25× more pretraining

  • v5b
    54.1%

    11.7M params · Same, higher learning rate

  • v6
    75.5%

    3.9M params · v4 + a paraphrase grammar · test 78.1%

  • Bigger was worse

    3× the parameters and 25× the pretraining scored up to 11 points lower on new phrasings. It memorized faster.

  • Data beat size

    Generating fresh phrasings every epoch took the same 3.9M model from 68.1% to 78.1% on the test set.

  • Dev sets wear out

    After five rounds of decisions, dev said 94% and test said 78%. A separate 453-question stress set predicted test within 3 points.

  • AdamW + weight decay
  • Warmup, cosine decay
  • Dropout
  • Gradient clipping
  • fp16 mixed precision
  • Early stopping
  • Answer-only loss
  • Resumable checkpoints

Results

Tested once, on 254 questions it never saw

The test set was locked away until the final model was chosen, so these numbers weren't tuned to look good.

80.0%
of answers contain every key fact
82.2%
word overlap (F1) with the reference answer
89.5%
of questions find the right chunk first
3.8%
said “I'm not sure” instead of guessing

Shipped for $0

7.7 MB
float16 weights, half of float32
86/86
answers identical to PyTorch
~1 s
per answer, on one CPU thread
0
servers or API calls

The weights, tokenizer and retrieval run in a Web Worker in your browser. A test suite checks that the TypeScript version produces the same tokens, retrieval and answers as PyTorch on 86 reference questions.

Honest limitations

  • 18.1% of answers give a true fact for a slightly different question ("What impact did SkySAR have?" gets SkySAR's summary). Wrong, but never invented.
  • It only knows what's on this site and only speaks English. It isn't a general chatbot.
  • Small on purpose: about a second per answer and 768 tokens of context, in exchange for $0 hosting and nothing leaving your browser.
Read the code on GitHub →