Alimentando LLMs con Apache Camel y LangChain4j

Los LLMs necesitan conectarse al mundo real. Las herramientas de LangChain4j, combinadas con Apache Camel, hacen que esto sea fácil. Camel proporciona una integración robusta, conectando tu LLM a cualquier servicio o API. Esto permite que tu IA interactúe con bases de datos, colas y más, creando aplicaciones verdaderamente poderosas. Exploraremos esta poderosa combinación y su potencial.

Configurando el Entorno de Desarrollo

  • Ollama: Proporciona una forma de ejecutar grandes modelos de lenguaje (LLMs) localmente. Puedes ejecutar muchos modelos, como LLama3, Mistral, CodeLlama y muchos otros en tu máquina, con soporte completo para CPU y GPU.
  • Visual Studio Code: Con Kaoto, Java y los complementos de Quarkus instalados.
  • OpenJDK 21
  • Maven
  • Quarkus 3.17
  • Quarkus Dev Services: Una función de Quarkus que simplifica el desarrollo y la prueba de aplicaciones que dependen de servicios externos como bases de datos, sistemas de mensajería y otros recursos.

Puedes descargar el código completo en el siguiente repositorio de GitHub.

Las siguientes instrucciones se ejecutarán en Visual Studio Code:

1. Creando el Proyecto Quarkus

Shell

 

mvn io.quarkus:quarkus-maven-plugin:3.17.6:create \
-DprojectGroupId=dev.mikeintoch \
-DprojectArtifactId=camel-agent-tools \
-Dextensions="camel-quarkus-core,camel-quarkus-langchain4j-chat,camel-quarkus-langchain4j-tools,camel-quarkus-platform-http,camel-quarkus-yaml-dsl"

2. Agregando Extensiones Quarkus langchain4j

Shell

 

./mvnw quarkus:add-extension -Dextensions="io.quarkiverse.langchain4j:quarkus-langchain4j-core:0.22.0"
./mvnw quarkus:add-extension -Dextensions="io.quarkiverse.langchain4j:quarkus-langchain4j-ollama:0.22.0"

3. Configurar Ollama para Ejecutar Ollama LLM

Abre el archivo application.properties y agrega las siguientes líneas:

Properties files

 

#Configurar modelo local de Ollama
quarkus.langchain4j.ollama.chat-model.model-id=qwen2.5:0.5b

quarkus.langchain4j.ollama.chat-model.temperature=0.0
quarkus.langchain4j.ollama.log-requests=true
quarkus.langchain4j.log-responses=true
quarkus.langchain4j.ollama.timeout=180s

Quarkus utiliza Ollama para ejecutar LLM localmente y también configurar automáticamente la configuración para su uso en componentes de Apache Camel en los siguientes pasos.

4. Creando Ruta de Apache Camel Usando Kaoto

Crea una nueva carpeta llamada route en la carpeta src/main/resources.

Crea un nuevo archivo en la carpeta src/main/resources/routes y nómbralo route-main.camel.yaml, y Visual Studio Code abrirá el editor visual de Kaoto.

Haz clic en el botón +Nuevo y se creará una nueva ruta.

Haz clic en las flechas circulares para reemplazar el componente temporizador.

Busca y selecciona el componente platform-http del catálogo.

Configura las propiedades requeridas de platform-http:

  • Establece la ruta con el valor /camel/chat

Por defecto, platform-http estará en el puerto 8080.

Haz clic en el Añadir icono de paso en la flecha después del componente platform-http.

Busca y selecciona el componente langchain4j-tools en el catálogo.

Configura las propiedades requeridas de langchain4j-tools:

  • Establece Id de herramienta con el valor mis-herramientas.
  • Establece Etiquetas con almacenar (Definir etiquetas es para agrupar las herramientas para usar con el LLM).

Debes procesar el mensaje de entrada del usuario para que el componente langchain4j-tools pueda utilizarlo, luego haz clic en el Añadir icono de paso en la flecha después del componente platform-http.

Busca y selecciona el componente Proceso en el catálogo.

Configura las propiedades requeridas:

  • Establece Ref con el valor createChatMessage.

El componente process utilizará el método createChatMessage que crearás en el siguiente paso.

5. Crear un Proceso para Enviar la Entrada del Usuario a LLM

Crea una nueva Clase Java en la carpeta src/main/java llamada Bindings.java.

Java

 

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

import org.apache.camel.BindToRegistry;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;

import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;

public class Bindings extends RouteBuilder{

    @Override
    public void configure() throws Exception {
        // Las rutas se cargan en archivos yaml.
    }


    @BindToRegistry(lazy=true)
    public static Processor createChatMessage(){

        return new Processor() {
            public void process(Exchange exchange) throws Exception{

                String payload = exchange.getMessage().getBody(String.class);
                List messages = new ArrayList<>();

                String systemMessage = """
                    You are an intelligent store assistant. Users will ask you questions about store product. 
                    Your task is to provide accurate and concise answers.

                    In the store have shirts, dresses, pants, shoes with no specific category

                    %s

                    If you are unable to access the tools to answer the user's query, 
                    Tell the user that the requested information is not available at this time and that they can try again later.
                        
                    """;

                String tools = """
                        You have access to a collection of tools
                        You can use multiple tools at the same time
                        Complete your answer using data obtained from the tools
                        """;

                messages.add(new SystemMessage(systemMessage.formatted(tools)));


                messages.add(new UserMessage(payload));

                exchange.getIn().setBody(messages);
            }
        };
    }
}

Esta clase ayuda a crear un Procesador Camel para transformar la entrada del usuario en un objeto que pueda manejar el componente langchain4j en la ruta. También proporciona el contexto de LLM para usar herramientas y explica la tarea del Agente.

6. Creando Herramientas Apache Camel para Usar con LLM

Crea un nuevo archivo en la carpeta src/main/resources/routes y nómbralo route-tool-products.camel.yaml, y en Visual Studio Code, abre el editor visual Kaoto.

Haz clic en el botón  +Nuevo, y se creará una nueva ruta.

Haz clic en las flechas circulares para reemplazar el componente timer.

Busca y selecciona el componente langchain4j-tools en el catálogo.

Configura langchain4j-tools, haz clic en la pestaña Todos y busca Propiedades del punto final.

  • Establece Id de herramienta con el valor productsbycategoryandcolor.
  • Establece Etiquetas con tienda (igual que en la ruta principal).
  • Establece Descripción con el valor Consultar productos de la base de datos por categoría y color (una breve descripción de la herramienta).


Agrega parámetros que serán utilizados por la herramienta:

  • NOMBRE: categoría, VALOR: cadena
  • NOMBRE: color, VALOR: cadena

Estos parámetros serán asignados por el LLM para ser utilizados en la herramienta y se pasan mediante encabezado.

Agrega el Componente SQL para consultar la base de datos, luego haz clic en Agregar Paso después del componente langchain4j-tools.

Busca y selecciona el componente Componente SQL.

Configura las propiedades SQL requeridas:

  • Consulta con el siguiente valor.
SQL

 

Select  name, description, category, size, color, price, stock from products where Lower(category)= Lower (:#category) and Lower(color) = Lower(:#color) 

Maneja los parámetros a utilizar en la consulta, luego agrega un Componente Convertir Encabezado para convertir los parámetros a un tipo de objeto correcto.

Haz clic en el botón Agregar Paso después de langchain4j-tools, busca y selecciona la transformación Convertir Encabezado A en el catálogo.

Configurar las propiedades requeridas para el componente:

  • Nombre con el valor categoría
  • Tipo con el valor String


Repetir los pasos con los siguientes valores:

  • Nombre con el valor color
  • Tipo con el valor String

Como resultado, así es como se ve la ruta:

Finalmente, necesitas transformar el resultado de la consulta en un objeto que pueda manejar LLM; en este ejemplo, lo transformas en JSON.

Haz clic en el botón Agregar paso después del Componente SQL, y agrega el Componente Marshal.

Configura las propiedades del formato de datos para el Marshal y selecciona JSon de la lista.

7. Configurar los Servicios Dev de Quarkus para PostgreSQL

Agrega la extensión de Quarkus para proporcionar PostgreSQL para propósitos de desarrollo, ejecuta el siguiente comando en la terminal.

Shell

 

./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-jdbc-postgresql"

Abre application.properties y agrega las siguientes líneas:

Properties files

 

#Configurando devservices para Postgresql
quarkus.datasource.db-kind=postgresql
quarkus.datasource.devservices.port=5432
quarkus.datasource.devservices.init-script-path=db/schema-init.sql
quarkus.datasource.devservices.db-name=store

Finalmente, crea nuestro script SQL para cargar la base de datos.

Crea una carpeta llamada db dentro de src/main/resources, y dentro de esta carpeta, crea un archivo llamado schema-init.sql  con el siguiente contenido.

SQL

 

DROP TABLE IF EXISTS products;

CREATE TABLE IF NOT EXISTS products (
    id SERIAL NOT NULL,
    name VARCHAR(100) NOT NULL,
    description varchar(150),
    category VARCHAR(50),
    size VARCHAR(20),
    color VARCHAR(20),
    price DECIMAL(10,2) NOT NULL,
    stock INT NOT NULL,
    CONSTRAINT products_pk PRIMARY KEY (id)
);

    INSERT INTO products (name, description, category, size, color, price, stock)
VALUES
    ('Blue shirt', 'Cotton shirt, short-sleeved', 'Shirts', 'M', 'Blue', 29.99, 10),
    ('Black pants', 'Jeans, high waisted', 'Pants', '32', 'Black', 49.99, 5),
    ('White Sneakers', 'Sneakers', 'Shoes', '40', 'White', 69.99, 8),
    ('Floral Dress', 'Summer dress, floral print, thin straps.', 'Dress', 'M', 'Pink', 39.99, 12),
    ('Skinny Jeans', 'Dark denim jeans, high waist, skinny fit.', 'Pants', '28', 'Blue', 44.99, 18),
    ('White Sneakers', 'Casual sneakers, rubber sole, minimalist design.', 'Shoes', '40', 'White', 59.99, 10),
    ('Beige Chinos', 'Casual dress pants, straight cut, elastic waist.', 'Pants', '32', 'Beige', 39.99, 15),
    ('White Dress Shirt', 'Cotton shirt, long sleeves, classic collar.', 'Shirts', 'M', 'White', 29.99, 20),
    ('Brown Hiking Boots', 'Waterproof boots, rubber sole, perfect for hiking.', 'Shoes', '42', 'Brown', 89.99, 7),
    ('Distressed Jeans', 'Distressed denim jeans, mid-rise, regular fit.', 'Pants', '30', 'Blue', 49.99, 12);

8. Incluye nuestra Ruta para ser Cargada por el Proyecto Quarkus

Camel Quarkus soporta varios lenguajes específicos de dominio (DSLs) para definir Rutas de Camel.

También es posible incluir rutas DSL yaml, agregando la siguiente línea en el archivo application.properties.

Properties files

 

# rutas a cargar
camel.main.routes-include-pattern = routes/*.yaml

Esto cargará todas las rutas en la carpeta src/main/resources/routes.

9. Probar la aplicación

Ejecuta la aplicación usando Maven, abre una Terminal en Visual Studio code y ejecuta el siguiente comando.

Shell

 

mvn quarkus:dev

Una vez iniciado, Quarkus llama a Ollama y ejecuta tu LLM localmente, abre una terminal y verifica con el siguiente comando.

Shell

 

ollama ps

NAME            ID              SIZE      PROCESSOR    UNTIL
qwen2.5:0.5b    a8b0c5157701    1.4 GB    100% GPU     4 minutes from now

También, Quarkus crea un contenedor ejecutando PostgreSQL y crea una base de datos y un esquema. Puedes conectarte usando el comando psql.

Shell

 

psql -h localhost -p 5432 -U quarkus -d store

Y consultar la tabla de productos:

Shell

 

store=# select * from products;
 id |        name        |                    description                     | category | size | color | price | stock
----+--------------------+----------------------------------------------------+----------+------+-------+-------+-------
  1 | Blue shirt         | Cotton shirt, short-sleeved                        | Shirts   | M    | Blue  | 29.99 |    10
  2 | Black pants        | Jeans, high waisted                                | Pants    | 32   | Black | 49.99 |     5
  3 | White Sneakers     | Sneakers                                           | Shoes    | 40   | White | 69.99 |     8
  4 | Floral Dress       | Summer dress, floral print, thin straps.           | Dress    | M    | Pink  | 39.99 |    12
  5 | Skinny Jeans       | Dark denim jeans, high waist, skinny fit.          | Pants    | 28   | Blue  | 44.99 |    18
  6 | White Sneakers     | Casual sneakers, rubber sole, minimalist design.   | Shoes    | 40   | White | 59.99 |    10
  7 | Beige Chinos       | Casual dress pants, straight cut, elastic waist.   | Pants    | 32   | Beige | 39.99 |    15
  8 | White Dress Shirt  | Cotton shirt, long sleeves, classic collar.        | Shirts   | M    | White | 29.99 |    20
  9 | Brown Hiking Boots | Waterproof boots, rubber sole, perfect for hiking. | Shoes    | 42   | Brown | 89.99 |     7
 10 | Distressed Jeans   | Distressed denim jeans, mid-rise, regular fit.     | Pants    | 30   | Blue  | 49.99 |    12
(10 rows)

Para probar la aplicación, envía una solicitud POST a localhost:8080/camel/chat con un cuerpo de texto plano solicitando algún producto.

El LLM puede haber alucinado. Por favor, inténtalo nuevamente modificando ligeramente tu solicitud.

Puedes ver cómo el LLM utiliza la herramienta y obtiene información de la base de datos utilizando la solicitud de lenguaje natural proporcionada. El LLM identifica los parámetros y los envía a la herramienta. Si revisas el registro de solicitudes, puedes encontrar las herramientas y parámetros que el LLM está utilizando para crear la respuesta.

Conclusión

Has explorado cómo aprovechar el poder de los LLMs en tus flujos de integración utilizando Apache Camel y el componente LangChain4j. Hemos visto cómo esta combinación te permite integrar de forma fácil modelos de lenguaje potentes en tus rutas Camel existentes, lo que te permite construir aplicaciones sofisticadas que pueden entender, generar e interactuar con el lenguaje humano.

Source:
https://dzone.com/articles/powering-llms-with-apache-camel-and-langchain4j