|
| 1 | +# Kakeya Inference Engine — Build Skill (SOP) |
| 2 | + |
| 3 | +**Audience / when to use this skill.** Read this before building, extending, |
| 4 | +benchmarking, or *validating* any part of the Kakeya Inference Engine (KIE) — on |
| 5 | +CUDA or Mac/MLX. It distills the full build journey (v0.4 → KIE-v1.x → KIE-v2 → |
| 6 | +v0.5-cuda) into: what the engine is, where the code lives, how to run/benchmark |
| 7 | +it, the milestone roadmap, the hard-won bugs+fixes, and — most important — the |
| 8 | +**validation honesty standards** (the rules that keep claims defensible). |
| 9 | + |
| 10 | +> If you only read one section, read **§7 Validation & honesty standards**. The |
| 11 | +> most expensive mistakes in this project were *overclaims*, not bugs. |
| 12 | +
|
| 13 | +--- |
| 14 | + |
| 15 | +## 1. North star (governs everything) |
| 16 | + |
| 17 | +The Kakeya Inference Engine is a **product-grade inference engine whose goal is to |
| 18 | +replace vLLM**, with **Kakeya Attention as its native, first-class attention |
| 19 | +algorithm**. It is **not** a research script, **not** a technique bolted onto HF |
| 20 | +transformers, and **not** "vLLM with a different cache". The whole engine |
| 21 | +(prefill, KV management, admission/scheduling, kernels) is designed |
| 22 | +**bounded-KV-native**: the full history is never resident; evicted context is |
| 23 | +reconstructed on demand. Authoritative source: `docs/adr/0015-kakeya-attention-and-engine-substrate.md` |
| 24 | +and `docs/design/kakeya-inference-engine-architecture.md`. |
| 25 | + |
| 26 | +### Kakeya Attention (the algorithm — one primitive) |
| 27 | + |
| 28 | +**sink+window bound + f_θ KV-projection + dLLM-proposer restoration, taken as one |
| 29 | +primitive.** It is a peer / drop-in replacement for eager attention, |
| 30 | +FlashAttention, vLLM PagedAttention, SGLang RadixAttention. Those keep the *whole* |
| 31 | +KV (memory grows with the conversation); Kakeya Attention bounds *how much* is |
| 32 | +resident and **reconstructs evicted context on demand** (proposer + f_θ), so the |
| 33 | +resident footprint does not grow with the session. |
| 34 | + |
| 35 | +- **Compute axis**: composable with FlashAttention (a flash kernel can compute a |
| 36 | + Kakeya window). |
| 37 | +- **Storage axis**: composable with paged/radix stores (they can hold the bounded |
| 38 | + window). |
| 39 | +- **The Kakeya-only axis**: the *total itself* is bounded. Cost = restoration |
| 40 | + compute (a proposer forward at prefill). |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | +## 2. Architecture & where the code lives |
| 45 | + |
| 46 | +| Component | Role | Code | |
| 47 | +| --- | --- | --- | |
| 48 | +| **AR verifier** (Gemma-4 26B-A4B, frozen) | the model being served; carries recall | `inference_engine/v04/dlm_restored_verifier.py`, `build_restored.py` | |
| 49 | +| **dLLM proposer** (DFlash) | reconstructs evicted K/V (restoration) | `inference_engine/v04/dflash_drafter.py`, `cross_model_dlm_verifier.py` | |
| 50 | +| **f_θ projection** | trained map from proposer hidden → verifier K/V | `inference_engine/v04/f_theta.py`; training: `docs/design/k3-f-theta-training-pipeline.md` | |
| 51 | +| **KV capture / merge / compress** | capture own K/V at prefill; pack/quantize | `inference_engine/v04/kv_capture.py`, `kv_merge.py`, `kv_compressor.py` | |
| 52 | +| **Engine runtime** (KIE-v1.x) | chunked restoration prefill + bounded-KV decode | `inference_engine/engine/kakeya_engine.py` | |
| 53 | +| **Admission / bounded-KV math** | peak-window admission, concurrency ceiling (pure stdlib) | `inference_engine/engine/admission.py` | |
| 54 | +| **Quantized attention** | tiled online-softmax over int8 KV (no bf16 transient) | `inference_engine/engine/quant_attention.py` | |
| 55 | +| **KakeyaVLLM (v0.5 entrypoint, KIE-v2)** | Kakeya window **on the vLLM runtime** | `inference_engine/engine/kakeya_vllm.py` | |
| 56 | +| **MLX backend** | Apple-Silicon port (`v0.4-mac`) | `inference_engine/backends/mlx/*` | |
| 57 | +| **gRPC session runtime** | session-bound serving (ADR 0008) | `inference_engine/session/*`, `inference_engine/server/*` | |
| 58 | + |
| 59 | +**Two engine substrates exist — know which you're touching:** |
| 60 | +1. **`KakeyaEngine`** (`engine/kakeya_engine.py`) — the eager HF-transformers |
| 61 | + research/feasibility substrate. Wins the **memory/concurrency** axis (N=75 @62k, |
| 62 | + recall 1.0) but decode speed is weak (eager 26B-MoE forward dominates). **Never |
| 63 | + ship or benchmark this as "Kakeya performance"** — it is a correctness probe. |
| 64 | +2. **`KakeyaVLLM`** (`engine/kakeya_vllm.py`) — the **product** path: Kakeya's |
| 65 | + bounded window **on vLLM**, inheriting vLLM's (Apache-2.0) fused-MoE Triton |
| 66 | + kernel + CUDA graphs + continuous-batching scheduler. This is the v0.5-cuda |
| 67 | + release artifact. |
| 68 | + |
| 69 | +> **Not a contradiction with §1's "not vLLM with a different cache".** The |
| 70 | +> *north-star* engine is bounded-KV-native and does not live inside vLLM. |
| 71 | +> `KakeyaVLLM` (KIE-v2 / v0.5) is the **pragmatic interim**: rebuilding vLLM's |
| 72 | +> fused-MoE + graphs + scheduler from scratch was attempted (KIE-v1.1.z2) and |
| 73 | +> shown to be a multi-week kernel project, so v0.5 wins the **decode-speed axis |
| 74 | +> now** by running Kakeya Attention *on* vLLM. ADR 0015 reconciles this |
| 75 | +> explicitly: vLLM's runtime is inherited; Kakeya owns the bounded-KV attention |
| 76 | +> layer; the native bounded-KV engine matures alongside. |
| 77 | +
|
| 78 | +--- |
| 79 | + |
| 80 | +## 3. Platforms & how to run |
| 81 | + |
| 82 | +### 3.1 CUDA (Vast.ai H200) — the primary benchmark platform |
| 83 | + |
| 84 | +GPU access is via SSH to a Vast.ai instance. Connection details live in injected |
| 85 | +secrets: `vast_ssh_host`, `VAST_SSH_PORT`, `VAST_SSH_USER`, `vast_ssh_key`. The |
| 86 | +**host/port changes between sessions** — the user supplies a fresh |
| 87 | +`ssh -p <port> root@<host>` each time; trust the user's latest details over the |
| 88 | +stale env vars. |
| 89 | + |
| 90 | +> **GOTCHA — the SSH key's newlines are collapsed.** `vast_ssh_key` is stored as a |
| 91 | +> single line (PEM newlines stripped) → `ssh` fails with `error in libcrypto`. You |
| 92 | +> MUST reconstruct a valid PEM before use: |
| 93 | +> ```python |
| 94 | +> import os, re |
| 95 | +> k = os.environ["vast_ssh_key"] |
| 96 | +> b, e = "-----BEGIN OPENSSH PRIVATE KEY-----", "-----END OPENSSH PRIVATE KEY-----" |
| 97 | +> body = re.sub(r"\s+", "", k.split(b,1)[1].split(e,1)[0]) |
| 98 | +> pem = b + "\n" + "\n".join(body[i:i+70] for i in range(0,len(body),70)) + "\n" + e + "\n" |
| 99 | +> open("/tmp/vk","w").write(pem); os.chmod("/tmp/vk",0o600) |
| 100 | +> ``` |
| 101 | +> Validate with `ssh-keygen -y -f /tmp/vk`. Then `ssh -i /tmp/vk -p <port> root@<host>`. |
| 102 | +
|
| 103 | +> **GOTCHA — disk is often tiny.** Some instances have ~4 GB free on the overlay |
| 104 | +> (`/workspace`, `/root`); the multi-TB devices shown by `df` are bind-mount |
| 105 | +> artifacts (NVIDIA libs, `/etc/hosts`), **not usable dirs**. Check |
| 106 | +> `findmnt`/writable space before assuming you can download a 26B model (~52 GB). |
| 107 | +> A pre-existing venv with vLLM is usually at `/root/venv-vllm`; HF cache under |
| 108 | +> `$HF_HOME` (e.g. `/workspace/.hf_home`). Set `HF_HUB_OFFLINE=1` to use cached models. |
| 109 | +
|
| 110 | +Provisioning helper: `scripts/research/run_on_vast.sh` (creates `.venv-vast`, |
| 111 | +installs CUDA torch + transformers, verifies GPU). Run scripts on the host with |
| 112 | +`PYTHONPATH=.:sdks/python`. |
| 113 | +
|
| 114 | +### 3.2 Mac / MLX (`v0.4-mac`) |
| 115 | +
|
| 116 | +MLX runs only on Apple Silicon; the cloud agent reaches a Mac M4 via the **Mac |
| 117 | +bridge** (`docs/design/mac-bridge-cloud-agent-access.md`, `docs/mac-bridge.md`). |
| 118 | +Port lessons: `docs/mlx-port-lessons.md`. |
| 119 | +
|
| 120 | +### 3.3 Key benchmark / test entrypoints |
| 121 | +
|
| 122 | +| Goal | Command | |
| 123 | +| --- | --- | |
| 124 | +| vLLM vs Kakeya-on-vLLM (KIE-v2 / v0.5) | `scripts/research/vllm_multitenant_parallel_bench.py --sliding-window 68` | |
| 125 | +| KIE eager engine throughput/concurrency | `scripts/eval/kakeya_engine_throughput_eval.py` (`--quant-attn`, `--compile-attn`, `--decoupled`) | |
| 126 | +| CUDA multi-tenant feasibility probe | `scripts/research/k3_cuda_multitenant_parallel_bench.py` | |
| 127 | +| MLX batched multi-tenant | `scripts/research/mlx_batched_multitenant_bench.py` | |
| 128 | +| Admission math unit tests | `pytest tests/inference_engine/engine/test_admission.py` | |
| 129 | +| v0.5 wrapper config unit tests | `pytest tests/inference_engine/engine/test_kakeya_vllm.py` | |
| 130 | +
|
| 131 | +--- |
| 132 | +
|
| 133 | +## 4. Milestone roadmap & current status |
| 134 | +
|
| 135 | +| Code | What | Status | |
| 136 | +| --- | --- | --- | |
| 137 | +| **v0.4-cuda / v0.4-mac** | restored Gemma-4 verifier + fused DFlash spec-decode | shipped — CUDA fused **≈1.79× AR** (committed scorecard); up to **~2.06–2.20× co-located** (ADR 0014). MLX **≈AR parity (~0.93–1.05× AR)** — a memory win, not a Mac speed win | |
| 138 | +| **KIE-v1** (#135) | engine core: chunked restoration prefill + bounded-KV decode + peak-window admission | done (core); concurrency gated on v1.1 | |
| 139 | +| **KIE-v1.1** (#136) | realize the bound at runtime: sliding-window-**evicting** StaticCache, graph capture OFF | done — 62k N=4→**N=16** (recall 1.0) with the evicting cache alone; **N=24** (1.55× vLLM) only after **prefill chunk-size tuning** (1024/512), see §below | |
| 140 | +| **KIE-v1.1.x** (#137) | int8/int4 exact-layer KV quant toward N=34+ | partial — recall-safe + halves stored bytes, but **N=34 OOMs** (dequant-on-read transient). The N=16→N=24 chunk-tuning lives here too | |
| 141 | +| **KIE-v1.1.y** (#138) | **quantized attention** (tiled online-softmax over int8, no bf16 transient) | done — **N=60 @62k** (peak 111.7 GB), recall 1.0, ~3.9× vLLM's ≈15.5 | |
| 142 | +| **KIE-v1.1.z** (#139) | throughput + N=75 | **N=75 MET** (recall 1.0, 126.7 GB, ~4.8× vLLM; ~31 tok/s aggregate); **decode ≥ vLLM NOT met** (eager 26B-MoE wall) | |
| 143 | +| **KIE-v1.1.z2** | rebuild fused-MoE + graph forward | **abandoned** — superseded by KIE-v2 (run *on* vLLM) | |
| 144 | +| **KIE-v2** (#140) | **Kakeya Attention on vLLM** | decode **≥ vLLM (1.15–1.23×)** @16k, recall 1.0, measured to N=70 — inherits vLLM runtime | |
| 145 | +| **v0.5-cuda** (#141) | release `KakeyaVLLM` + consolidated reports | done (gemma-4 instantiation). Product concurrency claim = **`KakeyaVLLM` N→70 @16k** on vLLM; the **N=75 @62k is the *eager* `KakeyaEngine` substrate**, not the v0.5 product path — do not conflate. See §7 for exact validation scope | |
| 146 | +| **v0.6** (= ADR 0015 KIE-v1.2) | **restoration backend on full-attention models** (Qwen/Llama): train f_θ/proposer + inject restoration at vLLM prefill + graph-capturable quantized-exact kernel | **planned — the real memory differentiator (~6×)** | |
| 147 | +
|
| 148 | +> **N=16 vs N=24 (KIE-v1.1 precaution).** The evicting StaticCache alone at the |
| 149 | +> default prefill chunk (2048) tops out at **N=16** @62k; **N=24** required smaller |
| 150 | +> prefill chunks (1024/512) and is tracked under KIE-v1.1.x. Don't credit N=24 to |
| 151 | +> the evicting cache alone (`docs/reports/kakeya-engine-vs-vllm-h200.md`, |
| 152 | +> `docs/design/kakeya-inference-engine-architecture.md` §9). |
| 153 | +
|
| 154 | +--- |
| 155 | +
|
| 156 | +## 5. Hard-won bugs & fixes (don't re-discover these) |
| 157 | +
|
| 158 | +| Symptom | Root cause | Fix | |
| 159 | +| --- | --- | --- | |
| 160 | +| MLX batched decode recall 0.125 | MLX **core kernel** bug for `B>1, L=1` quantized/rope decode (confirmed `0.31.2/0.31.3`) | `L>=2` padded decode workaround (recall 1.0, 0.67× tput); upstream bug, not ours | |
| 161 | +| MLX O(T²) throughput collapse | `restored_logits` did a full-sequence forward **per token** | Gap-A: capture restored K/V into native cache at prefill, decode incrementally (`mlx_lm.generate_step`) | |
| 162 | +| Eager prefill OOM (16k N=2, 32k N=1) | O(T²) scores + full-vocab logits + redundant forwards | SDPA + `logits_to_keep=1` + bf16 f_θ K/V | |
| 163 | +| StaticCache CUDA-graph **segfault** (chunked + long) | gemma-4 has non-graph-capturable ops (windowed `copy_` eviction; data-dependent MoE routing) — **structural** | pre-build StaticCache, `TORCHDYNAMO_DISABLE=1` (run evicting cache eager) | |
| 164 | +| `StaticSlidingWindowLayer` `AttributeError: device` | manual cache stacking dropped metadata | copy all metadata attrs in `_stack_caches` | |
| 165 | +| int8 exact-layer misclassified as `LinearAttention` | not subclassing `CacheLayerMixin` | lazy factory subclassing `transformers.cache_utils.CacheLayerMixin` | |
| 166 | +| `KakeyaLatticePackedCache` `expected last dim 256, got 512` | codec assumed uniform head_dim; gemma-4 full layers = 512, sliding = 256 | `kakeyalattice` v1.6.1 per-layer lazy head_dim (upstream) | |
| 167 | +| int8 storage halves bytes but **N=34 still OOMs** | cache `update()` returns **bf16** → each exact layer dequantizes full K/V on read; transients coexist | the real fix is **quantized attention** (KIE-v1.1.y) — attend on int8 without materializing bf16 | |
| 168 | +| `torch.compile` attention 6.6× but **0% e2e decode gain** | decode dominated by **eager 26B-MoE full-model forward**, not attention | need fused-MoE + full-forward graph capture → that's vLLM's job → **KIE-v2** | |
| 169 | +| fused-MoE port blocked | HF `kernels` incompatible w/ transformers 5.12; vLLM `fused_moe` cross-venv surgery; from-scratch = multi-week | **run Kakeya ON vLLM** instead of rebuilding it (KIE-v2) | |
| 170 | +| `KakeyaVLLM` crash on text-only model | unconditional `text_config` nesting (gemma multimodal) breaks Qwen/Llama (`num_attention_heads` missing) | **auto-detect** `text_config` via `AutoConfig`: nested for gemma-4, flat for Qwen/Llama | |
| 171 | +
|
| 172 | +--- |
| 173 | +
|
| 174 | +## 6. Engineering workflow (how this project ships) |
| 175 | +
|
| 176 | +- **One milestone = one PR, stacked.** KIE-v1 (#135) → v1.1 (#136) → v1.1.x (#137) |
| 177 | + → v1.1.y (#138) → v1.1.z (#139) → KIE-v2 (#140) → v0.5-cuda (#141), each based on |
| 178 | + the previous branch so the diff stays per-task. Branch prefix `AgentMemory/…`. |
| 179 | +- **ADR + report discipline.** Every milestone updates `docs/adr/0015-…` milestone |
| 180 | + table and a report under `docs/reports/`. Decisions and *honest caveats* are |
| 181 | + written down, not just code. |
| 182 | +- **Hypothesis-driven, runtime-evidenced.** Never claim a fix from code alone — |
| 183 | + reproduce, instrument, measure on the real GPU. Each optimization revealed the |
| 184 | + *next* bottleneck (eager prefill OOM → bf16 KV floor → dequant transient → MoE |
| 185 | + forward → vLLM runtime). Expect this ladder; don't skip rungs. |
| 186 | +- **Pragmatism over heroics.** Python-only workarounds and leveraging existing |
| 187 | + libraries (vLLM, kakeyalattice) beat multi-week from-scratch kernels within a |
| 188 | + session — *as long as the claim matches what was actually built*. |
| 189 | +
|
| 190 | +--- |
| 191 | +
|
| 192 | +## 7. Validation & honesty standards (READ THIS) |
| 193 | +
|
| 194 | +The single most damaging error pattern in this project is **overclaiming a |
| 195 | +validation**. Follow these rules rigidly. |
| 196 | +
|
| 197 | +### 7.1 What counts as validating "the engine" vs "the plumbing" |
| 198 | +
|
| 199 | +- **Engine/algorithm validation** = the actual claim (recall, memory, throughput) |
| 200 | + measured **on the release model, through the release code path, exercising the |
| 201 | + mechanism being claimed.** |
| 202 | +- **Plumbing/smoke test** = "the wrapper constructs, the config is applied, it |
| 203 | + generates" — proves the code runs, proves **nothing** about the algorithm. |
| 204 | +- **Label every artifact as one or the other.** Never let a smoke test masquerade |
| 205 | + as engine validation. (Case study: a Qwen3-4B run of `KakeyaVLLM` was wrongly |
| 206 | + presented as "end-to-end validation". It was plumbing-only — see §7.3.) |
| 207 | +
|
| 208 | +### 7.2 The Gemma-4 "S5 free lunch" — and why it does NOT generalize |
| 209 | +
|
| 210 | +- On **gemma-4-26B-A4B**, recall is **1.0 at `sliding_window=68` with NO |
| 211 | + restoration**, because **5 of 30 layers are native full-attention and carry |
| 212 | + recall**. So the gemma-4 instantiation (v0.5-cuda) is honest **without a trained |
| 213 | + f_θ/proposer** — restoration is *bypassed*, not exercised. |
| 214 | +- Therefore the gemma-4 **memory win over vLLM is small (~7% @62k)**: vLLM already |
| 215 | + hybrid-bounds the 25 sliding layers, and the 5 full layers dominate both engines. |
| 216 | +- **The large bounded-KV win (~6×) requires a FULL-ATTENTION model** (Qwen/Llama, |
| 217 | + all layers full), where shrinking the window **without restoration destroys |
| 218 | + recall** — so restoration is the *only* way to bound memory at full recall, and |
| 219 | + vLLM (no restoration) must keep full KV. |
| 220 | +
|
| 221 | +### 7.3 HARD RULE: never validate Kakeya Attention on a model without trained f_θ/proposer |
| 222 | +
|
| 223 | +A bounded window **without** trained restoration is **naive truncation, not Kakeya |
| 224 | +Attention.** On a full-attention model with no trained f_θ/proposer: |
| 225 | +- restoration never runs; |
| 226 | +- short prompts (< window) never even trigger eviction → the mechanism is untested; |
| 227 | +- long prompts lose recall (expected — that's *why* restoration is needed). |
| 228 | +
|
| 229 | +So you **cannot** demonstrate the engine on such a model. The v0.6 work is exactly |
| 230 | +"train f_θ/proposer for a full-attention model **then** validate". Until then, the |
| 231 | +only defensible engine evidence is gemma-4 (§7.2). |
| 232 | +
|
| 233 | +### 7.4 Decode-speed honesty |
| 234 | +
|
| 235 | +- The **eager `KakeyaEngine`** wins memory/concurrency but is slow at decode |
| 236 | + (~25–31 tok/s aggregate; the eager 26B-MoE forward dominates). Report decode-only |
| 237 | + tok/s **separately from prefill** — the `aggregate_tps_e2e` figure folds in the |
| 238 | + sequential 62k prefill and looks like ~2 tok/s, which is a harness artifact, not |
| 239 | + the decode rate. |
| 240 | +- The **product** decode-speed story is **KakeyaVLLM** (≥ vLLM), because it |
| 241 | + inherits vLLM's fused-MoE + CUDA graphs + scheduler. Don't claim product decode |
| 242 | + speed from the eager engine. |
| 243 | +
|
| 244 | +### 7.5 Checklist before writing "validated" anywhere |
| 245 | +
|
| 246 | +1. Did the **release code path** run (not a side script that approximates it)? |
| 247 | +2. Was the claim's **mechanism actually exercised** (restoration ran? eviction |
| 248 | + triggered? quant attention hit?)? |
| 249 | +3. Is it on the **release model**, or are you extrapolating from a proxy? If a |
| 250 | + proxy, say so and say what's still unproven. |
| 251 | +4. Is recall measured with a **real NIAH/needle test**, not vibes from a short prompt? |
| 252 | +5. Is the **artifact labelled** smoke-test vs engine-validation? |
| 253 | +6. Are the **caveats** (model-dependence, prefill-vs-decode, untrained components) |
| 254 | + in the report, not just the happy numbers? |
| 255 | +
|
| 256 | +If any answer is "no", write the weaker, true claim. |
| 257 | +
|
| 258 | +--- |
| 259 | +
|
| 260 | +## 8. Pointers |
| 261 | +
|
| 262 | +- North star + algorithm + milestones: `docs/adr/0015-kakeya-attention-and-engine-substrate.md` |
| 263 | +- Engine architecture: `docs/design/kakeya-inference-engine-architecture.md` |
| 264 | +- KIE-v2 feasibility (decode-cost decomposition): `docs/design/kakeya-vllm-backend-feasibility.md` |
| 265 | +- v0.5-cuda scorecard (+ honest §5): `docs/reports/kakeya-inference-engine-v0.5-cuda.md` |
| 266 | +- Engine vs vLLM long-context journey: `docs/reports/kakeya-engine-vs-vllm-h200.md`, `docs/reports/kakeya-vs-vllm-longcontext-h200.md` |
| 267 | +- MLX port lessons: `docs/mlx-port-lessons.md` |
| 268 | +- f_θ training pipeline: `docs/design/k3-f-theta-training-pipeline.md` |
| 269 | +- Session capacity / cross-host: `docs/adr/0014-agent-connection-capacity-and-cross-host-topology-tests.md` |
0 commit comments