Dean.Taxi Blog
/find
V4.1 finds DeepSeek. 4.1 doesn't. I can explain.

V4.1 finds DeepSeek. 4.1 doesn't. I can explain.

A friend, using ORCA for the bit, reports: I can look up "V4.1" to find DeepSeek, but looking up "4.1" doesn't bring it up.

The model is deepseek/deepseek-v4.1-flash. It landed a few days ago. The characters 4.1 are right there in the slug. You can see them. I can see them. The search box cannot.

This is the part where a normal person says "so add fuzzy matching" and I say "absolutely not," with the confidence of someone who has already lost this argument with himself.

The algorithm is incredible, actually

We do not fuzzy-match the grid. We do not Levenshtein. We do not "did you mean." We wrote a dynamic prefix search over slug-like fields, and I am going to talk about it as if it were a contribution to computer science.

The catalog is a hostile dataset. Every model id is two segments bolted together with a slash — author/model — and then you add providers, which are their own slugs, which also have slashes, and sometimes colons, and sometimes a speed tier hiding in the tag. Standard fuzzy search over that surface is a noisy jumble that rearranges itself whenever you type one more letter. From a user's chair it looks random. It is not random. It is worse: it is a scoring function with opinions you didn't ask for.

So we index prefixes. We keep punctuation. We rank exact token hits above "this string merely begins with what you typed." And when the scores tie, we sort by model recency, then model id, then provider tag, so you get a contiguous result surface of models instead of a shuffle of endpoints.

I will now justify this with the example that made me this way.

The mini problem

Type mini. Ninety-five rows. The first screen is not chaos. It is size suffixes.

GPT-5.4 Mini. GPT-5 Mini. GPT Audio Mini. o4 Mini. GPT-4.1 Mini. Seed-2.0-Mini. North Mini Code. Aion-3.0-Mini. OpenAI in particular has turned mini into a product line, and every Azure / OpenAI / flex / fast row of GPT-5.4 Mini sits together as a block you can actually read.

The endpoints grid filtered to mini: GPT-5.4 Mini as a contiguous block of providers, surrounded by other models whose slug ends in mini
The endpoints grid filtered to mini: GPT-5.4 Mini as a contiguous block of providers, surrounded by other models whose slug ends in mini

First screen of mini. Size suffixes. MiniMax is downstairs, which is the correct floor.

Then, further down, there is an author named MiniMax. Their series is MiniMax M1, M2, M2.1, M2.5, M2.7, M3. They are open models, so they have a market: DeepInfra, Together, Novita, Parasail, AtlasCloud, and so on. They are also a provider of their own models — a participant in the market they created. They additionally ship MiniMax Highspeed, which appears as a provider tag (minimax/highspeed), which is not quite a slug and not quite an id, and is a quagmire I am contractually obligated to write a separate article about.1

Now: is minimax/minimax-m2 served by minimax/highspeed more mini than openai/gpt-5.4-mini served by Azure?

No.

If you score by how many times the letters m-i-n-i appear, MiniMax MiniMax on MiniMax Highspeed is a slot-machine jackpot. The result list becomes a jumble of MiniMax endpoints with GPT-5.4 Mini sprinkled in wherever the scorer got bored. Type one more letter and the whole thing permutes. That is the "standard fuzzy match" outcome, and it is unusable for browsing.

Exact mini as a segment — the size suffix — ranks above minimax as a prefix of an author name. Then all the providers of a given model stay together. You browse models. You do not browse a vibe.

How it actually works (I am trying too hard)

Query tokens split on whitespace only. 4.1 mini is two tokens; both must hit. Punctuation inside a token is kept, because gpt-4- and google-vertex/ are real queries people type.

Indexed fields are the slugs: model id and provider tag. Display names are not searched. "DeepSeek V4.1 Flash" as a pretty label does not get a vote.

Note

We search slugs, not marketing. If the id doesn't contain what you typed, the row does not come back. This is a feature I will not be defending in the comments.

For indexing, /, -, and : are boundaries. . is not. A period is glue. We generate the full slug, every suffix that starts just after a boundary, and the plain segments between them.

// not the code. the vibe.
function tokens(slug: string): string[] {
  // "openai/gpt-4.1-mini" contributes:
  //   openai/gpt-4.1-mini
  //   gpt-4.1-mini
  //   4.1-mini
  //   mini
  //   openai, gpt, 4.1, mini
  return [...suffixesAfter("/-:"), ...segmentsBetween("/-:")];
}

function matches(query: string, slug: string) {
  return tokens(slug).some((t) => t === query || t.startsWith(query));
}

Matching is prefix from the left of a token. There is no "contains." There is no typo tolerance. There is no "treat 4.1 as a version family." We tried being clever about numbers. We stopped.

Ranking, and I cannot overstate how sophisticated this is:

score=106exactField+103exactToken+prefix

Three integers. A masterpiece.

So why doesn't 4.1 find DeepSeek

Because DeepSeek wrote v4.1, and a period is glue.

deepseek/deepseek-v4.1-flash tokenizes to things like v4.1-flash, flash, deepseek, v4.1. There is no token that starts with 4.1. The 4.1 you can see with your eyes is sitting inside v4.1, one character to the right of the start. Prefixes do not enter from the middle. That was the whole point of prefixes.

You type What you get Why
V4.1 DeepSeek V4.1 Flash, Cydonia 24B V4.1 exact token v4.1
4.1 Granite 4.1, Opus 4.1, GPT-4.1 exact token 4.1
mini size-suffix models, then MiniMax exact mini beats prefix minimax

V4.1 works because you typed the token we actually indexed. DeepSeek V4.1 Flash, twelve providers, one block, plus Cydonia 24B V4.1 at the bottom because they also glued a v onto their version. Case doesn't matter. The v does.

The endpoints grid filtered to V4.1: DeepSeek V4.1 Flash as a contiguous block of twelve providers, with Cydonia 24B V4.1 at the bottom
The endpoints grid filtered to V4.1: DeepSeek V4.1 Flash as a contiguous block of twelve providers, with Cydonia 24B V4.1 at the bottom

V4.1. There it is. A contiguous DeepSeek block, because that is what we optimized for — just not the query you typed.

4.1 works for everyone who put the version after a hyphen: openai/gpt-4.1, anthropic/claude-opus-4.1, ibm-granite/granite-4.1-8b. Their segment is 4.1. DeepSeek's segment is v4.1. Same catalog, two naming religions, one prefix machine.

The endpoints grid filtered to 4.1: Granite 4.1 8B, Claude Opus 4.1, and the GPT-4.1 family. No DeepSeek.
The endpoints grid filtered to 4.1: Granite 4.1 8B, Claude Opus 4.1, and the GPT-4.1 family. No DeepSeek.

4.1. Granite, Opus, the entire GPT-4.1 product line. The thing you wanted is not here.

It should just work. It currently just doesn't work that way bro. There are reasons.

I have not looked at this code in a very long time. It was never written with an exposé in mind. It is in the queue, the queue is never-ending, and today I wrote a blog post instead of teaching a period to pretend it is a hyphen. If you want the model, type v4.1. If you want the lecture, you already have it.

Live: orca.orb.town. The search box is the one that looks like it should just work.


  1. Provider tag vs slug vs id vs display name vs organization. OpenRouter flattened three concepts into fields that all look like names. `minimax/highspeed` is a tag. `sambanova-turbo` is a full record slug with no slash. `deepinfra/fp8` is a quantization suffix that may or may not have a matching record. I am not opening this door today.