Connect with us

Ingeniería de prompts

Optimiza LLM con DSPy: Una guía paso a paso para construir, optimizar y evaluar sistemas de IA

mm
DSPy is a framework for algorithmically optimizing LM prompts and weights

A medida que las capacidades de los grandes modelos de lenguaje (LLM) continúan expandiéndose, desarrollar sistemas de IA robustos que aprovechen su potencial se ha vuelto cada vez más complejo. Los enfoques convencionales a menudo involucran técnicas de prompting intrincadas, generación de datos para afinar, y orientación manual para garantizar el cumplimiento de restricciones específicas del dominio. Sin embargo, este proceso puede ser tedioso, propenso a errores y muy dependiente de la intervención humana.

Entonces, entra DSPy, un marco revolucionario diseñado para simplificar el desarrollo de sistemas de IA impulsados por LLM. DSPy introduce un enfoque sistemático para optimizar las prompts y pesos de LM, lo que permite a los desarrolladores construir aplicaciones sofisticadas con un esfuerzo manual mínimo.

En esta guía integral, exploraremos los principios básicos de DSPy, su arquitectura modular y la variedad de características poderosas que ofrece. También nos sumergiremos en ejemplos prácticos, demostrando cómo DSPy puede transformar la forma en que desarrolla sistemas de IA con LLM.

¿Qué es DSPy, y por qué lo necesitas?

DSPy es un marco que separa el flujo de tu programa (módulos) de los parámetros (prompts de LM y pesos) de cada paso. Esta separación permite la optimización sistemática de las prompts y pesos de LM, lo que te permite construir sistemas de IA complejos con mayor confiabilidad, previsibilidad y cumplimiento de restricciones específicas del dominio.

Tradicionalmente, desarrollar sistemas de IA con LLM involucraba un proceso laborioso de descomposición del problema en pasos, creación de prompts intrincados para cada paso, generación de ejemplos sintéticos para afinar y orientación manual para que los LLM cumplan con restricciones específicas. Este enfoque no solo era tiempo-consuming, sino también propenso a errores, ya que incluso cambios menores en la tubería, LM o datos podrían requerir una re-elaboración extensiva de prompts y pasos de afinamiento.

DSPy aborda estos desafíos al introducir un nuevo paradigma: optimizadores. Estos algoritmos impulsados por LM pueden ajustar las prompts y pesos de tus llamadas a LM, dado un métrico que desees maximizar. Al automatizar el proceso de optimización, DSPy capacita a los desarrolladores para construir sistemas de IA robustos con una intervención manual mínima, mejorando la confiabilidad y previsibilidad de las salidas de LM.

Arquitectura modular de DSPy

En el corazón de DSPy se encuentra una arquitectura modular que facilita la composición de sistemas de IA complejos. El marco proporciona un conjunto de módulos integrados que abstraen varias técnicas de prompting, como dspy.ChainOfThought y dspy.ReAct. Estos módulos se pueden combinar y componer en programas más grandes, lo que permite a los desarrolladores construir tuberías intrincadas adaptadas a sus requisitos específicos.

Cada módulo encapsula parámetros aprendibles, incluyendo instrucciones, ejemplos de pocos disparos y pesos de LM. Cuando se invoca un módulo, los optimizadores de DSPy pueden afinar estos parámetros para maximizar el métrico deseado, garantizando que las salidas de LM cumplan con las restricciones y requisitos especificados.

Optimización con DSPy

DSPy introduce una serie de optimizadores poderosos diseñados para mejorar el rendimiento y la confiabilidad de tus sistemas de IA. Estos optimizadores aprovechan algoritmos impulsados por LM para ajustar las prompts y pesos de tus llamadas a LM, maximizando el métrico especificado mientras se adhieren a las restricciones específicas del dominio.

Algunos de los optimizadores clave disponibles en DSPy incluyen:

  1. BootstrapFewShot: Este optimizador extiende la firma automáticamente generando y incluyendo ejemplos optimizados dentro de la prompt enviada al modelo, implementando el aprendizaje de pocos disparos.
  2. BootstrapFewShotWithRandomSearch: Aplica BootstrapFewShot varias veces con búsqueda aleatoria sobre demostraciones generadas, seleccionando el mejor programa sobre la optimización.
  3. MIPRO: Genera instrucciones y ejemplos de pocos disparos en cada paso, con la generación de instrucciones siendo consciente de los datos y las demostraciones. Utiliza la Optimización Bayesiana para buscar efectivamente el espacio de instrucciones de generación y demostraciones a través de tus módulos.
  4. BootstrapFinetune: Destila un programa de DSPy basado en prompts en actualizaciones de pesos para LLM más pequeños, lo que te permite afinar el LLM subyacente para una mayor eficiencia.

Al aprovechar estos optimizadores, los desarrolladores pueden optimizar sistemáticamente sus sistemas de IA, garantizando salidas de alta calidad mientras se adhieren a las restricciones y requisitos específicos del dominio.

Comenzando con DSPy

Para ilustrar el poder de DSPy, vamos a recorrer un ejemplo práctico de construcción de un sistema de generación mejorada con recuperación (RAG) para preguntas y respuestas.

Paso 1: Configuración del modelo de lenguaje y el modelo de recuperación

El primer paso implica configurar el modelo de lenguaje (LM) y el modelo de recuperación (RM) dentro de DSPy.

Para instalar DSPy, ejecuta:


pip install dspy-ai

DSPy admite múltiples API de LM y RM, así como alojamiento de modelos locales, lo que facilita la integración de tus modelos preferidos.


import dspy

# Configura el LM y el RM
turbo = dspy.OpenAI(model='gpt-3.5-turbo')
colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')

dspy.settings.configure(lm=turbo, rm=colbertv2_wiki17_abstracts)

Paso 2: Carga del conjunto de datos

A continuación, cargaremos el conjunto de datos HotPotQA, que contiene una colección de pares de preguntas y respuestas complejas que normalmente se responden de manera multi-paso.


from dspy.datasets import HotPotQA

# Carga el conjunto de datos
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)

# Especifica el campo 'pregunta' como la entrada
trainset = [x.with_inputs('pregunta') for x in dataset.train]
devset = [x.with_inputs('pregunta') for x in dataset.dev]

Paso 3: Construcción de firmas

DSPy utiliza firmas para definir el comportamiento de los módulos. En este ejemplo, definiremos una firma para la tarea de generación de respuestas, especificando los campos de entrada (contexto y pregunta) y el campo de salida (respuesta).


class GenerateAnswer(dspy.Signature):
"""Respuesta a preguntas con respuestas breves."""

contexto = dspy.InputField(desc="puede contener hechos relevantes")
pregunta = dspy.InputField()
respuesta = dspy.OutputField(desc="a menudo entre 1 y 5 palabras")

Paso 4: Construcción de la tubería

Construiremos nuestra tubería RAG como un módulo de DSPy, que consiste en un método de inicialización (__init__) para declarar los submódulos (dspy.Retrieve y dspy.ChainOfThought) y un método hacia adelante (forward) para describir el flujo de control de responder a la pregunta utilizando estos módulos.


class RAG(dspy.Module):
def __init__(self, num_passages=3):
super().__init__()

self.retrieve = dspy.Retrieve(k=num_passages)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)

def forward(self, pregunta):
contexto = self.retrieve(pregunta).passages
prediccion = self.generate_answer(contexto=contexto, pregunta=pregunta)
return dspy.Prediction(contexto=contexto, respuesta=prediccion.respuesta)

Paso 5: Optimización de la tubería

Con la tubería definida, ahora podemos optimizarla utilizando los optimizadores de DSPy. En este ejemplo, utilizaremos el optimizador BootstrapFewShot, que genera y selecciona prompts efectivos para nuestros módulos en función de un conjunto de entrenamiento y un métrico de validación.


from dspy.teleprompt import BootstrapFewShot

# Métrico de validación
def validate_context_and_answer(example, pred, trace=None):
answer_EM = dspy.evaluate.answer_exact_match(example, pred)
answer_PM = dspy.evaluate.answer_passage_match(example, pred)
return answer_EM and answer_PM

# Configura el optimizador
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)

# Compila el programa
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

Paso 6: Evaluación de la tubería

Después de compilar el programa, es esencial evaluar su rendimiento en un conjunto de desarrollo para garantizar que cumpla con la precisión y confiabilidad deseada.


from dspy.evaluate import Evaluate

# Configura el evaluador
evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=4, display_progress=True, display_table=0)

# Evalúa el programa RAG compilado
evaluation_result = evaluate(compiled_rag)

print(f"Resultado de evaluación: {evaluation_result}")

Paso 7: Inspección del historial del modelo

Para una comprensión más profunda de las interacciones del modelo, puedes revisar las generaciones más recientes inspeccionando el historial del modelo.


# Inspecciona el historial del modelo
turbo.inspect_history(n=1)

Paso 8: Realización de predicciones

Con la tubería optimizada y evaluada, ahora puedes utilizarla para realizar predicciones sobre nuevas preguntas.


# Pregunta de ejemplo
pregunta = "¿Qué premio recibió el primer libro de Gary Zukav?"

# Realiza una predicción utilizando el programa RAG compilado
prediccion = compiled_rag(pregunta)

print(f"Pregunta: {pregunta}")
print(f"Respuesta: {prediccion.respuesta}")
print(f"Contextos recuperados: {prediccion.contexto}")

Ejemplo mínimo de trabajo con DSPy

Ahora, vamos a recorrer otro ejemplo mínimo de trabajo utilizando el conjunto de datos GSM8K y el modelo OpenAI GPT-3.5-turbo para simular tareas de prompting dentro de DSPy.

Configuración

Primero, asegúrate de que tu entorno esté configurado correctamente:


import dspy
from dspy.datasets.gsm8k import GSM8K, gsm8k_metric

# Configura el LM
turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250)
dspy.settings.configure(lm=turbo)

# Carga preguntas matemáticas del conjunto de datos GSM8K
gsm8k = GSM8K()
gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]

print(gsm8k_trainset)

El conjunto de datos gsm8k_trainset y gsm8k_devset contiene una lista de ejemplos con cada ejemplo que tiene un campo de pregunta y respuesta.

Definir el módulo

A continuación, define un programa personalizado que utilice el módulo ChainOfThought para razonamiento paso a paso:


class CoT(dspy.Module):
def __init__(self):
super().__init__()
self.prog = dspy.ChainOfThought("pregunta -> respuesta")

def forward(self, pregunta):
return self.prog(pregunta=pregunta)

Compilación y evaluación del modelo

He pasado los últimos cinco años sumergiéndome en el fascinante mundo del Aprendizaje Automático y el Aprendizaje Profundo. Mi pasión y experiencia me han llevado a contribuir a más de 50 proyectos de ingeniería de software diversos, con un enfoque particular en AI/ML. Mi curiosidad continua también me ha llevado hacia el Procesamiento de Lenguaje Natural, un campo que estoy ansioso por explorar más a fondo.