SemanticRepair-0.8B / README.md
Gramscii's picture
The repair adapter at rank 32 and its card
bd5c1f7 verified
|
Raw History Blame Contribute Delete
11.6 kB
metadata
license: apache-2.0
base_model: Qwen/Qwen3.5-0.8B
base_model_relation: adapter
pipeline_tag: text-generation
datasets:
  - Gramscii-IT/semantic-repair-routing
language:
  - it
  - en
  - fr
  - de
  - es
tags:
  - query-rewriting
  - query-understanding
  - intent-detection
  - routing
  - capability-routing
  - distillation
  - lora
  - retrieval
  - rag
  - slm
  - gguf
  - multilingual
  - qwen3.5
model-index:
  - name: SemanticRepair-0.8B
    results:
      - task:
          type: text-generation
          name: >-
            The repair adapter in the chat's routing chain, with
            ToolChooser-0.8B: real chat questions
        dataset:
          type: gramscii-real-chat-questions
          name: 480 real Italian chat questions, held out from training
          split: test
        metrics:
          - type: accuracy
            name: Ran only capabilities the question asks for (%)
            value: 36.3
          - type: wrong-execution-rate
            name: >-
              Ran a capability the question does not ask for (%), lower is
              better
            value: 6.3
      - task:
          type: text-generation
          name: >-
            The repair adapter in the chat's routing chain: test messages
            written to probe it
        dataset:
          type: gramscii-repair-exam
          name: 100 test messages, 50 Italian and 50 English
          split: test
        metrics:
          - type: accuracy
            name: Routed right (%)
            value: 94
          - type: wrong-execution-rate
            name: Routed wrong (%), lower is better
            value: 4

SemanticRepair-0.8B

A LoRA adapter on Qwen3.5-0.8B that works behind an embedding router. When a message does not land clearly on one capability of a chat, it writes every request the message carries on its own line, and names for each line the capability that does its work among the ones the chat offers, or none. A message that asks for nothing comes back as NO_REQUEST. It reads the message after what the chat's last turns ran, so a message that continues the conversation («e per Milano?») is read as part of it.

It does not answer the question. The router checks every capability the repair names against its own scores, and the host application decides what runs: a model's output alone never authorizes an operation.

Three companion adapters load on the same base, each in a repository of its own:

  • ToolChooser-0.8B: when the router and the repair still leave two or more capabilities close, it chooses one of them, or none, in which case the person is asked.
  • QueryTranslator-0.8B: it writes a search request again in the language of the passages it will be looked up in.
  • FilterReader-0.8B: it reads a question's filters among the codes a capability declares.

What is in this repository

file what it is
qwen3.5-0.8b-base-2fc06364-q8_0.gguf the base: Qwen3.5-0.8B at revision 2fc06364, Q8_0, 833,592,320 bytes, sha256 6a94a8273ab1fc5735743967b621eb5a3baba8e36a202f61c20dc47fbb80eb51
semantic-repair-0.8b-repair-20261109-lora-f16.gguf the repair adapter, F16 LoRA at rank 32, 43,316,320 bytes, sha256 c1d903763cedd49b7b82eb58cb66f036e85e18ba4e4a058930cc1318133a0094
LICENSE the base model's Apache-2.0 licence

One base serves every job: an adapter costs 22 to 43 MB, not another 800 MB model. Pin the sha256 of both files: a routing decision has to be reproducible.

Where it runs

With llama-server, the model loaded only when it is needed and released after an idle window:

llama-server -m qwen3.5-0.8b-base-2fc06364-q8_0.gguf \
  --lora semantic-repair-0.8b-repair-20261109-lora-f16.gguf \
  --jinja --host 127.0.0.1 --port 9250 -ngl 99 -c 32768 --no-context-shift --cache-ram 0

When the companion adapters are loaded too, with one --lora each, every request names its adapter at full scale and the others at none, so the jobs never mix: for a repair, "lora": [{"id": 0, "scale": 1.0}, {"id": 1, "scale": 0.0}, ...]. --cache-ram 0 keeps llama-server from holding up to 8 GiB of earlier prompts in memory: every call asks about a message of its own.

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:

Capabilities: {the capability ids the chat offers, sorted, comma separated}
Earlier: {capability} | {request}
{Language}: {the message, verbatim}
=>

It completes with one line per request, capability | request, or the single token NO_REQUEST. A request no offered capability does is written none | request.

  • Earlier: lines are what the chat's last turns ran, one line for each request, in the capability | request form the adapter itself writes. A chat's first message has none, and the surface is then the two lines around it. They are how it reads «e per Milano?» after a question about Rome as the same request for another city.
  • The newline after => is part of the surface: a prompt that stops at => is a surface the model never read.
  • {Language} is the English name of the language the message is in: Italian, English, French, German, Spanish.
  • The capabilities line is context the model reads, not a formality. Pass the whole list your chat offers, not a shortlist (see What it does not fix).

This is the whole call, on /v1/completions and never on a chat endpoint:

{
  "prompt": "Capabilities: document-search, locate-place, opendata-statistics, web-search\nItalian: dov'è sassari? mostramelo nella mappa e dammi le ultime notizie in italia\n=>\n",
  "stop": ["\n=>"],
  "temperature": 0.0,
  "repeat_penalty": 1.0,
  "max_tokens": 512
}

Greedy, because the same words must always produce the same lines: a router that reruns on a different answer each time cannot be reasoned about. repeat_penalty 1.0 is neutral, since a restatement legitimately repeats the words of the message. The stop string cuts a runaway that starts echoing another message in its own trained format. 512 tokens is the answer cap every measure below used.

What it is measured to do

Served on the base at Q8_0 with the three companion adapters, through the chat's routing chain.

480 real Italian chat questions, held out from every training and selection step:

ran only capabilities the question asks for 174
ran a capability the question does not ask for 30
the person asked to choose 276

Most of the questions where the person is asked need something the chain was not given in this measure: a document search with no file selected, or a web search with the web switched off.

100 test messages, 50 Italian and 50 English, written to probe the repair:

right wrong the person asked
Italian 48 1 1
English 46 3 1

The repair alone on 363 real prompts, the distinct prompts the chain sends the repair for the real questions, each answer judged against the capabilities the prompt offered:

the capabilities asked for 98
nothing named, rightly 244
nothing named, though a capability was asked for 10
a capability the message does not ask for 7
a capability named where none was asked for 3
part of what was asked 1

Held-out rows of its own training set, which it never trained on: the right capabilities for 1,508 of 1,615.

What it does not fix

A list without the capability a request needs is answered none. Its training rows list the capabilities a chat offers, and in some of them the right one is taken out and the answer becomes none: it reads the list as context. Pass the whole list the chat offers.

Long briefs lose steps and names. A brief of several hundred tokens comes back with some of its steps and names missing: ask it about one step at a time.

The restatements are terse. «statistiche abitanti Cagliari» is good input for a router and poor prose. It is not meant to be shown to anyone.

Measured in Italian and English. The base pairs cover five languages, but the capability labels and every measure above are Italian and English.

The data it was trained on

159,079 training rows and 1,615 validation rows, from:

  • The published Gramscii-IT/semantic-repair-routing pairs, every line carrying the capability that does its work as two judge models, Qwen3.8-27B and Gemma-4-31B, agreed on it; a row they disagreed on is left out.
  • 57,473 generated rows in Italian and English, written by Qwen3.8-27B (about two thirds) and Gemma-4-31B (about one third), kept only with the capability each was written for; rows for the capabilities that held few lines, and trap and contrast rows for pairs of capabilities that are easy to confuse, kept when both judges found nothing the line leaves out.
  • 1,500 long briefs, each step of their plans a line.
  • 17,107 chat messages from scripted conversations played through the application, whose capability the run that answered them confirmed and both judges confirmed reading the message alone, each with the line Qwen3.8-27B wrote for that capability and both judges confirmed.
  • 4,360 follow-up messages, from scripted chats whose later turns continue the first question about public funding calls or tenders, each row carrying the requests the earlier turns ran as Earlier: lines. Each message was labelled twice by Qwen3.8-27B, greedy and with its own sampling, and kept only where both readings named the same capability, with the line Qwen3.8-27B wrote for it.
  • 6,510 messages written the way people write, each read by both judges as the capability it was written for, with the line Qwen3.8-27B wrote for it and both judges confirmed: typing mistakes, words of another language, capitals and impatience, a correction within the message, an attempt to steer the chat; short, colloquial and misspelled requests for every capability; Open Data questions of one sentence shape that different Open Data capabilities answer; requests about Italian municipalities; and compound messages, two confirmed lines joined into one.

Each row's prompt lists the capabilities its lines name plus a random draw of the others, because real chats offer lists as varied as that. For some rows the right capability is taken out of the list and the answer becomes none; every one of the 6,510 messages also comes that way, and a capability easy to confuse with the one taken out stays on the list. About one row in a hundred goes to validation, and no row equals a question of the measures above.

Training

base Qwen/Qwen3.5-0.8B at 2fc06364, its language model only
method LoRA, rank 32, alpha 64, dropout 0.05, on every linear layer but the embeddings and the head (186 modules, 21.6M parameters)
schedule one pass: 19,885 updates of 8 examples, learning rate 1×10⁻⁴, 100 warm-up steps
tokens 32.3M in the examples, 4.2M of them in the answers
loss on the answer only
hardware one NVIDIA A100 64 GB of the Leonardo supercomputer in Bologna, thanks to CINECA
release F16 LoRA GGUF

It starts from the original base.

Licence

Apache-2.0, as its base model Qwen3.5-0.8B. What it writes is yours, and so is the responsibility for what you let it decide.