Kept / trial active in llama-swap.yaml · aliases: ornith-15-35b-a3b-256k
| Run | Score | tok/step | R5 | Log |
|---|---|---|---|---|
| No results-*.log found for this id/alias. | ||||
ornith-ai/Ornith-1.5-35B-A3B-GGUF:Q4_K_M (20.22 GiB) + mmproj-Ornith-1.5-35B-BF16
(0.84 GiB), on /mnt/ssk500/gguf/ (direct -m, the qwen38 pattern — not -hf,
so the cold load is timed with no download-during-load confound and no
offline dangling-refs gotcha [[llama-cpp-offline-hf-refs]]).
Arch qwen3_5_moe (Qwen3_5MoeForConditionalGeneration) — SAME family as
[[pocket-35b]] (Qwen3.5-35B-A3B) and [[qwen36-35b-awq-trial]] (Qwen3.6-35B-A3B).
Real sparse MoE (256 experts, 8/tok, ~3B active), 40 layers
(full_attention_interval: 4 = 10 full-attn, rest linear/DeltaNet), head_dim
256, kv_heads 2, 262144 ctx. Vision-capable (qwen3_5_moe_vision, depth 27)
— mmproj WIRED, unlike text-only pocket-35b. THINKING model (CoT →
reasoning_content). No MTP head.
Ornith-1.5 ships 3 scales; only the 35B-A3B fits this 2×16 GB box:
118B trick would be ~3.4× that weight → catastrophic prefill).
ulkaa/Ornith-1.5-35B-A3B-AWQ-INT4 (24.33 GiB,0 downloads, unknown quantizer) — the official FP8 (~35 GB) doesn't fit
32 GB and the official NVFP4 is killed by the Ada card (SM 8.9, mixed-box
weakest-SM rule [[vram-spend-priority]]). AWQ on qwen3_5 arch has failed
systemically before ([[fable711-awq-self-quantize-todo]]: the (1+weight)
RMSNorm breaks AWQ smoothing). So vLLM is NOT the preferable path here — the
official GGUF (53k dl, the model's own org) is the higher-trust artifact.
Chose llama.cpp Q4_K_M despite the user's vLLM preference, and said why.
not the KLayout use case).
The blog claims the 35B-A3B "outperforms Qwen3.6-35B across all coding/agentic
benchmarks." The grill tests that apples-to-apples vs the served qwen36-35b
(KLayout+ref 15/16, the box's co-leader) and pocket-35b (22/23, R5 6/6) on
IDENTICAL serving (same arch family, q8_0 KV / 256k / sampler; only the model
differs). Ornith 1.0 was served here as agent-mini (9B, 18/23 + R5 6/6,
per bench/MODEL-RANKING.md) + a 35B, both retired 2026-07-27.
llama-swap.yaml entry ornith-15-35b (port 9147), aliases:
[ornith-15-35b-a3b-256k]. cmd mirrors pocket-35b: ${llama_bin}, -m +
--mmproj (direct ssk500 paths), --jinja --chat-template-file
chat-templates/qwen35moe-nonfirst-system-256k.jinja, -ngl 99 -c 262144 -fa on,
--tensor-split 48,52, -b 2048 -ub 512, temp 0.6/top-p 0.95/top-k 20/min-p 0,
--cache-type-k q8_0 --cache-type-v q8_0, --parallel 1.
has the non-first-system guard; multi-turn system+tools 400s without the
patched copy, and a single-turn smoke test does NOT catch it
([[jinja-system-guard-tool-parser]]). The family-neutral file is
byte-identical to pocket-35b's/kat-coder's. NOT hit by the peg-native bug
([[llama-cpp-peg-native-tool-parser-500]]).
the CLAUDE.md "some archs reject q8_0 V" warning).
test image correctly ("black helicopter... Statue of Liberty"). This is the
FIRST qwen3_5_moe vision model served here (pocket-35b was text-only).
models.json llama provider: ornith-15-35b + alias, input:["text", "image"]. The input modality is NOT derived from --mmproj — it comes from
the VISION_IDS set in .claude/sync-models.sh ("a missing id silently
downgrades to text-only"). Both ids added to VISION_IDS, then
sync-models.sh run (regenerates the llama provider from the yaml + updates
both statusline copies). pi/prime inherit via the models.json symlink.
~/.kimi-code/config.toml ([models.ornith-15-35b], provider coolbox, capabilities=["image_in",
"thinking"]), ~/.omp/agent/models.yml, ~/.config/opencode/opencode.json
(with modalities + attachment: true like qwen38).
Picked up via kill -HUP <MainPID> (no sudo) — re-reads llama-swap.yaml in
place; the resident vLLM TP=2 was torn down and **both workers reaped to 18 MiB
on both GPUs** by the [[qwen3-30b-a3b-thinking-vs-instruct]] orphan-reaper
wrapper (clean — no squat). Then:
headroom at q8_0 KV / 262144).
reasoning_content, finish: stop).patched template (answered "hello.py", no spurious tool call).
bench/grill-ornith-15-35b.sh ran all suites, GRILL_MAX_TOKENS=32000,
GRILL_TEMP=0.2, 1 rep, system python3 ([[klayout-office-grill-rounds]]).
Log: bench/grill-ornith-15-35b-20260821-1657/battery.log. Decode ~93 tok/s
(32000 tok / 344.8 s on realcase — pocket-35b's 102 tok/s class).
| suite | score | note |
|---|---|---|
| coding R1-4 | 21/23 | r1 6/8, r2-4 5/5 each |
| R5 agentic | 5/6 | clean — 0 loops, 0.0% redundant |
| klayout (no ref) | 0/8 | family baseline — runaways without ref |
| klayout +ref | 7/8 | min_spacing runaway @32000 — the ONLY true runaway |
| klvision | 5/6 | nested_rings FAIL (shape-detection miss) |
| closedloop (no ref) | 0/4 | both code arms fail → vision BLOCKED |
| closedloop +ref | 3/4 | ref closes the code loop; loop_ring:vision miss |
| office | 8/9 | bar_regions:vision miss |
| office +ref | 9/9 | perfect with ref |
| realcase | 7/7 PASS | cap-hit @32000/344.8s — verbose pass, NOT a runaway (all 7 sub-checks green) |
Runaway cleanliness: 1 true runaway (min_spacing) + 1 verbose-cap-hit-pass
(realcase, correct). qwen36-35b had 9 cap-hits — ornith is CLEANER here,
a point in its favor.
### The blog claim — NOT supported
Ornith-1.5's blog says the 35B-A3B "outperforms Qwen3.6-35B across all
coding/agentic benchmarks." It does not. It is parity, not a win — and it
is dominated on every individual axis by an incumbent:
grill_round*.py): coding 21/23 vs 22/23, R5 5/6 vs 6/6** — pocket-35b
ahead by 1 on both. pocket-35b is text-only (no vision/klayout/office), so
this only covers the shared coding+R5 axes, but pocket wins both.
its 08-09 run and now: klayout/klvision/office/closedloop suites were roughly
HALVED, coding 46→23, R5 12→6; raw scores are not directly comparable):**
n=1 — [[round5-is-a-sample-not-a-measurement]])
qwen36 was only the 2nd model EVER non-zero there)
So ornith TIES on closedloop+ref and office+ref, BEATS qwen36 on klvision +
office(unaided), but LOSES on R5, klayout+ref, and closedloop-no-ref. Mixed, not
a sweep.
The one open caveat on the verdict below was whether ornith's 256k window
actually retrieves or is generation-only like the qwen35 27B GGUF entries.
Tested after the 42,58 retune (model resident/warm), bench/needle.py 141000
0.1,0.5,0.9 NEEDLE_MAX_TOKENS=4000 via llama-swap :8090 (the qwen38 method):
pp=234,276 depth 0.1 PASS 142.1s in[content] ans='7Q-4412-ZX'
depth 0.5 PASS 144.8s in[content] ans='7Q-4412-ZX'
depth 0.9 PASS 145.0s in[content] ans='7Q-4412-ZX'
3/3 — code found in content at every depth. Per-depth times (~145 s each, no
~70x speedup) confirm COLD prefills, not a warm-cache replay
([[needle-warm-cache-invalidates-repeats]]). No depth-0.9 JSONDecodeError flake
(the qwen38 risk). The 42,58 split held through the full 234k prefill (4060Ti
12.8 GB / 5060Ti 14.6 GB, no OOM).
This narrows the cause, not just for ornith. [[qwen36-27b-deep-retrieval-fails]]
recorded fable-fusion / vision-coder / bonsai all 0/3 @222k on llama.cpp GGUF +
q8_0 KV + full_attention_interval 4, and called it architectural. ornith shares
ALL of that — llama.cpp, GGUF (Q4_K_M), q8_0 KV, full_attention_interval 4 (10
full-attn of 40) — yet retrieves at 234k. So the 0/3 @222k is specific to those
27B builds/weights, NOT to the llama.cpp GGUF q8_0 KV serving path or the
hybrid-attention design in general. (bonsai-awq already narrowed it by changing
quant+engine+KV together; ornith holds all three constant and varies only the
model — a cleaner isolation of "it's the build, not the path.")
Scope: one code at three depths, not a recall curve — the window is
addressable, not that reasoning over 234k is reliable. The 35B MoE siblings
pocket-35b and qwen36-35b were NEVER needle-tested, so this clears ornith and
the serving path, NOT the whole qwen3_5_moe family. Prefill is fast for a 234k
prompt (~145 s, ~3.7x qwen38's ~527 s at the same size — the sparse-MoE
prefill advantage), so the far end is more usable than qwen38's ~9-10 min,
though still not interactive.
### Verdict — KEEP as selectable TRIAL, do NOT promote
It does not win a quality role — every axis it contests, an incumbent already
wins: pocket-35b (coding+R5), qwen36-35b (klayout+ref, closedloop, the one-entry
vision+KLayout niche — qwen36 already replaced qwen3-vision AND
qwen3-vl-thinking), gemma-awq (coding+office, 44/46+18/18), qwen3next-thinking
(realcase+thinking champion, 7/7, already promoted). **But the differentiator
that keeps it is SPEED, not the capability combo.** qwen38 has vision+thinking
+256k too — but it is a DENSE 27B decoding at ~32 tok/s even with MTP,
while ornith is a sparse MoE (~3B active) at ~93 tok/s — 3× faster. Both
are thinking models (qwen38 even defaults reasoning_effort: xhigh), so tok/s
matters for both. **Wall-time on the SAME realcase task (both cap at 32000
tok): ornith 344.8 s → 7/7, qwen38 ~1048 s → 7/7 (and a 0/7 runaway in 3 reps)
— the 3× tok/s is a measured 3× wall-time to the same result.** For a thinking
model's long CoT, 32 tok/s is ~17 min/realcase vs ornith's ~6 min, so
**qwen38 does NOT substitute for ornith on the fast vision+thinking use
case.** qwen36-35b is fast+vision but has no thinking head; qwen3next-thinking
is fast+thinking but has no vision; qwen3-vl-thinking is the only other served
fast+vision+thinking model, and it carries documented quality red flags (false
geometry passes, runaways — see [[qwen3-vl-thinking-trial]]) where ornith passed
realcase 7/7 cleanly. So ornith's real, NON-redundant niche is **the fast
(MoE-class ~93 tok/s) vision+thinking+256k option with a clean realcase gate**
— and 256k retrieval is now VERIFIED (needle 3/3 @234k, above), so the window
is real, not generation-only like the qwen35 27B GGUF entries.
KEEP as selectable trial on that basis. (Verdict reasoning corrected
2026-08-21 after the AWQ trial underweighted speed and wrongly called it
redundant with qwen38.)
Caveats on the verdict:
([[single-run-scores-are-unreliable]], [[round5-is-a-sample-not-a-measurement]]
— 6 identical R5 runs once spanned 4/6-6/6). A re-grill (2-3 reps) would only
matter if ornith were a borderline promotion candidate; it isn't (dominated on
each axis), so a re-grill is NOT auto-justified — left to the user.
loop_ring:vision, bar_regions:vision) are all the same failure mode — losing
fine geometric detail (counting holes/rings/regions in shapes). The mmproj
describes broad scenes well (klvision 5/6) but loses fine geometry. First
qwen3_5_moe vision served, but not the box's vision pick (qwen36/gemma-awq
beat it).
AWQ on vLLM. The comparison is across serving stacks as well as weights.
### Why I keep it rather than remove
It's already wired into all 6 config surfaces and loads cleanly (97s cold, q8_0
KV, balanced GPUs). It costs nothing idle (llama-swap only loads on demand). It
is a legitimately usable vision+thinking 256k option for a user who wants the
qwen3_5_moe family with thinking (pocket-35b has no vision, qwen36 has no
thinking head). Demote-to-ssk500 is not warranted — it's not broken, just not
best. Leave as a selectable TRIAL.
"ornith-15-35b":
aliases: [ornith-15-35b-a3b-256k]
# ornith-ai/Ornith-1.5-35B-A3B-GGUF:Q4_K_M (20.22 GiB) + mmproj-BF16
# (0.84 GiB) — TRIAL 2026-08-21. Ornith-1.5-35B-A3B, arch qwen3_5_moe
# (Qwen3_5MoeForConditionalGeneration) — SAME family as pocket-35b /
# qwen36-35b. Real sparse MoE (256 experts, 8/tok, ~3B active), 40 layers
# (full_attention_interval 4 = 10 full-attn, rest linear/DeltaNet),
# head_dim 256, kv_heads 2, 262144 ctx. Vision-capable
# (qwen3_5_moe_vision, depth 27) — mmproj WIRED, unlike text-only
# pocket-35b. Weights on ssk500 (direct -m, the qwen38 pattern) not -hf,
# so the cold load is timed with no download-during-load confound.
#
# WHY IT WAS TRIED: the Ornith-1.5 blog claims the 35B-A3B "outperforms
# Qwen3.6-35B across all coding/agentic benchmarks". This grills that claim
# apples-to-apples vs the served qwen36-35b (KLayout+ref 15/16, the box's
# co-leader) and pocket-35b (22/23, R5 6/6) on IDENTICAL serving. Ornith
# 1.0 was served here as agent-mini (9B, 18/23 6/6) + a 35B, both retired
# 2026-07-27; 1.5 is a self-improvement-RL post-train on the Qwen3.5 base.
#
# SAMPLER/CONFIG mirrors pocket-35b (temp 0.6 / top-p 0.95 / top-k 20 /
# min-p 0, q8_0 KV, 256k) so the only real variable is the model. Grill
# overrides temp to 0.2 for parity. q8_0 V-cache is accepted by
# qwen3_5_moe (pocket-35b proves it).
#
# SPLIT is NOT pocket-35b's 48,52 — it is 42,58 (retuned 2026-08-21).
# ornith's q8_0 KV @262k + mmproj puts ~4.0 GB of non-weight memory (KV +
# projector + compute buffers) on device0 (CUDA0 = 4060 Ti, the default
# llama.cpp order — see [[gpu-device-ordering]]), vs only ~1.5 GB on
# device1. At 48,52 the 4060 Ti = 48% weight + 4.0 GB = 14.5 GB (1.9 GB
# free, tight) AND it was the prefill compute bottleneck (100% util vs
# the 5060 Ti's 47%). 42,58 relieves the 4060 Ti (42% + 4.0 = 13.2 GB,
# 3.2 GB free, 42% compute) and shifts 58% of compute to the faster
# 5060 Ti (58% + 1.5 = 14.1 GB, 2.2 GB free). The 4060 Ti stays device0
# ON PURPOSE: keeping the overhead on the slow card + lowering its
# weight is what lets the fast 5060 Ti carry MORE compute — pinning
# (PCI_BUS_ID -> CUDA0=5060 Ti) would move the 4.0 GB onto the 5060 Ti,
# cap its weight at ~48% and force the 4060 Ti to do MORE compute.
#
# TEMPLATE: the qwen3_5_moe family template has the non-first-system guard
# (raise_exception('System message must be at the beginning.')); multi-turn
# system+tools 400s without the patched copy, and a single-turn smoke test
# does NOT catch it. --chat-template-file is LOAD-BEARING
# (see [[jinja-system-guard-tool-parser]]); the family-neutral file is
# byte-identical to pocket-35b's/kat-coder's. NOT affected by the peg-native
# parser bug ([[llama-cpp-peg-native-tool-parser-500]]).
#
# REASONING MODEL — budget max_tokens generously. CoT -> reasoning_content;
# at max_tokens=40 it hits the cap mid-think and returns EMPTY `content`
# with no error — looks broken when it isn't.
cmd: |
/usr/bin/env
CUDA_DEVICE_ORDER=PCI_BUS_ID
${llama_bin}
-m /mnt/ssk500/gguf/Ornith-1.5-35B-Q4_K_M.gguf
--mmproj /mnt/ssk500/gguf/mmproj-Ornith-1.5-35B-BF16.gguf
--alias ornith-15-35b
--jinja --chat-template-file chat-templates/qwen35moe-nonfirst-system-256k.jinja
-ngl 99 -c 262144 -fa on
--tensor-split 42,58
-b 2048 -ub 512
--temp 0.6 --top-p 0.95 --top-k 20 --min-p 0.0
--cache-type-k q8_0 --cache-type-v q8_0
--host 127.0.0.1 --port 9147 --parallel 1
proxy: http://127.0.0.1:9147