¿Buscas nuestro logo?
Aquí te dejamos una copia, pero si necesitas más opciones o quieres conocer más, visita nuestra área de marca.
¿Buscas nuestro logo?
Aquí te dejamos una copia, pero si necesitas más opciones o quieres conocer más, visita nuestra área de marca.
dev
Simón Rodríguez Hace 3 días Cargando comentarios…
En el post anterior, “Deep Learning” sobre Spring AI: RAG, Embeddings y Vector Databases, exploramos el patrón RAG y vimos que básicamente consistía en dos fases: la primera, de ingesta y transformación de datos; y la segunda, de ejecución.
En esta ocasión vemos las opciones que nos proporciona Spring AI para la primera fase de ingesta (ETL) del patrón RAG.
Además, nos adentraremos en uno de los conceptos que más auge está teniendo en los últimos tiempos dentro de la IA: el MCP.
Si te has perdido alguno de los posts de la serie, puedes echarles un vistazo a continuación:
Dentro del patrón RAG, el framework ETL organiza el flujo de procesamiento de datos, desde el momento de obtención de datos sin procesar hasta conseguir guardar datos estructurados en una base de datos vectorial.
Las pipelines ETL crean, transforman y guardan Documents, existiendo tres componentes principales:
Para construir una pipeline ETL se puede encadenar una instancia de cada tipo anterior:
Por ejemplo, con las instancias:
Se podría usar el siguiente código para ejecutar el patrón RAG en su fase de ingesta de datos:
vectorStore.accept(textSplitter.apply(pdfReader.get()));
En la siguiente imagen se pueden ver las interfaces e implementaciones que soportan esta fase de ETL en Spring AI:
public interface DocumentReader extends Supplier<List<Document>> {
default List<Document> read() {
return get();
}
}
public interface DocumentTransformer extends Function<List<Document>, List<Document>> {
default List<Document> transform(List<Document> transform) {
return apply(transform);
}
}
public interface DocumentWriter extends Consumer<List<Document>> {
default void write(List<Document> documents) {
accept(documents);
}
}
En las siguientes secciones inspeccionaremos más a fondo cada una de ellas.
Algunas implementaciones existentes son:
1. JSON: procesa documentos JSON convirtiéndolos en Documents.
public class CustomJsonReader {
...
public List<Document> loadJson() {
JsonReader jsonReader = new JsonReader(this.resource, "etiqueta", "content");
return jsonReader.get();
}
}
Parámetros posibles en el constructor:
Comportamiento para cada objeto JSON (en un array o como objeto sencillo):
2. Text: procesa documentos de texto convirtiéndolos en Documents.
public class CustomTextReader {
...
public List<Document> loadText() {
TextReader textReader = new TextReader(this.resource);
textReader.getCustomMetadata().put("filename", "text-source.txt");
return textReader.read();
}
}
Parámetros posibles en el constructor:
Comportamiento:
3. HTML con Jsoup: procesa documentos HTML transformándolos en Documents usando la librería JSoup.
4. Markdown: procesa documentos Mardown convirtiéndolos en Documents. Se debe incluir la siguiente dependencia:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-markdown-document-reader</artifactId>
</dependency>
public class CustomMarkdownReader {
...
public List<Document> loadMarkdown() {
MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder() .withHorizontalRuleCreateDocument(true).withIncludeCodeBlock(false).withIncludeBlockquote(false).withAdditionalMetadata("filename", "README.md").build();
MarkdownDocumentReader reader = new MarkdownDocumentReader(this.resource, config);
return reader.get();
}
}
La clase MarkdownDocumentReaderConfig permite hacer algunas personalizaciones:
5. PDF Page: gracias a la librería Apache PdfBox se pueden parsear ficheros PDF a través de la clase PagePdfDocumentReader. Se tiene que añadir la siguiente dependencia:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
private Resource arancelesPdf;
...
var pdfReader = new PagePdfDocumentReader(arancelesPdf);
6. PDF Paragraph: con la misma librería que el PDF Page permite dividir el PDF en párrafos y transformar cada uno de ellos en un Document.
private Resource arancelesPdf;
...
var pdfReader = new ParagraphPdfDocumentReader(arancelesPdf);
7. Tika: una librería Apache Tika para extraer texto de ficheros con distintos formatos (PDF, DOC/DOCX, PPT/PPTX, HTML).
Se incluye la siguiente dependencia:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
public class CustomTikaReader {
...
public List<Document> loadData() {
TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(this.resource);
return tikaDocumentReader.read();
}
}
Algunas implementaciones existentes son:
1. TextSplitter: la clase abstracta base que ayuda a dividir los ficheros para que no superen los límites de tokens.
2. TokenTextSplitter: implementación de TextSplitter que divide el texto en piezas según el número de tokens:
public class CustomTokenTextSplitter {
public List<Document> splitCustomized(List<Document> documents) {
TokenTextSplitter splitter = new TokenTextSplitter(10, 5, 2, 15, true);
return splitter.apply(documents);
}
}
Parámetros posibles en el constructor:
Comportamiento:
3. ContentFormatTransformer: asegura formatos de contenido uniformes en todos los documentos.
4. KeywordMetadataEnricher: usa IA generativa para extraer las palabras clave del fichero y añadirlas como metadata.
public class CustomKeywordEnricher {
private final ChatModel chatModel;
CustomKeywordEnricher(ChatModel chatModel) {
this.chatModel = chatModel;
}
public List<Document> enrichDocuments(List<Document> documents) {
KeywordMetadataEnricher enricher = new KeywordMetadataEnricher(this.chatModel, 2);
return enricher.apply(documents);
}
}
Parámetros posibles en el constructor:
Comportamiento:
5. SummaryMetadataEnricher: usa IA generativa para crear resúmenes de los ficheros y añadirlos como metadatos.
public class CustomSummaryEnricher {
private final SummaryMetadataEnricher enricher;
CustomSummaryEnricher(SummaryMetadataEnricher enricher) {
this.enricher = enricher;
}
public List<Document> enrichDocuments(List<Document> documents) {
return this.enricher.apply(documents);
}
}
@Configuration
public class SummaryMetadataConfig {
@Bean
SummaryMetadataEnricher summaryMetadata(ChatModel chatmodel) {
return new SummaryMetadataEnricher(chatmodel, List.of(SummaryType.PREVIOUS, SummaryType.CURRENT, SummaryType.NEXT));
}
}
Parámetros posibles en el constructor:
Comportamiento:
Algunas implementaciones existentes son:
1. File: implementación que escribe el contenido de una lista de Documents en un fichero.
public class CustomDocumentWriter {
public void writeDocuments(List<Document> documents) {
FileDocumentWriter writer = new FileDocumentWriter("./src/main/resources/static/docs/output.txt", true, MetadataMode.ALL, false);
writer.accept(documents);
}
}
Parámetros posibles en el constructor:
Comportamiento:
2. VectorStore: integración con las distintas VectorStores.
Definimos los siguientes endpoints para ver el funcionamiento de readers, transformers y writers:
Readers:
Transformers:
Writers:
RAG: empleando algunas de las funcionalidades anteriores para el patrón RAG, se puede crear una endpoint que a raíz de uno o varios ficheros de código existentes se le pueda pedir recomendaciones de código:
package com.example.springai.demo.springai_demo.application;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@Service
@Slf4j
public class ParadigmaSpecialService {
public void callingSpecialService() {
log.info("This is the implementation for the special service with Paradigma rules");
}
}
En este enlace se puede descargar el código de la aplicación de ejemplo.
Originalmente creado por Anthropic, el MCP o Model Context Protocol es un protocolo que estandariza la interacción entre aplicaciones y los LLMs.
Como se comenta por la red, se podría decir que el MCP es como el USB-C. De la misma forma en la que el USB-C es una conexión estándar entre distintos dispositivos, MCP sería un protocolo estándar para conectar los modelos de IA a aplicaciones u orígenes de datos.
Surge para la integración de datos y herramientas con los LLMs, ofreciendo:
Básicamente se trataría de un concepto similar (pero enfocado desde otra perspectiva) al Tool-Calling visto previamente de cara a crear funcionalidades que se puedan construir una vez y que sean aprovechadas por diferentes clientes/aplicaciones de una forma transparente.
Como en muchas ocasiones, se afianza mejor el concepto a través de ejemplos. Vamos a levantar una demo con un caso práctico para, por ejemplo, conocer qué ficheros tenemos en una carpeta concreta de nuestro sistema usando un LLM.
Para ver en cómo nos ayuda el MCP, seleccionamos uno de los múltiples clientes y servidores de ejemplo que podemos encontrar en las referencias de la especificación. En este caso, hacemos uso del cliente LibreChat y del servidor filesystem.
En primer lugar, en caso de tener ejecutándose el servicio de Ollama en el sistema, se tendrá que desactivar (en Linux se lanza el comando: systemctl stop ollama.service).
Posteriormente, ejecutamos LibreChat con la configuración por defecto asociada a Ollama usando docker-compose (además de esta configuración por defecto habrá que entrar en el contenedor en el que se ejecuta Ollama para descargar el LLM correspondiente).
Accediendo a la interfaz web (por defecto en http://localhost:3080/) y una vez registrados y hecho el login (la cuenta que se crea es local), podemos ver la típica interfaz de chat que tan extendida está últimamente:
Como se puede observar, ya se ha seleccionado el modelo correspondiente de Ollama y le preguntamos sobre algunos ficheros existentes en una carpeta de nuestro equipo (en este caso al ejecutarse Ollama en un contenedor, la carpeta deberá estar disponible en dicho contenedor).
Debido a que el modelo no tiene acceso a nuestro sistema de ficheros, nos responde que no nos puede ayudar.
A continuación, reiniciamos el docker-compose habilitando en esta ocasión la configuración de los servidores MCP. Volvemos a entrar en la interfaz observando cómo ya se ha habilitado la opción de “MCP Servers” en la sección de mensajes con el correspondiente server configurado:
Realizando la misma consulta que en el caso previo, se puede verificar la función que ejecuta el servidor MCP sobre nuestro sistema de ficheros así como la respuesta acorde del modelo:
En este punto, lo que hemos conseguido con el MCP es extender la información disponible (contexto) para que el LLM pueda ayudarnos con más tareas que de primeras no sería posible.
En este post de la serie dedicada a Spring AI, continuamos revisando la fase de ingesta de datos del patrón RAG y cómo implementarlo.
También hemos hablado de una de las últimas funcionalidades de moda en el mundo de la IA, el MCP (Model Context Protocol), visualizando todo su potencial a través de un ejemplo práctico.
En la siguiente entrega ahondaremos en la implementación del MCP sobre Spring AI, tanto por la parte cliente como por la parte servidor.
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.
Cuéntanos qué te parece.