The primary recommendation engine. Decompose the user's natural language
query into these structured parameters — ModelAtlas does deterministic math.
── START HERE: NARROW, THEN ORDER ──────────────────────────────────
`require_anchors` is the ONLY parameter that narrows the candidate set.
Bank directions, `prefer_anchors`, `avoid_anchors`, and `similar_to`
all SCORE a set they never shrink. Omit `require_anchors` and every
model in the corpus is scored, with `limit` lopping off the tail — you
get the top slice of an unfiltered corpus, not the best of a considered
field. The response says so: `refine.scope_unfiltered: true`.
So drive it in that order:
1. NARROW — one or two `require_anchors` naming what the model must
have ("code-generation", "GGUF-available"). The vocabulary is
CLOSED — an anchor that does not exist returns zero results, so do
not invent labels. If you do not know it, call with no
`require_anchors` and read the anchors offered by
`refine.options` and `refine.splitting_anchors`: they are real
labels drawn from the returned window. The `anchors` list on each
result is the same vocabulary seen from the other side.
2. ORDER — `prefer_anchors` for what would be nice. Without them the
ranking is filtered but not meaningfully sorted
(`refine.ranking_degraded: true`).
3. SHAPE — bank directions, `mode`, `bank_weights` to tilt the result.
4. REFINE — answer `refine.question` and re-call (see below).
A well-formed query considers hundreds of candidates, not tens of
thousands. If you find yourself reaching for `limit` to make a broad
query manageable, add a `require_anchor` instead — `limit` truncates,
it does not select.
BANK DIRECTIONS (-1, 0, or +1 for each; omit to express "don't care"):
architecture: -1=simpler/older (encoder-only, RNN)
0=standard transformer decoder (most models)
+1=novel/specialized (Mamba, RWKV, SSM, MoE)
capability: -1=narrow/single-task (classifier, embedding-only)
0=general language model
+1=rich/multi-capability (code, reasoning, tool-calling)
efficiency: -1=smaller/lighter (3B, 1B, sub-1B, edge)
0=~7B mainstream sweet spot
+1=larger/frontier (13B, 30B, 70B+)
compatibility: 0=standard PyTorch/transformers
+1=specific format/hardware (GGUF, MLX, Apple Silicon)
lineage: -1=predecessor/earlier in family
0=base/foundational model
+1=derivative (fine-tune, quantized, community merge)
domain: 0=general knowledge
+1=domain-specialized (code, medical, legal, finance)
quality: -1=legacy/declining/abandoned
0=established mainstream
+1=trending/rising momentum
training: -1=simpler methods (LoRA, adapter, distillation)
0=standard supervised fine-tuning (SFT)
+1=complex alignment (RLHF, DPO, multi-stage)
ANCHOR TARGETING:
require_anchors: Model MUST have ALL of these (hard filter).
Examples: "code-generation", "instruction-following", "Llama-family",
"GGUF-available", "consumer-GPU-viable", "tool-calling"
prefer_anchors: Boost models with these (soft preference, IDF-weighted).
avoid_anchors: Penalize models with these (each halves the score).
context_anchors: Anchors the CALLING CONTEXT has already established
as relevant (e.g. earlier-turn state, the user's stated situation).
Soft multiplicative bias in [1.0, 1.5]× based on IDF-weighted
overlap — never a filter. Use for "the same query would resolve
differently in a different context" cases: passing
`["Apple-Silicon-native"]` on a Mac user's session biases toward
MLX/GGUF-Metal without excluding CUDA-only models from the ranking.
QUERY MODE:
mode: How aggressively to weight the soft signals.
- "auto" (default) — derives from the query's mechanical (size,
format, structure) vs semantic (capability, domain, quality)
character. Mechanical-heavy queries let PageRank dominate;
semantic-heavy queries let rare-anchor / absence-bonus signals
dominate. Sensible default for most callers.
- "canonical" — amps PageRank. Established mainstream models rise.
Use for "give me the well-known thing that matches."
- "niche" — amps rare-match, absence-bonus, superadditive signals.
Specialists rise over popular near-misses. Use for
"find the specific specialist, not the popular generalist."
- "balanced" — fixed default weights (no auto-adaptation).
DEPTH — HOW FAR, NOT JUST WHICH WAY:
min_depth: {BANK: minimum steps from the zero state}, e.g.
{"EFFICIENCY": 3} alongside `efficiency=1`. A bank position is
[SIGN][DEPTH]; a direction alone says only which way, so
`efficiency=+1` admits a 13B model and a 400B one equally. Depth is
the "how far" half.
This is a FILTER, applied by set intersection when candidates are
selected — not a scoring term. Depth decides who is admissible;
what ORDERS the admissible set is the separate scalar signal. Ask
for the shape you want, then let ranking do its own job.
Ignored for a bank whose direction is 0 or unset — the zero state
is depth 0, so "at least N steps from it" means nothing there.
max_depth: the ceiling to min_depth's floor, e.g.
{"EFFICIENCY": 1}. Unlike min_depth this DOES apply at direction 0,
where it reads as a band around the zero state:
`efficiency=0, max_depth={"EFFICIENCY": 1}` is "the ~7B sweet spot,
give or take one class" and excludes a 400B model that happens to sit
at the zero state because nobody recorded its size.
Rough EFFICIENCY guide: 1 ~ one class out (3B / 13B), 2 ~ two
(1B / 30B), 3+ ~ the far end (sub-1B / 70B+).
BANK WEIGHTS:
bank_weights: Optional per-bank exponent overrides,
e.g. {"QUALITY": 0.0, "CAPABILITY": 2.0} to neutralize quality-
tiering and double-weight capability alignment. Missing bank →
weight 1.0 (default). Zero → the bank contributes nothing to
alignment (neutralized). > 1 → the bank counts extra.
Renormalized across active banks so total attention-mass is
preserved. Feature, not a knob-to-hide: sometimes the caller
knows better than the defaults.
SEED SIMILARITY:
similar_to: A model_id to use as similarity seed (IDF-weighted Jaccard
on anchor sets). Example: "meta-llama/Llama-3.1-8B-Instruct"
SCORING:
score = bank_alignment * anchor_relevance * seed_similarity * coherence
* context_bias * epa_alignment * soft_combined
Multiplicative, so any zero factor kills the result. The first six are
≤ 1.0 and filter; `soft_combined` REWARDS (PageRank, PMI-match, rare
boost, absence bonus, folded submodularly), so scores are NOT bounded
at 1.0. Every factor is returned in `score_breakdown`.
THE REFINEMENT LOOP — read this before reporting results to a user:
Every response carries a `refine` block. The engine is deterministic:
it knows which dimensions its own answer is silent on, and it will not
pretend to an ordering it cannot justify. Use it.
1. Call navigate_models with whatever the user gave you.
2. Read `refine.question` — one plain question naming the single
most useful thing still unspecified.
3. Ask the user that question (or answer it yourself if the earlier
conversation already settles it).
4. Merge the chosen option's `apply` dict into the SAME arguments you
just sent — do NOT rebuild the query from scratch. Scalar keys
(`efficiency`) replace; list keys (`require_anchors`) append.
5. Re-call. Repeat until `refine.question` is empty.
`refine.scope_unfiltered: true` means you passed no `require_anchors`,
so the candidate set was the whole corpus. This is the sibling of
`ranking_degraded` one stage earlier, and it is asked FIRST — no
ordering signal repairs a field that was never narrowed. The options
on that question are anchors drawn from the window itself, so each one
names something at least one returned model actually has.
`refine.ranking_degraded: true` means you passed no `prefer_anchors`.
The results are correctly FILTERED but not meaningfully ORDERED —
three of five soft signals score identically for every candidate that
clears the `require` filter. Treat the window as a SET, not a ranking,
and do not tell the user result #1 beats result #2. Add prefer_anchors.
`tie_cluster_id` on a result means the same thing locally: those
results are indistinguishable given the constraints, and
`discriminating_axis` names the bank that would separate them.
Args:
architecture: Bank direction for ARCHITECTURE (-1, 0, or +1)
capability: Bank direction for CAPABILITY (-1, 0, or +1)
efficiency: Bank direction for EFFICIENCY (-1, 0, or +1)
compatibility: Bank direction for COMPATIBILITY (-1, 0, or +1)
lineage: Bank direction for LINEAGE (-1, 0, or +1)
domain: Bank direction for DOMAIN (-1, 0, or +1)
quality: Bank direction for QUALITY (-1, 0, or +1)
training: Bank direction for TRAINING (-1, 0, or +1)
require_anchors: Anchors the model MUST have (hard filter)
prefer_anchors: Anchors that boost score (soft, IDF-weighted)
avoid_anchors: Anchors that penalize score
context_anchors: Ambient-context anchors (soft bias, ≤ 1.5× boost)
mode: Query mode — "auto" | "canonical" | "niche" | "balanced"
bank_weights: Optional {bank: exponent} per-bank weight overrides
min_depth: Optional {bank: minimum depth} hard filter, e.g.
{"EFFICIENCY": 3}. Needs that bank's direction set to +1/-1.
max_depth: Optional {bank: maximum depth} hard filter. Applies at
direction 0 as a band around the zero state.
similar_to: Model ID for anchor-similarity seed
limit: Max results to return (default 20)