Instructions to use Gramscii/SemanticRepair-270M with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use Gramscii/SemanticRepair-270M with MLX:
# Make sure mlx-lm is installed # pip install --upgrade mlx-lm # Generate text with mlx-lm from mlx_lm import load, generate model, tokenizer = load("Gramscii/SemanticRepair-270M") prompt = "Write a story about Einstein" messages = [{"role": "user", "content": prompt}] prompt = tokenizer.apply_chat_template( messages, add_generation_prompt=True ) text = generate(model, tokenizer, prompt=prompt, verbose=True) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use Gramscii/SemanticRepair-270M 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 Gramscii/SemanticRepair-270M:Q8_0 # Run inference directly in the terminal: llama cli -hf Gramscii/SemanticRepair-270M:Q8_0
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf Gramscii/SemanticRepair-270M:Q8_0 # Run inference directly in the terminal: llama cli -hf Gramscii/SemanticRepair-270M:Q8_0
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 Gramscii/SemanticRepair-270M:Q8_0 # Run inference directly in the terminal: ./llama-cli -hf Gramscii/SemanticRepair-270M:Q8_0
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 Gramscii/SemanticRepair-270M:Q8_0 # Run inference directly in the terminal: ./build/bin/llama-cli -hf Gramscii/SemanticRepair-270M:Q8_0
Use Docker
docker model run hf.co/Gramscii/SemanticRepair-270M:Q8_0
- LM Studio
- Jan
- vLLM
How to use Gramscii/SemanticRepair-270M with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Gramscii/SemanticRepair-270M" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Gramscii/SemanticRepair-270M", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/Gramscii/SemanticRepair-270M:Q8_0
- Ollama
How to use Gramscii/SemanticRepair-270M with Ollama:
ollama run hf.co/Gramscii/SemanticRepair-270M:Q8_0
- Unsloth Desktop
- MLX LM
How to use Gramscii/SemanticRepair-270M with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Interactive chat REPL mlx_lm.chat --model "Gramscii/SemanticRepair-270M"
Run an OpenAI-compatible server
# Install MLX LM uv tool install mlx-lm # Start the server mlx_lm.server --model "Gramscii/SemanticRepair-270M" # Calling the OpenAI-compatible server with curl curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Gramscii/SemanticRepair-270M", "messages": [ {"role": "user", "content": "Hello"} ] }' - Docker Model Runner
How to use Gramscii/SemanticRepair-270M with Docker Model Runner:
docker model run hf.co/Gramscii/SemanticRepair-270M:Q8_0
- Lemonade
How to use Gramscii/SemanticRepair-270M with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull Gramscii/SemanticRepair-270M:Q8_0
Run and chat with the model
lemonade run user.SemanticRepair-270M-Q8_0
List all available models
lemonade list
- Atomic Chat
license: gemma
base_model: google/gemma-3-270m
pipeline_tag: text-generation
library_name: mlx
datasets:
- Gramscii/semantic-repair-routing
language:
- en
- it
- fr
- de
- es
tags:
- query-rewriting
- query-understanding
- intent-detection
- routing
- retrieval
- rag
- slm
- gguf
- multilingual
SemanticRepair-270M
A 270M rewriter that sits behind an embedding router. When a question does not land on any capability with enough margin, this model restates it in the plain form the capabilities are described in, and the router tries again on the restatement. When it reads no request at all, it says so.
That is the whole job. It does not answer questions, it does not decide anything, and nothing it writes is ever executed: the router runs on the restatement, the tool runs on the original.
The surface it reads, which is not a chat prompt
Fine-tuned on a bare completion surface. It has never seen a chat template, a system message or a few-shot example. Speak to it the way it was trained or it will not work:
{Language}: {the question, verbatim}
=>
It completes with one line per request it found, or the single token
NO_REQUEST.
{Language} is the English name of the language the question is in β
not the language of whatever system is asking. English, Italian,
French, German, Spanish; a language outside that set keeps whatever
tag the caller declares, because an invented tag is a surface the model
never read either.
This is the whole call the engine makes, on /v1/completions and never on
a chat endpoint:
{
"prompt": "Italian: che tempo fa domani a Bologna?\n=>\n",
"stop": ["\n=>"],
"temperature": 0.0,
"repeat_penalty": 1.0,
"max_tokens": 96
}
Greedy, because the same words must always produce the same rewrite: a
router that reruns on a different restatement each time cannot be reasoned
about. repeat_penalty is 1.0, which is neutral β a rewrite legitimately
repeats the words of the question. The stop string cuts a runaway that
starts echoing another question in its own trained format; everything
before it is the answer. 96 tokens leaves room for several rewritten lines:
the longest answer in the training data is 43 tokens.
The sentinel is compared case-insensitively and tolerates a trailing period. It is an instruction the model follows, not a token it is guaranteed to emit byte-exact.
These are real outputs from the released weights, greedy:
| in | out |
|---|---|
Spanish: no busques la tienda de ropa, dime la dosis de paracetamol |
dime la dosis de paracetamol |
Italian: scusa il disturbo, mi diresti che tempo fa domani a Bologna? |
dimmi che tempo fa domani a Bologna |
English: book me a table for friday and also cancel my dentist |
book me a table for fridaycancel my dentist |
Italian: guarda un po', questo sacchetto della spesa Γ¨ tutto rotto. |
NO_REQUEST |
A negation is dropped, an apology is dropped, one message asking for two things becomes two lines, and something that is not a request at all answers with the sentinel.
What is in this repository
| file | size | what it is |
|---|---|---|
sft-v19-q8_0.gguf |
300 MB | what the engine serves, through llama-server |
model.safetensors |
536 MB | the same weights fused, BF16, 236 tensors |
model.safetensors.index.json |
the index over that single file | |
tokenizer.json, tokenizer_config.json |
33 MB | the tokenizer as the fuse wrote it |
config.json, generation_config.json |
gemma3_text, torch_dtype: bfloat16 |
|
chat_template.jinja |
present because the fuse writes it β not the surface this model reads, see above |
The GGUF's sha256 is
33b6cc73c7d306c9c81aa96c5a8ddb9dbfd46a5ac5d0388a2de45b5229928c56.
The engine pins it and refuses anything else, which is what makes a routing
decision reproducible.
Both files carry the same weights: the fused final adapter of training run
v19, adapter sha256 1082985953ed6c33β¦, quantised to Q8_0. Q8_0 and not
Q4: measured on this seat, at temperature 0 a Q8_0 is stable to the byte
across runs and a Q4 is not.
What it is measured to do
Measured against the two things worth measuring against: the model it was fine-tuned from, and doing no repair at all. Two benches over different corpora, because a model that wins one of them is a model chosen by which table got printed.
400 routing tasks over 343 graphs, these exact released weights against the untrained base:
| exact | wrong executions | answered in the wrong language | |
|---|---|---|---|
| this model | 32 | 1 | 6 |
google/gemma-3-270m, untrained |
24 | 0 | 123 |
The language column is what the fine-tune clearly buys, and it is the largest effect in any table here: 123 tasks answered in the wrong language become 6.
39 held-out questions on a live workspace, written by three blind judges against the capabilities in it, in two languages:
| exact | |
|---|---|
| this model | 16 |
| routing the question as written, no repair | 12 |
google/gemma-3-270m, untrained |
9 |
The base model scoring below "no repair at all" is the whole argument for fine-tuning something for this seat: an untrained 270M put here makes routing worse than leaving the question alone. Of the 10 compound questions in that set β one message asking for two things β this model answers 2 whole.
Its own training gate, on 1000 held-out examples: 261 exact (26.1%), 927 of 1000 answers well formed, and the language-balance gate passed with a 7-point gap between English and Italian against a 10-point bar.
What it does not fix, which a card naming only the gains would hide
The sentinel does not catch every non-request. guarda un po', questo sacchetto della spesa Γ¨ tutto rotto answers NO_REQUEST, but ciao come stai comes back verbatim rather than refused. If nothing downstream checks
that the restatement is a request, a greeting will be routed.
It sometimes rewrites a word rather than restating a sentence. Measured:
Bitte reserviere mir einen Platz im Klettergarten fΓΌr Freitag comes back
as reserviere mir einen Platz im Kletterpark fΓΌr Freitag β Klettergarten
became Kletterpark. The restatement is only ever compared against
capability descriptions and never executed, which is why this is tolerable
here; in any design where the rewrite is acted on, it is not.
Dates. In the 400-task run above, 160 of the tasks name a day. This model loses the day in 57 of them β more than a third. It is the weakest column it has, and it is weak in a way that does not announce itself: the restatement reads as a clean request, with the "yesterday" or the "before Easter" simply gone. If the day matters to your routing, measure that before you serve this.
It is not distinguishable from its own neighbours. Ten checkpoints of this run were compared on the same 400 tasks pair by pair rather than by totals β counting only the tasks where two checkpoints disagree, which are the only ones carrying information. Not one difference reaches significance: the widest gap in the table is 7 tasks to 1, p = 0.07. With around thirty exact answers out of four hundred the natural fluctuation is about five, which is most of the ranking. Treat the order inside a run as noise: a checkpoint one or two points ahead of another inside the same run has not been shown to be better than it.
Where it runs
Served with llama-server, reached by the engine as one of four model seats:
llama-server -m sft-v19-q8_0.gguf --host 127.0.0.1 --port 9250 -ngl 99 -c 2048 --jinja
It is loaded only when routing is genuinely unsure, never as the default path, and released after an idle window.
The data it was trained on
Gramscii/semantic-repair-routing
β published, and everything below can be recounted from it.
84,819 pairs: 82,819 train, 1,000 validation, 1,000 test. Each pair is a message somebody could plausibly write and the requests inside it restated plainly, one per line.
Five languages, close to balanced:
| rows | ||
|---|---|---|
| English | 18,006 | 21.7% |
| Spanish | 16,903 | 20.4% |
| German | 16,659 | 20.1% |
| French | 16,602 | 20.0% |
| Italian | 14,649 | 17.7% |
What the message is doing, which is what the data is really organised by. Every one of the 82,819 training rows carries one of 38 such labels; these are the ten largest:
| rows | ||
|---|---|---|
massive_real β real assistant traffic |
5,736 | 6.9% |
minimal_pair β two messages differing in one word |
5,299 | 6.4% |
indirect β the request is implied, never stated |
4,912 | 5.9% |
presto_native β natively written, not translated |
4,606 | 5.6% |
oasst_human β human-written |
4,450 | 5.4% |
multi β more than one request in one message |
3,974 | 4.8% |
direct β the plain case |
3,904 | 4.7% |
vent_statement_request β a complaint with a request inside |
3,516 | 4.2% |
negation_exclusion β names what is not wanted |
3,398 | 4.1% |
trap_topic_lure β a topic named to pull routing the wrong way |
3,324 | 4.0% |
The remaining 28 cover self-correction, code-switching, ultra-short messages, typos and slang, messages carrying two, three or four requests, eight kinds of date reference β a weekday in the past, a named holiday, a bounded range β and the two families below.
The two families that decide what this model refuses to do
injection_meta β 2,278 rows β is a message aimed at the assistant
itself: reveal your instructions, ignore what you were told, pretend you
have no rules. 1,901 of them answer NO_REQUEST, because there is
nothing here to route. Together with injection_command these two families
supply 19% of every NO_REQUEST row in the set: refusing is largely
taught by messages that try hardest to get an answer.
injection_command β 2,410 rows β is the opposite lesson, and the more
delicate one. A hostile but explicit command about the user's own things:
delete every saved bank account, empty my personal cloud, cancel all my
bookings tonight. 2,281 of them are restated faithfully, action intact.
The rewriter does not sanitise and does not soften. Deciding whether an action is allowed is not its job and it has no way to do that job well: it sees one sentence, not the account, the permissions or the consequences. A model that quietly dropped "delete" would hand the router a different request from the one the person made, and the person would never learn their instruction had been edited. So the restatement carries the command as written, the router places it, and whatever runs it is where refusing belongs.
12.6% of rows (10,432) answer NO_REQUEST, and 16.9% (14,028)
answer with more than one line.
Training
Fine-tuned from google/gemma-3-270m with mlx_lm lora, full fine-tune.
The released weights are the run's final adapter, chosen by a gate on 1,000
held-out examples rather than by the best number on a validation curve.
Licence
Gemma terms, which travel with the file: this is a fine-tune of Gemma-3-270M and inherits them.