Prompt Engineering con DSPy

Joshua Noble

Data Scientist

DSPy es un marco Python de código abierto para construir aplicaciones de modelos de lenguaje de gran tamaño (LLM) y afinar su rendimiento mediante código en lugar de técnicas únicas para la optimización de instrucciones. Un programa DSPy proporciona una forma modular de configurar y afinar las aplicaciones LLM optimizando las instrucciones para obtener salidas precisas. La principal ventaja de DSPy es que le permite hacer prompt engineering y seguimiento del rendimiento del modelo a través del código Python en lugar de tener que realizar un seguimiento del rendimiento del modelo usted mismo.

El poder de DSPy es que utiliza IA generativa para generar lenguaje natural y luego probar los resultados para crear las instrucciones más efectivas. Esto le permite crear un sistema de IA automejorable. Admite una amplia variedad de interfaces para modelos de recuperación y modelos de lenguaje. Puede ejecutar modelos localmente a través de sistemas como ollama o huggingface o puede ejecutarlos utilizando una API si está utilizando ChatGPT o GPT-4 de OpenAI. DSPy admite una amplia variedad de casos de uso como la cadena de pensamiento (CoT), la generación aumentada por recuperación (RAG), así como el resumen. 

En este tutorial, recorrerá el flujo de trabajo para crear una aplicación de respuesta a preguntas RAG con DSPy en IBM® watsonx. Utilizará Llama 3 como modelo de lenguaje y ColBERT como modelo de recuperación. Tendrás DSPy afina las instrucciones para ayudar y estructurar varios enfoques diferentes para responder a las preguntas para ver cómo generar mejores respuestas, incluso con preguntas muy complejas.

Configurar su entorno

Aunque puede elegir entre varias herramientas, este tutorial le muestra cómo configurar una cuenta de IBM para utilizar un Jupyter Notebook.

Inicie sesión en watsonx.ai con su cuenta de IBM® Cloud.

Cree un proyecto watsonx.ai.

Puede obtener el ID de su proyecto desde su proyecto.

A continuación, haga clic en la pestaña "Gestionar" y copie el ID del proyecto de la sección "Detalles" de la página "General". Necesita este ID para este tutorial.

A continuación, cree un Jupyter Notebook en el entorno que elija. Copiará el código de este tutorial en el nuevo cuaderno. También puede descargar este cuaderno desde GitHub a su sistema local y cargarlo en su proyecto watsonx.ai como activo.

Configurar una instancia de servicio de Watson Machine Learning (WML) y una clave de API

Cree una instancia de servicio de watsonx.ai Runtime (seleccione la región adecuada y elija el plan Lite, que es una instancia gratuita).

Genere una clave de API en watsonx.ai Runtime.

Asocie el servicio watsonx.ai Runtime al proyecto que ha creado en watsonx.ai.

Instalar la biblioteca DSPy y configure sus credenciales

Para usar DSPy, realice una instalación pip simple. También instalará dotenv para gestionar sus variables de entorno:

!pip install dspy-ai python-dotenv;

A continuación, importará las bibliotecas necesarias para el resto de este tutorial:

import dspy
from dspy import LM
from dspy.datasets import HotPotQA
from dspy.teleprompt import BootstrapFewShot
import json
import os

from dotenv import load_dotenv
load_dotenv(os.getcwd()+’/.env’, override=True)

Para configurar sus credenciales, necesita el WATSONX_APIKEY y el PROJECT_ID que generó en el paso 1. Puede almacenarlos en un archivo .env en su directorio o reemplazar el texto del marcador de posición. También establece la URL que sirve como endpoint de la API.

os.environ[‘WX_URL’] = “https://us-south.ml.cloud.ibm.com”
os.environ[‘WX_APIKEY’] = os.getenv(“WATSONX_APIKEY”, “”)

WATSONX_APIKEY= os.getenv(“WATSONX_APIKEY”, “”)
PROJECT_ID = os.getenv(“PROJECT_ID”,””)

Usar watsonx con DSPy

Ahora configurará DSPy para trabajar con modelos watsonx con la clase DSPy LM. Esta clase le permite llamar a las API de watsonx tanto para generar nuevas instrucciones como para generar respuestas a esas instrucciones que puede probar. Debajo, DSPy utiliza otra biblioteca llamada LiteLLM para acceder a los servicios de watsonx. LiteLLM proporciona un contenedor simple para llamar a una amplia gama de API LLM utilizando el formato OpenAI que incluye Hugging face, Azure y watsonx.

Antes de poder acceder a su cuenta de watsonx, debe almacenar un token del servicio watsonx con la clave de API que generó en el primer paso. Llame a la biblioteca del sistema operativo para acceder a "https://iam.cloud.ibm.com/identity/token" y recupere su token y guárdelo para su uso posterior.

token = os.popen(‘curl -k -X POST \
    --header “Content-Type: application/x-www-form-urlencoded” \
    --header “Accept: application/json” \
    --data-urlencode “grant_type=urn:ibm:params:oauth:grant-type:apikey” \
    --data-urlencode “apikey=’ + WATSONX_APIKEY + ‘” \
    “https://iam.cloud.ibm.com/identity/token”’).read()

Ahora puede crear una instancia de LanguageModel que utilice watsonx . Utilice el token que ha recuperado anteriormente como clave de API y nosotros utilizaremos el modelo "llama-3-8b-instruct" de Meta como modelo de lenguaje. Pase la ruta a ese modelo a DSPy para que lo use como modelo de lenguaje junto con la temperatura que desea que use el modelo de lenguaje. Encontrará más información sobre la configuración de LiteLLM para utilizar watsonx en sus documentos de GitHub. En este caso, 0,7 le da algo de creatividad sin exceso de alucinaciones.

lm = dspy.LM(‘watsonx/meta-llama/llama-3-8b-instruct’, api_key=WATSONX_APIKEY, api_base=”https://us-south.ml.cloud.ibm.com”)

dspy.configure(lm=lm, trace=[], temperature=0.7, experimental=True)

Agregar un modelo de recuperación

Ahora, cargue el modelo de recuperación para la R de su RAG. Utilice ColBERTv2 para cargar los extractos del conjunto de datos de Wikipedia 2017. ColBERT es un modelo de recuperación rápido y preciso, que permite la búsqueda escalable basada en BERT en grandes colecciones de texto en decenas de milisegundos. ColBERT es simplemente una de las muchas opciones que se pueden utilizar para recuperar información de una base de datos vectorial. Es comparable a otras bases de datos vectoriales como Qdrant, Milvus, Pinecone, Chroma o Weaviate.

Las bases de datos vectoriales tendrán un conjunto específico de información a la que el modelo de lenguaje puede acceder rápidamente. En este caso, va a utilizar un conjunto de resúmenes de Wikipedia 2017 para proporcionar una amplia gama de hechos para que su modelo de lenguaje los utilice en la generación. Esta combinación de ColBERT y el conjunto de datos Wiki 17 también es especialmente útil porque el equipo de DSPy aloja una versión de este de forma gratuita para que cualquiera pueda utilizarla. Proporciona acceso a una amplia gama de información sin necesidad de consumir datos o configurar su propio sistema de base de datos vectorial. Una desventaja que presenta este conjunto de datos es que no contiene nada sobre eventos posteriores a 2017, pero a efectos de demostración es muy útil.

Si está interesado en ejecutar su propia versión de ColBERT con sus propios datos o un conjunto de datos actualizado, los tutoriales aquí son útiles.

Después de eso, cargue el conjunto de datos HotPotQA y divídalo en conjuntos de entrenamiento y prueba que puede usar para probar su cadena de recuperación. HotpotQA es un conjunto de datos de respuesta a preguntas que contiene preguntas naturales de varios saltos, con una fuerte supervisión de los hechos de apoyo para permitir sistemas de respuesta a preguntas más explicables. 

colbertv2_wiki17_abstracts = dspy.ColBERTv2(url=’http://20.102.90.50:2017/wiki17_abstracts’)
dspy.configure(rm=colbertv2_wiki17_abstracts)

Pruebas de control de calidad básico

Ahora creará una firma que se utilizará para su ejemplo inicial. Una firma es una clase que define las entradas y las salidas de un módulo, lo que garantiza la compatibilidad entre diferentes módulos en un programa DSPy. Una firma combina múltiples tareas como consumir una pregunta y generar una respuesta y el razonamiento de los modelos. La firma que utilizará aquí solo admite una pregunta y proporciona una respuesta:

class BasicQA(dspy.Signature):
    “””Answer questions with short factoid answers.”””

    question = dspy.InputField()
    answer = dspy.OutputField(desc=”often between 1 and 5 words”)

Ahora dispone de un predictor que puede probar simplemente llamando al método Predict de DSPy. Este método toma la clase newBasicQA que definió anteriormente y utiliza esa clase cuando pasa una pregunta a DSPy.

# Define the predictor.
generate_answer = dspy.Predict(BasicQA)

Ahora creará una pregunta que requiera varios datos para responderla correctamente y la probará con una arquitectura que utilice únicamente un modelo de lenguaje. Utilizará la función thegenerate_answer que acaba de crear para responder a la pregunta.

# Call the predictor on a particular input.
test_question = “What country was the winner of the Nobel Prize in Literature in 2006 from and what was their name?”

pred = generate_answer(question=test_question)

if pred == None:
    print(“ no answer “)
else:
    # Print the input and the prediction.
    print(f”Answer: Turkey, Orhan Pamuk”)
    print(f”Predicted Answer: {pred.answer}”)

El código devuelve lo siguiente (su respuesta puede ser diferente):

Answer: Turkey, Orhan Pamuk
Predicted Answer: The winner was France and the author was Orhan Pamuk.

Orhan Pamuk fue el ganador del Premio Nobel de Literatura 2006, pero no es de Francia y el encuadre de la respuesta no es correcto. Ahora aumentará el modelo con recuperación utilizando Generación aumentada por recuperación y hará que DSPy diseñe mejores instrucciones para mejorar el rendimiento.

Generación aumentada por recuperación (RAG)

La generación aumentada por recuperación (RAG) es una arquitectura que optimiza el output de un modelo de lenguaje grande utilizando referencias de una base de conocimiento autorizada. Esto aumenta los datos de entrenamiento con fuentes verificadas antes de que el modelo de lenguaje genere una respuesta. Los LLM se entrenan en grandes corpus y utilizan miles de millones de parámetros para generar resultados, pero es posible que no puedan acceder a información actualizada o precisa de sus corpus de entrenamiento. RAG amplía las ya potentes capacidades de los LLM a un dominio específico sin necesidad de volver a entrenar el modelo. Es una forma potente y potencialmente rentable de mejorar los outputs de los LLM para que sigan siendo relevantes, precisos y útiles en diversos contextos.

En DSPy, se utiliza una arquitectura RAG añadiendo un paso de contexto en Signature. Este paso recopila el contexto del modelo de recuperación y lo añade a la instrucción del modelo de lenguaje para, con suerte, provocar una mejor respuesta.

class GenerateAnswer(dspy.Signature):
    “””Answer questions with short factoid answers.”””

    context = dspy.InputField(desc=”may contain relevant facts”)
    question = dspy.InputField()
    answer = dspy.OutputField(desc=”often between 1 and 5 words”)

Esa firma newGenerateAnswer se puede utilizar con su modelo RAG. Pase theGenerateAnswer al módulo 'ChainOfThought' para que el contexto recuperado y la pregunta y la respuesta utilicen un enfoque de cadena de pensamiento.

También actualiza el método forward para generar pasajes contextuales a partir del RAG y utiliza esos pasajes contextuales para generar respuestas. DSPy llamará a este método `forward` cada vez que genere una nueva respuesta a una pregunta, recopilando tanto el contexto del conjunto de datos de resúmenes ColBERT Wiki 17 como luego pasando ese contexto al modelo de lenguaje, en este caso, Llama 3.1. A medida que se genera cada respuesta, DSPy comparará el resultado con el resultado deseado para asegurarse de que las instrucciones ayuden al modelo a generar las respuestas correctas.

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, question):
        context = self.retrieve(question).passages
        prediction = self.generate_answer(context=context, question=question)
        return dspy.Prediction(context=context, answer=prediction.answer)

Para ayudar a DSPy a diseñar las mejores instrucciones para nosotros, necesita un conjunto de datos de prueba que pueda utilizar para probar las instrucciones y luego evaluarlas.

Para hacer preguntas de prueba de DSPy, deberá cargar el conjunto de datos HotPotQA. HotpotQA es un conjunto de datos de respuesta a preguntas que presenta preguntas naturales de varios saltos que requieren múltiples recuperaciones e inferencias para llegar a la respuesta correcta. Es una gran herramienta para probar cómo los modelos generan hechos de apoyo para entrenar y probar sistemas de respuesta a preguntas más explicables. 

Por ejemplo, una pregunta del conjunto de datos es: "¿A quién nombró el presidente Franklin Roosevelt para que fuera responsable de transmitir los votos del Colegio Electoral al Congreso?" Como puede ver, esta pregunta requiere varios datos para responderla correctamente.

The answer is: “Robert Digges Wimberly Connor”.

El contexto de apoyo proviene de las páginas de Wikipedia sobre Robert Digges Wimberly Connor y sobre la Administración Nacional de Archivos y Registros.

HotPotQA es recopilado y publicado por un equipo de investigadores de PLN de la Universidad Carnegie Mellon, la Universidad de Stanford y la Universidad de Montreal. Más información sobre HotPotQA está disponible en su sitio de GitHub.

Después de cargar el conjunto de datos, divídalo en conjuntos de entrenar y de prueba. Esto le permite probar la cadena de recuperación y ayudar a DSPy a localizar las mejores instrucciones para el modelo de lenguaje.

# Load the dataset.
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)

# Tell DSPy that the ‘question’ field is the input. Any other fields are labels and/or metadata.
trainset = [x.with_inputs(‘question’) for x in dataset.train]
devset = [x.with_inputs(‘question’) for x in dataset.dev]

A continuación, realizará el bootstrapping de más ejemplos para dar a DSPy más oportunidades de generar instrucciones y evaluarlas. Callingcompile es lo que utiliza toda la arquitectura que ha configurado, así como el conjunto de datos HotPotQA, para generar y probar instrucciones y obtener el mejor rendimiento de su modelo de lenguaje.

  from dspy.teleprompt import BootstrapFewShot

# Validation logic: check that the predicted answer is correct.
# Also check that the retrieved context does actually contain that answer.
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

# Set up a basic DSPy optimizer, which will compile your RAG program.
bfs_optimizer = BootstrapFewShot(metric=validate_context_and_answer)

# Compile!
compiled_rag = bfs_optimizer.compile(RAG(), trainset=trainset)

Ahora que DSPy ha realizado el prompt engineering por usted, lo probará con la pregunta personalizada sobre el Premio Nobel de 2006 que utilizó anteriormente. Dado que el modelo de recuperación utiliza extractos de Wikipedia de 2017, funcionará mejor con el conocimiento que pueda estar presente en ese corpus:

# Get the prediction. This contains `pred.context` and `pred.answer`.
pred = compiled_rag(test_question)

# Print the contexts and the answer.
print(f”Question: {test_question}”)
print(f”Predicted Answer: {pred.answer}”)

Ahora obtendrá la respuesta correcta. 

    Question: What country was the winner of the Nobel Prize in Literature in 2006 from and what was their name?
    Predicted Answer: Turkey, Orhan Pamuk

Orhan Pamuk es de Turquía, por lo que esta respuesta es correcta. La versión compilada de DSPy no solo dio la respuesta correcta, sino que también la enmarcó correctamente, respondiendo con una respuesta breve y clara. Veamos el contexto de esta respuesta prevista para ver cómo el modelo llegó a la respuesta correcta:

pred.context

Esto devuelve:

    ["Orhan Pamuk | Ferit Orhan Pamuk (generally known simply as Orhan Pamuk; born 7 June 1952) is a Turkish novelist, screenwriter, academic and recipient of the 2006 Nobel Prize in Literature. One of Turkey's most prominent novelists, his work has sold over thirteen million books in sixty-three languages, making him the country's best-selling writer.",
     '2006 Palanca Awards | The Carlos Palanca Memorial Awards for Literature winners in the year 2006 (rank, title of winning entry, name of author).',
     "Miguel Donoso Pareja | Miguel Donoso Pareja (July 13, 1931 – March 16, 2015) was an Ecuadorian writer and 2006 Premio Eugenio Espejo Award-winner (Ecuador's National Prize in literature, given by the President of Ecuador)."]

La respuesta está en el primer fragmento de contexto devuelto. Puede ver cómo DSPy diseñó instrucciones óptimas observando el historial del modelo de lenguaje utilizando el método inspect_history() del modelo de lenguaje.

lm.inspect_history()

Este historial es muy largo, ya que incluye todos los ejemplos del proceso de compilación en los que DSPy probó sus instrucciones generadas. La última parte del historial muestra cómo el modelo llegó a la respuesta correcta y en el formato correcto:

    [[ ## context ## ]]
    [1] «Orhan Pamuk | Ferit Orhan Pamuk (generally known simply as Orhan Pamuk; born 7 June 1952) is a Turkish novelist, screenwriter, academic and recipient of the 2006 Nobel Prize in Literature. One of Turkey's most prominent novelists, his work has sold over thirteen million books in sixty-three languages, making him the country's best-selling writer.»
    [2] «2006 Palanca Awards | The Carlos Palanca Memorial Awards for Literature winners in the year 2006 (rank, title of winning entry, name of author).»
    [3] «Miguel Donoso Pareja | Miguel Donoso Pareja (July 13, 1931 – March 16, 2015) was an Ecuadorian writer and 2006 Premio Eugenio Espejo Award-winner (Ecuador's National Prize in literature, given by the President of Ecuador).»
    
    [[ ## question ## ]]
    What country was the winner of the Nobel Prize in Literature in 2006 from and what was their name?
    
    Respond with the corresponding output fields, starting with the field `[[ ## reasoning ## ]]`, then `[[ ## answer ## ]]`, and then ending with the marker for `[[ ## completed ## ]]`.
    
    
    [31mResponse:[0m
    
    [32m[[ ## reasoning ## ]]
    The text mentions the 2006 Nobel Prize in Literature and states that Orhan Pamuk, a Turkish novelist, was the winner.
    
    [[ ## answer ## ]]
    Turkey, Orhan Pamuk
    
    [[ ## completed ## ]][0m
    

Puede ver que DSPy utilizó el modelo para generar la instrucción:

Responda con los campos de resultado correspondientes, comenzando por el campo [[ ## reasoning ## ]] , entonces [[ ## answer ## ]] y, a continuación, termine con el marcador de [[ ## completed ## ]] .

Esto conduce a la respuesta correcta y al encuadre adecuado.

Resumen

En este tutorial, utilizó DSPy para ayudar a afinar un agente RAG utilizando la plataforma watsonx. Su agente RAG constaba de un modelo de lenguaje, Llama 3 y un modelo de recuperación, ColBERT. A continuación, utilizó DSPy para ejectuar prompt engineering para una tarea de respuesta a preguntas compilando su modelo y generando una instrucción optimizada.

Puede obtener más información sobre DSPy en su repositorio de GitHub, donde alojan tutoriales, demostraciones y sus documentos.

Soluciones relacionadas
IBM watsonx.ai

Entrene, valide, ajuste e implemente IA generativa, modelos fundacionales y capacidades de machine learning con IBM watsonx.ai, un estudio empresarial de nueva generación para desarrolladores de IA. Cree aplicaciones de IA en menos tiempo y con menos datos.

Explore watsonx.ai
Soluciones de inteligencia artificial

Ponga la IA al servicio de su negocio con la experiencia líder del sector y el portfolio de soluciones de IA de IBM.

Explore las soluciones de IA
Servicios y consultoría de inteligencia artificial (IA)

Los servicios de IA de IBM Consulting ayudan a reinventar la forma de trabajar de las empresas usando IA para la transformación.

Explore los servicios de IA
Dé el siguiente paso

Gracias a la IA, IBM Concert descubre información crucial sobre sus operaciones y ofrece recomendaciones de mejora personalizadas para cada aplicación. Descubra cómo Concert puede hacer avanzar su negocio.

Explorar el concierto Explore las soluciones de automatización de procesos empresariales