Ejercicio: Desarrollo de una aplicación RAG con Spring AI y Azure OpenAI
En esta unidad, creará una aplicación de generación aumentada de recuperación (RAG) mediante Spring AI, Azure OpenAI y VectorStore de Spring AI.
Configurar variables de entorno
Para este ejercicio, necesita algunas variables de entorno de los ejercicios anteriores. Si usa la misma ventana de Bash, estas variables seguirán existiendo. Si las variables ya no están disponibles, use los siguientes comandos para volver a crearlas. Asegúrese de reemplazar los <...> marcadores de posición por sus propios valores y utilice los mismos valores que empleó anteriormente.
export RESOURCE_GROUP=<resource-group>
export LOCATION=<location>
export DB_SERVER_NAME=<server-name>
export PGHOST=$(az postgres flexible-server show \
--resource-group $RESOURCE_GROUP \
--name $DB_SERVER_NAME \
--query fullyQualifiedDomainName \
--output tsv \
| tr -d '\r')
También necesita una nueva variable de entorno para esta unidad. Use el siguiente comando para definir esta variable:
export OPENAI_RESOURCE_NAME=OpenAISpringAI
Implementación de los modelos de Azure OpenAI
Para su aplicación, primero necesita implementar un modelo de chat - gpt-4o - y un modelo de inserción - text-embedding-ada-002. Para implementar estos modelos, primero debe crear un recurso de Azure OpenAI.
Creación de una cuenta de Azure OpenAI
Use el comando siguiente para crear una cuenta de Azure OpenAI:
az cognitiveservices account create \
--resource-group $RESOURCE_GROUP \
--name $OPENAI_RESOURCE_NAME \
--kind OpenAI \
--sku S0 \
--location $LOCATION \
--yes
Implementación de un modelo de chat de Azure OpenAI
Use el siguiente comando para implementar un modelo de chat denominado gpt-4o:
az cognitiveservices account deployment create \
--resource-group $RESOURCE_GROUP \
--name $OPENAI_RESOURCE_NAME \
--deployment-name gpt-4o \
--model-name gpt-4o \
--model-version 2024-11-20 \
--model-format OpenAI \
--sku-capacity "15" \
--sku-name GlobalStandard
Implementación de un modelo de inserción de Azure OpenAI
Ahora puede implementar un modelo de inserción denominado text-embedding-ada-002 mediante el siguiente comando:
az cognitiveservices account deployment create \
--resource-group $RESOURCE_GROUP \
--name $OPENAI_RESOURCE_NAME \
--deployment-name text-embedding-ada-002 \
--model-name text-embedding-ada-002 \
--model-version 2 \
--model-format OpenAI \
--sku-capacity 120 \
--sku-name Standard
Creación de una aplicación spring AI
Use el siguiente curl comando para generar un nuevo proyecto de inicio de Spring Boot con todas las dependencias necesarias:
curl https://start.spring.io/starter.zip \
-d groupId=com.example \
-d artifactId=spring-ai-app \
-d name=spring-ai-app \
-d description="Spring AI Azure Integration" \
-d version=0.0.1-SNAPSHOT \
-d bootVersion=3.4.3 \
-d javaVersion=17 \
-d dependencies=web,jdbc,azure-support,spring-ai-azure-openai,spring-ai-vectordb-pgvector \
-d type=maven-project \
-d packageName=com.example.springaiapp \
--output spring-ai-app.zip
El proyecto de inicio de Spring Boot generado incluye las siguientes configuraciones y dependencias:
- Versión de Spring Boot: 3.4.3
- Versión de Java: 17
- Dependencias:
web: agrega compatibilidad con la creación de aplicaciones web, incluidos los servicios RESTful mediante spring Model View Controller (MVC).jdbc: proporciona compatibilidad con la conectividad de bases de datos java (JDBC) para el acceso a bases de datos.azure-support: agrega compatibilidad para la integración con los servicios de Azure.spring-ai-azure-openai: agrega compatibilidad para la integración con los servicios de Azure OpenAI.spring-ai-vectordb-pgvector: agrega compatibilidad con el uso depgvector, una extensión de PostgreSQL para incrustaciones de vectores.
Use los siguientes comandos para descomprimir el archivo descargado y navegar al directorio creado:
unzip -u spring-ai-app.zip -d spring-ai-app
cd spring-ai-app
A continuación, debe cambiar el archivo pom.xml para incluir una dependencia para la autenticación sin contraseña para PostgreSQL. Abra el archivo pom.xml , busque la <dependencies> sección y agregue la dependencia siguiente:
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-jdbc-postgresql</artifactId>
</dependency>
A continuación, use el siguiente comando para compilar la aplicación y omitir las pruebas:
mvn clean package -DskipTests
La salida debe incluir un mensaje de operación correcta similar al ejemplo siguiente:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 25.392 s
[INFO] Finished at: 2025-03-02T15:53:07-05:00
[INFO] ------------------------------------------------------------------------
Estructura de proyecto
En el directorio spring-ai-app , use los siguientes comandos para crear nuevos directorios para los nuevos archivos de origen que se van a agregar:
mkdir -p src/main/java/com/example/springaiapp/controller
mkdir -p src/main/java/com/example/springaiapp/service
Inspeccione el código mediante Visual Studio Code o su IDE favorito. El código de inicio incluye la siguiente estructura:
src/
├── main/
│ ├── java/
│ │ └── com/example/springaiapp/
│ │ ├── controller/
│ │ ├── service/
│ │ └── SpringAiAppApplication.java
│ └── resources/
│ └── application.properties
├── test/
│ └── java/
│ └── com/example/springaiapp/
│ └── SpringAiAppApplicationTests.java
└── pom.xml
Configuración de Spring AI
Para poder ejecutar correctamente la aplicación, debe agregar la siguiente configuración necesaria:
- Un punto de conexión de Azure OpenAI.
- Una clave de API de Azure OpenAI.
- Una dirección URL de PostgreSQL.
Recupere el punto de conexión de Azure OpenAI mediante el comando siguiente:
export AZURE_OPENAI_ENDPOINT=$(az cognitiveservices account show \
--resource-group $RESOURCE_GROUP \
--name $OPENAI_RESOURCE_NAME \
--query "properties.endpoint" \
--output tsv \
| tr -d '\r')
Recupere la clave de API de Azure OpenAI mediante el comando siguiente:
export AZURE_OPENAI_API_KEY=$(az cognitiveservices account keys list \
--resource-group $RESOURCE_GROUP \
--name $OPENAI_RESOURCE_NAME \
--query "key1" \
--output tsv \
| tr -d '\r')
Recupere la dirección URL de PostgreSQL mediante el comando siguiente:
az postgres flexible-server show \
--resource-group $RESOURCE_GROUP \
--name $DB_SERVER_NAME \
--query fullyQualifiedDomainName \
--output tsv
Actualización del archivo application.properties
Busque y abra el archivo application.properties en el directorio src/main/resources . Hay tres propiedades que se inicializan mediante valores de las siguientes variables de entorno: AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINTy PGHOST. Reemplace el contenido del archivo por el siguiente contenido:
spring.application.name=spring-ai-app
spring.ai.azure.openai.api-key=${AZURE_OPENAI_API_KEY}
spring.ai.azure.openai.endpoint=${AZURE_OPENAI_ENDPOINT}
spring.ai.azure.openai.chat.model=gpt-4o
spring.ai.azure.openai.embedding.model=text-embedding-ada-002
spring.datasource.url=jdbc:postgresql://${PGHOST}/postgres?sslmode=require
spring.datasource.username=azureuser
spring.datasource.azure.passwordless-enabled=true
spring.ai.vectorstore.pgvector.initialize-schema=true
spring.ai.vectorstore.pgvector.schema-name=postgres
Implementación de un servicio RAG
Creación del servicio
En el directorio de servicio , cree un nuevo archivo denominado RagService.java y agregue el código siguiente:
package com.example.springaiapp.service;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.ai.document.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RagService {
private static final Logger logger = LoggerFactory.getLogger(RagService.class);
private final ChatClient chatClient;
@Autowired
VectorStore vectorStore;
public RagService(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
public String processQuery(String query) {
List<Document> similarContexts = vectorStore.similaritySearch(
SearchRequest.builder()
.query(query)
.similarityThreshold(0.8)
.topK(3)
.build()
);
String context = similarContexts.stream()
.map(ch -> String.format("Q: %s\nA: %s", ch.getMetadata().get("prompt"), ch.getText()))
.collect(Collectors.joining("\n\n"));
logger.debug("Found {} similar contexts", similarContexts.size());
String promptText = String.format("""
Use these previous Q&A pairs as context for answering the new question:
Previous interactions:
%s
New question: %s
Please provide a clear and educational response.""",
context,
query
);
return this.chatClient.prompt()
.user(promptText)
.call()
.content();
}
}
Este código implementa RAG mediante la generación de una respuesta a una consulta determinada, lo que aumenta el conocimiento del modelo mediante contextos similares de VectorStore.
Creación del controlador RAG
A continuación, debe exponer un punto de conexión REST para la aplicación RAG. Cree un nuevo archivo denominado RagController.java en el directorio del controlador y agregue el código siguiente:
package com.example.springaiapp.controller;
import com.example.springaiapp.service.RagService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/rag")
public class RagController {
@Autowired
private RagService ragService;
@GetMapping
public String processQuery(@RequestParam String query) {
return ragService.processQuery(query);
}
}
Prueba de la aplicación RAG
Con estos cambios implementados, use el siguiente comando para compilar y ejecutar el código:
mvn spring-boot:run
Pruebe el nuevo punto de conexión REST desde un explorador o mediante el comando siguiente:
curl -G "http://localhost:8080/api/rag" \
--data-urlencode "query=What is pgvector?"
Debería ver una respuesta válida similar al ejemplo siguiente:
pgvector is an open-source PostgreSQL extension that enables efficient storage, indexing,
and querying of vector embeddings within a PostgreSQL database.
A continuación, pruebe el siguiente comando:
curl -G "http://localhost:8080/api/rag" \
--data-urlencode "query=How does QuestionAnswerAdvisor work in Spring AI?"
Aunque la respuesta puede parecer válida, podría incluir expresiones que indican que es una suposición razonada.
Prueba de la aplicación con conocimientos adicionales
A continuación, proporcione conocimientos adicionales agregando documentos al almacenamiento de vectores. Cree un nuevo archivo denominado DocumentService.java en el directorio de servicio y agregue el código siguiente:
package com.example.springaiapp.service;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
@Service
public class DocumentService {
private static final Logger logger = LoggerFactory.getLogger(DocumentService.class);
@Autowired
VectorStore vectorStore;
@PostConstruct
private void init() {
vectorStore.add(documents);
logger.info("DocumentService initialized with. Document count: {}", documents.size());
}
List<Document> documents = List.of(
new Document("3e1a1af7-c872-4e36-9faa-fe53b9613c69",
"""
The Spring AI project aims to streamline the development of applications that
incorporate artificial intelligence functionality without unnecessary complexity.
The project draws inspiration from notable Python projects, such as LangChain
and LlamaIndex, but Spring AI is not a direct port of those projects.
The project was founded with the belief that the next wave of Generative AI
applications will not be only for Python developers but will be ubiquitous
across many programming languages.
""",
Map.of("prompt", "What is Spring AI?")),
new Document("7a7c2caf-ce9c-4dcb-a543-937b76ef1098",
"""
A vector database stores data that the AI model is unaware of. When a user
question is sent to the AI model, a QuestionAnswerAdvisor queries the vector
database for documents related to the user question.
The response from the vector database is appended to the user text to provide
context for the AI model to generate a response. Assuming you have already
loaded data into a VectorStore, you can perform Retrieval Augmented Generation
(RAG) by providing an instance of QuestionAnswerAdvisor to the ChatClient.
""",
Map.of("prompt", "How does QuestionAnswer Advisor work?"))
);
}
Para probar estos cambios, use el siguiente comando para compilar y ejecutar el código:
mvn spring-boot:run
A continuación, haga una pregunta con el comando siguiente:
curl -G "http://localhost:8080/api/rag" \
--data-urlencode "query=How does QuestionAnswerAdvisor work in Spring AI?"
Ahora debería ver una respuesta que explique claramente el rol de QuestionAnswerAdvisor dentro de Spring AI.
Resumen de la unidad
En esta unidad, ha creado con éxito una aplicación RAG usando Spring AI, Azure OpenAI y Spring AI VectorStore. El módulo expone la funcionalidad RAG a través de un punto de conexión REST dedicado a través de la RagController clase .