Fan-out spéculatif
Envoie beaucoup de questions en un seul appel, y compris des questions spéculatives, et laisse ton code décider ce qui est pertinent.
Comme TypeSafe permet d’envoyer beaucoup de questions dans un seul appel API, nous recommandons de placer dans une seule requête toutes les questions dont ton système a besoin, puis d’utiliser le code pour décider après coup ce qui est pertinent. Toutes les questions sont évaluées en parallèle, donc ajouter des questions a généralement peu d’effet sur le temps de réponse.
Exemple : tri de tickets de support
Imagine que tu construis un système de support qui doit trier les tickets. Tu dois classer le ticket dans une catégorie. S’il s’agit d’un rapport de bug, tu dois aussi déterminer la gravité du bug.
Au lieu de demander d’abord la catégorie puis la gravité dans un appel de suivi, tu peux demander les deux en même temps. Si le ticket n’est pas un rapport de bug, tu ignores simplement les résultats de la question sur la gravité du bug.
%%{init: {"fontFamily": "Inter, sans-serif", "flowchart": {"rankSpacing": 35, "wrappingWidth": 300, "subGraphTitleMargin": {"top": 8, "bottom": 60}}}}%%
flowchart LR
t["support ticket"]
subgraph req["TypeSafe AI model<br/>evaluates each question<br/>against the ticket in parallel"]
direction TB
c["<b>Choice:</b> category"]
b["<b>Score:</b> bug severity"]
r["<b>Noul:</b> reproducible steps?"]
f["<b>Noul:</b> refund requested?"]
s["<b>Score:</b> frustration"]
%% invisible links: without an edge these share a rank and sit side by side
c ~~~ b ~~~ r ~~~ f ~~~ s
end
t -- "one request<br/>ticket + 5 questions" --> req
req -- "one response: 5 answers<br/>decisions + probabilities" --> route{"<b>filter, combine, and route</b><br/>in your code"}
route -- "bug_report" --> eng["read severity + repro steps<br/>escalate or backlog"]
route -- "billing" --> bill["refund requested<br/>send to billing"]
route -- "feature_request" --> feat["log it<br/>sent to devs"]
Étape 1 : fan-out spéculatif
{
"category": {
"type": "choice",
"instructions": "Determine the broad category of this support ticket",
"criteria": {
"bug_report": "The user is reporting something that is broken or producing errors",
"billing": "Charges, invoices, refunds, subscriptions",
"feature_request": "The user is requesting new functionality",
"account": "Login, permissions, profile, security"
}
},
"bug_severity": {
"type": "score",
"instructions": "How severe is the reported issue",
"criteria": [
"Cosmetic; no impact to functionality",
"Broken or degraded feature; workaround exists",
"Blocking issue; no workaround exists"
]
},
"has_reproducible_steps": {
"type": "noul",
"instructions": "The user describes specific steps to reproduce the issue"
},
"refund_requested": {
"type": "noul",
"instructions": "The user is explicitly asking for a refund or credit"
},
"frustration": {
"type": "score",
"instructions": "How frustrated the user appears",
"criteria": [
"Calm, matter-of-fact",
"Frustrated but civil",
"Very angry"
]
}
}Étape 2 : router avec du code
Ton code décide ce qui est pertinent à partir du résultat de classification :
triage.py
category = response.answers["category"]
bug_severity = response.answers["bug_severity"]
bug_repro = response.answers["has_reproducible_steps"]
refund = response.answers["refund_requested"]
frustration = response.answers["frustration"]
if category.choice == "bug_report":
if bug_severity.score > 1.5 and bug_repro.noul > 0.6:
escalate_to_engineering(ticket_id, severity="high")
else:
add_to_bug_backlog(ticket_id)
elif category.choice == "billing":
if refund.noul > 0.7:
route_to_billing_with_flag(ticket_id, refund_likely=True)
else:
route_to_billing(ticket_id)
elif category.choice == "feature_request":
log_feature_request(ticket_id)
# Frustration is useful regardless of category
if frustration.score > 1.5:
flag_for_priority_response(ticket_id)
Tout ce qu’il faut pour l’arbre de décision complet provient d’un seul appel. Les questions spéculatives sont ignorées quand elles ne sont pas pertinentes, et économisent un aller-retour quand elles le sont.