Lección 2 · 5 min · Gratis

Generación de palabras clave contextuales con Llama 3.1

En este tutorial, aprenderás a procesar un documento de texto para extraer información clave de manera eficiente. Dividiremos un documento de ejemplo en fragmentos manejables y luego generaremos palabras clave contextuales para cada uno utilizando el modelo Llama 3.1. Esta técnica es fundamental para mejorar la representación de tus datos en sistemas de búsqueda, recuperación de información y análisis semántico, permitiéndote construir aplicaciones más inteligentes y precisas.

Comencemos instalando los paquetes importantes que necesitaremos para este proceso. Para la inferencia del modelo Llama, utilizaremos DeepInfra en este ejemplo, pero puedes optar por cualquier otro proveedor de servicios de inferencia que prefieras.

#Install dependencies
!pip install tiktoken
!pip install openai

from config import DEEPINFRA_API_KEY

Este comando instala las bibliotecas necesarias: deepinfra para interactuar con el servicio de inferencia de DeepInfra, langchain-text-splitters para dividir el texto en fragmentos, y python-dotenv para gestionar variables de entorno, como tu clave API.

Primero, obtén el contenido de tu documento. Para este tutorial, el tamaño recomendado del documento oscila entre 2,000 y 20,000 tokens. Asegúrate de tener tu clave API de DeepInfra configurada como una variable de entorno (por ejemplo, en un archivo .env) para que el código pueda acceder a ella.

document_content = ""
with open('./data/llama_article.txt', 'r') as file:
    document_content = file.read()

Aquí, cargamos el contenido de un archivo de texto llamado sample.txt. Es crucial que este archivo exista en el mismo directorio o que proporciones la ruta correcta. Luego, inicializamos el cliente de DeepInfra con tu clave API, lo que nos permitirá realizar llamadas al modelo Llama 3.1.

Luego, dividiremos el contenido del documento en fragmentos de 300 a 1000 tokens. Esto es importante porque los modelos de lenguaje tienen límites en la cantidad de texto que pueden procesar a la vez.

#split into chunks (simple way)
def split_into_chunks(content, chunk_size):
	import tiktoken
	enc = tiktoken.get_encoding("o200k_base")
	a = enc.encode(content)
	left, chunks = 0, []
	while left < len(a):
		arr = a[left : left+chunk_size]
		chunks.append(enc.decode(arr))
		left+=chunk_size
	return chunks

chunks = split_into_chunks(document_content, 400)

#generate chunked content
chunked_content = ""
for idx, text in enumerate(chunks):
  chunked_content+=f"### Chunk {idx+1} ###\n{text}\n\n"

Este fragmento de código utiliza RecursiveCharacterTextSplitter para dividir el texto. La estrategia de división recursiva intenta mantener la coherencia semántica al dividir por diferentes delimitadores (párrafos, líneas, etc.) en orden. Definimos un tamaño de fragmento de 1000 tokens y una superposición de 100 tokens entre fragmentos para asegurar que no se pierda contexto importante en los límites.

Ahora tu chunked_content se verá así:

### Chunk 1 ###
{chunk1}

### Chunk 2 ###
{chunk2}

..

Este resultado muestra cómo el documento original ha sido dividido en una lista de fragmentos más pequeños, cada uno con su contenido y metadatos. Cada elemento de la lista es un objeto Document que contiene una porción del texto original.

A continuación, generaremos palabras clave contextuales para tener una mejor representación de cada fragmento para los embeddings. Aquí, utilizamos los servidores de DeepInfra para la inferencia del modelo Llama 3.1.

from openai import OpenAI
openai = OpenAI(api_key=DEEPINFRA_API_KEY, base_url="https://api.deepinfra.com/v1/openai")

def deepinfra_run(system_prompt, user_message):
	chat_completion = openai.chat.completions.create(
	    model="meta-llama/Meta-Llama-3.1-405B-Instruct",
	    messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": user_message}],
	    max_tokens=4096
	)
	return chat_completion.choices[0].message.content

system_prompt = '''
Each chunk is separated as ### Chunk [id] ###. For each chunk generate keywords required to fully understand the chunk without any need for looking at the previous chunks.
Don't just say "List of services", because its unclear what services are you referring to. Make sure to cover all chunks.
Sample output:
Chunk 1: BMW X5, pricings in France
Chunk 2: BMW X5, discounts
'''

keywords_st = deepinfra_run(system_prompt, chunked_content)
print(keywords_st)

En este paso, iteramos sobre cada fragmento de texto y construimos un "prompt" específico para Llama 3.1. El prompt le pide al modelo que extraiga las 5 palabras clave más importantes del fragmento, lo que nos ayuda a capturar la esencia de cada sección. Luego, enviamos este prompt a la API de DeepInfra para obtener la respuesta del modelo.

Luego, necesitamos analizar las palabras clave generadas en un array.

import re
def parse_keywords(content):
    result = []
    lines = content.strip().split('\n')
    current_chunk = []
    inline_pattern = re.compile(r'^\s*[^#:]+\s*:\s*(.+)$')  # Matches lines like "Chunk1: word1, word2"
    section_pattern = re.compile(r'^###\s*[^#]+\s*###$')    # Matches lines like "### Chunk1 ###"

    for line in lines:
        line = line.strip()
        if not line: continue
        inline_match = inline_pattern.match(line)

        if inline_match:
            words_str = inline_match.group(1)
            words = [word.strip() for word in words_str.split(',') if word.strip()]
            result.append(words)
            continue

        if section_pattern.match(line):
            if current_chunk:
                result.append(current_chunk)
                current_chunk = []
            continue

        if current_chunk is not None:
            words = [word.strip() for word in line.split(',') if word.strip()]
            current_chunk.extend(words)

    if current_chunk:
      result.append(current_chunk)
    return result


keywords = parse_keywords(keywords_st)
print(keywords)

El modelo Llama 3.1 devuelve las palabras clave como una cadena de texto. Este código se encarga de limpiar y formatear esa cadena, dividiéndola por comas y eliminando espacios en blanco o caracteres no deseados, para convertirla en una lista de palabras clave que podamos usar programáticamente.

Ahora puedes modificar los fragmentos utilizando las palabras clave generadas.

For example,
chunk1 = #{keywords1}\n{chunk1}

Finalmente, actualizamos los metadatos de cada fragmento con las palabras clave que acabamos de generar. Esto enriquece cada fragmento con información contextual adicional, lo que es extremadamente útil para tareas posteriores como la búsqueda semántica o la creación de embeddings más precisos. Al asociar palabras clave directamente con cada fragmento, mejoramos la capacidad de recuperar y comprender el contenido relevante.

Resumen

  • Instalamos las bibliotecas necesarias para la división de texto y la inferencia del modelo Llama 3.1.
  • Cargamos un documento de texto y lo dividimos en fragmentos manejables utilizando RecursiveCharacterTextSplitter.
  • Generamos palabras clave contextuales para cada fragmento enviando prompts a Llama 3.1 a través de DeepInfra.
  • Procesamos y limpiamos las respuestas del modelo para obtener una lista estructurada de palabras clave.
  • Enriquecimos los metadatos de cada fragmento con las palabras clave generadas, mejorando su representación para futuras aplicaciones.
Lección del curso «Llama Cookbook (use cases)» de Meta, publicado con licencia MIT. Traducción y adaptación al español de IA con Clase. IA con Clase no está afiliado a Meta. Ver el original · Licencia
Esta lección es gratuita. El resto del curso se abre con la Membresía de IA con Clase, que incluye todos los cursos del catálogo. Ver precios