Ingeniería rápida con DSPy

Joshua Noble

Data Scientist

DSPy es un marco Python de código abierto para construir aplicaciones de modelos de lenguaje grandes (LLM) y ajustar su rendimiento a través de código en lugar de técnicas únicas para la optimización de instrucciones. Un programa DSPy proporciona una forma modular de configurar y ajustar las aplicaciones de LLM optimizando las instrucciones para obtener resultados precisos. La principal ventaja de DSPy es que le permite realizar ingeniería rápida y seguimiento del rendimiento 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 de mejora automática. 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 mediante 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, por sus siglas en inglés), así como el resumen. 

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

Configure su entorno

Si bien puede elegir entre varias herramientas, este tutorial lo guiará a través de cómo configurar una cuenta de IBM para usar un Jupyter Notebook.

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

Cree un proyecto watsonx.ai.

Puede obtener su ID de proyecto desde dentro de su proyecto.

A continuación, haga clic en la pestaña "Manage" y copie el ID del proyecto de la sección "Details" 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 Notebook. También puede descargar este Notebook de GitHub a su sistema local y cargarlo en su proyecto watsonx.ai como un activo.

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

Cree una instancia de servicio 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 de watsonx.ai Runtime al proyecto que creó en watsonx.ai.

Instale la biblioteca DSPy y configure sus credenciales

Para usar DSPy, realice una instalación pip simple. También instalará dotenv para administrar 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 WATSONX_APIKEY y 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 debe establecer la URL que sirve como punto de enlace 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”,””)

Uso de watsonx con DSPy

Ahora, configurará DSPy para que funcione 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 mediante el formato OpenAI que incluye Hugging face, Azure y watsonx.

Antes de poder acceder a su cuenta watsonx, debe almacenar un token del servicio watsonx con su clave de API que generó en el primer paso. Llame a la biblioteca os para acceder a “https://iam.cloud.ibm.com/identity/token” y recupere su token para almacenarlo y usarlo más adelante.

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 recuperó 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 su modelo de lenguaje junto con la temperatura que desea que use el modelo de lenguaje. Hay más información sobre la configuración de LiteLLM para usar watsonx en sus documentos de GitHub. En este caso, 0.7 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 el 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, utilizará un conjunto de resúmenes de Wikipedia 2017 para proporcionar una amplia gama de datos para que su modelo de lenguaje los use 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 usarla. Proporciona acceso a una amplia gama de información sin necesidad de ingerir 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, para fines 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, estos tutoriales son útiles.

Después de eso, cargue el conjunto de datos de 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 multi-hop, con una supervisión sólida 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 básicas de control de calidad

Ahora creará una firma que se utilizará para su ejemplo inicial. Una firma es una clase que define los tipos de entrada y salida de un módulo, lo que garantiza la compatibilidad entre diferentes módulos en un programa DSPy. Una firma combina múltiples tareas, como ingerir una pregunta y tener los resultados una respuesta y el razonamiento de los modelos. La firma que usará aquí solo toma 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 tiene 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 requiere múltiples datos para responderla correctamente y la probará con una arquitectura que utiliza solo un modelo de lenguaje. Utilizará la función generate_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 marco de la respuesta no es correcto. Ahora aumentará el modelo con recuperación mediante 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, por sus siglas en inglés) es una arquitectura que optimiza los resultados de un modelo de lenguaje grande utilizando referencias de una base de conocimientos 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. La 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 poderosa y potencialmente rentable de mejorar los resultados de los LLM para que sigan siendo relevantes, precisos y útiles en diversos contextos.

En DSPy, se utiliza una arquitectura de RAG agregando un paso de contexto en el archivo Signature. Este paso recopila el contexto del modelo de recuperación y lo agrega a la instrucción del modelo de lenguaje para, con suerte, generar 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 usar con su modelo de RAG. Se pasa GenerateAnswer al módulo `ChainOfThought` para que el contexto recuperado y la pregunta y respuesta utilicen un enfoque de Chain of Thought.

También actualiza el método forward para generar pasajes de contexto a partir de la RAG y utilizar 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 de 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 garantizar 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 usar para probar las instrucciones y luego evaluarlas.

Para dar preguntas de prueba de DSPy, cargará el conjunto de datos de HotPotQA. HotpotQA es un conjunto de datos de respuesta a preguntas que presenta preguntas naturales multi-hop que requieren múltiples recuperaciones e inferencias para llegar a la respuesta correcta. Es una gran herramienta para probar qué tan bien 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 como responsable de transmitir los votos del Colegio Electoral al Congreso?" Puede ver que esta pregunta requiere varios datos para responder correctamente.

The answer is: “Robert Digges Wimberly Connor”.

El contexto de apoyo proviene de páginas de Wikipedia sobre Robert Digges Wimberly Connor y sobre la National Archives and Records Administration.

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. Hay más información sobre HotPotQA en su sitio de GitHub.

Después de cargar el conjunto de datos, divídalo en conjuntos de entrenamiento 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, pondrá en marcha más ejemplos para que DSPy tenga 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 de 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 la ingeniería rápida para usted, la probará con la pregunta personalizada sobre el Premio Nobel 2006 que utilizó anteriormente. Debido a que el modelo de recuperación utiliza extractos de Wikipedia de 2017, funcionará mejor con el conocimiento que podría 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 obtiene la respuesta correcta. 

    Pregunta: ¿De qué país era el ganador del Premio Nobel de Literatura en 2006 y cuál era su nombre?
    Respuesta prevista: Turquía, Orhan Pamuk

Orhan Pamuk es de Turquía, por lo que esta respuesta es correcta. La versión compilada de DSPy no solo obtuvo 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 (generalmente conocido simplemente como Orhan Pamuk; nacido el 7 de junio de 1952) es un novelista, guionista, académico y ganador del Premio Nobel de Literatura 2006 turco. Uno de los novelistas más destacados de Turquía, su obra ha vendido más de trece millones de libros en sesenta y tres idiomas, lo que lo convierte en el escritor más vendido del país".,
     'Premios Palanca 2006 | Los ganadores de los Premios Carlos Palanca Memorial de Literatura en el año 2006 (rango, título de la entrada ganadora, nombre del autor).',
     "Miguel Donoso Pareja | Miguel Donoso Pareja (13 de julio de 1931 - 16 de marzo de 2015) fue un escritor ecuatoriano y ganador del Premio Eugenio Espejo 2006 (Premio Nacional de Literatura de Ecuador, otorgado por el Presidente de 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()

Esta historia es muy larga, ya que incluye todos los ejemplos del proceso de compilación en los que DSPy probó las 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 (generalmente conocido como Orhan Pamuk; nacido el 7 de junio de 1952) es un novelista, guionista, académico turco y ganador del Premio Nobel de Literatura 2006. Uno de los novelistas más destacados de Turquía, su obra ha vendido más de trece millones de libros en sesenta y tres idiomas, lo que lo convierte en el escritor más vendido del país.»
    [2] «Premios Palanca 2006 | Los ganadores de los Premios Carlos Palanca Memorial de Literatura en el año 2006 (rango, título de la obra ganadora, nombre del autor).»
    [3] «Miguel Donoso Pareja | Miguel Donoso Pareja (13 de julio de 1931 - 16 de marzo de 2015) fue un escritor ecuatoriano y ganador del Premio Eugenio Espejo 2006 (Premio Nacional de Literatura de Ecuador, otorgado por el Presidente de Ecuador).»
    
    [[ ## question ## ]] ¿De qué país era el ganador del Premio Nobel de Literatura en 2006 y cuál era su nombre?
    
    Responda con los campos de salida correspondientes, comenzando con el campo `[[ ## reasoning ## ]]`, then `[[ ## answer ## ]]`, y luego terminando con el marcador para `[[ ## completaded # # ]]`.
    
    
    [31mResponse:[0m [32m[[ ## reasoning ## ]] El texto menciona el Premio Nobel de Literatura 2006 y afirma que Orhan Pamuk, un novelista turco, fue el ganador.
    
    [[ ## answer ## ]] Turquía, Orhan Pamuk [[ ## completed ## ]][0m
    

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

Responda con los campos de salida correspondientes, comenzando con el campo [[ ## reasoning ## ]] , entonces [[ ## answer ## ]] , y luego termina con el marcador para [[ ## completed ## ]] .

Esto lleva a la respuesta y al encuadre correctos.

Resumen

En este tutorial, utilizó DSPy para ayudar a ajustar un agente RAG mediante la plataforma watsonx. Su agente de RAG constaba de un modelo de lenguaje, Llama 3, y un modelo de recuperación, ColBERT. Luego utilizó DSPy para hacer ingeniería rápida para una tarea de respuesta a preguntas compilando su modelo y generando una instrucción optimizada.

Puede aprender más sobre DSPy en su repositorio de GitHub, donde hay tutoriales, demostraciones y sus documentos.

Soluciones relacionadas
IBM® watsonx.ai

Entrene, valide, ajuste y despliegue IA generativa, modelos fundacionales y capacidades de machine learning con IBM watsonx.ai, un estudio empresarial de próxima generación para creadores de IA. Diseñe aplicaciones de IA en menos tiempo y con menos datos.

Explore watsonx.ai
Soluciones de inteligencia artificial

Ponga a trabajar la IA en su negocio con la experiencia en IA líder del sector y la cartera de soluciones de IBM a su lado.

Explore las soluciones de IA
Consultoría y servicios de inteligencia artificial (IA)

Los servicios de IA de IBM Consulting ayudan a reinventar la forma en que las empresas trabajan con IA para la transformación.

Explore los servicios de IA
Dé el siguiente paso

Con la IA, IBM Concert muestra insights cruciales sobre operaciones y proporciona recomendaciones de mejora específicas de las aplicaciones. Descubra cómo Concert puede hacer avanzar su negocio.

Explore Concert Explore las soluciones de automatización de procesos de negocio