Ir al contenido
angel.library

Laya: decisiones tipadas estilo Jev con encoders que corren en local

Laya es una alternativa de código abierto a Jev, el modelo System One de TypeSafe. Igual que Jev y que Kev, no genera texto: recibe un estado (un ticket, un correo, un JSON) y un conjunto de preguntas tipadas, y devuelve para cada una un valor estructurado con su distribución de probabilidad.

  • Corre en tu máquina: los datos no salen de ahí.
  • Tres tipos de pregunta: choice (elegir una opción), score (una nota en una escala) y noul (probabilidad de que la respuesta sea “sí”).
  • Una sola pasada hacia delante para todas las preguntas: unos 33 ms por pregunta en una GPU T4, según el README.
  • Más de 100 idiomas, con un router que elige el checkpoint según el idioma del texto.
  • Se puede entrenar con tus datos: el fine-tuning es donde está la mayor parte de la precisión.
  • Servidor HTTP compatible con Jev: un cliente que ya habla con Jev solo necesita cambiar la URL base.

Un detalle de nombre: la pregunta de sí/no se llama noul, no null. Es el término que usa la API de Jev y Laya lo conserva para ser compatible.

Un LLM normal es autorregresivo: genera la respuesta token a token, y cada token depende de los anteriores. Para clasificar algo hay que pedirle “devuelve JSON”, esperar el texto y parsearlo, con el riesgo de que invente una categoría o rompa el formato.

Laya es un encoder (de la familia de BERT): lee todo el texto de una vez y una cabeza de decisión puntúa cada opción en la misma pasada. Como no escribe nada, no hay texto que parsear ni categorías inventadas: la respuesta siempre es una de las opciones que tú definiste.

CheckpointEncoderParámetrosContextoPara qué
layaModernBERT-large421M512 tokensInglés
laya-multilingualmmBERT-base322M1.024 (hasta 8.192)Más de 100 idiomas, unas 2 veces más rápido
laya-typed-decisionsModernBERT-large421M1.024 tokensAjustado a los flujos del benchmark de decisiones tipadas

El Router detecta el alfabeto y el idioma del estado y envía el texto en inglés a laya y el resto a laya-multilingual. Se puede forzar un checkpoint con model= o dar una pista de idioma con lang= / lang_guess=.

Los modelos se entrenan con RLCD: aprendizaje por refuerzo con recompensas basadas en reglas de puntuación estrictamente propias, la técnica que busca que una probabilidad de 0,8 signifique de verdad “acierta 8 de cada 10 veces”.

Ventana de terminal
pip install laya

Extras opcionales según lo que necesites:

Ventana de terminal
pip install "laya[serve]" # servidor HTTP compatible con Jev
pip install "laya[mcp]" # servidor MCP para agentes
pip install "laya[langchain]" # integración con LangChain y LangGraph

También hay extras para LlamaIndex, CrewAI, ONNX Runtime y una ruta rápida en GPU con TileLang, y un paquete para Node.js y navegador (laya-ts).

from laya import Router
router = Router() # descarga el checkpoint la primera vez
state = "Hi, we were billed twice for March. Please refund the duplicate today or we will cancel our plan."
questions = {
"department": {"type": "choice", "instructions": "Which department should handle this?",
"criteria": {"billing": "invoices, payments, refunds",
"technical": "bugs, outages, system errors",
"other": "everything else"}},
"urgency": {"type": "score", "instructions": "How urgent is this?",
"criteria": ["not urgent", "soon", "blocking"]},
"churn_risk": {"type": "noul", "instructions": "Does the user threaten to cancel or leave?"},
}
result = router.predict(state, questions)
print(result["answers"]["department"]["choice"]) # billing
print(result["answers"]["churn_risk"]["noul"]) # probabilidad de "sí"
print(result["routing"]["model"]) # english

La misma llamada con un texto en español o en hindi se enruta sola a laya-multilingual.

El paquete instala un comando laya:

Ventana de terminal
laya "I was charged twice, please refund" # solo la decisión de enrutado, sin descargar nada
laya "My payment failed twice" --predict # respuestas completas
laya "My payment failed twice" --preset triage # conjunto de preguntas predefinido
laya "Where is my card" --questions intents.json # tus propias preguntas en un JSON
cat tickets.txt | laya --batch - --predict --json # un lote desde stdin

Los presets incluidos cubren cinco casos: router entre modelos pequeños y frontera, guardarraíles de prompts (jailbreaks e inyecciones), moderación de contenido, triaje de tickets y triaje de correo.

Ventana de terminal
pip install "laya[serve]"
LAYA_DEVICE=cuda LAYA_PRELOAD=1 laya-serve # escucha en 0.0.0.0:8000
Ventana de terminal
curl -s localhost:8000/v1/systemone -H 'content-type: application/json' -d '{
"state": {"body": "billed twice, refund please or we cancel"},
"questions": {"dept": {"type": "choice", "instructions": "which team?",
"criteria": {"billing": "refunds", "tech": "bugs"}}}
}'

Expone POST /v1/systemone y /v1/systemone/batch (hasta 64 estados) con el mismo protocolo que la API alojada de Jev. Con LAYA_API_KEY exige un token bearer. Al migrar un cliente de Jev cambian tres cosas:

  • Opciones por pregunta: Jev acepta hasta 255; Laya reparte un presupuesto de tokens entre ellas y el servidor corta en 100.
  • Niveles de score: todos necesitan descripción; un nivel null devuelve 422.
  • confidence se calcula con otra fórmula (1 menos la entropía normalizada), así que un umbral que funcionaba en Jev no sirve tal cual. Para un número calibrado en todos los tipos, usa answer_confidence.

Para agentes, laya-mcp-server expone las mismas decisiones como herramientas MCP (laya_predict, laya_route, laya_preset…).

Este es el punto que más pesa. En el benchmark de decisiones tipadas (2.000 decisiones en cuatro flujos de trabajo):

ModeloPrecisión
Elección aleatoria0,318
laya base, sin ajustar0,362
Clase mayoritaria0,461
Jev (cifra publicada por TypeSafe)0,727
laya-typed-decisions (ajustado)0,766

Es decir: los modelos base no aportan casi nada en ese benchmark; toda la capacidad viene del ajuste. El repositorio trae un notebook para Kaggle (dos T4 gratuitas, unas 4 a 5 horas para 4 épocas sobre ~30.000 preguntas) y un script para Apple Silicon que hace todo el ciclo: preparar el dataset, entrenar con RLCD, calibrar temperaturas, evaluar y exportar.

Ventana de terminal
python notebooks/laya_finetune_typed_decisions_mps.py --micro-batch 1 --grad-accum 32
JevKevLaya
TipoAPI alojada, sin pesos abiertosLoRA sobre Qwen (0.8B a 27B)Encoders BERT (322M y 421M)
Dónde correServidores de TypeSafeTu GPU o MacCPU, GPU o Mac
Latencia236–276 ms p50 medidos por tercerosDepende del tamaño~33 ms por pregunta en T4
Opciones por preguntaHasta 255Hasta 255Bien hasta ~20; tope de 100 en el servidor
Sin ajustarListo para usarBastante preciso desde 4BCerca del azar en decisiones tipadas

Laya gana en coste de hardware y velocidad; a cambio, exige entrenarlo para tu dominio. Si no quieres entrenar nada, Jev alojado o un Kev de 4B en adelante son mejores puntos de partida.

  • Etiquetas booleanas: en preguntas choice, claves como true/false o yes/no pueden confundir al modelo. Usa etiquetas con significado o neutras (A/B).
  • Negaciones: en los ejemplos del issue #377, “no quiero cancelar” se clasificó como cancel_account en varios casos, incluso con probabilidad 0,9998. Valida frases negadas con tus datos.
  • Calibración: el README reconoce que ambos checkpoints salen demasiado seguros de sí mismos y que laya-multilingual no trae temperaturas ajustadas. Calibra antes de fijar umbrales.
  • Documentos largos: laya-multilingual lee hasta 8.192 tokens con max_len=8192, pero por encima de ~4.000 tokens la precisión varía mucho.