Serve a Model
Four chips, one command. tt serve downloads or finds the weights, starts the model in a
container, waits until it answers, and tells you the address. What you get is an
OpenAI-compatible HTTP API running on your own hardware, which every chat app, coding agent
and SDK already knows how to talk to.
This chapter serves Qwen3-32B, the model your QB2 shipped with. Its weights and compiled kernels are already on disk, so the first serve does not download 62 GB.
Pick the Model
tt knows which models run on your hardware:
tt model list
On a QB2 it detects a p300x2 configuration (two p300 boards, four chips) and lists the
models that have a serving profile for it. tt model info tells you what a model needs and how
well it is validated:
tt model info Qwen3-32B
┌─────────────────────┬────────────────────────────────────────────────────────┐
│ hf_repo │ Qwen/Qwen3-32B │
│ type │ llm │
│ engines │ vLLM │
│ via │ inference-server, studio │
│ servable │ yes — `tt serve Qwen3-32B` (`--studio` deploys it with │
│ │ TT-Studio) │
│ parameters │ 32B │
│ min disk │ 84 GB │
│ min ram │ 80 GB │
│ on p300x2 │ vLLM — FUNCTIONAL, max context 131072 │
│ ... │ │
└─────────────────────┴────────────────────────────────────────────────────────┘
Validation status goes EXPERIMENTAL, FUNCTIONAL, COMPLETE. FUNCTIONAL means it runs
correctly and is not fully tuned. The status is per board, so check the p300x2 row.
Models worth starting with on a QB2
These have a p300x2 profile in the released catalog, from tt model list --catalog:
| Model | Kind | Status on QB2 | Why start here |
|---|---|---|---|
Qwen3-32B |
LLM | FUNCTIONAL | Ships with the box. Weights and compiled cache are local. |
Qwen3.8-27B |
LLM | COMPLETE | Fully validated chat and reasoning model, 262k context. |
gemma-4-31B-it / gemma-4-12B-it |
LLM | COMPLETE | Fully validated, 262k context. |
Llama-3.3-70B-Instruct |
LLM | FUNCTIONAL | The largest LLM in the catalog for this box. |
FLUX.1-dev / FLUX.1-schnell |
Image | COMPLETE | Image generation. |
whisper-large-v3 |
Audio | COMPLETE | Speech to text. |
Wan2.2-T2V-A14B-Diffusers |
Video | COMPLETE | Text to video. |
Gated models (Llama, Gemma) need you to accept the license on the model’s Hugging Face page
first. The hf_repo line in tt model info names the page.
Log In to Hugging Face
Serving needs a Hugging Face token, even for models that are free to download, because
tt-inference-server checks it before it starts. Log in once:
tt model login
Choose Log in with your browser (it shows a URL and a short code) or paste a read token
from huggingface.co/settings/tokens. tt finds the
token again on every later run, and tt serve --dry-run tells you where it came from without
printing it.
Check That tt Will Reuse the Shipped Weights
Preview the serve before you run it. --dry-run starts nothing:
tt serve Qwen3-32B --dry-run
✓ Detecting device configuration p300x2 (override with --device)
tt serve Qwen3-32B — dry run
┌──────────────────┬──────────────────────────────────────────────────────────┐
│ backend │ tt-inference-server │
│ workflow │ server │
│ device │ p300x2 │
│ engines │ vLLM │
│ status │ FUNCTIONAL │
│ docker image │ ghcr.io/tenstorrent/tt-inference-server/vllm-tt-metal-… │
│ tool-call parser │ hermes │
│ reasoning parser │ qwen3 │
│ weights │ /home/ttuser/data/tt-cache │
│ │ pre-seeded volume — weights and tt_metal_cache reused; │
│ │ the HF cache is not consulted │
│ HF token │ from the Hugging Face login store │
│ port │ 20000 (server default) │
└──────────────────┴──────────────────────────────────────────────────────────┘
Look at the weights row. pre-seeded volume means tt found the shipped weights and
the compiled kernel cache, so the first start takes minutes and downloads nothing. If it says
~/.cache/huggingface instead, tt did not recognize the shipped directory and a real serve
would download 62 GB. The fix is one symbolic link:
Magic of symlinks. tt looks for a volume named volume_id_tt_transformers-Qwen3-32B-v<version>
(the version comes from the model spec; the dry run’s image tag shows it). The shipped directory
on our QB2 ended in -vqb2_launch, so we aliased it:
ln -s ~/data/tt-cache/volume_id_tt_transformers-Qwen3-32B-vqb2_launch \
~/data/tt-cache/volume_id_tt_transformers-Qwen3-32B-v0.17.0
Re-run the dry run after every tt update; if it falls back to the Hugging Face cache, the
version changed. Two more links are handy: ln -s .cache/huggingface/hub ~/models (run from your home
directory, so the target is relative) for a short path to the Hugging Face cache (skip this one if you use the
hf download --local-dir ~/models/... steps elsewhere in this guide, which want ~/models to be a real directory), and ln -s code/tt-metal ~/tt-metal so older instructions work.
Make links relative and keep targets inside your home directory. Containers mount home at
/home/user, so absolute links and links that leave home dangle inside them (a Hugging Face
cache linking to a blob store outside the model directory failed this way).
Serve It
tt serve Qwen3-32B
tt serve shows the boot as a live checklist instead of thousands of log lines: host ready,
weights ready, image ready, container started, engine started, device opened, KV cache
configured, model warmed up, endpoint answering. It returns only once the endpoint answers, so
whatever you run next will work. When it finishes you get a box with the endpoint
(http://127.0.0.1:20000/v1) and the commands to look at logs and stop the model.
To watch the raw server log while it boots, run this in a second terminal:
tt model logs Qwen3-32B --follow
Pressing Ctrl-C in the tt serve terminal stops watching. The server is a separate container and keeps
booting, and tt model stop Qwen3-32B ends it.
A first serve of a model you have not run before takes longer. The image (about 18 GB) and
the weights are downloaded, then the model is compiled for your chips and warmed up. In the
tt documentation, a first serve of a 27B model on a QB2 took about 15 minutes, 7 of them
downloading weights. The shipped Qwen3-32B skips the download and the compile.
The endpoint has no password. In tt 1.2.1 and later, tt serve starts the server with
authentication off, and the server’s default bind address is 0.0.0.0 (every network
interface). Anyone who can reach port 20000 can use your model. Serve only on a network you
trust or behind a firewall, and do not forward the port to the internet. To keep a server
local-only, or to turn authentication on, run tt-inference-server yourself as shown in
Serving Models on QB2.
Ask It a Question
tt model curl "Explain what an API is in one sentence." --max-tokens 2048
tt model curl asks the server which model it is serving, sends your prompt as a chat
completion, and prints the JSON reply. The text is in choices[0].message.content. Unknown
options become fields of the request, so --max-tokens 2048 sets max_tokens. Add --print to
see the equivalent curl command.
Qwen3-32B is a reasoning model (the dry run above shows a qwen3 reasoning parser): it
thinks first, in a separate reasoning field, and then answers in content. A small token
budget can be used up by the thinking, so give it room when content comes back empty.
Pick prompts that do not depend on the model knowing about Tenstorrent. We asked Llama-3.1-8B “In one sentence, what is Tenstorrent?” and it replied with a confident, invented company history. Small models do not know recent or niche facts. That is a property of the model and says nothing about your hardware.
The same endpoint speaks the standard OpenAI API, so any client works. Note the model name:
the server reports the full Hugging Face id, which differs from the short name you gave tt serve
(for Llama-3.1-8B-Instruct we saw meta-llama/Llama-3.1-8B-Instruct).
curl -s http://localhost:20000/v1/models | python3 -m json.tool | grep '"id"'
curl -s http://localhost:20000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-32B",
"messages": [{"role": "user", "content": "Explain what an API is in one sentence."}],
"max_tokens": 2048
}' | python3 -m json.tool
Manage What Is Running
tt model ps # what is served, on which port, and whether it is healthy
tt model logs Qwen3-32B # the newest server log
Keep the model running for the next chapter. When you are finished with it, tt model stop Qwen3-32B stops it.
tt model ps shows every server tt started, including ones on other ports:
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━┳━━━━━━━━┓
┃ name ┃ backend ┃ container ┃ port ┃ health ┃ uptime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━╇━━━━━━━━┩
│ Llama-3.1-8B-Instruct │ inference-server │ tt-inference-server-162a825f │ 20000 │ healthy │ 5m │
└───────────────────────┴──────────────────┴──────────────────────────────┴───────┴─────────┴────────┘
healthy means the server answers GET /v1/models. starting means the container is running
and not answering yet. tt model stop stops only the named model’s container.
Serving on Half the Machine
A QB2 is two p300 boards. A model with a p300 profile uses one board (two chips). For example,
Llama-3.1-8B-Instruct has a p300 profile:
tt serve Llama-3.1-8B-Instruct --device p300 --dry-run
Use --device to override what tt detected. tt serve does not let you choose which board:
the container is given every Tenstorrent device node on the machine, so run a half-machine model
only when nothing else is using the chips. How to pin a server to specific chips is in
Serving Models on QB2.
What Just Happened
tt serve ran tt-inference-server, which started a container holding vLLM and the
Tenstorrent plugin. The container opened a mesh across your chips, loaded the weights into
device memory, compiled and warmed up the kernels, and published the API. The detail of each
stage, and how to run tt-inference-server yourself, is in
Serving Models on QB2.
Next: Launch Software →