kaggle-tpu-lab README

The project's README from github.com/ARahim3/kaggle-tpu-lab. As one markdown file: README.md.

kaggle-tpu-lab

Serve Qwen3.8-27B — a frontier-class 27B hybrid-attention model — on Kaggle's free TPU v5e-8, with a public OpenAI-compatible endpoint you can plug into Claude Code, Codex CLI, opencode, or anything else that speaks the OpenAI API.

No paid GPU, no cloud account, no quantization. Full bf16 weights, up to the model's native 262,144-token context, and real speed:

What Measured (TPU v5e-8, bf16, TP=8)
Decode, single stream ~130 tok/s with MTP speculative decoding (78 without, measured before the token-bucket change)
Decode, 8 concurrent streams ~540 tok/s aggregate (~107 tok/s each, MTP on)
Decode, 16 concurrent streams ~900 tok/s aggregate (with --mtp 0 — see tuning note below)
Prefill 10,300 tok/s — a 105k-token prompt in ~10 s
Native 262k context works — 225k-token prompt prefilled in ~28 s
Time to live endpoint ~22 min with the env dataset attached (~12 with --text-only, ~6 with --fast-start; ~40 without the dataset)
Output correctness with MTP verified lossless — 12/12 greedy prompts exactly match non-speculative

Tuning note: speculative decoding pays off up to ~8 concurrent streams and fades beyond that (verification competes with batch compute). Serving many users? Launch with --max-model-len 131072 --max-num-seqs 16 --mtp 0 for max aggregate throughput.

Why this works (the one-paragraph version)

Qwen3.8-27B is a hybrid: 48 of its 64 layers are gated-DeltaNet linear attention, only 16 are classic full attention. That makes its KV cache tiny (~64 KB/token), which is why a 27B can serve 131k+ contexts on 8×16 GB TPU chips with room to spare. Until recently no TPU stack could run the DeltaNet layers — vllm-tpu 0.28.0 shipped native Pallas kernels for them (Aug 2026), and this repo is the recipe that puts it all together on Kaggle's free tier: a pre-built Python runtime with pinned versions, pre-mirrored weights, a pre-built XLA compile cache, MTP speculative decoding, and a tunnel to the outside world.

Quick start A — as a Kaggle notebook

Copy & Edit the published Kaggle notebook and Run it — kaggle.com/code/rahim3/qwen3-8-27b-bf16-on-kaggle-tpu-130-tok-s-api — or upload notebook/qwen38-tpu-serve.ipynb yourself. Set Accelerator = TPU VM v5e-8, Internet = ON, attach the two datasets named in the first cell, and run top to bottom. The last cell is the server — the endpoint URL and API key appear in its output.

Quick start B — from your terminal

You need Python 3.9+ and a Kaggle account with TPU access (Settings → phone-verify your account if you haven't; free tier includes ~20 TPU hours/week).

# 1. Kaggle CLI + API token (one-time)
pip install kaggle
# kaggle.com → Settings → API → Create New Token, then place the file:
#   Linux/macOS: ~/.kaggle/kaggle.json     Windows: %USERPROFILE%\.kaggle\kaggle.json

# 2. Get this repo and launch
git clone https://github.com/ARahim3/kaggle-tpu-lab
cd kaggle-tpu-lab
python launch.py serve

That's it. The launcher pushes a script kernel to your Kaggle account, and streams progress to your terminal so you always know what's happening:

[14:05]  Pushing kernel you/qwen38-tpu-serve (TPU v5e-8)...
[14:06]  Kaggle: queued — waiting for a TPU v5e-8 slot...
[14:08]  Kaggle: provisioning the VM and attaching datasets (a few minutes)...
[14:14]  Building the Python runtime with uv (~30 s)...
[14:15]  Runtime ready.
[14:15]  XLA compile cache restored for this exact config — fast start.
[14:15]  Weights found mounted (no download needed).
[14:15]  Starting vLLM — loading 55 GB of weights, then TPU graph compile...
[14:15]  Endpoint URL reserved: https://xxxx-yyyy.trycloudflare.com/v1  (not live yet — wait for the banner)
[14:19]  Loading / compiling... 4 min elapsed (typically ~20 min with the env dataset, ~35 min without)
[14:35]  Server is HEALTHY after 20 min.

==================================================================
  YOUR ENDPOINT IS LIVE
  base URL : https://xxxx-yyyy.trycloudflare.com/v1
  API key  : sk-....
  model    : qwen3.8-27b   (context: 262144)
==================================================================

Ctrl-C detaches without stopping the server. Re-attach with python launch.py status -f; kill the TPU session with python launch.py stop.

Useful flags (the default launch serves the full native 262k context, 4 concurrent sequences):

python launch.py serve --max-model-len 131072 --max-num-seqs 16  # many parallel streams (~900 tok/s aggregate)
python launch.py serve --reasoning-effort medium                 # server-side default
python launch.py serve --keepalive-min 120                       # auto-stop after 2 h
python launch.py serve --text-only                               # skip the vision tower: ~10 min faster, no image inputs
python launch.py serve --fast-start                              # live in ~6 min; common shapes warmed after, rare ones stall ~1 min once

Using it with coding agents

The endpoint is standard OpenAI API, with tool calling enabled (--enable-auto-tool-choice, qwen3_coder parser — matches Qwen3.8's XML tool format) and the qwen3 reasoning parser, so thinking content is separated properly. The launcher/notebook print the endpoint URL and API key in a banner when the server is up.

Codex CLI / opencode / aider / anything OpenAI-compatible:

export OPENAI_BASE_URL="https://<your-tunnel>.trycloudflare.com/v1"
export OPENAI_API_KEY="sk-<your-key>"
# model name: qwen3.8-27b

Claude Code — the bundled vLLM also exposes an Anthropic-compatible /v1/messages (reasoning arrives as proper thinking blocks; we verified Claude Code end-to-end against it). One gotcha: the server authenticates with a Bearer header only, so use ANTHROPIC_AUTH_TOKEN, not ANTHROPIC_API_KEY:

export ANTHROPIC_BASE_URL="https://<your-tunnel>.trycloudflare.com"
export ANTHROPIC_AUTH_TOKEN="sk-<your-key>"
export ANTHROPIC_MODEL="qwen3.8-27b"
export ANTHROPIC_SMALL_FAST_MODEL="qwen3.8-27b"
claude

Reasoning effort

Qwen3.8 has three thinking levels: xhigh (default), medium, low — plus off. Set a per-request level (works from any client that lets you add request fields):

{"chat_template_kwargs": {"reasoning_effort": "low"}}

or turn thinking off entirely with {"enable_thinking": false}. To change the server-side default (for clients that can't pass extra fields), launch with --reasoning-effort medium.

What's actually in this repo

launch.py                        the CLI: serve / status / stop, with live progress
kernel/serve_qwen38.py           the Kaggle kernel: runtime → cache → weights → vLLM → tunnel → READY
notebook/qwen38-tpu-serve.ipynb  the same flow as a run-it-yourself notebook
patches/mtp-rollback-v0280.diff  GDN state-rollback fix (port of tpu-inference PR #3178)
tools/embed_patch.py             re-embeds the patch into the kernel script after edits

Plus two public Kaggle datasets the kernel attaches:

Where the startup time goes (and went)

The first version of this recipe took 50 min from "Run" to a live URL. Measured now: ~22 (12 with --text-only, ~6 with --fast-start):

Step Before Now How
pip install 11 min 30 s uv into a fresh venv with CPU torch (the PyPI default is the CUDA build + 3 GB of NVIDIA libs), resolution pinned to the cache's build date
Weights → TPU 3 min 3 min reading 55 GB; unchanged
Vision-tower graphs 13–23 min ~8 min (0 with --text-only) the compile part is now cached; the rest is tpu-inference tracing the vision encoder at warm-up, which no cache can skip
Text graphs at all in --fast-start — 0 at startup precompile skipped; the script warms the common shapes right after READY, rare shapes stall ~1 min once
Text graphs 8 buckets, ~19 min cold 6 buckets, ~4 min cache built for the shipped config (the old cache never matched, so every run compiled cold), MIN_TOKEN_BUCKET=64, 4 parallel compile threads
Tunnel after the self-test in parallel with the server start URL is printed early, banner marks readiness

Maintainers rebuild the bundle with python launch.py build-env (serves each config once on a TPU kernel, ~2 h) and create/version the dataset from the kernel's output folder in the Kaggle UI (Output tab → New Dataset).

Good to know / limits

Credits

License

MIT for everything in this repo. Model weights follow the upstream Qwen3.8-27B license (Apache-2.0).

kaggle-tpu-lab (ARahim3/kaggle-tpu-lab)

Searching Database…

这是什么?这是一套方案,在 Kaggle 免费 TPU v5e-8 上部署前沿级开源 LLM——GLM-5.3-Flash 320B MoE 和 Qwen3.8-27B bf16——并暴露一个公开的 OpenAI 兼容(及 Anthropic 兼容)端点,可以接入 Claude Code、Codex、opencode、pi 等编程智能体。
这是托管服务,还是我自己运行的东西?由你自己运行:一个 Kaggle notebook 或本地 launch.py 脚本会把脚本内核推送到你自己的 Kaggle 账号,用你的个人 TPU 配额来部署模型,并打印一个临时的公开端点 URL。
怎么让它跑起来?要么复制并编辑已发布的 Kaggle notebook,把 Accelerator 设为 TPU VM v5e-8、打开 Internet,挂载列出的两个数据集,然后从头到尾运行;要么在终端里运行 `python launch.py` 远程完成同样的事。
开始之前需要什么?本地要有 Python 3.9+,以及一个有 TPU 权限的 Kaggle 账号(如果还没有,去 Settings 里完成手机验证)——免费额度大约是每周 20 小时 TPU。
有什么限制?每个 Kaggle 账号同一时间只能开一个 TPU 会话,会话最长 9 小时,免费配额大约每周 20 TPU 小时;另外这个混合注意力模型目前禁用了前缀缓存,多轮智能体对话每一轮都要重新 prefill。
API 端点会暴露在互联网上吗?会——启动器会开启一个公开的 cloudflared 隧道 URL,但它由每次启动时新生成的 API key 保护,请把这对 URL 和 key 当作机密保管。
我需要自己的 GPU 吗?不需要——它完全跑在 Kaggle 免费 TPU v5e-8 配额上,不需要付费 GPU、云账号,也不需要量化。
具体怎么把它接入 Claude Code?内置的 vLLM 暴露了一个 Anthropic 兼容的 /v1/messages 端点;把 Claude Code 指向打印出来的端点 URL,并把 ANTHROPIC_AUTH_TOKEN(不是 ANTHROPIC_API_KEY)设置为生成的 key。
MTP 投机解码在这里为什么有风险?修好了吗?原版 vllm-tpu 0.28.0 在 MTP 与该模型的 gated-DeltaNet 层一起使用时会损坏输出;仓库附带一个补丁,使其经过验证无损(12/12 个贪婪提示词与非投机输出完全一致),解码速度提升约 34%。
这个端点能处理图片吗?可以,Qwen3.8 是视觉语言模型,接受 image_url 内容;新分辨率的第一张图片大约需要一分钟来编译,之后同尺寸的图片都能即时处理。
为什么前缀缓存被禁用了?vllm-tpu 0.28.0 有意在 TPU 上为混合线性注意力模型关闭了自动前缀缓存,所以多轮会话每一轮都要重新 prefill——能感觉到,但很快(5 万 token 的对话约 5 秒)。
Creator
ARahim3
Size
0.4 MB
Stars
657
Updated
CommitOct 06
Age
1mo
Commits · 90 Days