Volviendo la primavera AI y OpenAI GPT útiles con RAG en tus propios documentos

Revolucionando la primavera con IA y GPT de OpenAI Cómo hacer tus propios documentos más útiles con RAG

El proyecto AIDocumentLibraryChat utiliza el proyecto Spring AI con OpenAI para buscar respuestas a preguntas en una biblioteca de documentos. Para hacerlo, se utiliza una generación aumentada de recuperación en los documentos.

Generación Aumentada de Recuperación

El proceso se ve así:

El proceso se ve así:

  • Cargar Documento
  • Almacenar el Documento en una base de datos Postgresql.
  • Dividir el Documento para crear Empotramientos.
  • Crear Empotramientos con una llamada al Modelo de Empotramiento de OpenAI.
  • Almacenar los Empotramientos del Documento en la base de datos Vector de Postgresql.

Buscar Documentos:

  • Crear Pista de Búsqueda
  • Crear Empotramiento de la Pista de Búsqueda con una llamada al Modelo de Empotramiento de OpenAI.
  • Consultar la base de datos Vector de Postgresql para buscar documentos con embotramientos más cercanos.
  • Consultar la base de datos Postgresql para obtener el Documento.
  • Crear Pista con la Pista de Búsqueda y el fragmento de texto del Documento.
  • Solicitar una respuesta del Modelo GPT y mostrar la respuesta basada en la pista de búsqueda y el fragmento de texto del Documento.

Carga de Documentos

El documento cargado se guarda en la base de datos para tener el documento fuente de la respuesta. El texto del documento debe dividirse en fragmentos para crear empotramientos por fragmento. Los empotramientos son creados por un modelo de empotramiento de OpenAI y son vectores con más de 1500 dimensiones para representar el fragmento de texto. El empotramiento se guarda en un documento de IA con el fragmento de texto y el ID del documento fuente en la base de datos vectorial.

La búsqueda de documentos toma la pista de búsqueda y utiliza el modelo de empotramiento de OpenAI para convertirla en un empotramiento. El empotramiento se utiliza para buscar en la base de datos vectorial el vector más cercano. Esto significa que se buscan los empotramientos de la pista de búsqueda y el fragmento de texto que tienen las mayores similitudes. El ID en el documento de IA se utiliza para leer el documento de la base de datos relacional. Con la Pista de Búsqueda y el fragmento de texto del documento de IA, se crea la Pista de Documento. Luego, se llama al modelo de OpenAI GPT con la pista para crear una respuesta basada en la Pista de Búsqueda y el contexto del documento. Esto hace que el modelo cree respuestas que se basan estrechamente en los documentos proporcionados y mejora la precisión. Se devuelve y muestra la respuesta del modelo GPT con un enlace al documento para proporcionar la fuente de la respuesta.

Arquitectura

La arquitectura del proyecto está construida en torno a Spring Boot con Spring AI. La interfaz de usuario Angular proporciona la interfaz de usuario para mostrar la lista de documentos, cargar los documentos y proporcionar la Pista de Búsqueda con la respuesta y el documento fuente. Se comunica con el backend de Spring Boot a través de la interfaz REST. El backend de Spring Boot proporciona los controladores REST para el frontend y utiliza Spring AI para comunicarse con los modelos de OpenAI y la base de datos vectorial de Postgresql. Los documentos se almacenan con Jpa en la base de datos relacional de Postgresql. La base de datos de Postgresql se utiliza porque combina la base de datos relacional y la base de datos vectorial en una imagen de Docker.

Implementación

Frontend

El frontend se basa en componentes independientes cargados de forma perezosa construidos con Angular. Los componentes independientes cargados de forma perezosa se configuran en el archivo app.config.ts:

La configuración establece las rutas y habilita el cliente HTTP y las animaciones.

Las rutas cargadas de forma perezosa se definen en app.routes.ts:

En ‘loadChildren’, ‘import(“…”).then((mod) => mod.XXX)’ carga de forma perezosa la ruta desde la ruta proporcionada y establece las rutas exportadas definidas en la constante ‘mod.XXX’.

La ruta cargada de forma perezosa ‘docsearch’ tiene el index.ts para exportar la constante:

Eso exporta el archivo doc-search.routes.ts:

Define la ruta hacia el ‘DocSearchComponent’.

El archivo se encuentra en el DocImportComponent con la plantilla doc-import.component.html:

La carga del archivo se realiza con la etiqueta ‘<input type=”file” (change)=”onFileInputChange($event)”>’. Proporciona la función de carga y llama al método ‘onFileInputChange(…)’ después de cada carga.

El botón de ‘Cargar’ llama al método ‘upload()’ para enviar el archivo al servidor al hacer clic.

El doc-import.component.ts tiene métodos para la plantilla:

Este es el componente independiente con sus módulos importados y el ‘DestroyRef’ inyectado.

El método ‘onFileInputChange(…)’ recibe el parámetro de evento y almacena su propiedad ‘files’ en la constante ‘files’. Luego verifica el primer archivo y lo almacena en la propiedad de componente ‘file’.

El método ‘upload()’ verifica la propiedad ‘file’ y crea el ‘FormData()’ para la carga del archivo. La constante ‘formData’ tiene el tipo de datos (‘file’), el contenido (‘this.file’) y el nombre del archivo (‘this.file.name’) adjunto. Luego se utiliza el ‘documentService’ para enviar el objeto ‘FormData()’ al servidor. La función ‘takeUntilDestroyed(this.destroyRef)’ cancela la suscripción a la canalización de Rxjs después de que se destruye el componente. Eso hace que la cancelación de canalizaciones sea muy conveniente en Angular.

Backend

El backend es una aplicación Spring Boot con el framework Spring AI. Spring AI gestiona las solicitudes a los modelos de OpenAI y las solicitudes de la base de datos de vector.

Configuración de la base de datos con Liquibase

La configuración de la base de datos se realiza con Liquibase y el script se encuentra en db.changelog-1.xml:

En el conjunto de cambios 4 se crea la tabla para la entidad Jpa de documentos con la clave primaria ‘id’. El tipo/tamaño de contenido es desconocido y se establece como ‘blob’. En el conjunto de cambios 5 se crea la secuencia para la entidad Jpa con las propiedades predeterminadas de las secuencias Hibernate 6 que son utilizadas por Spring Boot 3.x.

En el conjunto de cambios 6 se crea la tabla ‘vector_store’ con una clave primaria ‘id’ de tipo ‘uuid’ que es creada por la extensión ‘uuid-ossp’. La columna ‘content’ es de tipo ‘text’ (‘clob’ en otras bases de datos) para tener un tamaño flexible. La columna ‘metadata’ almacena los metadatos en un tipo ‘json’ para los AIDocuments. La columna ’embedding’ almacena el vector de incrustación con el número de dimensiones de OpenAI.

En el conjunto de cambios 7 se establece el índice para la búsqueda rápida de la columna ’embeddings’. Debido a los parámetros limitados del ‘<createIndex …>’ de Liquibase, se utiliza directamente ‘<sql>’ para crearlo.

Implementación de Spring Boot / Spring AI

El DocumentController para el frontend se ve así:

El método ‘handleDocumentUpload(…)’ maneja el archivo cargado con el ‘documentService’ en la ruta ‘/rest/document/upload’.

El método ‘getDocumentList()’ maneja las solicitudes ‘get’ para las listas de documentos y elimina el contenido del documento para ahorrar en el tamaño de la respuesta.

El método ‘getDocumentContent(…)’ maneja las solicitudes ‘get’ para el contenido del documento. Carga el documento con el ‘documentService’ y asigna el ‘DocumentType’ al ‘MediaType’. Luego devuelve el contenido y el tipo de contenido, y el navegador abre el contenido según el tipo de contenido.

El método ‘postDocumentSearch(…)’ coloca el contenido de la solicitud en el objeto ‘SearchDto’ y devuelve el resultado generado por AI de la llamada ‘documentService.queryDocuments(…)’.

El método ‘storeDocument(…)’ de DocumentService se ve así:

El método ‘storeDocument(…)’ guarda el documento en la base de datos relacional. Luego, el documento se convierte en un ‘ByteArrayResource’ y se lee con el ‘TikaDocumentReader’ de Spring AI para convertirlo en una lista de AIDocumentos. Luego, la lista de AIDocumentos se aplana para dividir los documentos en fragmentos con el método ‘splitToTokenLimit(…)’ que se convierten en nuevos AIDocumentos con el ‘id’ del documento almacenado en el mapa Metadata. El ‘id’ en Metadata permite cargar la entidad de documento coincidente para los AIDocumentos. Luego se crean implícitamente los embeddings para los AIDocumentos con llamadas al método ‘documentVsRepository.add(…)’ que llama al modelo de embeddings de OpenAI y almacena los AIDocumentos con los embeddings en la base de datos vectorial. Luego se devuelve el resultado.

El método ‘queryDocument(…)’ se ve así:

El método primero carga los documentos que mejor coinciden con ‘searchDto.getSearchString()’ de la base de datos vectorial. Para hacer eso, se llama al modelo de embeddings de OpenAI para convertir la cadena de búsqueda en un embedding y con ese embedding se consulta la base de datos vectorial en busca de los AIDocumentos con la distancia más corta (la distancia entre los vectores del embedding de búsqueda y el embedding de la base de datos). Luego, el AIDocumento con la distancia más corta se almacena en la variable ‘mostSimilar’. Luego, todos los AIDocumentos de los fragmentos de documentos se recopilan mediante la coincidencia de la entidad de documento ‘id’ de sus Metadata. El ‘systemMessage’ se crea con el contenido de ‘documentChunks’ o ‘mostSimilar’. El método ‘getSystemMessage(…)’ los toma y corta los fragmentos de contenido a un tamaño que los modelos OpenAI GPT pueden manejar y devuelve el ‘Message’. Luego, el ‘systemMessage’ y el ‘userMessage’ se convierten en un ‘prompt’ que se envía con ‘aiClient.generate(prompt)’ al modelo OpenAI GPT. Después de eso, la respuesta de AI está disponible y se carga la entidad de documento con el id del metadato del AIDocumento ‘mostSimilar’. Se crea el ‘AiResult’ con la cadena de búsqueda, la respuesta de GPT, la entidad de documento y se devuelve.

El repositorio de vector database DocumentVsRepositoryBean con el ‘VectorStore’ de Spring AI se ve así:

El repositorio tiene la propiedad ‘vectorStore’ que se utiliza para acceder a la base de datos vectorial. Se crea en el constructor con los parámetros inyectados con la llamada ‘new PgVectorStore(…)’. La clase PgVectorStore se proporciona como extensión de la base de datos vectorial de Postgresql. Tiene el ’embeddingClient’ para usar el modelo de embeddings de OpenAI y el ‘jdbcTemplate’ para acceder a la base de datos.

El método ‘add(…)’ llama al modelo de embeddings de OpenAI y agrega AIDocumentos a la base de datos vectorial.

Los métodos ‘retrieve(…)’ consultan la base de datos vectorial para obtener los embeddings con las distancias más cortas.

Conclusión

Angular facilitó la creación del frontend. Los componentes independientes con carga lenta han hecho que la carga inicial sea pequeña. Los componentes de Angular Material han ayudado mucho con la implementación y son fáciles de usar.

Spring Boot con Spring AI ha facilitado el uso de los Large Language Models. Spring AI proporciona el marco para ocultar la creación de los embeddings y proporciona una interfaz fácil de usar para almacenar los AIDocumentos en una base de datos vectorial (se admiten varias). La creación del embedding para la consulta de búsqueda para cargar los AIDocumentos más cercanos también se hace por usted y la interfaz de la base de datos vectorial es sencilla. Las clases de prompt de Spring AI facilitan también la creación del prompt para los modelos OpenAI GPT. La llamada al modelo se realiza con el ‘aiClient’ inyectado y se devuelven los resultados.

Spring AI es un Framework muy bueno del equipo de Spring. No ha habido problemas con la versión experimental.

Con Spring AI, los Large Language Models ahora son fáciles de usar en nuestros propios documentos.

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Drones Protegen los Aerogeneradores del Hielo

Los investigadores desarrollaron un método para proteger los aerogeneradores del hielo utilizando drones.

Inteligencia Artificial

Aprendizaje profundo para objetos profundos ZoeDepth es un modelo de IA para la estimación de profundidad en múltiples dominios

¿Alguna vez te has encontrado con ilusiones en las que un niño en la imagen parece más alto y más grande que un adult...

Inteligencia Artificial

Stability AI lanza el primer modelo japonés de visión y lenguaje

La creación y formulación de un modelo único y completo capaz de manejar una variedad de tareas definidas por el usua...

Inteligencia Artificial

Llama-2, GPT-4 o Claude-2; ¿Cuál es el mejor modelo de lenguaje de inteligencia artificial?

Los Modelos de Lenguaje Grandes (LLMs) han recibido mucha apreciación a nivel mundial y han ganado inmensa popularida...

Inteligencia Artificial

¿Qué es la innatismo y importa para la inteligencia artificial? (Parte 2)

La cuestión de la innatitud, tanto en biología como en inteligencia artificial, es crucial para el futuro de la IA si...