Text Classification
Transformers
Safetensors
GGUF
English
llama
text-generation
tiny-model
from-scratch
router
tool-use
intent-classification
agentic
text-embeddings-inference
Instructions to use textilelabs/Loom-Router-1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use textilelabs/Loom-Router-1 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="textilelabs/Loom-Router-1")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("textilelabs/Loom-Router-1") model = AutoModelForCausalLM.from_pretrained("textilelabs/Loom-Router-1", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use textilelabs/Loom-Router-1 with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf textilelabs/Loom-Router-1:F16 # Run inference directly in the terminal: llama cli -hf textilelabs/Loom-Router-1:F16
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf textilelabs/Loom-Router-1:F16 # Run inference directly in the terminal: llama cli -hf textilelabs/Loom-Router-1:F16
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf textilelabs/Loom-Router-1:F16 # Run inference directly in the terminal: ./llama-cli -hf textilelabs/Loom-Router-1:F16
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf textilelabs/Loom-Router-1:F16 # Run inference directly in the terminal: ./build/bin/llama-cli -hf textilelabs/Loom-Router-1:F16
Use Docker
docker model run hf.co/textilelabs/Loom-Router-1:F16
- LM Studio
- Jan
- Ollama
How to use textilelabs/Loom-Router-1 with Ollama:
ollama run hf.co/textilelabs/Loom-Router-1:F16
- Unsloth Desktop
- Docker Model Runner
How to use textilelabs/Loom-Router-1 with Docker Model Runner:
docker model run hf.co/textilelabs/Loom-Router-1:F16
- Lemonade
How to use textilelabs/Loom-Router-1 with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull textilelabs/Loom-Router-1:F16
Run and chat with the model
lemonade run user.Loom-Router-1-F16
List all available models
lemonade list
- Atomic Chat
File size: 7,496 Bytes
ebb16d0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | ---
license: mit
language: en
library_name: transformers
pipeline_tag: text-classification
tags:
- tiny-model
- llama
- from-scratch
- router
- tool-use
- intent-classification
- agentic
- gguf
---
<div align="center">
<img src="banner.jpg" alt="Loom Router 1" width="520">
</div>
# Loom Router 1
<img src="logo.jpg" alt="" width="20" height="20" style="border-radius:4px;vertical-align:middle;margin-right:6px;"> **1.4M parameters Β· 2.8MB Β· Textile Labs**
**Give it a user message. It tells you which tool should handle it, in one token.**
That's the whole product. Your harness passes the user's original text to whichever tool it
names β the model never rewrites your input, so nothing can be copied wrong or malformed.
```
"whats the weather in leeds tomorrow" β <route:weather>
"remind me to call mum at 6" β <route:reminder>
"whats my sisters name" β <route:unknowable>
```
**86.5% accuracy on 2,969 real held-out human utterances**, across 17 routes. Random
guessing scores 5.9%.
It is trained **from scratch** β randomly initialised weights, trained end to end. Nothing
is fine-tuned from a pretrained base. Comparable open routers we looked at are considerably
larger and fine-tuned from pretrained checkpoints; we make no claim to be the smallest of
its kind.
## What it's for
A **first stage in front of a bigger model or an agent loop.** Deciding which tool to reach
for is a cheap decision that does not need a large model β but people usually pay for a
large model to make it. This does it in one token, on a CPU, in a 2.8MB file.
Concretely: use it to pick the tool, then hand the user's original text to that tool. Or use
it to decide whether you need to call a large model at all.
**It is not a chat model.** It has no conversational output and cannot introduce itself. It
answers with a route and nothing else.
## The routes
**Tools (13)** β `search` `calc` `time` `weather` `calendar` `reminder` `email` `notes`
`maps` `translate` `convert` `define` `music`
**Control (4)** β `answer` `clarify` `unknowable` `refuse`
## The Loom philosophy, as routes
Every Loom model is built on the same bet: at small sizes, **knowing your limits is more
achievable than knowing things β and more useful.** In a generative model that means
saying "I don't know". In a router it becomes something sharper β a decision:
| route | what it means |
|---|---|
| `answer` | no tool needed. Don't reach for one reflexively. |
| `clarify` | the request is ambiguous. Don't guess β ask. |
| `unknowable` | this depends on something only the user knows. No tool can fix that. |
| `refuse` | this shouldn't be done. |
A router that only answers *"which tool?"* has assumed a tool is always the answer. In an
agent loop that assumption is the expensive one: sending *"what's my sister's name"* to a
search tool burns a call and returns a confident wrong answer. `answer` and `clarify` are
also what let a loop **terminate** instead of spinning.
So this card publishes the **false-tool-call rate**: how often it sends a request to a
tool that cannot possibly help. Ours is **20.2%**, and the honest reading of that is below.
## Measured
Evaluated one bare prompt at a time, the way the model is actually used.
**Overall 86.5%** Β· tools **89.3%** Β· control **71.2%**
| route | n | recall | | route | n | recall |
|---|---:|---:|---|---|---:|---:|
| `translate` | 21 | 100.0% | | `email` | 202 | 87.6% |
| `notes` | 163 | 95.1% | | `reminder` | 134 | 87.3% |
| `weather` | 113 | 93.8% | | `search` | 599 | 86.8% |
| `music` | 368 | 93.8% | | `define` | 104 | 84.6% |
| `answer` | 335 | 93.7% | | `calc` | 32 | 71.9% |
| `convert` | 64 | 90.6% | | `refuse` | 36 | 25.0% |
| `time` | 123 | 89.4% | | `clarify` | 41 | 12.2% |
| `calendar` | 342 | 88.9% | | `unknowable` | 54 | 7.4% |
| `maps` | 238 | 88.7% | | | | |
## Read this before relying on it
**Tool routing works. The honesty routes largely do not.** `clarify` 12.2%, `unknowable`
7.4%, `refuse` 25.0%. Treat a tool prediction as a strong signal and a control prediction
as a weak hint.
The cause is understood and worth stating plainly. On synthetic data those routes scored
~76%, because *"my"* and *"I"* were reliable cues. Real assistant traffic is full of *"my
calendar"*, *"my alarms"*, *"remind me"* β so the cue stopped being a cue. The real
distinction is whether the referent **lives in a tool's data or only in the user's head**,
which is a subtler thing to learn. Tripling the control training data made it *worse*, so
it is not a volume problem.
`calc` (71.9%) has only 32 validation examples; that figure is noisy.
## Usage β Ollama
```bash
ollama run hf.co/textilelabs/Loom-Router-1 "whats the weather in leeds tomorrow"
# <route:weather>
```
Ollama reads the `template` and `params` files in this repo, so there is nothing to set up.
`params` pins `temperature: 0` and `num_predict: 4` β a router should be deterministic and
emit one token. To build it locally instead: `ollama create loom-router-1 -f Modelfile`.
## Usage β transformers
```python
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
ROUTES = ["search","calc","time","weather","calendar","reminder","email","notes",
"maps","translate","convert","define","music","answer","clarify",
"unknowable","refuse"]
tok = AutoTokenizer.from_pretrained("textilelabs/Loom-Router-1")
model = AutoModelForCausalLM.from_pretrained("textilelabs/Loom-Router-1").eval()
route_ids = {tok.convert_tokens_to_ids(f"<route:{r}>"): r for r in ROUTES}
ids_t = torch.tensor(list(route_ids))
def route(message: str) -> str:
prompt = f"<user>\n{message.strip()}\n<|eot|>\n<loom>\n"
ids = tok(prompt, return_tensors="pt", add_special_tokens=False).input_ids
with torch.no_grad():
logits = model(input_ids=ids).logits[0, -1]
# Decide only among legal routes, so the output is always a valid label.
return route_ids[int(ids_t[logits[ids_t].argmax()])]
route("add milk to my shopping list") # -> 'notes'
```
The prompt format is exact: `<user>\n{message}\n<|eot|>\n<loom>\n`, no trailing space.
## In an agent loop
```
user β router β your harness runs the tool β result β router again
β 'answer' ends the loop
```
Cap the number of steps in your harness. `answer` and `clarify` are the terminating routes.
## Files
```
config.json / model.safetensors the model
tokenizer.json / tokenizer_config.json custom BPE tokenizer, 2,048 tokens
loom-router-1-f16.gguf 2.8MB, for Ollama / llama.cpp
template / params read automatically by `ollama run hf.co/...`
Modelfile for building locally
ATTRIBUTION.md required credits for the training corpora
```
## Training data
Real human utterances from two openly licensed corpora, remapped onto the routes above:
- **MASSIVE** β Amazon (CC BY 4.0), derived from **SLURP** (CC BY 4.0)
- **CLINC150** β `clinc/oos-eval` (CC BY 3.0)
23,674 real utterances. The four control routes have no public equivalent and are
procedurally generated. Validation is a held-out split of the *real* utterances β never
templates written by the same process that produced the training data.
See `ATTRIBUTION.md`; both licences require credit.
## License
Model: MIT. Training data retains its original licences and attribution.
|