JEV - primitivas choice, score y noul

Resumen

TypeSafe expone tres primitivas de IA: bloques tipados que se componen en código. Cada una pide un tipo de pregunta y devuelve un tipo de respuesta. Todas se pueden mezclar en una sola llamada, se evaluan en paralelo y de forma aislada contra el mismo estado.

TipoQue respondeDevuelve
ChoiceCual de estas opcioneschoice, probabilities, confidence
ScoreQue nivelscore, legend, probabilities, confidence
NoulEs esto verdadnoul (0 a 1)

Regla clave: una pregunta = un juicio atomico. “Does this message convey urgency?” es buena. “Analyze this message and determine the best course of action” no lo es (eso es System 2, requiere descomponer).

Si un juicio depende de varios factores, se pregunta por cada factor por separado y se combinan en código. Cambiar prioridades = cambiar un coeficiente, no reescribir un prompt.

Estructura común

Toda pregunta tiene:

  • ID (clave que tu eliges; se devuelve bajo el mismo id). No se envía al modelo.
  • type: choice, score o noul.
  • instructions: la pregunta. Aquí va la lógica. Puede ser string, objeto o array.
  • criteria: opciones (Choice), niveles (Score), o aclaración true/false (Noul opcional).

Choice

Para elegir una opción de un conjunto fijo y sin orden. Hasta 255 opciones. Incluir other/none of the above si la lista puede no cubrir todo.

  • criteria: mapa opción -> descripción. Descripción puede ser null si el nombre es claro.
  • Respuesta: choice (mayor probabilidad), probabilities (suma 1), confidence.
{
  "department": {
    "type": "choice",
    "instructions": "Which team should handle this?",
    "criteria": {
      "returns": "Exchanges, refunds, wrong or damaged items",
      "shipping": "Delivery status, delays, lost packages",
      "billing": "Charges, invoices, payment problems"
    }
  }
}

Respuesta de ejemplo:

{
  "department": {
    "type": "choice",
    "choice": "returns",
    "confidence": 0.39,
    "probabilities": { "shipping": 0.02, "billing": 0.38, "returns": 0.6 }
  }
}

Criterios contrastivos (lo más útil): cuando dos opciones se confunden, usar objeto con campos como what, not_for, examples. Los nombres de campo los eliges tu (no son API reservada); el modelo los ve.

{
  "return_topic": {
    "type": "choice",
    "instructions": { "question": "Which returns topic?", "focus": "Classify the information the customer wants." },
    "criteria": {
      "return_policy": {
        "what": "Whether and how an item can be returned",
        "not_for": "Progress of a return already sent",
        "examples": ["Can I return shoes I've worn once?"]
      },
      "return_status": {
        "what": "Progress of a return already sent",
        "not_for": "Whether and how an item can be returned",
        "examples": ["When will my refund be paid?"]
      }
    }
  }
}

Score

Para posicionar el estado en una escala ordenada. criteria es un array ordenado de niveles, de menor a mayor. Mínimo 2, máximo 10 niveles.

  • El número de nivel es su posición en el array (empieza en 0). El orden del array es la numeración.
  • Respuesta: score (media ponderada por probabilidad, puede caer entre niveles), legend (nivel → descripción), probabilities (clave = número de nivel como string), confidence.
  • Ejemplo: probabilidades 0:0.0, 1:0.70, 2:0.30 → score = 0x0.0 + 1x0.70 + 2x0.30 = 1.30.
{
  "bug_severity": {
    "type": "score",
    "instructions": "How severe is the reported issue?",
    "criteria": [
      "Cosmetic; no impact to functionality",
      "Broken or degraded feature, but workaround exists",
      "Blocking issue; no workaround exists"
    ]
  }
}

Escribir buenos niveles

  • Describir situaciones, no grados. “Broken or degraded feature, but workaround exists” (bueno) vs “Moderately severe” (malo).
  • Cada nivel se evalua por separado: el modelo no ve el número ni los vecinos. “Worse than the previous level” no significa nada.
  • Niveles solo numericos (["0","1","2"]) rinden mucho peor: el modelo no tiene con que comparar y reparte probabilidad.
  • Un Score por una sola dimensión. “puntual y listo y con experiencia” mide tres cosas: dividir.
  • Si hay un extremo raro que requiere acción distinta, darle su propio nivel (p.ej. “abusive or threatening” en sentimiento).
  • Si no hay continuo y son categorias discretas, usar Choice o varios Noul.
  • Objetos con what + examples mejoran la concentración cuando dos niveles se confunden. Ejemplos útiles suben confianza; ejemplos no relacionados apenas cambian. Más confianza no prueba que la respuesta sea correcta.

Combinar varios Scores (Composite scoring)

Escalas de distinta longitud: normalizar dividiendo por len(criteria) - 1 para llevar a 0-1. Luego pesos.

def normalized(answers, question_id):
    top_level = len(TRIAGE_QUESTIONS[question_id].criteria) - 1
    return answers[question_id].score / top_level
 
priority = 0.6 * normalized(answers, "severity") \
         + 0.3 * normalized(answers, "frustration") \
         + 0.1 * normalized(answers, "report_quality")

Dos distribuciones distintas pueden dar el mismo score (1.0 puede ser todo en nivel 1, o mitad en 0 y mitad en 2). Leer probabilities y confidence junto al score.

Noul

Pregunta si/no. Devuelve noul, la probabilidad de que la respuesta sea si (0 a 1). No tiene confidence separada.

  • Cerca de 1 = si fuerte; cerca de 0 = no fuerte; cerca de 0.5 = empate.
  • Formular de modo que probabilidad alta = “si”, para que el valor sea inequivoco.
  • criteria opcional con true / false para aclarar el limite cuando es sutil.
  • Se puede formular como pregunta o como afirmación a evaluar por veracidad.
{
  "is_repeat_contact": {
    "type": "noul",
    "instructions": "Has the customer contacted support about this before?",
    "criteria": {
      "true": "Mentions a prior attempt, ticket, or that they have asked before",
      "false": "No sign of any previous contact"
    }
  }
}

Cuidado: “Is the candidate strong in Python?” → definir “strong”. Un noul de 0.5 no significa “nivel medio”; para eso usar Score.

Elegir el tipo

SituaciónTipo
Categorias conocidas sin ordenChoice
Espectro con niveles descriptiblesScore
Si/no limpio donde la probabilidad es la señalNoul

Si dos encajan, preferir el que tu código pueda accionar directamente: Choice → rutas de código, Score → umbral, Noul → if.

Varias preguntas a la vez

  • Enviar todas las preguntas que usan el mismo estado en una sola petición. Se evaluan en paralelo; anadir preguntas apenas cambia el tiempo y solo cuesta tokens (baratos).
  • Incluir preguntas especulativas (que solo importan para algunas entradas) y que el código ignore las irrelevantes: patron Speculative Fan-Out.
  • El limite de preguntas por petición es el presupuesto de tokens (~32k para state + pregunta más larga; ~150.000 caracteres de ingles).
  • Dependencias: las preguntas de una petición son independientes. Si una pregunta posterior depende de una respuesta anterior, hacer una segunda petición en código (solo cuando el código no puede construir la segunda sin la primera). Dos peticiones son la excepción, no la regla.

Referencia rápida de respuesta

TipoCampos
Choicetype, choice, probabilities, confidence
Scoretype, score, legend, probabilities, confidence
Noultype, noul

Relacionado