En esta aplicación, la ingesta de todos los documentos de ejemplo se activa con el comando flask create-index . La implementación de este comando está en el archivo app.py del directorio API y simplemente importa el módulo index_data.py desde el directorio de datos y llama a su función main() , que realiza una importación completa de todos los documentos almacenados en el archivo data.json .

Estructura del documento

La estructura de cada documento es la siguiente:

  • name: el título del documento
  • url: una URL al documento alojado en un sitio externo
  • summary: un breve resumen del contenido del documento
  • content: el cuerpo del documento
  • created_on: fecha de creación
  • updated_at: fecha de actualización (podría faltar si el documento nunca se actualizó)
  • category: la categoría del documento, que puede ser github, sharepoint o teams
  • rolePermissions: una lista de licencias de rol

A partir de estos, esta aplicación de ejemplo emplea el campo content como texto para los índices, y agrega name, summary, url, category y updated_at como metadatos asociados.

El siguiente fragmento de código Python muestra cómo se importan los documentos:

Aquí se emplea el módulo json de la biblioteca estándar de Python para leer el archivo de datos, y luego, para cada documento incluido, se crea un objeto Document de Langchain. Los documentos tienen un atributo page_content que define el contenido a convertir en vectores y buscar, además de varios campos adicionales que se almacenan como metadatos. El metadata_keys determina qué campos del contenido original se almacenarán como metadatos del documento.

Dependiendo de tus necesidades de ingestión, el método puede ser refinado o modificado. El proyecto Langchain ofrece una amplia selección de cargadores de documentos que pueden usar dependiendo del formato del contenido fuente.

El modelo Elastic Learned Sparse EncodeR (ELSER)

El índice Elasticsearch empleado en esta aplicación está configurado para crear automáticamente incrustaciones vectoriales dispersas para todos los documentos que se insertan. La función install_elser() en index_data.py cerciora que el modelo ELSER esté instalado y desplegado en la instancia de Elasticsearch que estás usando.

División de texto

El campo de content en estos documentos es largo, lo que significa que una sola incrustación no podrá representarlo completamente. La solución estándar al trabajar con grandes cantidades de texto es dividir el texto en pasajes más cortos y luego obtener incrustaciones para los pasajes individuales, todos los cuales se almacenan e indexan.

En esta aplicación, se emplea la clase RecursiveCharacterTextSplitter de la biblioteca Langchain , emparejada con el codificador tiktoken de OpenAI, que cuenta las longitudes de los pasajes en los tokens, las mismas unidades que usan los LLM.

Consideremos el siguiente ejemplo, que demuestra cómo funciona la división de texto en la aplicación:

Estableciendo el argumento chunk_size del divisor de texto, es posible controlar la longitud de los pasajes resultantes. El chunk_overlap permite cierto solapamiento entre pasajes, lo que a menudo ayuda a obtener mejores incrustaciones.

En la aplicación real, el divisor se inicializa con los siguientes argumentos:

Puedes cambiar estos valores y ver cómo afectan los cambios a la calidad del chatbot. Cada vez que cambias la configuración del divisor deberías volver a generar el índice ejecutando el comando flask create-index .

Ten en cuenta que hay más consideraciones sobre la división de texto en combinación con el modelo ELSER que deberías tener en cuenta. Para casos de uso en producción puede que tengas que elegir otro método de tokenización como en este tutorial.

Almacenamiento de documentos

Los documentos se almacenan en un índice de Elasticsearch. El nombre del índice está controlado por la variable de entorno ES_INDEX , que se define en el archivo .env archivo. Por defecto, el nombre de este índice es workplace-app-docs.

La aplicación emplea la clase ElasticsearchStore , que forma parte de la integración de Elasticsearch en Langchain, y emplea la biblioteca cliente oficial de Elasticsearch para Python.

La lógica completa que trata el índice de Elasticsearch se muestra a continuación:

El método ElasticsearchStore.from_documents() importa todas las instancias Document almacenadas en workplace_docs, escribiéndolas al índice dado en el argumento index_name . Todas las operaciones se realizan a través del cliente dado en el argumento es_connection .

El argumento strategy define cómo se va a emplear este índice. Para esta aplicación, la clase SparseVectorRetrievalStrategy indica que se deben mantener incrustaciones vectoriales dispersas para cada documento. Esto agregará una tubería al índice que generará incrustaciones a través del modelo aplicar (ELSER versión 2 en este caso).

La integración de Elasticsearch con Langchain ofrece otras estrategias que pueden emplear según el caso de uso. En individuo, la AproxRetrievalStrategy puede emplear cuando se emplean incrustaciones de vectores densos.

¿Estás listo para crear experiencias de búsqueda de última generación?

No se logra una búsqueda suficientemente avanzada con los esfuerzos de uno. Elasticsearch está impulsado por científicos de datos, operaciones de ML, ingenieros y muchos más que son tan apasionados por la búsqueda como tú. Conectemos y trabajemos juntos para crear la experiencia mágica de búsqueda que te dará los resultados que deseas.

Pruébalo tú mismo