Java como lenguaje de producción para IA: Spring Boot, RAG y pgvector
Un mapa práctico para desarrollar servicios RAG en la JVM con Spring AI o LangChain4j, eligiendo un almacén de vectores y gestionando aspectos como arrendamiento, costos, evaluación y soluciones alternativas.
Python entrena los modelos, mientras que Java se está convirtiendo silenciosamente en el lenguaje que permite su implementación. Durante aproximadamente tres años, el ámbito de la IA parecía una conferencia dedicada a Python con un presupuesto mayor: demostraciones en cuadernos de notas, tutoriales que comenzaban con pip install, y diagramas de arquitectura en los que un pequeño recuadro llamado “servicio LLM de Python” aparecía separado del verdadero backend. Ese verdadero backend solía ser Spring Boot, que ya se encargaba de la autenticación, la facturación, los registros de auditoría y la base de datos.
Ese pequeño recuadro ya no es obligatorio. Spring AI ya superó la versión 1.0 y ahora está en la 2.0. LangChain4j es una biblioteca adecuada para JVM que cuenta con más de veinte proveedores de modelos y más de treinta almacenes de vectores. PostgreSQL almacena los embeddings a través de pgvector. Un servicio de Spring Boot que ya esté en ejecución puede llamar a un LLM, obtener contexto relevante, invocar herramientas, transmitir tokens y publicar métricas Micrometer, todo dentro de la JVM.
¿Eso convierte a Java en el nuevo rey de la IA? No en el sentido de las habituales guerras de lenguajes. Nadie está reemplazando PyTorch por Java. Lo que sí está ganando Java es el campo donde está el dinero: las aplicaciones empresariales que deben ser correctas, observables y, a la vez, lo suficientemente sencillas. Si trabajas en ese ámbito, el ganador es lo que ya ejecute tu clúster de producción, y cada vez más ese sistema utiliza Java.
El resto de este artículo describe este cambio. Explica por qué ocurrió, cómo se ve un servicio RAG en Spring Boot, cómo elegir un almacén de vectores y qué detalles de producción diferencian una demostración de algo en lo que se podría confiar con datos de clientes.
La ventaja de Python siempre fue la investigación
Python se impuso en la era de la investigación por razones válidas que siguen siendo relevantes: NumPy, PyTorch, Hugging Face, Jupyter y toda una generación de ingenieros expertos en tensores. El ajuste fino de modelos, la prueba de nuevas arquitecturas de incrustación o el entrenamiento en GPUs siguen siendo tareas propias de Python.
El despliegue en producción es otro asunto. La mayoría de las empresas nunca entrenan un modelo base. Simplemente lo llaman y entonces comienza el trabajo real: obtener documentos, aplicar políticas, separar usuarios, registrar solicitudes, limitar gastos y asegurarse de que nada genere cifras erróneas de reembolso. Eso incluye el diseño de APIs, el acceso a datos, la seguridad y las operaciones, tareas que Spring Boot maneja desde 2014.
La solución popular de colocar el modelo detrás de FastAPI conllevaba costos recurrentes:
- dos lenguajes dentro de un mismo producto
- pipelines de despliegue separados
- sistemas de monitoreo independientes
La gente aceptó esto porque Java carecía de herramientas serias para LLM. Para 2025 eso ya no era cierto. Spring AI 1.0 se puso a disposición general en mayo de 2025, y la versión 2.0 llegó en junio de 2026 junto con Spring Boot 4. LangChain4j alcanzó la versión 1.0 en el mismo período. La pila JVM ya no está intentando ponerse al día. Para los equipos que ya usan Spring, es una opción razonable por defecto.
Qué significa “añadir IA” en una aplicación Spring
No se requiere reescribir nada, solo tres funcionalidades.
- Una capa de chat.
ChatClienten Spring AI, o unAiServiceen LangChain4j, convierte una solicitud y el historial de mensajes en una respuesta del modelo. La transmisión en tiempo real es estándar, y la salida estructurada puede almacenarse en un registro de Java, lo que evita tener que procesar JSON a partir de texto con expresiones regulares. - Acceso a sus propios datos. Usted calcula los embeddings y los guarda en un almacén de vectores, de modo que las respuestas provienen de sus políticas, facturas, manuales de operaciones y documentación del producto, y no de lo que el modelo recuerda a medias. Esto se conoce como Generación Aumentada por Búsqueda (RAG).
- Llamadas a herramientas. El modelo puede invocar métodos de Java según sus reglas de autorización, por ejemplo para buscar un pedido, abrir un caso o consultar el saldo. Aquí resultan útiles el sistema de tipos y los servicios que ya posee. El modelo no es su fuente de verdad; simplemente razona sobre ella.
Con Spring Security, Spring Data, Actuator y PostgreSQL ya implementados, se trata de otro tipo de cliente más, similar a lo que ocurrió con Redis o Kafka.
RAG, explicado para desarrolladores de Java
Si eliminamos el misterio, RAG es un pipeline de búsqueda que termina en un modelo de lenguaje. Los pasos son:
- Dividir los documentos en fragmentos.
- Convertir cada fragmento en un embedding, es decir, un vector de números flotantes que codifica su significado.
- Guardar los vectores junto con metadatos como el propietario, el ID del documento, la URI de origen y la fecha de registro.
- Cuando llega una pregunta, embedearla y buscar los fragmentos más cercanos.
- Incluir esos fragmentos en el prompt.
- Indicar al modelo que responda únicamente a partir de ellos y que admita cuando no contengan la respuesta.
Una base de datos vectorial no sustituye a tu base de datos transaccional. Es un índice semántico, algo similar a Elasticsearch pero con un vocabulario más avanzado.
Para las aplicaciones basadas en Spring Boot, normalmente se comienza con PostgreSQL junto a pgvector. Postgres ya está desplegado, respaldado y gestionado en grupos de recursos, por lo que instalar una extensión cuesta menos que adoptar inmediatamente Pinecone, Weaviate o Qdrant. Los motores dedicados sí son ventajosos cuando la escala es extrema o se necesita búsqueda híbrida, pero la mayoría de las aplicaciones internas de tipo RAG operan con un nivel de demanda muy por debajo de ese umbral.
Un esqueleto listo para funcionar
La configuración que se muestra a continuación combina Spring AI 2.0 con Boot 4; en Boot 3.4 o 3.5 se debe utilizar la versión 1.1.x en su lugar. Primero hay que incluir el BOM para que todas las dependencias estén alineadas con la misma versión:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
A continuación, indique solo las dependencias que necesite:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
JDBC se incluye intencionadamente. El starter de pgvector funciona a través de JdbcTemplate, y olvidar esa dependencia es una causa sorprendentemente frecuente de un arranque fallido.
La configuración se encuentra en application.yml. Ese es el propósito de Spring AI: un modelo debe configurarse como una fuente de datos.
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app
username: app
password: ${DB_PASSWORD}
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o-mini
temperature: 0.2
embedding:
options:
model: text-embedding-3-small
vectorstore:
pgvector:
initialize-schema: true
index-type: HNSW
distance-type: COSINE_DISTANCE
dimensions: 1536
Dos detalles en este archivo son más importantes de lo que parecen. La dimensión de incrustación debe ser igual a la que produce el modelo de incrustación, y text-embedding-3-small genera 1536. Si cambias el modelo y olvidas ese número, la búsqueda por similitud empeora sin que aparezca ningún error. El segundo detalle es utilizar una temperatura baja para RAG, ya que lo que se desea es un resultado cercano al texto recuperado, y no una reescritura creativa de un estado financiero.
Trata la ingesta de datos como un servicio independiente en lugar de una instrucción simple dentro de un controlador. VectorStore.add(...) acepta fragmentos de tipo Document, y cada fragmento debe contener los metadatos con los que filtrarás posteriormente, como tenantId, source, docType y effectiveDate. Sin filtros, la búsqueda semántica podría mostrar el contrato de un cliente dentro de la respuesta de otro cliente.
La consulta es igual de sencilla. QuestionAnswerAdvisor en Spring AI representa una versión predefinida de este proceso: recuperar datos, agregar contexto y llamar al modelo. Si necesita filtros, reclasificación o citas, utilice similaritySearch por sí mismo y considere filterExpression como una cláusula WHERE, ya que ese es precisamente su propósito.
Elegir un almacén de vectores sin dogmas
Existen cuatro opciones:
- Postgres con pgvector. Es la opción por defecto más razonable y bien comprendida desde el punto de vista operativo. Gracias a la indexación HNSW, la supervisión del rendimiento y los bloques compactos, puede manejar decenas de millones de vectores. Sin embargo, falla cuando se requiere una búsqueda híbrida avanzada o un equipo dedicado al funcionamiento de infraestructuras de vecinos más cercanos aproximados.
El método para tomar decisiones es sencillo, y esa es su ventaja. Comience con pgvector cuando Postgres ya esté en producción. Cambie de estrategia cuando la recuperación, la latencia o la búsqueda híbrida no cumplan con los requisitos reales de rendimiento, y no porque algún artículo afirme que las aplicaciones avanzadas de IA utilizan cierto producto. Además, mantenga una referencia al registro original junto a cada vector, para poder volver a incrustarlo siempre que cambie la política.
Ese último punto es el que los tutoriales omiten. Los modelos de incrustación se actualizan, la división en fragmentos se vuelve más inteligente y los documentos legales se modifican. Una tarea de ingesta que sea idempotente y esté indexada por versión del documento le ahorrará tiempo intentando averiguar por qué el bot muestra la tabla de tarifas del año pasado.
Spring AI versus LangChain4j
Ambos están listos para su uso en producción. Cuál es el más adecuado depende de la situación actual de su equipo.
Spring AI toma la conocida idea de Spring sobre abstracciones portátiles y la aplica a los modelos. Si lo imaginas como Spring Data para LLMs, le resultará natural, ya que la autocompletación, ChatClient, los asesores, Actuator y Micrometer encajan perfectamente. Utiliza la versión 2.0 con Boot 4. En Boot 3, debes quedarte en la versión 1.1.x, ya que la 2.0 no se puede instalar directamente.
LangChain4j está escrito primero para Java y ofrece un starter de Spring adicional. Soporta más proveedores, sus AiServices tipados se asemejan a clientes Feign orientados a modelos, y es adecuado para equipos que también utilizan Quarkus o Java puro. Aquellos que desean un control estricto sobre el ciclo del agente suelen elegirlo.
Nada impide que utilice ambos. Una división viable es usar Spring AI para las conversaciones y RAG en los servicios orientados al cliente, con LangChain4j para cubrir necesidades específicas de ciertos proveedores o patrones de agentes. Mantenga sus componentes separados y nunca permita que dos modelos de embedding diferentes escriban vectores incompatibles en una misma tabla.
Un entorno completamente basado en Spring-Boot que pueda programar una actualización a Boot 4 debería optar por Spring AI. Un entorno híbrido con JVM, o uno que lleve un año usando Boot 3, probablemente encontrará que LangChain4j depende menos de las versiones del framework.
En producción es donde JVM tiene ventaja
Cualquiera puede demostrar una respuesta. Un producto, en cambio, debe resistir una auditoría. Estos son los aspectos que deben abordarse:
- Anclaje y rechazos. Limitar el modelo al contexto recuperado e incluir citas. Cuando las puntuaciones de similitud estén por debajo de un umbral, la respuesta debe ser “eso no está en la base de conocimientos” y no una conjetura. En finanzas, operaciones y salud, un error cometido con confianza cuesta más que un rechazo directo.
- Arrendamiento y eliminación de datos sensibles. Filtrar los vectores por arrendatario y eliminar secretos de las solicitudes. Mantener números de tarjetas, números de cuenta y datos de salud fuera de los registros brutos de las solicitudes. Si la depuración exige registrarlos, tokenizarlos primero y conservarlos según las reglas de retención del sistema original.
- Presupuestos para costos y latencia. Los tokens cuestan dinero, por lo que se deben registrar los tokens de entrada, los tokens de salida, el tiempo de recuperación y el tiempo del modelo. Establecer un límite máximo de tokens en cada llamada, almacenar en caché los embeddings de documentos que se repiten y enviar la clasificación o enrutamiento a un modelo más pequeño, utilizando uno mayor solo cuando sea necesario.
Todo esto es algo típico de Spring: envolver una llamada remota, etiquetar una métrica, rechazar solicitudes no autenticadas. El LLM es una nueva dependencia con un SLA peor, por lo que hay que gestionarlo como tal.
Dónde es cierta la frase “Java es el rey”
Java es un punto de partida mejor cuando el sistema de registro ya funciona en la JVM, cuando la función de IA debe compartir identidad, tenencia y auditoría con APIs existentes, cuando necesita llamar a servicios internos en Java como herramientas, cuando el cumplimiento normativo no permite usar una capa de Python oculta, y cuando las personas de soporte técnico a las 2 a.m. ya conocen Spring Boot.
Python sigue siendo la opción preferida cuando se está entrenando o ajustando modelos, cuando se necesita una biblioteca de investigación la misma semana en que se publica, o cuando el modelo en sí mismo es el producto y no solo una función dentro de una aplicación más grande.
Eso son tareas separadas, y durante dos años la industria actuó como si no lo fueran. El resultado fue una avalancha de arquitecturas que incluían un componente auxiliar en Python, con la esperanza de que sus contratos permanecieran estables. El patrón que parece interesante para 2026 es mixto: Python, o un laboratorio de modelos alojado, se encarga del entrenamiento y la evaluación; Java sirve para el servicio, la búsqueda vectorial funciona junto a los datos operativos; el modelo proviene de un proveedor y la lógica del dominio queda en tus manos.
Un primer proyecto sensato
No comiences con un chatbot para toda la empresa sin límites. Elige un conjunto de contenido específico y valioso, además de una pregunta cuya respuesta pueda puntuarse. Algunas opciones efectivas:
- Preguntas y respuestas tipo manual de operaciones para ingenieros de soporte, vinculadas a la página original
- Un asistente de políticas que cita la cláusula exacta
- Preguntas y respuestas sobre una factura o estado de cuenta que el usuario acaba de subir
Póngalo detrás de una API autenticada que ya posee, registre cada consulta, muestre las citaciones en la interfaz de usuario, agregue un interruptor de apagado de configuración y averigüe el costo por solicitud antes de ampliar el corpus. El primer proyecto enseña la división en fragmentos, los metadatos, la evaluación y el control de cambios en los prompts; esas habilidades son transferibles, pero no la marca del framework.
El entorno de ejecución en el que ya confía
“Java es el nuevo rey de la IA” funciona como titular, pero falla como tesis. Java no ganó en el campo del aprendizaje automático; simplemente llevó la IA aplicada a la plataforma que ya alberga los sistemas de transacciones del mundo.
Un ingeniero de Spring Boot no necesita permiso de nadie para trabajar aquí, ni tampoco un título en ciencias de datos. Lo que se requiere es un proveedor de modelos, un modelo de embedding, un índice vectorial y la misma atención operativa que se aplica a los pagos y las comunicaciones. Python sigue siendo la herramienta principal para entrenar los modelos del laboratorio. Java se está convirtiendo en el líder en el camino desde el laboratorio hasta los registros contables, donde las respuestas necesitan fundamentación, las llamadas a herramientas requieren autorización y cada factura necesita una explicación. Para la mayoría de los equipos, ese es el único reconocimiento que realmente importa.
Si un servicio de Spring Boot ya controla la identidad, el dinero y el historial de auditoría, no hay razón para esperar a usar un componente adicional. Elige este mes un conjunto de datos específico, coloca ChatClient delante de pgvector y exige que el modelo proporcione referencias claras.
Lecturas relacionadas
- Spring AI vs LangChain4j: mismo RAG, diferentes elecciones ocultas — Twin Java RAG, basado en un manual que mostró cómo las diferencias en el recuento de líneas disminuyen con la integración de Spring, y una respuesta incorrecta reveló los valores predeterminados de fragmentación.
- Notas prácticas: Spring AI + MCP: Exponer tus herramientas Java a cualquier cliente de IA (incluso — Guía paso a paso de las Notas prácticas: Spring AI + MCP: Exponer tus herramientas Java a cualquier cliente de IA (incluso: contratos, verificaciones y espacios para código listos para usar para equipos que implementan este patrón.