À partir de la version 0.35, Ollama prend en charge les modèles de décision basés sur l’API Jev de TypeSafe. Ce ne sont pas des modèles de chat au sens habituel du terme : ils n’écrivent pas de texte, mais répondent à un ensemble de questions tapées sur l’état transféré. Pour la classification, le routage, la modération et le tri, cela s’avère plus rapide et plus fiable que de demander à un LLM classique de renvoyer du JSON puis d’analyser sa réponse.
Dans cet article, j’examinerai ce que sont les modèles de décision, comment ils fonctionnent au niveau HTTP, quels modèles sont déjà disponibles et comment les intégrer dans le code existant afin que les modèles génératifs réguliers continuent de fonctionner.
En quoi les modèles de décision diffèrent-ils des modèles classiques
Un LLM standard reçoit une invite et génère du texte jeton par jeton. Même si vous lui demandez de répondre en un mot, la génération se produit toujours à l’intérieur et le format de la réponse doit être contrôlé par un diagramme, des instructions et une vérification ultérieure. Le modèle de décision fonctionne différemment : vous transmettez l’état et les questions avec des types, et le modèle renvoie les probabilités et les options sélectionnées. Pas de texte libre, pas d’analyse JSON de la réponse.
Le nouveau point de terminaison s’appelle /v1/systemone. Dans une seule demande, vous pouvez poser plusieurs questions à la fois et le modèle répondra à toutes. Ceci est pratique pour les tâches où vous devez prendre plusieurs décisions connexes : par exemple, déterminer l’équipe, la nécessité d’un retour et l’urgence du ticket.
Quels modèles sont disponibles
Vous pouvez désormais exécuter trois modèles de décision via Ollama :
- nimble est un modèle ouvert avec 9 milliards de paramètres de Bespoke Labs. Il s’agit du plus grand et du plus précis disponible.
- tev1 est un modèle expérimental avec 4 milliards de paramètres de Together AI.
- tev1:0.8b est un modèle expérimental avec 0,8 milliard de paramètres de Together AI. Le plus rapide et le plus simple.
Ils travaillent tous localement, ne nécessitent aucun paiement et n’envoient pas de données à un service externe. Ollama 0.35 et versions ultérieures sont pris en charge.
Installation
Vérifiez d’abord la version Ollama :
ollama --version
Téléchargez ensuite le modèle souhaité. Pour le plus simple :
ollama pull tev1:0.8b
Pour la version complète de tev1 :
ollama pull tev1
Pour les agiles :
ollama pull nimble
Le modèle agile occupe environ 9,5 Go d’espace disque, c’est donc une bonne idée de libérer de l’espace avant le téléchargement. tev1:0.8b occupe moins d’un gigaoctet.
Première requête via curl
L’exemple le plus simple consiste à déterminer si un texte est une offre d’emploi :
curl http://localhost:11434/v1/systemone -d '{
"model": "tev1:0.8b",
"state": {
"message": "Senior Swift developer, Berlin, remote friendly"
},
"questions": {
"isJob": {
"type": "noul",
"instructions": "Does the message advertise a job posting that someone can apply to?"
}
}
}'
La réponse ressemble à ceci :
{
"model": "tev1:0.8b",
"answers": {
"isJob": {
"type": "noul",
"noul": 0.921
}
},
"usage": {
"input_tokens": 42,
"output_tokens": 0
}
}
Le champ nul est une probabilité de 0 à 1. La décision est prise par comparaison avec un seuil, généralement 0,5. Contrairement au modèle génératif, il n’est pas nécessaire de demander une réponse au format JSON puis de vérifier que le modèle ne l’a pas cassée.
Types de questions
Les modèles de décision prennent en charge trois types de questions.
noul est une question binaire. Renvoie la probabilité qu’une affirmation soit vraie :
{
"questions": {
"refund": {
"type": "noul",
"instructions": "Does the customer explicitly ask for a refund?"
}
}
}
choix – sélection d’une option dans un ensemble donné. Renvoie l’option sélectionnée, les probabilités de toutes les options et la confiance :
{
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": {
"billing": "Payments and refunds",
"technical": "Bugs and integrations",
"other": "None of the above"
}
}
}
}
score – note sur une échelle. Renvoie le nombre, la légende et les probabilités pour chaque point d’échelle :
{
"questions": {
"urgency": {
"type": "score",
"instructions": "How urgent is this ticket?",
"criteria": ["Routine", "Soon", "Urgent"]
}
}
}
Une demande peut contenir plusieurs questions de types différents à la fois. C’est ce qui rend les modèles de décision pratiques pour le tri : une opération, un état, plusieurs décisions indépendantes.
Python sans bibliothèques supplémentaires
Pour les requêtes, l’urllib standard est suffisante ; un SDK distinct n’est pas requis :
import json
from urllib.request import Request, urlopen
OLLAMA_DECISION_URL = "http://localhost:11434/v1/systemone"
def ask_decision(state, questions, model="tev1:0.8b"):
payload = {
"model": model,
"state": state,
"questions": questions,
}
request = Request(
OLLAMA_DECISION_URL,
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"},
method="POST",
)
with urlopen(request, timeout=3600) as response:
return json.loads(response.read().decode())["answers"]
Usage:
answers = ask_decision(
{"message": "Senior Swift developer, Berlin, remote friendly"},
{
"isJob": {
"type": "noul",
"instructions": "Does the message advertise a job posting that someone can apply to?"
}
},
)
probability = answers["isJob"]["noul"]
is_job = probability >= 0.5
Si vous avez besoin d’un SDK Python officiel, il s’appelle typesafe-sdk. Pour localhost, il peut être dirigé vers Ollama avec les variables d’environnement TYPESAFE_BASE_URL, TYPESAFE_API_KEY et TYPESAFE_DEFAULT_MODEL. Mais pour des tâches simples, une requête HTTP directe suffit.
Comment comprendre qu’un modèle soutient la décision
Les modèles de décision ne peuvent pas répondre via /api/generate ou /api/chat. Si vous envoyez une telle demande, Ollama renverra une erreur 400 avec un texte comme :
"tev1:0.8b" does not support generate
Ceci est important si vous disposez déjà d’un code qui fonctionne avec des modèles standards via /api/generate : si vous changez le modèle en modèle de décision, il cessera de fonctionner. Il est préférable de connaître à l’avance les capacités du modèle via /api/show et de choisir la méthode d’appel appropriée :
import json
from urllib.request import Request, urlopen
OLLAMA_SHOW_URL = "http://localhost:11434/api/show"
def supports_decision(model):
request = Request(
OLLAMA_SHOW_URL,
data=json.dumps({"model": model}).encode(),
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urlopen(request, timeout=30) as response:
capabilities = json.loads(response.read().decode()).get("capabilities", [])
except (OSError, TypeError, ValueError):
return False
return "decision" in capabilities
Les modèles de décision n’auront que la décision dans leurs capacités. Les modèles réguliers auront des complétions, des outils ou d’autres fonctionnalités. Si Ollama n’est pas disponible, il est raisonnable de considérer le modèle comme normal et d’utiliser le chemin génératif.
Comment intégrer dans du code existant
Le plus simple n’est pas de réécrire le classificateur, mais de le diviser en deux stratégies. La stratégie générative fonctionne comme avant : elle collecte l’invite, l’envoie à /api/generate et analyse le JSON. La stratégie de décision envoie l’état et la question saisie à /v1/systemone et compare la probabilité avec un seuil.
Le choix de la stratégie s’effectue en un seul endroit, lors de la création d’un classificateur :
def create_classifier(model):
if supports_decision(model):
return DecisionClassifier(model)
return GenerativeClassifier(model)
Cette approche présente plusieurs avantages. Les modèles génératifs continuent de fonctionner sans changement. Le modèle de décision peut être activé en modifiant une variable d’environnement. Et toute la différence entre les deux méthodes est concentrée dans deux petites classes et n’est pas répartie dans toute l’application.
Pour une classification binaire, la stratégie de décision ressemble à ceci :
async def classify(text):
answers = await ask_decision(
{"message": text},
{
"isJob": {
"type": "noul",
"instructions": instructions,
}
},
model,
)
probability = answers["isJob"]["noul"]
return probability >= 0.5, probability
Veuillez noter que le modèle de décision ne renvoie pas d’explication. Si votre format de résultat comporte un champ de raison, vous pouvez le construire à partir de la probabilité : par exemple, stockez la probabilité elle-même ou une chaîne telle que « le modèle a évalué le message à 0,935 comme poste vacant ». C’est plus honnête que d’inventer une raison que le modèle n’a pas donnée.
Les instructions devraient être une question
C’est la conclusion pratique la plus importante. Les modèles de décision ne comprennent pas les longues invites du style « vous classez les messages, répondez vrai si…, faux sinon ». Ils veulent une question courte et directe.
Sur le même message concernant un poste vacant, j’ai reçu les probabilités suivantes :
- Question directe : “Ce message est-il une offre d’emploi ?” — 0,921.
- De longues instructions expliquant ce qui est considéré comme un poste vacant – 0,026.
- Des instructions longues avec une question à la fin – 0,391.
La différence est presque trente fois supérieure. Le modèle ne se trompe pas dans la classification, il ne comprend tout simplement pas ce qu’il en attend lorsque la question est cachée à l’intérieur d’un paragraphe. Par conséquent, pour les modèles de décision, il vaut la peine de conserver des instructions courtes séparées et de laisser de longues invites pour les modèles génératifs.
Il est pratique de créer une variable d’environnement distincte :
OLLAMA_JOB_CLASSIFIER_DECISION_INSTRUCTIONS=Does the message advertise a job posting that someone can apply to?
Et utilisez une invite régulière uniquement pour le chemin génératif.
Seuil et probabilités
Le seuil de 0,5 convient comme valeur par défaut, mais il est utile de l’inclure dans la configuration. Pour différentes tâches, le coût d’une réponse faussement positive et faussement négative est différent. Pour la modération, il est plus sûr de relever le seuil ; pour rechercher des postes vacants, il est plus sûr de le baisser, afin de ne pas manquer de messages utiles.
Il est également utile d’enregistrer la probabilité elle-même, et pas seulement le booléen résultant. Lorsque le classificateur fait une erreur, le journal indique s’il s’agit d’une réponse sûre ou d’une décision à la frontière. Pour les questions de choix, il vaut la peine de conserver les probabilités et la confiance : elles montrent à quel point le modèle fluctue entre les options.
Performances et mémoire
La vitesse dépend grandement de la taille du modèle et du matériel. Sur le CPU, lors de mes tests, j’ai obtenu les chiffres suivants :
- tev1:0.8b – fractions de secondes à résoudre, s’intègre facilement dans la mémoire.
- tev1 – 4B, nettement plus lent, mais toujours adapté aux tâches interactives.
- agile – 9 B en Q8_0, environ 10 Go de mémoire. La première requête, y compris le chargement du modèle, a pris environ 137 secondes, les solutions suivantes ont pris entre 12 et 32 secondes sur le processeur.
Nimble nécessite beaucoup de RAM. Sur une machine avec 16 Go et Docker/WSL avec une limite d’environ 8 Go, le modèle ne rentre pas : le système commence à permuter et les conteneurs ne répondent plus. L’augmentation de la limite WSL à 12 Go via le fichier .wslconfig a aidé :
[wsl2]
memory=12GB
swap=8GB
Après le changement, vous avez besoin de wsl –shutdown et redémarrez Docker Desktop. Mais même avec 12 Go, la réserve reste faible : le modèle occupe environ 10 Go, et il ne reste plus grand chose pour le système.
Par défaut, Ollama décharge le modèle après cinq minutes d’inactivité, libérant ainsi de la mémoire. C’est pratique : Nimble ne garde pas 10 Go occupés en permanence, mais chaque nouveau lancement après une pause recommence à charger le modèle.
Quand utiliser des modèles de décision
Les modèles de décision sont bien adaptés aux tâches pour lesquelles vous avez besoin d’une réponse rapide et peu coûteuse à une question clairement formulée :
- Classification des messages, tickets et demandes.
- Routage par commandes ou exécuteurs.
- Modération du contenu et contrôles de sécurité.
- Solutions binaires et multivariées rapides dans les applications de jeux ou interactives.
Ils sont mal adaptés aux tâches où un texte détaillé est nécessaire : explication, extraction de champs, résumé, génération de réponses. Pour cela, les modèles génératifs habituels restent. Le meilleur résultat est obtenu lorsqu’il est combiné : un modèle de décision prend une décision et un modèle génératif l’explique ou extrait des données.
Total
Les modèles de décision dans Ollama sont un outil distinct et plus restreint que les LLM classiques. Ils ne remplacent pas les modèles génératifs, mais ils suppriment la partie routinière du travail : réponses saisies, probabilités au lieu de l’analyse de texte et format prévisible. Si vous disposez déjà d’un pipeline de classification, la transition se résume à vérifier les capacités du modèle, une stratégie d’appel distincte et de courtes questions pédagogiques.
Sources
https://ollama.com/blog/ollama-now-supports-jev-style-decision-models
https://ollama.com/library/nimble
https://ollama.com/library/tev1
https://typesafe.ai
Leave a Reply