Metadata, ¿cómo se personaliza un objeto Document en LlamaIndex?

Puedes seguir el artículo y descargar el código en este notebook subido en GitHub.

Ahora vamos a ver diferentes maneras de personalizar un objeto Document. La clase Document es una subclase de TextNode que hereda de BaseNode, que en última instancia es una clase subclase de BaseModel la cual depende Pydantic, la librería de validación de datos más utilizada en Python.

1. Incluir Metadata en un objeto Document de LlamaIndex

Los documentos ofrecen la posibilidad de incluir metadata útill. Utilizando el diccionario de metadatos de cada Document, se puede incluir información adicional que será de gran utilidad cuando preguntemos al modelo LLM.

Se puede incluir cualquier cosa, como nombres de archivos o categorías. Si estás trabajando con bases de datos vectorizadas o vector database tienes que tener en cuenta que algunas de ellos requieren claves que sean strings, y los valores deben ser planos (es decir, str, float o int).

Recuerda que la información que incorpores en los metadatos se hereda. Es decir, que también aparecerá en los nodos creados a partir de ese documento. Lo bueno es que toda esa información que se incluye en los nodos permitirá al índice la utilice en las consultas y las repuestas. Por defecto, será la información que se incluya cuando se hagan los embeddings y las llamadas al modelo LLM.

Puedes incluir mdetadats en un objeto Document de la siguiente manera:

1. En la construcción del documento, de esta manera:

document = Document(
    text="text",
    metadata={"filename": "<doc_file_name>", "category": "<category>"},
)

Document(id_=’5e7274e4-22f0-4a6b-a876-6fc07dbefe0a’, embedding=None, metadata={‘filename’: ‘<doc_file_name>’, ‘category’: ‘<category>’}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={}, text=’text’, start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}’, metadata_template='{key}: {value}’, metadata_seperator=’\n’)

2. Una vez el documento se haya creado:

document.metadata = {"tag": "<tag>"}

Document(id_=’5e7274e4-22f0-4a6b-a876-6fc07dbefe0a’, embedding=None, metadata={‘tag’: ‘<tag>’}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={}, text=’text’, start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\n\n{content}’, metadata_template='{key}: {value}’, metadata_seperator=’\n’)

2. Personalizando el ID de un objeto Document de LlamaIndex

Como se menciona en un apartado posterior (Document Management), doc_id se utiliza para permitir la actualización de los documentos en el índice. Al utilizar SimpleDirectoryReader, se puede configurar automáticamente el documento doc_id para que sea la ruta completa a cada documento:

documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data()
print([x.doc_id for x in documents])

c:\\Users\\Usuario\\Downloads\\medium\\data\\TSLA-Q1-2024-Update.pdf_part_0‘, ‘c:\\Users\\Usuario\\Downloads\\medium\\data\\TSLA-Q1-2024-Update.pdf_part_1′, ‘c:\\Users\\Usuario\\Downloads\\medium\\data\\TSLA-Q1-2024-Update.pdf_part_2′, […]

O configurar el doc_id de un documento directamente con document.doc_id = "ID PERSONALIZADO"


Lee estos artículos relacionados:

SimpleDirectoryReader. ¿Cómo cargar datos de archivos locales con LlamaIndex?

AVANZADO – Personalización de Metadata en Documents

Un detalle clave a tener en cuenta es que, por defecto, cualquier metadato que añadas se incluirá en el proceso de generación de embeddings y en las llamadas al LLM.

¿Cómo personalizar el texto de los metadatos al que accederá un modelo LLM?

Por defecto, un Document puede tener muchas clave-valor, pero es posible que no te interese que todas sean visibles para el LLM cuando vaya a generar la respuesta. Por ejemplo, es posible que NO nos interese que el LLM lea el nombre del archivo de nuestros documentos, pero SI que nos interese incluirlo cuando vayamos a generar los embeddings ya que eso nos ayudará a mejorar la recuperación de los datos sin cambiar la información que vaya a consultar el LLM.

Utilizando la fuente de datos de Tesla que introducíamos en este artículo, y una vez cargada la información utilizando SimpleDirectoryReader, podemos hacerlo accediendo a:

document.excluded_llm_metadata_keys = ["file_name"]

Luego podemos probar lo que el LLM realmente terminará leyendo utilizando la función get_content() y especificando MetadataMode.LLM de esta manera:

from llama_index.core.schema import MetadataMode

print(document.get_content(metadata_mode=MetadataMode.LLM))
from llama_index.core.schema import MetadataMode

El módulos schema define la estructura base de las estructuras de datos como Document y Node dentro de LlamaIndex. Una de las clases del módulo es MetadataMode que enumera los diferentes modos de gestión de los metadatos cuando construímos el índice e interactuamos con los LLM.

¿Cómo personalizar el formato de los metadatos de un Document?

Como decíamos, los metdatos se incluyen en el texto real de cada Document / Node cuando se envía a un LLM para generar una respuesta o en el proceso de generación de embeddings.

Por defecto, el formato de estos metadatos está controlado por tres atributos:

1. document.metadata_seperator, por defecto -> ‘\n’. Los campos clave-valor de los metadatos se concatenan, este campo controla el separador entre cada par clave-valor.

2. document.metadata_template, por defecto -> ‘{key}: {value}’. Este atributo controla como se formatea cada par clave-valor en los metadatos.

3. document.text_template, por defecto -> ‘{metadata_str}\n\n{content}’. Este atributo controla cómo se ven los metadatos cuando se unen con el contenido de texto del documento.

Vamos a ver un ejemplo, incorporando todo lo anterior:

from llama_index.core import Document
from llama_index.core.schema import MetadataMode

document = Document(
    text="Este es el texto de un documento personalizado",
    metadata={
        "file_name": "<tu-archivo>.txt",
        "category": "FINANZAS",
        "author": "Albert Gil López",
    },

    excluded_llm_metadata_keys=["file_name"],
    metadata_seperator="::",
    metadata_template="{key}=>{value}",
    text_template="Metadata: {metadata_str}\n-----\nContent: {content}",
)

print(
    "Esto es lo que el LLM verá: \n",
    document.get_content(metadata_mode=MetadataMode.LLM),
)
print(
    "Esto es lo que el modelo de embeddings verá: \n",
    document.get_content(metadata_mode=MetadataMode.EMBED),
)

El resultado de ejecutar esto es:

Esto es lo que el LLM verá:

Metadata: category=>FINANZAS::author=>Albert Gil López —– Content: Este es el texto de un documento personalizado

Esto es lo que el modelo de embeddings verá:

Metadata: file_name=>.txt::category=>FINANZAS::author=>Albert Gil López —– Content: Este es el texto de un documento personalizado


Lee estos artículos relacionados con la extracción de metadatos de los documentos:

AVANZADO. Extracción de Metadata para una mejor indexación y comprensión de un objeto Document en LlamaIndex