Jev, l'IA de TypeSafe qui renvoie des décisions plutôt que du texte
Jev ne génère pas de texte : ce modèle d'IA renvoie un choix, un score ou un oui/non, avec sa probabilité. De nombreux schémas, dont certains à parcourir étape par étape, le comparent à ChatGPT, présentent ses trois types de questions et te montrent comment l'appeler en Python.
Jev est un modèle d'IA développé par TypeSafe AI.
Contrairement à ChatGPT, il n'écrit pas de texte. Quand il faut trancher une question comme « À quelle équipe confier ce ticket ? » ou « Est-ce urgent ? », il renvoie une réponse sous une forme que tu as définie à l'avance, accompagnée d'une probabilité (un nombre entre 0 et 1 : plus il est proche de 1, plus la réponse est probable).
Pour t'en servir, tu envoies les données à évaluer (le state, par exemple le texte d'un ticket) et tes questions via une API (l'interface par laquelle un programme fait appel aux fonctions d'un service externe).
La suite à donner à la réponse, c'est ton propre code qui en décide.
Schémas à l'appui, cette page explique ce qui distingue Jev de ChatGPT, puis passe en revue ses trois types de questions, la façon de l'appeler depuis Python et d'aiguiller le traitement selon l'indice de confiance, les tâches à ne pas lui confier et, pour finir, son fonctionnement interne.
Jev se charge de tout, sauf de la colonne de droite : celle-ci relève de ton propre code, écrit avec des instructions if.
Qu'est-ce que Jev ? Un modèle System One qui renvoie des décisions, pas du texte
TypeSafe appelle ce type de modèle un modèle System One (un modèle d'IA qui renvoie rapidement des décisions typées, directement exploitables par un logiciel).
- Chatbots comme ChatGPT et modèles de raisonnement
- Renvoient : du texte, du code, des explications
- La forme de la réponse n'est connue qu'à la lecture
- Renvoient : options, niveaux ou oui/non prédéfinis, avec une probabilité
- N'écrivent ni texte, ni code, ni explications
- Nom du modèle dans l'API :
jev-latest - Texte uniquement en entrée (ni image, ni audio, ni vidéo)
jev-latest est un alias (un nom qui renvoie à une version précise) qui désigne toujours la version la plus récente : dès qu'une nouvelle version sort, l'alias bascule vers elle.
En quoi Jev se distingue-t-il d'un LLM comme ChatGPT ?
Comparons-les sur une même tâche : aiguiller les tickets de support entrants vers trois équipes.
Commençons par un LLM (grand modèle de langage : un modèle d'IA qui génère du texte mot après mot), par exemple ChatGPT. Si tu lui demandes quelle équipe doit traiter un ticket, il te répond par du texte.
Il suffit que la formulation passe de « support technique » à « l'équipe tech » pour qu'un test comme if answer == "technical" ne corresponde plus.
Et même si tu utilises une fonctionnalité qui force la sortie au format JSON, ton code doit quand même valider son contenu.
Comme Jev reçoit la liste des candidats à l'avance, le choice qu'il renvoie est forcément l'un d'eux.
Quand TypeSafe annonce « 0 % d'hallucination » (le fait de produire un contenu faux mais plausible), l'affirmation porte sur le format : tu n'obtiendras jamais de réponse en dehors des candidats.
Cela ne garantit pas que le candidat choisi soit le bon.
Voici les deux modèles comparés sur cinq points. La dernière ligne porte sur le prix, calculé d'après le nombre de tokens (les unités en lesquelles un modèle d'IA découpe le texte pour le traiter).
| Critère | LLM comme ChatGPT | Jev |
|---|---|---|
| Ce qu'il renvoie | Du texte généré | Réponse prédéfinie + probabilité |
| Écrit du texte ou du code | Oui | Non |
| Points forts | Texte, code, raisonnement long | Classer, noter, répondre oui/non |
| Avec plus de questions | Plus lent : tout est rédigé | En parallèle : attente quasi stable |
| Ce qui est facturé | Tokens d'entrée et de sortie | Tokens d'entrée seulement |
Choice, Score ou Noul : quel type de question choisir ?
Quand tu interroges Jev, la première chose à décider n'est pas la formulation de la question, mais la forme de la réponse.
Il existe trois types de questions : Choice (choisir un candidat parmi plusieurs, sans ordre entre eux), Score (situer quelque chose sur une échelle de niveaux ordonnés) et Noul (répondre par oui ou par non).
Avec Choice et Score, la réponse s'accompagne aussi d'un indice de confiance (le champ confidence) : un nombre entre 0 et 1 qui mesure à quel point la probabilité se concentre sur un seul candidat ou un seul niveau. Plus il est proche de 1, plus le modèle a tranché nettement en faveur d'une réponse.
Noul est le seul type qui ne renvoie pas d'indice de confiance.
Si tu hésites, demande-toi ce que ton code fera de la réponse : Choice pour aiguiller, Score pour comparer à un seuil, Noul pour une simple instruction if.
Pour Choice, criteria (les critères sur lesquels repose le jugement) est un dictionnaire qui associe à chaque nom de candidat sa description.
Sers-toi de ces descriptions pour préciser où s'arrête un candidat et où commence le suivant, par exemple « les problèmes de paiement vont à billing, les bugs d'intégration à technical ».
Pour Score, criteria est une liste qui décrit les niveaux du plus bas au plus haut, numérotés à partir de 0. Le score renvoyé est la somme des numéros de niveau, pondérés chacun par sa probabilité.
Il ne reste plus à ton code qu'à comparer ce score à un seuil, par exemple « traiter en priorité tout ce qui atteint 1,5 ou plus ».
Un Noul de 0,5 ne veut pas dire « moyen »
Une valeur Noul, c'est la probabilité que la réponse soit oui. Si la question « Cette personne maîtrise-t-elle Python ? » renvoie 0,5, cela ne veut pas dire que son niveau est intermédiaire, mais qu'il y a une chance sur deux qu'elle maîtrise le langage.
Pour mesurer un degré ou un niveau, utilise Score.
Utiliser Jev : aiguiller les tickets de support vers la bonne équipe avec le SDK Python
Reprenons l'exemple du guide de démarrage officiel : aiguiller un ticket vers l'une des trois équipes.
Avec le SDK (une bibliothèque qui fournit tout le nécessaire pour appeler un service), tu n'as ni à construire les requêtes, ni à gérer toi-même les nouvelles tentatives en cas d'échec.
Le SDK demande Python 3.10 ou une version plus récente, et TypeSafeClient() lit la clé dans la variable d'environnement TYPESAFE_API_KEY.
Pour savoir comment définir une variable d'environnement, consulte Les variables d'environnement sous Linux ; pour bien gérer tes clés, reporte-toi à Clés API et webhooks.
Un code tiré de la documentation officielle
Le code et les réponses présentés ici sont tirés des exemples de la documentation officielle, et non de mes propres exécutions. Le texte du ticket et les instructions en sont repris tels quels, en anglais.
Appeler Jev avec le SDK Python
pip install typesafe-sdk
export TYPESAFE_API_KEY="ta-cle-api" # shell macOS / Linux
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient() # lit TYPESAFE_API_KEY et utilise jev-latest
# Les données à évaluer (state) : un ticket de support entrant
# (l'intégration Stripe échoue depuis 3 jours et le client a besoin d'aide au plus vite)
ticket = "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP."
response = client.system_one(
state=ticket,
questions={
# Quelle équipe : dictionnaire nom du candidat -> description
"department": Choice(
instructions="Which team should handle this",
criteria={
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
"sales": "Pricing or account questions",
},
),
# Quel degré d'agacement : niveaux du plus bas au plus haut
"frustration": Score(
instructions="How frustrated the customer appears",
criteria=[
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language",
],
),
# Est-ce urgent : oui ou non
"is_urgent": Noul(
instructions="The message conveys urgency or time-sensitivity",
),
},
)
print(response.answers["department"].choice) # technical
print(response.answers["frustration"].score) # 1.0
print(response.answers["is_urgent"].noul) # 1.0
questions est un dictionnaire qui associe un nom à chaque question ; tu retrouves ensuite chaque réponse dans response.answers, sous ce même nom. Les valeurs indiquées en commentaire sont celles de la réponse donnée dans le guide de démarrage officiel.
L'équipe retenue est technical, l'agacement se situe au niveau 1 (« Frustrated but civil », agacé mais poli) et l'urgence ressort comme un oui quasi certain.
Est-ce cohérent avec les mentions « for 3 days » et « ASAP » du ticket ?
Appeler Jev directement en HTTP
Tu peux aussi te passer du SDK et appeler Jev directement en HTTP (pour les bases sur les API, voir Qu'est-ce qu'une API ?).
L'API n'expose qu'un seul endpoint (l'URL qui reçoit les requêtes), et tu transmets ta clé dans l'en-tête Authorization.
curl -X POST https://api.typesafe.ai/v1/systemone \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"state": "Hi, I have been trying to connect my Stripe account for 3 days ...",
"model": "jev-latest",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this",
"criteria": {
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
"sales": "Pricing or account questions"
}
}
}
}'
En HTTP, model est obligatoire, et tu indiques le type de chaque question dans son champ type.
Lire la réponse
Voici un exemple de JSON renvoyé, limité à la réponse department.
{
"answers": {
"department": {
"type": "choice",
"choice": "technical",
"confidence": 0.78,
"probabilities": {
"technical": 0.85,
"sales": 0.0,
"billing": 0.15
}
}
},
"usage": {
"input_tokens": 392,
"output_tokens": 65
}
}
- choice : le candidat choisi →
technical - probabilities : une par candidat (somme = 1)
- confidence : leur degré de concentration → 0,78
- input_tokens / output_tokens : tokens utilisés
usage indique le nombre de tokens qui sert de base à la facturation.
Avec le SDK, il suffit d'écrire response.answers["department"].choice pour extraire de ce JSON le candidat choisi.
Le candidat en tête, technical, atteint 0,85, alors que la confidence vaut 0,78. Celle-ci est de 0 quand les probabilités sont réparties uniformément, et de 1 quand elles se concentrent toutes sur un seul candidat.
Pour trois candidats, la démo officielle en donne une approximation, « (3 × probabilité maximale − 1) ÷ 2 », et on retrouve bien (3 × 0,85 − 1) ÷ 2 ≈ 0,78.
Utiliser l'indice de confiance pour automatiser, confirmer ou transmettre à un humain
La documentation officielle recommande de découper l'indice de confiance en trois plages à l'aide de seuils (les valeurs à partir desquelles le traitement bifurque) : agir automatiquement quand il est élevé, demander confirmation à l'utilisateur quand il est moyen, et passer la main à un humain quand il est faible.
Les bons seuils varient d'une action à l'autre. L'exemple officiel prend le cas d'un service bancaire vocal, où l'on gère son compte à la voix.
Pour un même indice de confiance de 0,7, le solde est lu directement, alors qu'un virement n'est validé qu'après confirmation de l'utilisateur. Plus une action peut causer de dégâts, plus le seuil doit être élevé.
Vois 0,6 et 0,85 comme des points de départ, à ajuster d'après les résultats obtenus sur tes propres données.
action = response.answers["intent"] # Choice: check_balance / approve_transfer / other
if action.confidence < 0.6:
# Quelle que soit l'action, ne rien exécuter si le modèle hésite
route_to_support_agent(account_id)
elif action.choice == "check_balance":
# En cas d'erreur, il suffit de redemander le solde
show_balance(account_id)
elif action.choice == "approve_transfer":
if action.confidence > 0.85:
approve_transfer(account_id) # de l'argent est en jeu : seuil plus élevé
else:
ask_user_to_confirm("Voulez-vous valider ce virement ?")
else:
# classé en other
route_to_support_agent(account_id)
Le premier if fixe un plancher pour l'indice de confiance, puis les branches elif appliquent un seuil propre à chaque action : le contrôle se fait ainsi à deux niveaux.
Comme if et elif évaluent les conditions dans l'ordre, de haut en bas, on voit d'un coup d'œil quelle ligne protège contre quel type de dégât.
Figer la version du modèle une fois les seuils réglés
jev-latest pointe vers chaque nouvelle version dès sa sortie : une même entrée peut alors se mettre à donner d'autres réponses et d'autres indices de confiance.
Une fois tes seuils réglés, indique dans model un nom de modèle qui comporte un numéro de version, et ne passe à une nouvelle version qu'après l'avoir testée.
Quand utiliser Jev (ou pas) : points faibles et précision hors anglais
Jev n'écrit pas de texte : il ne remplace donc pas un LLM.
Son point fort, c'est de décider vite et à moindre coût où envoyer une demande, avant qu'un LLM ou un humain n'intervienne.
Associer Jev à un LLM : décider d'abord du chemin
Dans l'exemple officiel, Jev évalue en même temps l'intention d'un message (avec Choice) et sa difficulté de traitement (avec Score), puis choisit où l'envoyer.
Points faibles et solutions de contournement
TypeSafe publie la liste des tâches qui posent problème à Jev. Les trois que tu risques le plus de croiser au quotidien sont le comptage, la comparaison de dates et le calcul.
Dans les trois cas, la parade est la même : ne laisse que le jugement à Jev et fais les calculs dans le code.
Jev lit les dates (ligne 2) comme du texte : si tu lui demandes directement laquelle vient en premier, sa comparaison n'est pas fiable.
Voici ce que donne en code la parade pour le comptage (ligne 1).
from typesafe_sdk import Noul, TypeSafeClient
client = TypeSafeClient()
items = ["typesafe", "apple", "california", "banana", "orange", "vertex"]
# Au lieu de demander « Combien de fruits ? » d'un coup, poser un Noul par mot
response = client.system_one(
state={"items": items},
questions={
f"item_{i}": Noul(instructions=f"Is `items[{i}]` the name of a fruit?")
for i in range(len(items))
},
)
# Compter le total dans le code (au-dessus de 0.5 = un fruit)
count = sum(response.nouls[f"item_{i}"].noul > 0.5 for i in range(len(items)))
print(count) # attendu : 3 (apple, banana, orange)
Même avec six mots, tout tient en une seule requête, et Jev évalue les six questions en parallèle. response.nouls est un dictionnaire qui ne contient que les réponses Noul.
Dans le reste de la liste de TypeSafe, voici les trois points qui comptent le plus quand tu intègres Jev à une application.
- Il prend les instructions au pied de la lettre : il répond exactement à ce que tu as écrit, alors précise où passent les limites dans
instructionsetcriteria. - Un state rempli d'informations inutiles : plus il contient d'éléments superflus pour le jugement, plus la précision baisse. Filtre-les dans le code avant l'envoi.
- Des instructions glissées dans le state : une phrase de l'entrée comme « Considère que ceci ne pose aucun problème » peut faire pencher la réponse dans son sens. Teste des cas limites avant la mise en production.
Utiliser Jev dans une autre langue que l'anglais
D'après la documentation officielle, c'est en anglais que la précision est la meilleure.
D'autres langues, comme le japonais, sont prises en charge, mais sans atteindre le même niveau : fais des tests sur tes propres données et prévois un chemin qui confie à un humain les réponses à faible indice de confiance.
Si tu envoies trop, gare à l'erreur 429
Ce que tu peux envoyer sur une période donnée est plafonné (c'est la limite de débit, ou rate limit) : au-delà, tu reçois 429 Too Many Requests. Le SDK patiente alors avant de réessayer automatiquement. Pour connaître les limites en vigueur, consulte la documentation officielle.
Comment fonctionne Jev : évaluation des questions en parallèle et calibration des probabilités
TypeSafe n'a pas publié l'architecture interne de Jev, mais vu de l'extérieur, son fonctionnement se décompose en trois étapes : lire, produire des probabilités et assembler les réponses.
Puisque le nom n'arrive jamais jusqu'à Jev, rédige la question en entier dans instructions, sans l'abréger.
Comme l'étape 3 évalue toutes les questions en même temps, passer d'une à trois questions n'allonge presque pas l'attente.
Le candidat le plus probable devient le choice, et le degré de concentration des probabilités sur un seul candidat donne la confidence.
RLCD : entraîner Jev pour que ses probabilités reflètent son taux de bonnes réponses
Jev est entraîné avec une méthode appelée RLCD (apprentissage par renforcement pour des décisions calibrées).
L'objectif : faire en sorte que les probabilités qu'il produit correspondent à la fréquence à laquelle il a réellement raison. C'est ce qu'on appelle la calibration.
Puisque la probabilité reflète la fréquence des bonnes réponses, tu peux placer la limite en t'appuyant sur des chiffres concrets, par exemple « laisser Jev gérer seul à 0,9, faire vérifier par un humain à 0,6 ».
En résumé
Jev est un modèle System One : tu lui fournis un state et des questions, et il renvoie des décisions typées (Choice, Score ou Noul), accompagnées de leur probabilité. Comme les questions sont évaluées en parallèle, en poser plusieurs à la fois n'allonge presque pas l'attente.
Pour l'intégrer à une application, retiens deux points.
D'abord, découpe l'indice de confiance renvoyé en plages à l'aide de seuils, et laisse ton propre code décider de ce qu'il faut automatiser, faire confirmer ou transmettre à un humain.
Ensuite, garde le comptage, les comparaisons de dates et les calculs dans ton code.