Finjustering af Ministral-3 på vLLM

En Praktisk Guide til Almindelig Tekst og JSON-Svar

Jeopardy-Game-Benchmark
Jeopardy-Game-Benchmark

Lærdomme fra opbygningen af en AI-Jepardy-simulation med 12 spillere drevet af Ministral-3-14B-Instruct-2512.


Introduktion

Ministral-3 på vLLM er overraskende kraftfuldt. Modellen er hurtig, kreativ og i stand til at producere højkvalitetsresponser selv ved tung belastning.

Når man bevæger sig fra enkle chattoprompt til strukturerede udgaver, automatisering eller programmeringsmæssig brug, bliver det hurtigt kompliceret.

Udviklingen af et KI-drevet Jeopardy-spil med 12 samtidige spillere og hundredevis af modelløb, stødte vi på flere praktiske udfordringer:

Denne vejledning opsummerer de praktiske erfaringer vi har gjort os under løsningen af disse udfordringer, sammen med konkrete mønstre du kan genbruge i dine egne projekter.


Det virkelige scenarie

Vores benchmark-projekt simulerer et fuldt Jeopardy-spil, hvor:

Et enkelt spilforløb kan nemt overstige 800 API-opkald

Denne miljø afslørede grænseflader, der sjældent opstår i enkle demonstrationsmiljøer – hvilket gør det til et fremragende testgrundlag for at forstå, hvordan Ministral klare sig under reelle produktionsbelastninger


1. Betjening af Ministral-3 på vLLM

Ministral-modeller bruger ikke den standardiserede HuggingFace-tokenisatorkonfiguration

Det kræver, at opsætningen af kommandolinjen eksplicit aktiverer Mistral-tokenisatorformatet

bash
vllm serve mistralai/Ministral-3-14B-Instruct-2512 \
  --tokenizer_mode mistral \
  --config_format mistral \
  --load_format mistral

Hvis din applikation afhænger af funktionstildeling, skal du tilføje følgende værktøjsflags:

bash
--enable-auto-tool-choice
--tool-call-parser mistral

Vigtig begrænsning

Ministral understøtter ikke chat_template_kwargs, som nogle andre modeller gør.

Hvis du sender en anmodning som denne:

json
{
  "chat_template_kwargs": {
    "enable_thinking": false
  }
}

vLLM returnerer:

Kode
HTTP 400: chat_template is not supported for Mistral tokenizers

Det betyder, at funktioner som eksplicit slåning af «tænkemodus» til/fra (brugt med modeller som Qwen eller DeepSeek) blot ikke er tilgængelige

Heldigvis er dette sjældent nødvendigt, da Ministral allerede producerer koncise output som standard.


2. Temperatur: Den vigtigste parameter

Den officielle vLLM-dokumentation bruger konsekvent følgende værdi med Ministral-3:

Kode
temperature = 0.15

På første øjekast virker det ekstremt lavt. Dog viser det sig at være afgørende for strukturerede opgaver

Hvad sker der ved højere temperaturer

Ved brug af OpenAI-standardindstillingen:

javascript
temperature: 0.7

modellen bliver for kreativ med strukturen

En simpel forespørgsel som:

json
{ "expertise": "2-3 topics they know best" }

kan returnere noget i stil med:

json
{
  "expertise": [
    {
      "category": "Gourmet Pizza Alchemy",
      "detail": "Can transform random ingredients into Michelin-star pizza"
    },
    {
      "category": "Sumo Wrestling Physics",
      "detail": "Understands body mechanics and center-of-gravity combat"
    }
  ]
}

Det er ikke det skemaet spurgte om, selvom det teknisk set er gyldig JSON.

Resultatet:


Hvorfor 0.15 fungerer bedre

strukturelt disciplineret

javascript
temperature: 0.15

Fordele:

Selv kreativ tekstgenerering forbliver stærk — modellen holder simpelthen op med at improvisere med strukturen.

Anbefaling: Brug temperatur: 0.15 som standard for Ministral-3.


3. Getting Clean JSON Responses

Maskinlæselig JSON at producere fra store sprogmodeller er sværere end det lyder.

Ministral har en tendens til at tolke skemas felter semantisk i stedet for strukturelt, hvilket fører til dybt indlejrede svar.


Den naive tilgang

En prompt som:

Kode
Return JSON with these fields.

producerer ofte verbøse strukturer.

Eksempel på anmodning:

json
{ "expertise": "2-3 topics they know best" }

Typisk svar:

json
{
  "expertise": [
    {
      "category": "Ancient Roman Engineering",
      "detail": "Knows aqueduct systems in surprising detail"
    },
    {
      "category": "Pizza Dough Chemistry",
      "detail": "Obsessed with yeast fermentation dynamics"
    }
  ]
}

Dette bruger tre gange så mange tokens som forventet


Den pålidelige løsning: Promptering i to lag

to instruktioner

Lag 1 — Systeminstruktion

Kode
Respond with ONLY valid JSON.
No markdown, no explanation, no text before or after the JSON.
Keep values as short plain strings — never use nested objects or arrays.

Lag 2 — Skemabegrænsning

Lige ved siden af skema definitionen:

Kode
Every value MUST be a short plain string — NO arrays, NO nested objects.

temperatur 0.15, dette producerer forudsigeligt fladt JSON


Tokenbudgettering

Ministral producerer ofte længere værdier end andre modeller, selv når det er begrænset.

Eksempel på observation fra vores benchmark:

Model Nødvendige tokens
GPT-4o ~512
Qwen ~512
Ministral-3 ~1024

En sikker regel:

Budgetér 1,5–2 gange så mange tokens til JSON-outputs.


Forsvarende JSON-analyse

Selv med perfekte prompter genererer modeller af og til misdannet JSON.

robuste afkodningslag


1) Udtræk JSON fra Markdown

javascript
function extractJSON(raw, shape) {
  var text = raw.replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/i, '').trim();
  if (shape === 'array') {
    var m = text.match(/\[[\s\S]*\]/);
    if (m) text = m[0];
  } else {
    var m = text.match(/\{[\s\S]*\}/);
    if (m) text = m[0];
  }
  return text;
}

2) Reparer afkortet output

Spor åbne parenteser og luk dem automatisk:

javascript
var stack = [];
var inStr = false, esc = false;

for (var i = 0; i < text.length; i++) {
  var ch = text[i];

  if (esc) { esc = false; continue; }
  if (ch === '\\') { esc = true; continue; }
  if (ch === '"') { inStr = !inStr; continue; }
  if (inStr) continue;

  if (ch === '{') stack.push('}');
  else if (ch === '[') stack.push(']');
  else if (ch === '}' || ch === ']') stack.pop();
}

text = text.replace(/,\s*$/, '');

while (stack.length > 0)
  text += stack.pop();

3) Udflad indlejrede værdier

Hvis modellen stadig returnerer indlejrede strukturer:

javascript
if (Array.isArray(value)) {
  flat = value.map(function(item) {
    if (typeof item === 'string') return item;
    if (typeof item === 'object') return Object.values(item).join(' — ');
    return String(item);
  }).join(', ');
}

4) Gentag mislykkede anmodninger

En simpel retry-løkke øger pålideligheden dramatisk.

Ministral opfører sig konsistent ved lav temperatur, så gentagelser lykkes normalt.

Anbefalet:

Kode
2–3 retry attempts

4. Getting Clean Plain-Text Responses

Ministral elsker formatering.

Selv når du beder om klar tekst, har den tendens til at producere:

  • fed tekst
  • kursiv fremhævning
  • overskrifter
  • formatering af inline-kode

Dette sker fordi modellen leveres med en indbygget systemprompt, der opmuntrer til rig markdowntilformatering


Hvorfor dette er vigtigt

Mange pipelines er afhængige af simple strengtjek.

Eksempel:

javascript
verdict.toUpperCase().startsWith('CORRECT')

Men hvis modellen returnerer:

Kode
**CORRECT**

kontrollen mislykkes.


Løsning: Fjern altid markdown

Den sikreste tilgang er at normalisere alle output før behandling.

javascript
function stripMarkdown(text) {
  if (!text) return text;

  var s = text.replace(/\*\*([^*]+)\*\*/g, '$1');
  s = s.replace(/__([^_]+)__/g, '$1');
  s = s.replace(/\*([^*]+)\*/g, '$1');
  s = s.replace(/^#{1,6}\s+/gm, '');
  s = s.replace(/`([^`]+)`/g, '$1');
  s = s.replace(/^```[a-z]*\s*$/gm, '');

  return s.trim();
}

Anvend dette på alle modellsvar, ikke kun til Ministral.

Det undgår modelspecifik forgrening og holder pipelines konsistente.


5. Centralisering af Model-Specifik Adfærd

Hvis dit system understøtter flere modellfamilier (Mistral, Qwen, DeepSeek, Llama osv.), er den mest vedligeholdelige løsning at centralisere modeladfærd på ét sted.

Eksempel:

javascript
function buildModelProfile(modelName) {
  var lower = modelName.toLowerCase();
  var isMistral = lower.includes('mistral') || lower.includes('ministral');

  return {
    family: isMistral ? 'Mistral' : 'Generic',

    jsonSystemInstruction: isMistral
      ? 'Respond with ONLY valid JSON. No markdown. Keep values as short plain strings.'
      : 'You output only valid JSON. No markdown fences, no explanation.',

    jsonSchemaHint: isMistral
      ? ' Every value MUST be a short plain string — NO arrays, NO nested objects.'
      : '',

    jsonTemperature: isMistral ? 0.15 : 0.7,
    defaultTemperature: isMistral ? 0.15 : 0.7,

    plainTextInstruction: ' Do not use markdown formatting.'
  };
}

Dette tillader resten af dit system at blive model-uafhængig.

Det bliver trivielt at tilføje en ny model senere.


Ministral-3 Snyd ark

Indstilling Anbefalet værdi Årsag
tokenizer_mode mistral Påkrævet for korrekt tokenizer
config_format mistral Påkrævet
load_format mistral Påkrævet
chat_template_kwargs Send ikke Ikke understøttet
temperatur 0.15 Forhindrer strukturel hallucination
JSON-instruktion Eksplicitte flade værdier Undgå indlejrede objekter
max_tokens 1,5–2× typisk Modellen er ordrig
Fjernelse af Markdown Altid Forhindre formateringsfejl
JSON-genforsøg 2–3 forsøg Pålidelig gendannelse

Afsluttende tanker

Ministral-3 yder ekstremt godt, når det er korrekt indstillet.

Når du:

  • sænk temperaturen
  • begræns JSON-strukturer
  • normaliser markdown output
  • tilføj defensiv parsing

meget forudsigeligt og klar til produktionsbrug

I vores Jeopardy-benchmark understøttede denne opsætning:

  • 12 samtidige AI-deltagere
  • 800+ API-forespørgsler pr. session
  • 2.000+ tokens/sekund igennemstrømning
  • konsistent struktureret output

Alt kører lokalt på Trooper.AI's GPU-infrastruktur


Kom i gang

Prøv den fulde vLLM-deployeringsskabelon her: vLLM OpenAI-Kompatibel Server