Documentación

Fan-out especulativo

Envía muchas preguntas en una sola llamada, incluidas las especulativas, y deja que tu código decida qué es relevante.

Como TypeSafe admite enviar muchas preguntas en una sola llamada a la API, recomendamos poner todas las preguntas que tu sistema necesita en una sola solicitud y luego usar el código para decidir qué es relevante a posteriori. Todas las preguntas se evalúan en paralelo, así que añadir más preguntas suele tener poco efecto en el tiempo de respuesta.

Ejemplo: triaje de tickets de soporte

Imagina que estás construyendo un sistema de soporte que necesita hacer triaje de tickets de soporte. Necesitas clasificar el ticket en una categoría. Si es un informe de error, también necesitas determinar la gravedad del error.

En lugar de preguntar primero por la categoría y luego por la gravedad en una llamada de seguimiento, puedes preguntar por ambas al mismo tiempo. Si el ticket no es un informe de error, simplemente ignoras los resultados de la pregunta de gravedad del error.

%%{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"]

Paso 1: fan-out especulativo

questions
{
  "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"
    ]
  }
}

Paso 2: enruta con código

Tu código decide qué es relevante según el resultado de la clasificación:

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)

Todo lo necesario para el árbol de decisión completo proviene de una sola llamada. Las preguntas especulativas se ignoran cuando son irrelevantes y ahorran un viaje de ida y vuelta cuando no lo son.