Aller au contenu principal

Jev

Ce qui est renvoyé est une probabilité, pas une décision

Jev renvoie des vraisemblances et des similarités. 0.92 signifie « penche fortement dans ce sens », pas « c'est réglé ». Le nom renvoyé par choice est l'option qui a obtenu le meilleur score, pas une décision. Rien ici ne décide quoi que ce soit — transformer une probabilité en décision en choisissant un seuil est votre travail, en tant qu'appelant, tout comme ce qui se passe de part et d'autre de ce seuil.

C'est pourquoi cet endpoint s'appelle /v1/jev et non /v1/decisions. Une décision est une chose lourde, discrète et définitive, prise par une personne. Un nom plus lourd que ce qu'il désigne pousse les lecteurs à traiter 0.92 comme un verdict ; nous avons donc changé le nom. POST /v1/decisions a été supprimé le 2026-09-23 et renvoie désormais 404 — il n'existe pas d'alias.

Cet endpoint est le Jev de TypeSafe. Même modèle, mêmes réponses — "model": "jev-1.13.0" figure dans chaque réponse. Pas de compte TypeSafe, pas de compte Cloudflare, pas de liste d'attente : la clé aicu_live_ que vous avez déjà suffit. Les exemples publiés par Cloudflare fonctionnent ici en changeant uniquement l'URL et la clé.

Posez une question, recevez une valeur typée sur laquelle votre code peut brancher — un choix, un score ou une vraisemblance — chacune accompagnée des probabilités qui la sous-tendent. Pas de JSON à extraire d'un texte en prose, pas de nouvel essai quand un modèle enveloppe sa réponse dans un bloc de code.

Le problème que cela remplace​

La méthode habituelle pour obtenir une décision d'un modèle de langage consiste à demander du JSON et à espérer. Nous avons mesuré à quel point cela tient réellement — 10 cas, trois exécutions chacun (n=30), tous via cette même API, le 2026-09-22.

MéthodeAnalysé sans erreurValeur parmi celles déclaréesp50p95
POST /v1/jev30 / 3030 / 30439 ms525 ms
gpt-5.4-nano, avec demande de JSON30 / 3030 / 30949 ms1,451 ms
deepseek-v3, avec demande de JSON20 / 3020 / 301,697 ms2,402 ms

Un modèle compétent renvoie du JSON propre. Une version antérieure de cette page indiquait 5/6 pour gpt-5.4-nano et bâtissait un argument là-dessus ; à n=30, c'est 30/30. Nous lisions du bruit. Si votre modèle est bon et votre prompt soigné, « il ne sait pas renvoyer du JSON » n'est pas la raison d'utiliser cet endpoint.

Trois différences résistent à l'échantillon plus large, et ce sont les vrais arguments en sa faveur.

  1. La vitesse, surtout dans la queue de distribution. 525 ms au p95 contre 1,451 ms — 2,8x. La médiane est à 2,2x. C'est cette queue courte qui permet de placer une décision sur le chemin d'une requête.
  2. La même entrée donne la même réponse. Sur les 10 cas, /v1/jev a été d'accord avec lui-même 3 fois sur 3 à chaque fois. gpt-5.4-nano s'est partagé à 2/3 sur l'un d'eux.
  3. Vous obtenez des probabilités et un indice de confiance. Pas seulement la réponse, mais avec quelle force — c'est ce qui vous permet d'orienter les cas incertains vers un humain au lieu de deviner un seuil.

deepseek-v3 est une autre histoire : il a échoué 10 fois sur 30, sans tentative de récupération des blocs de code. Il a renvoyé "route":"tech|billing" à plusieurs reprises — en recopiant la liste d'options séparées par des barres verticales depuis le prompt comme s'il s'agissait d'une valeur. Les modèles plus faibles échouent bien de cette façon, et un endpoint de décision supprime entièrement cette catégorie d'erreur : vous déclarez les options, la réponse est l'une d'elles.

Les trois types de questions​

TypeVous fournissezVous recevez
choicedes options nomméesl'une de vos clés d'option, plus une probabilité pour chacune
scoredes libellés ordonnés, du plus bas au plus hautun score continu sur votre échelle, plus une probabilité par niveau
noulseulement la questionun nombre de 0 à 1 — à quel point c'est un oui

noul n'est pas un booléen. C'est la force d'un oui : c'est donc vous qui choisissez le seuil, plutôt que le modèle à votre place. Une boîte de dialogue de confirmation pourrait se déclencher à 0.5 ; une suppression pourrait exiger 0.9.

Votre premier appel​

curl -X POST https://api.aicu.ai/v1/jev \
-H "Authorization: Bearer aicu_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"state": "Ticket: \"Since yesterday /v1/chat/completions returns 401. The key was issued last week. I have not received an invoice either.\"",
"questions": {
"route": {
"type": "choice",
"instructions": "Pick the team that should handle this first",
"criteria": {
"tech": "Technical support",
"billing": "Billing",
"sales": "Sales",
"abuse": "Abuse investigation"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this",
"criteria": ["next business day", "today", "within hours", "immediately"]
},
"needs_human": {
"type": "noul",
"instructions": "Should a human operator take over"
}
}
}'

La réponse, sans retouche :

{
"object": "jev",
"model": "jev-1.13.0",
"answers": {
"route": {
"type": "choice",
"choice": "tech",
"probabilities": { "tech": 0.89, "billing": 0.1, "abuse": 0.01, "sales": 0 },
"confidence": 0.85
},
"urgency": {
"type": "score",
"score": 1.57,
"legend": { "0": "next business day", "1": "today", "2": "within hours", "3": "immediately" },
"probabilities": { "0": 0.04, "1": 0.4, "2": 0.5, "3": 0.06 },
"confidence": 0.45
},
"needs_human": { "type": "noul", "noul": 0.8 }
},
"usage": { "input_tokens": 492, "output_tokens": 79 },
"ap_cost": 2
}

answers.route.choice est l'une des clés que vous avez déclarées. Ce ne peut être rien d'autre — le branchement ci-dessous n'a donc jamais besoin d'un default: qui journalise une alerte et réveille quelqu'un.

route = res["answers"]["route"]["choice"] # "tech" | "billing" | "sales" | "abuse"
urgency = res["answers"]["urgency"]["score"] # 0.0 .. 3.0
if res["answers"]["needs_human"]["noul"] > 0.7:
assign_to_human(route, urgency)

Lisez la confiance, pas seulement la réponse​

Chaque question revient avec son propre indice de confiance, et ils diffèrent au sein d'une même réponse. Dans l'exemple ci-dessus, route est à 0.85 tandis que urgency est à 0.45 — le modèle sait clairement qui doit prendre le ticket, mais hésite réellement sur la rapidité. Les probabilités disent pourquoi : urgency est partagé à 0.40 / 0.50 entre « today » et « within hours ».

C'est la partie utile. Traitez une confiance faible comme un signal d'orientation à part entière :

r = res["answers"]["route"]
if r["confidence"] < 0.6:
queue_for_review(ticket) # laisser une personne regarder plutôt que deviner
else:
assign(r["choice"])

Les réponses en prose ne vous donnent pas cela. Un modèle qui dit « c'est un problème de facturation » le dit exactement sur le même ton, qu'il en soit sûr ou non.

Poser plusieurs questions à la fois​

Les trois questions de l'exemple ont obtenu leur réponse en un seul appel, pour un seul prix. Regroupez tout ce dont vous avez besoin sur un même état dans une seule requête : c'est moins cher, c'est un seul aller-retour, et chaque réponse est produite dans le même contexte.

Les scores : mettez votre échelle dans les libellés​

Pour un score, criteria est un tableau ordonné, du plus bas au plus haut. Les libellés font un vrai travail — c'est grâce à eux que le modèle comprend ce que signifie l'échelle ; rédigez-les donc comme vous le feriez pour un nouveau collègue.

{
"risk": {
"type": "score",
"instructions": "How far does this submission fall outside the rules",
"criteria": ["fine", "minor", "serious", "clear violation"]
}
}

Pour une participation à un concours dont l'auteur avait écrit s'être entraîné sur les photos d'une personne réelle sans autorisation, cela a renvoyé 2.94 avec une confiance de 0.94 et des probabilités {"2": 0.05, "3": 0.95} — calé en haut de l'échelle plutôt que prudemment au milieu.

Limites​

LimiteValeur
Questions par requête20
state20,000 caractères
instructions, par question2,000 caractères
Éléments de criteria, par question20
Chaque élément de criteria500 caractères
Total de questions, en JSON64,000 octets
Délai d'attente du fournisseur20 secondes

state est obligatoire. model est facultatif et accepte jev-latest (par défaut) ou jev-1.13.0 ; toute autre valeur est rejetée, avec la liste des valeurs acceptées dans allowed_models.

Tarifs​

2 AP par requête, plus 1 AP par tranche de 1,000 caractères d'entrée, arrondi à l'inférieur — une question typique coûte donc 2 AP. Le nombre de questions dans une requête ne change pas le prix ; c'est la taille de ce que vous envoyez qui compte.

Ici, l'entrée désigne le state plus les questions, puisque les deux sont envoyés au fournisseur. Une requête aux limites coûte environ 27 AP.

Le montant est réservé avant l'appel au fournisseur et intégralement remboursé si l'appel échoue — une décision qui échoue ne coûte rien. Chaque réponse contient X-AICU-AP-Cost, X-AICU-AP-Balance et X-Credits-Remaining.

Authentification​

Clé Bearer avec le scope llm. Si votre clé appelle déjà /v1/chat/completions, elle fonctionne déjà ici — pas de nouveau scope, pas de réémission.

Erreurs​

StatutcodeQuand
400invalid_parameterstate manquant, question mal formée, model inconnu, ou limite dépassée
400invalid_jsonle corps n'est pas du JSON
402insufficient_creditsAP insuffisants
403—la clé n'a pas le scope llm
502generation_failedle fournisseur a échoué ou n'a renvoyé aucune réponse — remboursé
503internal_errorle fournisseur de décisions est indisponible — remboursé

Quand ne pas l'utiliser​

Cet endpoint renvoie des décisions, pas du texte. Si vous avez besoin d'une phrase destinée à un humain, appelez l'API LLM — et si vous avez besoin des deux, il est normal de faire les deux : décider avec celui-ci, puis rédiger la réponse avec un modèle, uniquement pour les tickets qui en ont effectivement besoin.

Sous le capot​

Les requêtes sont servies par le Jev de TypeSafe via Cloudflare Workers AI. Vous n'avez besoin ni d'un compte TypeSafe, ni d'un compte Cloudflare, ni d'une clé pour l'un ou l'autre — la même clé aicu_live_ que vous avez déjà suffit.

Jev est un modèle System One : au lieu de générer une chaîne que vous analysez ensuite, il évalue un état face à des questions typées et renvoie les réponses en parallèle, avec des probabilités calibrées. C'est pourquoi une requête de trois questions coûte le même prix et prend à peu près le même temps qu'une requête d'une seule question.

state accepte une chaîne, un objet ou un tableau — les exemples publiés par Cloudflare, y compris ceux qui passent des objets imbriqués, fonctionnent ici sans modification. Les nombres, les booléens et null sont rejetés avec 400 invalid_parameter, car le Jev du fournisseur ne les accepte pas non plus.