En el post anterior se realizó la primera inmersión en Spring AI y sus APIs. Hablamos de clases como ChatClient y ChatModel, que son las principales para interactuar con los LLMs. En este post seguimos examinando el módulo para ver features como la multimodularidad, prompts o algo tan transversal como la observabilidad en los modelos.

Multimodularidad

Los seres humanos obtenemos nuestros conocimientos desde varias “fuentes de datos” (imágenes, sonido, texto, etc), por lo que se puede decir que nuestras experiencias son multimodales. Por el contrario, el Machine Learning se había enfocado hacia una única modalidad hasta que, recientemente, empezaron a aparecer modelos que pueden procesar varias entradas como imagen y texto o audio y vídeo al mismo tiempo.

La multimodularidad se refiere a la capacidad del modelo de poder procesar información de varias fuentes y Spring AI, a través de su Message API, ofrece este soporte. El campo content de la clase UserMessage se usa para textos, mientras que el campo media permite añadir contenido adicional de otras formas como imágenes, audio y vídeo, indicado por el MimeType correspondiente.

@RestController
public class MultimodalController {

    private OllamaChatModel chatModel;
    
    public MultimodalController(OllamaChatModel chatModel) {
        this.chatModel = chatModel;
    }

    @GetMapping("/multimodal")
    String multimodal() {


    ClassPathResource imageResource = new ClassPathResource("/static/multimodal.jpg");

    UserMessage userMessage = new UserMessage("Explicame lo que ves en la imagen", new Media(MimeTypeUtils.IMAGE_JPEG, imageResource));

    return chatModel.call(new Prompt(List.of(userMessage))).getResult().getOutput().getText();
    }
    
}

Para verlo en un ejemplo, pediremos una descripción sobre la siguiente imagen:

brazo de un robot señalando hacia arriba sobre un fondo azul con puntos blancos unidos por líneas blancas

Se obtienen respuestas como:

La imagen muestra un fondo azul con una serie de puntos blanca, similares a una constellación estrellada o a un mapa de estrellas. En primer plano, there is a person holding what appears to be a smartphone or tablet in their hands, with the screen showing more of these white points, possibly indicating connectivity or data transmission. The overall effect gives the impression of digital interconnectivity, with the human element suggesting that technology is an essential part of our lives.
1 Lo que vemos en la imagen es una escena de un entorno futurista o tecnológico. Atrás, hay una figura iluminada por una fuente de luz blu, con las silhouetas de varios puntos de datos o nodos conectores que forman una red. Esto sugiere que el entorno es un lugar en donde se trabaja con tecnologías avanzadas, tal vez relacionado con redes neuronales, IoT (Internet of Things), Big Data o similares. 2 3 En primer plano, una mano emergente de la izquierda del cuadro parece estar alcanzar o manipulando la red de datos virtuales. Esta acción puede representar el control o manipulación de los sistemas de datos en tiempo real, lo que podría indicar un contexto de seguridad, desarrollo de aplicaciones o ciencia. 4 5 El ambiente es oscuro, pero la iluminación azul crea una atmósfera mágica y tecnológica, lo que combina elementos de fantasía con la realidad de la tecnología. La imagen parece ser parte of a presentación o material promocional relacionado con la tecnologia y su impacto en el futuro.

Como se ve, el modelo usado puede producir respuestas extrañas incluso mezclando idiomas. Otro aspecto importante a tener en cuenta es el tiempo de respuesta (en general a todas las llamadas al modelo), por lo que es importante manejar la asincronía además de la mejora de rendimiento en el código (como por ejemplo con virtual-threads).

Prompts

Como se mencionó anteriormente, los prompts son las entradas que se envían a los modelos. El diseño y cómo están estructurados influyen significativamente en las respuestas de los modelos. En última instancia, Spring AI maneja los prompts con los modelos de la misma forma que se maneja la capa “vista” en Spring MVC. Esto implica la creación de marcadores que se sustituyen por el valor correspondiente para enviar contenido de forma dinámica.

La estructura de los prompts ha ido evolucionando con la IA, al principio eran simples strings y han ido creciendo hasta existir algunos que pueden incluir placeholders para entradas concretas (como por ejemplo USER:<usuario>). OpenAI ha creado prompts más estructurados categorizando distintos strings en distintos roles.

Roles

A cada mensaje se le asocia un rol. Los roles categorizan el mensaje aportando contexto y finalidad para el modelo, permitiendo mejorar la eficacia en las respuestas. Los roles básicos son:

En Spring AI, los roles son un enumerado.

public enum MessageType {

    USER("user"),

    ASSISTANT("assistant"),

    SYSTEM("system"),

    TOOL("tool");

    ...
}

Prompt Template

La clase PromptTemplate es la clave en la gestión de plantillas para los prompts, facilitando la creación de prompts estructurados.

public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {}

Las interfaces que implementa la clase proporcionan distintos aspectos para la creación de prompts:

Algunos ejemplos de usos de PromptTemplate:

@GetMapping("/simple")
String simplePromptTemplate(@RequestParam String adjective, @RequestParam String country) {

    PromptTemplate promptTemplate = new PromptTemplate("Give a {adjective} city from {country}");

    Prompt prompt = promptTemplate.create(Map.of("adjective", adjective, "country", country));

    return chatModel.call(prompt).getResult().getOutput().getText();
}
@GetMapping("/system")
String systemPromptTemplate(@RequestParam String tema) {

    String userText = """
            Dame información sobre Barcelona.
            Responde por lo menos con como mínimo 5 líneas.
            """;

    Message userMessage = new UserMessage(userText);

    String systemText = """
            Eres una asistente de IA que ayuda a la gente con información sobre ciudades.
            Tienes que responder con información de la ciudad sobre el tema {tema}.
            Responde como si estuvieras creando un blog de viajes
            """;

    SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
    Message systemMessage = systemPromptTemplate.createMessage(Map.of("tema", tema));

    Prompt prompt = new Prompt(List.of(userMessage, systemMessage));

    return chatModel.call(prompt).getResult().getOutput().getText();
}

Además de usar Strings para la creación de prompts, Spring AI soporta la creación de prompts a través de recursos (Resource), permitiendo indicar el prompt en un fichero que luego pueda ser usado como PromptTemplate:

@Value("classpath:/static/prompts/system-message.st")
private Resource systemResource;

SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);

Prompt Engineering

Como se mencionaba anteriormente, la calidad y estructura de los prompts tienen una gran repercusión en las respuestas del modelo, llevando esto a generar una nueva profesión. En la comunidad de desarrollo se analiza y comparte continuamente la forma de mejorar los prompts en distintas situaciones, lo que deriva en algunos puntos importantes para la creación de prompts eficientes como:

En la propia documentación de Spring nos enlazan a múltiples recursos para mejorar los prompts, existiendo también en internet una gran comunidad dedicada a esta tarea.

Observabilidad

Como en cualquier framework/módulo de Spring existente, no puede faltar la sección de observabilidad, puesto que es clave de cara a mantener y comprender cómo funcionan las aplicaciones, sobre todo cuando aparecen los problemas. Spring AI proporciona métricas y trazas sobre los distintos componentes comentados en las secciones anteriores como pueden ser ChatClient, ChatModel y otros que se comentarán más adelante.

Algunas de las métricas y trazas que se pueden encontrar ofrecen información como los parámetros que se le indican al modelo, tiempos de respuesta, tokens y modelos usados, etc. Se debe tener especial cuidado en los valores que se pintan en los logs, puesto que se puede filtrar información sensible de los usuarios. En la documentación se pueden encontrar los distintos datos que se pueden visualizar.

Habilitando las trazas con las dependencias de Actuator, Zipkin y Opentelemetry se pueden ver algunas métricas como:

listado de métricas que se pueden habilitar

De las que se pueden extraer datos como tokens, modelos usados, tiempos, etc.

Extracción métricas del token
Extracción de métricas gen ai client operation

Además, al habilitar la trazabilidad con Zipkin y Opentelemetry, también se obtendrán las trazas en el servidor Zipkin:

Pantallazo de las trazas en el servidor zipkin
Trazas en el servidor zipkin

Si nos fijamos, podemos ver el input del usuario (propiedad spring.ai.chat.client.user.text). Esto es posible porque se ha habilitado con la propiedad spring.ai.chat.client.observations.include-input, aunque hay que indicar que se deben extremar las precauciones porque se puede exponer información sensible del usuario (también nos lo indica Spring AI con un warning en las trazas).

Aviso de spring AI para tener en cuenta que puede exponerse información sensible

Demo con Ollama

Con todos los conocimientos previos, ya podemos crear una demo con Ollama. Una vez se tiene Ollama habilitado en el sistema, se crea la app con distintos endpoints que permiten comprobar el funcionamiento de las distintas features de Spring AI:

1 ¡Hola! Me alegra que estés buscando un destino emocionante para tu próximo viaje. Aquí te presento tres opciones de ciudades con menos de 50.000 habitantes que podrían interesarte: 3 1. Plassey, Bangladés (alrededor de 3.200 personas): Esta ciudad es un destino emblemático en el este del país y ofrece una rica historia y cultura. Puedes visitar el famoso castillo de Bagerhat, disfrutar de la comida local y explorar las avenidas históricas. 4 2. Kochi, India (alrededor de 3.200 personas): Conocida como la "Cidade Perdida" por su arquitectura colonial, Kochi es un destino perfecto para aquellos que buscan una mezcla de historia, arte y naturaleza. Puedes explorar el puerto, visitar el Castillo de Fort Kochi y disfrutar del clima agradable. 5 3. Syracuse, Sicilia, Italia (alrededor de 70.000 personas): Esta ciudad es un destino encantador en la costa sur de Italia, con una rica historia, arte y cultura. Puedes visitar el Palacio Real, explorar las avenidas históricas y disfrutar del clima mediterráneo.
1 ¡Hola! Me alegra que estés buscando un destino emocionante para tu próximo viaje. 2 3 Quiero recomendarte tres lugares increibles que son muy atractivos desde la perspectiva de una ciudad pequeña con menos de 1000 habitantes. Estos lugares ofrecen una experiencia única y auténtica: 5 1. Puerto Montt, Chile: Con un poblado de solo 1100 habitantes, Puerto Montt es un destino ideal para aquellos que buscan una experiencia de aventura en la naturaleza. La ciudad es rodeada de montañas y bosques, lo que la convierte en un lugar perfecto para caminar, senderismo o simplemente disfrutar del paisaje. 6 2. Cuenca, Ecuador: Con un poblado de solo 2500 habitantes, Cuenca es una ciudad colonial que ha sido declarada Patrimonio de la Humanidad por la UNESCO. La ciudad es conocida por su arquitectura impresionante, sus calles empedradas y su cultura rica. También ofrece una gran variedad de actividades como senderismo, ciclismo y degustación de vino.
{
    "result": {
        "output": {
            "messageType": "ASSISTANT",
            "metadata": {
                "messageType": "ASSISTANT"
            },
            "toolCalls": [],
            "media": [],
            "text": "..."
        },
        "metadata": {
            "finishReason": "stop",
            "contentFilters": [],
            "empty": true
        }
    },
    "metadata": {
        "id": "",
        "model": "llama3.2:1b",
        "rateLimit": {
            "requestsLimit": 0,
            "requestsRemaining": 0,
            "requestsReset": "PT0S",
            "tokensLimit": 0,
            "tokensRemaining": 0,
            "tokensReset": "PT0S"
        },
        "usage": {
            "promptTokens": 34,
            "completionTokens": 428,
            "totalTokens": 462
        },
        "promptMetadata": [],
        "empty": false
    },
    "results": [
        {
            "output": {
                "messageType": "ASSISTANT",
                "metadata": {
                    "messageType": "ASSISTANT"
                },
                "toolCalls": [],
                "media": [],
                "text": "..."
            },
            "metadata": {
                "finishReason": "stop",
                "contentFilters": [],
                "empty": true
            }
        }
    ]
}
Travel recommendation / entity

Como apunte, este endpoint es muy susceptible de fallar puesto que la transformación correcta de la respuesta en formato JSON falla mucho (es una de las grandes features pendientes de Spring AI y de los modelos, puesto que en muchas ocasiones no crean JSON en formato correcto).

1 ¡Claro! Aquí te dejo 5 nombres de ciudades inventados: 2 3 1. Aerthys - una ciudad ubicada en un valle rodeado de montañas y conocida por su belleza natural. 4 2. Eldrida - una ciudad medieval con murallas antiguas y un puente histórico que cruza el río. 5 3. Nyxoria - una ciudad futurista ubicada en la costa oeste, conocida por sus torres de energía solar y su vibrante vida nocturna. 6 4. Luminaria - una ciudad encantadora con calles pavimentadas de piedra blanca y edificios con techos de cristal que reflejan el sol. 7 5. Caelum - una ciudad en el centro del país, conocida por su arquitectura moderna y sus jardines botánicos impresionantes.
Madrid is the capital and largest city of Spain. It is located in the center of the country and is known for its rich history, vibrant culture, and modern architecture. Some popular attractions in Madrid include the Royal Palace, Prado Museum, Puerta del Sol, and Retiro Park.
¡Hola! Como asistente de IA, estoy encantado de ayudarte con cualquier pregunta que tengas sobre la ciudad de Barcelona. Barcelona es una ciudad emocionante y vibrante situada en el noreste de España. Es conocida por sus bellas playas, su arquitectura única y sus deliciosos platos típicos como la paella y el calamares a la romana. Además, es una ciudad que se ha desarrollado en una de las áreas más tecnológicas del mundo. Es conocida por ser un pionero en el sector tecnológico con empresas líderes en el campo como La Caixa Móvil, Vodafone y Nokia, entre otras. innovación en los campos de la ciencia y la salud. Hay un gran número de empresas y startups que se dedican a desarrollar soluciones tecnológicas que pueden cambiar el mundo. Si estás interesado en la tecnología, es posible que quieras visitar algunas de las empresas más importantes de la ciudad o incluso asistir a eventos y congresos sobre tecnología que se realizan regularmente en Barcelona. También puedes visitar los museos científicos, como el Museo de Ciencias Naturales y Tecnológicos, para aprender más sobre la tecnologia y sus avancements. Si estás pensando en mudarse o trabajar a Barcelona, es importante tener en cuenta que esta ciudad también tiene una gran cantidad de instituciones educativas y universidades, como la Universidad de Barcelona y la Universidad Pompeu Fabra, que ofrecen diversos programas y especializaciones en tecnologia. En resumen, si estás interesado en la tecnología, Barcelona es una ciudad emocionante y vibrante que se encuentra liderando el campo tecnológico.
Londres es una ciudad llena de historia y cultura, situada en el sur de Inglaterra. Es conocida por ser uno de los centros financieros más importantes del mundo, con numerosos bancos y empresas que tienen sus sedes aquí. En cuanto a la negociación y el comercio, Londres cuenta con una vasta gama de oportunidades de trabajo en diferentes ámbitos. La ciudad alberga importantes empresas multinacionales, así como numerosas pequeñas y medias empresas que contribuyen al crecimiento económico. 5 Además, la ciudad cuenta con un importante número de ferias y eventos comerciales que se realizan a lo largo del año. Algunos ejemplos de estos eventos son la Feria Internacional de Moda y Accesorios, el Salón del Automóvil de Londres o la Feria de Exposiciones Internacionales de London. Pero no solo es una ciudad de negocios, sino que también ofrece a los visitantes un ambiente cultural rico y variado. Conocido por su arquitectura gótica y neoclásica, la ciudad cuenta con numerosos monumentos y edificios de importancia histórica y artística. También es una ciudad conocida por sus museos y galerías de arte, que albergan colecciones valiosas y destacadas. 9 Por último, la gastronomía en Londres es una experiencia única. La ciudad cuenta con numerosos restaurantes y pubs que ofrecen comida tradicional inglesa así como cocinas de diferentes partes del mundo. En resumen, Londres es una ciudad que ofrece a los visitantes una combinación única de cultura, historia y negocios.

En la aplicación se incluyen las dependencias y propiedades necesarias para tener observabilidad sobre las distintas peticiones realizadas a los modelos. De cara a exportar las trazas a un servidor Zipkin, se puede habilitar un servidor local de Zipkin con Docker mediante el comando:

docker run -d -p 9411:9411 openzipkin/zipkin

En general, también hay que indicar que, dependiendo del prompt indicado y de la precisión del modelo, se pueden encontrar respuestas sin sentido o que no cumplan los requisitos establecidos, pudiendo producirse errores de formato o incluso de memoria, mostrándose trazas como:

java.lang.RuntimeException: [500] Internal Server Error - {"error":"model requires more system memory (6.1 GiB) than is available (5.3 GiB)"}

Puedes descargar el código de la aplicación de ejemplo en este enlace.

Conclusión

En esta segunda parte de la serie de Spring AI, hemos podido ver cómo ejecutar modelos multimodales además de cómo gestionar la entrada al modelo de distintas formas a través de los prompts. Otro apartado siempre importante en los módulos de Spring es la observabilidad, ofreciendo en este caso las métricas correspondientes al comportamiento de los modelos empleados, importantes tanto para el buen funcionamiento de las aplicaciones como para la posible facturación de los LLMs.

Si bien es cierto que lo visto hasta ahora se puede considerar como el “Hello world” dentro de la IA, hay que tener en cuenta que es la parte más básica del módulo de Spring AI y que ya nos ofrece una multitud de opciones a tener en cuenta en los distintos casos de uso de la vida real, especialmente enfocado en los chatbots.

En sucesivos posts revisaremos otras funciones más avanzadas de Spring AI. ¡Te leo en comentarios! 👇

Referencias

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete