Artículo

Usando Groq Chat con Spring AI

Usando Groq Chat con Spring AI

1. Visión general

En este tutorial aprenderemos a usar Spring AI para integrarnos con los modelos ofrecidos por el motor de inferencia Groq AI basado en LPU (https://groq.com/), construyendo un chatbot.

Groq expone APIs REST que las aplicaciones pueden invocar para consumir sus servicios. Además, existen SDKs disponibles en varios lenguajes de programación, como Python y JavaScript. En Python, bibliotecas populares como LangChain y LiteLLM también lo soportan. Además, el Vercel AI SDK es una biblioteca basada en JavaScript que tiene un módulo para la integración con Groq.

Las aplicaciones pueden cambiar cómodamente de OpenAI a los servicios de Groq AI porque Groq es totalmente compatible con las bibliotecas cliente de OpenAI. Como resultado, el cliente de chat OpenAI de Spring AI puede conectarse a Groq con cambios mínimos de configuración. Además, Spring AI no proporciona ninguna biblioteca separada para Groq.

2. Prerrequisitos

El framework Spring AI ofrece integración con una infinidad de servicios LLM a través de sus bibliotecas de inicio correspondientes. De manera similar, para integrar con los servicios de Groq, las aplicaciones Spring Boot deben importar la biblioteca de inicio Spring AI OpenAI:

<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
   <version>1.0.0-M6</version>
</dependency>

Normalmente usamos la herramienta Spring Initializr para importar las bibliotecas necesarias de manera óptima.

Finalmente, debemos registrarnos en la nube de Groq y crear una clave API para usarla en la configuración de Spring AI: Clave API de Groq

Cuando los usuarios se registran en la nube de Groq, reciben una suscripción gratuita para comenzar con las APIs de Groq. Sin embargo, Groq aplica límites de tasa específicos del modelo en las solicitudes API para garantizar un uso justo y la disponibilidad.

3. Componentes y configuraciones clave de Spring AI

Para utilizar eficazmente la biblioteca OpenAI de Spring AI para acceder a las APIs de servicio de Groq, es esencial comprender sus clases clave, como OpenAiChatModel y OpenAiChatOptions. La clase OpenAiChatModel es la clase cliente que recibe el objeto Prompt para llamar a los servicios subyacentes de OpenAI.

Sin embargo, para este artículo, demostraremos la conexión al servicio de Groq. Además, la clase OpenAiChatOptions ayuda a especificar el nombre del modelo disponible en Groq, la temperatura, maxTokens y otras propiedades esenciales. La utilizamos cuando necesitamos anular las propiedades predeterminadas del cliente de chat pasando como argumento al método OpenAiChatModel#call(). Finalmente, existen algunas clases generales de Spring AI, como Prompt y ChatResponse, para ayudar a crear el prompt de chat y recibir la respuesta, respectivamente.

Para autoconfiguración del OpenAiChatModel, podemos especificar las configuraciones de chat OpenAI de Spring AI bajo el espacio de nombres spring.ai.openai.chat. Como mínimo, debemos anular la configuración spring.ai.openai.chat.base-url para apuntar al punto final de la API de Groq, que es api.groq.com/openai. Además, debemos establecer la clave API de Groq correspondiente a la propiedad spring.ai.openai.chat.api-key. Como mejor práctica, recomendamos leerla desde una propiedad de entorno o un cofre seguro y luego configurarla en la clave de configuración.

También podemos establecer la URL y las claves API en las configuraciones spring.ai.openai.base-url y spring.ai.openai.api-key. Sin embargo, las claves bajo el espacio de nombres spring.ai.openai.chat tienen prioridad.

4. Autoconfiguración del cliente Groq

En esta sección veremos cómo la clase OpenAiAutoConfiguration crea un bean OpenAiChatModel con la configuración del archivo de propiedades de la aplicación.

Primero, hagamos algunas entradas de configuración importantes de OpenAI en el archivo application-groq.properties:

spring.application.name=spring-ai-groq-demo
spring.ai.openai.base-url=https://api.groq.com/openai
spring.ai.openai.api-key=gsk_XXXX

spring.ai.openai.chat.base-url=https://api.groq.com/openai
spring.ai.openai.chat.api-key=gsk_XXXX
spring.ai.openai.chat.options.temperature=0.7
spring.ai.openai.chat.options.model=llama-3.3-70b-versatile

Como se mencionó anteriormente, en el archivo de propiedades hemos configurado el punto final de la API de Groq, las claves API y un modelo de lenguaje grande. Curiosamente, también hemos especificado el punto final de la API y las claves en el espacio de nombres spring.ai.openai. Dado que algunas de las beans de Spring AI dependen de ellos, la aplicación no iniciará en su ausencia.

A continuación, definamos una clase Spring GroqChatService personalizada que será responsable de llamar al servicio Groq:

@Service
public class GroqChatService {
    @Autowired
    private OpenAiChatModel groqClient;

    public String chat(String prompt) {
        return groqClient.call(prompt);
    }

    public ChatOptions getChatOptions() {
        return groqClient.getDefaultOptions();
    }
}

El bean OpenAiAutoConfiguration instancia la clase OpenAiChatModel con las propiedades del archivo de configuración, junto con algunas propiedades predeterminadas. En la clase de servicio, hemos autoinyectado el bean OpenAiChatModel de Spring. El método GroqChatservice#chat() usa su método call() para invocar el servicio Groq. Además, el método GroqChatService#getChatOptions() devuelve el objeto ChatOptions que contiene las configuraciones del cliente de chat.

Finalmente, veamos el cliente de chat Groq en acción con la ayuda de una prueba JUnit:

void whenCallOpenAIClient_thenReturnResponseFromGroq() {
    String prompt = """
      Context:
      Support Ticket #98765:
      Product: XYZ Wireless Mouse
      Issue Description: The mouse connects intermittently to my laptop.
      I've tried changing batteries and reinstalling drivers, 
      but the cursor still freezes randomly for a few seconds before resuming normal movement.
      It affects productivity significantly.
      Question:
      Based on the support ticket, what is the primary technical issue
      the user is experiencing with their 'XYZ Wireless Mouse'?;
     """;
    String response = groqChatService.chat(prompt);
    logger.info("Response from Groq:{}", response);

    assertThat(response.toLowerCase()).isNotNull()
      .isNotEmpty()
      .containsAnyOf("laptop", "mouse", "connect");

    ChatOptions openAiChatOptions = groqChatService.getChatOptions();
    String model = openAiChatOptions.getModel();
    Double temperature = openAiChatOptions.getTemperature();

    assertThat(openAiChatOptions).isInstanceOf(OpenAiChatOptions.class);
    assertThat(model).isEqualTo("llama-3.3-70b-versatile");
    assertThat(temperature).isEqualTo(Double.valueOf(0.7));
}

El bean groqChatService de Spring está autoinyectado en la clase que contiene el método de prueba. El método invoca groqChatService#chat() con un prompt que consiste en una pregunta y un contexto pertinente incrustado en él. El contexto incluye información sobre un ticket de soporte levantado sobre un ratón de computadora. En la mayoría de los casos, en una aplicación del mundo real, se recupera un contexto correspondiente a una consulta de usuario desde una base de datos vectorial. A continuación, el servicio Groq responde con una respuesta que hace referencia al contexto:

The primary technical issue the user is experiencing with their 
'XYZ Wireless Mouse' is intermittent connectivity, resulting in the
cursor freezing randomly for a few seconds before resuming normal movement.

Finalmente, al final, el método verifica que las opciones de chat, como el modelo y la temperatura, coincidan con los valores de configuración del archivo de propiedades.

5. Personalizar el cliente Groq

Hasta ahora, hemos usado las configuraciones de Spring AI en el archivo de propiedades de la aplicación para ayudar a autoconfiguración del cliente de chat. Sin embargo, en las aplicaciones del mundo real, terminaremos de personalizándolo para establecer propiedades como modelo, temperatura, etc.

Primero, definamos un bean OpenAiChatModel personalizado en una clase de configuración Spring:

@Configuration(proxyBeanMethods = false)
public class ChatAppConfiguration {
    @Value("${groq.api-key}")
    private String GROQ_API_KEY;

    @Value("${groq.base-url}")
    private String GROQ_API_URL;

    @Bean
    public OpenAiChatModel customGroqChatClient() {
        OpenAiApi groqOpenAiApi = new OpenAiApi.Builder()
          .apiKey(GROQ_API_KEY)
          .baseUrl(GROQ_API_URL)
          .build();
        return OpenAiChatModel.builder()
          .openAiApi(groqOpenAiApi)
          .build();
    }
}

El método ChatAppConfiguration#customGroqChatClient() en la clase construye un bean OpenAiChatModel usando la clase de bajo nivel OpenAiApi. Aquí, leemos la clave API y la URL de un archivo de propiedades. Además, también podemos modificar la clase para incluir lógicas complejas y leerlas de sistemas descendentes. Cuando la aplicación Spring Boot se inicia, el objeto del cliente de chat está disponible como un bean de Spring con el nombre customGroqChatClient.

A continuación, definamos una clase de servicio Spring Boot donde podamos autoinyectar el bean OpenAIChatModel personalizado que construimos en la clase de configuración Spring:

@Service
public class CustomGroqChatService {
    @Autowired
    private OpenAiChatModel customGroqChatClient;

    public String chat(String prompt, String model, Double temperature) {
        ChatOptions chatOptions = OpenAiChatOptions.builder()
          .model(model)
          .temperature(temperature)
          .build();
        return customGroqChatClient.call(new Prompt(prompt, chatOptions))
          .getResult()
          .getOutput()
          .getText();
    }
}

En el método chat(), establecemos las configuraciones del cliente de chat, como model y temperature, en el objeto ChatOptions. Además, pasamos el prompt y el objeto ChatOptions al método customGroqChatClient#call() y finalmente extraemos el texto de la respuesta del objeto ChatResponse.

A continuación, veamos el cliente Groq personalizado en acción en una prueba JUnit:

void whenCustomGroqClientCalled_thenReturnResponse() {
    String prompt = """
      Context: 
      The Eiffel Tower is one of the most famous landmarks
      in Paris, attracting millions of visitors each year.
      Question:
      In which city is the Eiffel Tower located?
    """;
    String response = customGroqChatService.chat(prompt, "llama-3.1-8b-instant", 0.8);

    assertThat(response)
      .isNotNull()
      .isNotEmpty()
      .contains("Paris");
    logger.info("Response from custom Groq client: {}", response);
}

La prueba inicia una llamada al método chat() del bean customGroqChatService autoinyectado, pasando el prompt (que comprende contexto y una pregunta relacionada), model y temperature. El método CustomGroqChatService#call() luego proporciona una respuesta. Posteriormente, validamos que la respuesta aborde con precisión la pregunta: ¿En qué ciudad se encuentra la Torre Eiffel?.

Finalmente, veamos la respuesta de Groq:

The Eiffel Tower is located in Paris, France.

6. Conclusión

En este artículo, destacamos la integración del motor de inferencia Groq con la biblioteca OpenAI de Spring AI. Además, la biblioteca permite usar la función de herramientas de Groq para registrar e invocar herramientas externas para acción.

Desafortunadamente, Groq tiene limitaciones en el soporte de modelos multimodales, y por lo tanto, Spring AI también carece de esa función. Inherentemente, Groq no es totalmente compatible con OpenAI. Por lo tanto, debemos ser conscientes de estas restricciones al usar su API.

Newsletter Semanal de Java

Cada viernes recibe lo más nuevo del ecosistema Java: frameworks, herramientas y mejores prácticas.

Sin spam. Cancela cuando quieras.

Compartir artículo