Primero voy a confesar algo: el año pasado apunté un modelo de clase frontera a la pregunta «¿este comentario es spam?» y pagué el precio completo por cada respuesta, en dinero y en los 800 milisegundos que mis usuarios pasaban mirando un spinner. Ya entonces parecía absurdo y ahora queda peor, porque Laravel AI SDK acaba de publicar la v1.0.0 y la pieza a la que sigo volviendo es la más pequeña. La clasificación ahora es una capacidad de primera clase, corriendo sobre Jev, un modelo de TypeSafe construido para exactamente un trabajo: responder rápido preguntas baratas de sí o no y de elegir una opción. Aquí va mi tesis, y la voy a defender: la mayoría de lo que los product managers llaman «funciones de IA» en una aplicación web típica son problemas de clasificación, y que un framework por fin lo diga en voz alta importa más que cualquier widget de chat.

TicketTriage.php
<?php

use Laravel\Ai\Classification;
use Laravel\Ai\Classification\Boolean;
use Laravel\Ai\Classification\Choice;

$response = Classification::of($ticket->body)->questions([
    'is_urgent' => new Boolean('Does this message convey urgency?'),
    'department' => new Choice('Which team should handle this?', [
        'billing' => 'Payments, invoicing, refunds',
        'technical' => 'Bugs, outages, integrations',
        'sales' => 'Pricing, plans, upgrades',
    ]),
])->classify();

La API refleja esa honestidad. Le pasas a Classification::of() el cuerpo de un ticket, le adjuntas una pregunta Boolean sobre urgencia y una pregunta Choice sobre qué equipo es responsable, llamas a classify() y obtienes respuestas estructuradas sobre las que puedes ramificar tu lógica. Para el caso de una sola línea existe incluso una macro Str::decide(), lo que significa que el chequeo de spam por el que pagué de más ahora es un método de string. Triaje de tickets de soporte, moderación de comentarios, enrutado, marcado: nada de esto necesita un modelo capaz de escribir sonetos. Necesita un veredicto rápido e inspeccionable, y necesita costar tan poco que nunca pienses en la factura.

¿Por qué importa que el framework le ponga nombre a esto? Porque los valores por defecto moldean a los equipos. Cuando la única herramienta en laravel/ai era «envía un prompt a un modelo grande», cada decisión trivial acababa pasando por el camino más caro disponible, igual que antes cada problema de datos recibía una instancia de Redis lo necesitara o no. En cuanto el framework ofrece un carril dedicado para decisiones pequeñas, la conversación en tus revisiones de código cambia. Alguien echa mano de una llamada de generación completa para comprobar si un mensaje transmite urgencia, y ahora un colega puede señalar Classification y preguntar por qué. Ese efecto social vale más que la mejora de latencia, y la mejora de latencia es real.

El contraargumento honesto merece su espacio. La clasificación de momento habla con dos proveedores, TypeSafe y OpenRouter, y me incomoda un poco que un SDK oficial se estrene con el modelo a medida de un solo proveedor como estrella. Los modelos pequeños también se pierden matices, y un «no urgente» mal etiquetado es un cliente real esperando toda la noche. Aun así mantengo mi postura, por dos razones. Primera, el equipo de Laravel dice que más proveedores se conectarán a la misma API, y la abstracción está claramente construida para eso. Segunda, los modelos grandes también se equivocan en el triaje, a treinta veces el coste, y una salida booleana es trivialmente fácil de registrar, muestrear y auditar. Si puedes medir la tasa de error, puedes gestionarla. Eso nunca podrías decirlo de un párrafo de razonamiento en texto libre.

El resto de la versión 1.0 respalda la historia de madurez. El contrato Approvable permite que un agente se detenga y espere a un humano antes de ejecutar una herramienta arriesgada, y puedes rechazar la llamada con una razón que el modelo realmente ve, o editar los argumentos antes de que se ejecute. Esa es la diferencia entre una demo de agente y un agente que conectarías a cualquier cosa que borre datos. El streaming ahora habla de forma nativa los protocolos Vercel Chat y AG-UI, ToolSearch carga de forma perezosa las herramientas poco usadas en OpenAI y Anthropic, y el middleware se ejecuta en cada paso de generación en lugar de una vez por prompt. El cambio incompatible que debes conocer: el historial de conversación se movió a una única columna steps, así que si consultabas las columnas antiguas directamente, reserva tiempo para la migración. El equipo sugiere dejar que el comando /upgrade-ai-sdk-v1 de Laravel Boost guíe al asistente de tu editor durante el proceso, lo cual es un uso agradablemente circular de la tecnología.

Mientras tanto, Laravel 13.33 llegó con el tipo de arreglos que solo aprecias si te han mordido antes. El atributo #[Refreshes] resuelve por fin el problema del modelo desactualizado con columnas calculadas en la base de datos: creas una fila cuyo net_salary sale de una expresión storedAs y, hasta la 13.32, tu objeto de Eloquent simplemente no tenía ese valor a menos que llamaras a refresh() y lo recargaras todo. Ahora el framework recupera solo las columnas indicadas con una pequeña consulta acotada después de cada guardado. Una advertencia que conviene respetar: esa consulta se dispara en cada guardado de ese modelo, así que si necesitas el valor en un único sitio, el refresh() manual sigue siendo el mejor trato. Que Cache::memo() gane soporte de tags es la otra joya, porque te ahorra viajes repetidos a Redis por la misma comprobación de permisos dentro de una sola petición. Suma que AsCollection::nullable() por fin guarda un NULL de verdad en lugar del string "null", y tienes una versión menor que se gana el sueldo.

Da un paso atrás y las dos versiones riman. Usa la herramienta más pequeña que responda la pregunta, ya sea un modelo de decisión hecho a medida o una consulta de seguimiento de una sola columna en lugar de recargar la fila entera. La gente de Go lleva años predicando el dimensionamiento justo mientras nosotros atornillábamos otra capa encima tan contentos, así que resulta satisfactorio ver a Laravel convertir la frugalidad en una funcionalidad oficial. Ahora dime dónde trazas tú la línea: ¿qué decisión de tu codebase le entregarías mañana a un clasificador, y cuál no dejarías nunca que un modelo tomara sin un humano en el bucle, por barata que sea la llamada?