Explorando DSPy y su integración con Milvus para crear pipelines RAG altamente eficientes
Introducción
Los modelos de lenguaje grandes (LLMs) poseen capacidades generativas transformadoras y se complementan con herramientas como bases de conocimiento y recuperadores, impulsando aplicaciones avanzadas de GenAI como chatbots y agents. En el centro de la interacción con los LLMs están los prompts, que son instrucciones que guían a estos modelos para realizar tareas específicas. Sin embargo, crear prompts efectivos es un proceso matizado e intrincado, que a menudo requiere técnicas sofisticadas como Chain-of-Thought y ReAct. Con eso añadido, los prompts se están volviendo cada vez más complejos. Además, incluso prompts idénticos pueden producir resultados divergentes en diferentes LLMs, como GPT-4 y Gemini, debido a variaciones en sus métodos y conjuntos de datos de preentrenamiento. Este desafío ha impulsado un aumento del interés en Prompt Engineering—una tarea laboriosa centrada en ajustar y optimizar prompts para obtener resultados mejores y personalizados.
Aunque la creación manual de prompts funciona bien para aplicaciones simples de LLM, se vuelve frustrante y consume mucho tiempo en canalizaciones complejas basadas en LLM que involucran múltiples componentes. DSPy representa un cambio de paradigma en la forma en que los desarrolladores interactúan con los modelos de lenguaje al introducir una interfaz programable que permite la optimización algorítmica de los prompts y pesos del modelo, lo que conduce a un desarrollo de modelos de lenguaje más eficiente. DSPy ha integrado de manera fluida la base de datos vectorial Milvus, automatizando la optimización de aplicaciones de Generación Aumentada por Recuperación (RAG) mediante un enfoque programático.
En las siguientes secciones, exploraremos la esencia de DSPy y su mecánica operativa, y proporcionaremos un ejemplo práctico que demuestra cómo construir y optimizar una aplicación RAG usando DSPy y la base de datos vectorial Milvus.
¿Qué es DSPy?
DSPy, presentado por el Stanford NLP Group, es un marco programático diseñado para optimizar prompts y pesos en modelos de lenguaje, lo cual es particularmente útil cuando los LLMs se integran en múltiples etapas de una canalización. Proporciona diversos módulos componibles y declarativos para instruir a los LLMs con sintaxis Pythonic.
A diferencia de las técnicas tradicionales de ingeniería de prompts que dependen de crear y ajustar prompts manualmente, DSPy aprende ejemplos de preguntas y respuestas e imita este aprendizaje para generar prompts optimizados con resultados más personalizados. Este enfoque permite el reensamblaje dinámico de toda la canalización, adaptada explícitamente a los matices de tu tarea, eliminando así la necesidad de ajustes manuales continuos de prompts.
Conceptos clave y componentes fundamentales
En DSPy, tres elementos fundamentales—Signatures, Modules y Optimizers (anteriormente denominados Teleprompters)—forman los bloques de construcción centrales para la optimización automatizada de prompts y el ajuste fino de modelos.
Signatures
Las Signatures son especificaciones declarativas que definen el comportamiento de entrada/salida de un módulo DSPy. Le indican al modelo de lenguaje qué tareas debe ejecutar en lugar de cómo debemos indicárselo al modelo de lenguaje.
- Una firma comprende tres elementos esenciales:
- Una descripción concisa de la subtarea que el modelo de lenguaje busca resolver.
- Una descripción de uno o más campos de entrada (por ejemplo, preguntas de entrada) que proporcionamos al modelo de lenguaje.
- Una descripción de uno o más campos de salida (por ejemplo, respuestas a preguntas) que esperamos del modelo de lenguaje.
Aquí hay ejemplos de firmas para tareas populares de LLM:
- Respuesta a preguntas:
"question -> answer" - Clasificación de sentimiento:
"sentence -> sentiment" - Respuesta a preguntas aumentada con recuperación:
"context, question -> answer" - Respuesta a preguntas de opción múltiple con razonamiento:
"question, choices -> reasoning, selection"
Estas firmas guían a DSPy para orquestar eficientemente las operaciones de LLM dentro de varios módulos, fomentando una ejecución de tareas optimizada y precisa.
Módulos
Los módulos de DSPy abstraen técnicas convencionales de prompting dentro de un pipeline de LLM. Tienen tres características clave:
- Cada módulo integrado abstrae una técnica de prompting específica (como Chain of Thoughts o ReAct) y maneja las firmas de DSPy.
- Los módulos de DSPy tienen parámetros aprendibles, incluidos componentes de prompts y pesos de LLM, lo que les permite procesar entradas y generar salidas.
- Los módulos de DSPy pueden combinarse para crear módulos más grandes y complejos.
- DSPy proporciona siete módulos integrados para diversos propósitos, incluidos
dspy.ReAct,dspy.ChainofThought,dspy.Predict,dspy.ProgramOfThought,dspy.ReAct,dspy.MultiChainComparisonydspy.Retrieve.
Optimizadores
Los optimizadores de DSPy, anteriormente Teleprompters, son algoritmos diseñados para ajustar finamente los parámetros de un programa DSPy —como prompts y pesos de LLM— para maximizar métricas especificadas como la precisión. Un optimizador típico de DSPy requiere tres entradas:
Tu programa DSPy: puede ser un único módulo (por ejemplo,
dspy.Predict) o un programa complejo de múltiples módulos.Tu métrica elegida: una función que evalúa la salida del programa y le asigna una puntuación (las puntuaciones más altas denotan mejores resultados).
Un pequeño conjunto de entradas de entrenamiento: a menudo solo de 5 a 10 ejemplos.
Una vez que defines tus datos de entrenamiento, módulos y métricas, el optimizador optimiza los pesos de LLM, las instrucciones de prompts y las demostraciones few-shot para mejorar la eficiencia del programa. Por ejemplo, el optimizador BootstrapFewShot genera respuestas que se alinean con la métrica especificada, mientras que módulos como COT (Chain of Thought) generan razonamiento estructurado para llegar a respuestas precisas. DSPy registra estas instancias exitosas y razonamientos como demostraciones few-shot para manejar futuras consultas de prueba.
Además de los bloques de construcción principales mencionados anteriormente, DSPy incorpora datos, métricas y aserciones como componentes complementarios, enriqueciendo su funcionalidad y adaptabilidad. Consulta la documentación de DSPy para más detalles.
Flujos de trabajo de DSPy: Construcción de pipelines de LLM eficientes
¿Cómo funciona exactamente DSPy en la construcción de pipelines de LLM? Para mayor claridad, podemos desglosar el proceso en varios pasos clave.
- Primero, debes definir tu tarea y preparar algunos ejemplos de entrada, a menudo sin etiquetas (o solo con etiquetas para los resultados finales, si tu métrica las requiere).
- Segundo, construye tu pipeline eligiendo entre los módulos integrados, asignando a cada módulo una firma (especificación de entrada/salida) e incorporando estos módulos sin problemas en tu código Python.
- Tercero, define la lógica de validación para tu pipeline, incluyendo qué métricas y ejemplos de entrada usar para evaluar la calidad de los prompts y los resultados finales.
- Cuarto, compila tu código usando un optimizador DSPy, que genera instrucciones de alta calidad, ejemplos few-shot automáticos o pesos LLM actualizados.
- Finalmente, participa en un proceso iterativo de refinamiento de tu conjunto de datos, programa o lógica de validación para lograr el nivel de rendimiento deseado para tu pipeline. Evalúa y mejora continuamente para cumplir con requisitos cambiantes y optimizar los resultados.
DSPy vs. LlamaIndex/LangChain/AutoGPT
DSPy destaca por su enfoque en comparación con muchos otros frameworks de IA populares como LangChain, LlamaIndex y AutoGPT. Aquí tienes una mirada más detallada a cómo difieren y se alinean:
LangChain es un kit de herramientas para crear aplicaciones personalizadas. Aprovecha varios modelos de lenguaje y paquetes de utilidades, lo que permite a los desarrolladores adaptar las aplicaciones a necesidades específicas.
LlamaIndex es un framework de orquestación diseñado para agilizar la integración de varias fuentes de datos privadas con modelos de lenguaje. Simplifica las tareas de manejo y procesamiento de datos.
AutoGPT es un agente de IA avanzado impulsado por GPT-4 y GPT3.5. Está programado para tomar decisiones y realizar acciones basadas en reglas y objetivos predefinidos. Hace énfasis en la autonomía y las capacidades de toma de decisiones.
Características distintivas de DSPy:
- DSPy optimiza y automatiza la construcción de prompts para mejorar la interacción con modelos de lenguaje.
- A diferencia de LangChain y LlamaIndex, que se orientan al desarrollo de aplicaciones de alto nivel con módulos preconstruidos, DSPy proporciona módulos potentes y de propósito general capaces de aprender a generar prompts o ajustar LLMs dentro de pipelines personalizados. La fortaleza de DSPy reside en su capacidad para adaptar dinámicamente los prompts y ajustar los LLMs en función de datos cambiantes, ajustes en el flujo de control del programa o variaciones del idioma objetivo. Este proceso de optimización automatizado puede conducir a resultados de calidad superior con un esfuerzo mínimo, especialmente cuando los desarrolladores están abiertos a escalar sus programas simples o de prototipado hacia otros más sofisticados para fines de producción.
- DSPy es ideal para casos de uso que requieren un modelo de programación ligero pero que se optimice automáticamente, en lugar de depender de prompts e integraciones predefinidos ofrecidos por bibliotecas como LangChain y LlamaIndex.
Integración de DSPy con la base de datos vectorial Milvus
Milvus es una base de datos vectorial cloud-native, open-source, altamente flexible, confiable y ultrarrápida. Impulsa la búsqueda de similitud vectorial y es particularmente beneficiosa para crear diversas aplicaciones de GenAI y Retrieval Augmented Generation (RAG).
Milvus se ha integrado en el flujo de trabajo de DSPy como un módulo de recuperación en forma del cliente MilvusRM, lo que facilita la implementación de un pipeline RAG rápido y eficiente.
Creación de una aplicación RAG con DSPy y Milvus
Retrieval Augmented Generation (RAG) es un método que permite a los LLMs acceder a repositorios de conocimiento externos, buscar en estos repositorios información contextual relevante para las consultas de los usuarios y generar respuestas refinadas.
En esta demostración, crearemos una aplicación RAG sencilla usando GPT-3.5 (gpt-3.5-turbo) para la generación de respuestas. Usamos Milvus como almacén vectorial a través de MilvusRM y DSPy para configurar y optimizar el pipeline RAG.
Requisitos previos
Antes de crear la app RAG, instala el cliente MilvusRM y Milvus.
- Para instalar MilvusRM, ejecuta el siguiente código.
pip install dspy-ai[milvus]
- Instala Milvus. Consulta la documentación de Milvus para obtener instrucciones detalladas.
Carga del conjunto de datos
En este ejemplo, usamos HotPotQA, una colección de pares complejos de preguntas y respuestas, como nuestro conjunto de datos de entrenamiento. Podemos cargarlos a través de la clase HotPotQA.
from dspy.datasets import HotPotQA
# 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]
Importar datos en la base de datos vectorial Milvus
Ingiere la información de contexto en la colección Milvus para la recuperación vectorial. Esta colección debe tener un campo embedding y un campo text. Usamos el modelo text-embedding-3-small de OpenAI como función predeterminada de embedding de consulta en este caso.
import requests
MILVUS_URI = "http://localhost:19530"
MILVUS_TOKEN = ""
from pymilvus import MilvusClient, DataType, Collection
from dspy.retrieve.milvus_rm import openai_embedding_function
client = MilvusClient(
uri=MILVUS_URI,
token=MILVUS_TOKEN
)
if 'dspy_example' not in client.list_collections():
client.create_collection(
collection_name="dspy_example",
overwrite= True,
dimension=1536,
primary_field_name="id",
vector_field_name="embedding",
id_type="int",
metric_type="IP",
max_length=65535,
enable_dynamic=True
)
text = requests.get('https://raw.githubusercontent.com/wxywb/dspy_dataset_sample/master/sample_data.txt').text
for idx, passage in enumerate(text.split('\n')):
if len(passage) == 0:
continue
client.insert(collection_name="dspy_example", data = [{"id": idx , "embedding": openai_embedding_function(passage)[0], "text": passage}])
Definir MilvusRM.
Ahora, debes definir MilvusRM.
from dspy.retrieve.milvus_rm import MilvusRM
import os
import dspy
os.environ["OPENAI_API_KEY"] = "<YOUR_OPENAI_API_KEY>"
retriever_model = MilvusRM(
collection_name="dspy_example",
uri=MILVUS_URI,
token=MILVUS_TOKEN, # ignore this if no token is required for Milvus connection
embedding_function = openai_embedding_function
)
turbo = dspy.OpenAI(model='gpt-3.5-turbo')
dspy.settings.configure(lm=turbo)
Creación de firmas
Ahora que hemos cargado los datos, empecemos a definir las firmas para las subtareas de nuestro pipeline. Podemos identificar nuestra entrada simple question y salida answer, pero como estamos creando un pipeline RAG, recuperaremos información contextual desde Milvus. Así que definamos nuestra firma como context, question --> answer.
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")
Incluimos descripciones breves para los campos context y answer con el fin de definir directrices más claras sobre lo que el modelo recibirá y debería generar.
Creación del pipeline
Ahora, definamos el pipeline RAG.
class RAG(dspy.Module):
def __init__(self, rm):
super().__init__()
self.retrieve = rm
# This signature indicates the task imposed on the COT module.
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
def forward(self, question):
# Use milvus_rm to retrieve context for the question.
context = self.retrieve(question).passages
# COT module takes "context, query" and output "answer".
prediction = self.generate_answer(context=context, question=question)
return dspy.Prediction(context=[item.long_text for item in context], answer=prediction.answer)
Ejecutar el pipeline y obtener los resultados
Ahora, hemos construido este pipeline RAG. Probémoslo y obtengamos resultados.
rag = RAG(retriever_model)
print(rag("who write At My Window").answer)
# The result:
# 'Townes Van Zandt'
Podemos evaluar los resultados cuantitativos en el conjunto de datos.
from dspy.evaluate.evaluate import Evaluate
from dspy.datasets import HotPotQA
evaluate_on_hotpotqa = Evaluate(devset=devset, num_threads=1, display_progress=False, display_table=5)
metric = dspy.evaluate.answer_exact_match
score = evaluate_on_hotpotqa(rag, metric=metric)
print('rag:', score)
# The result:
# rag: 50.0
Optimizar el pipeline
Después de definir este programa, el siguiente paso es la compilación. Este proceso actualiza los parámetros dentro de cada módulo para mejorar el rendimiento. El proceso de compilación depende de tres factores críticos:
- Conjunto de entrenamiento: Utilizaremos los 20 ejemplos de pregunta-respuesta de nuestro conjunto de datos de entrenamiento para esta demostración.
- Métrica de validación: Estableceremos una métrica simple
validate_context_and_answer. Esta métrica verifica la precisión de la respuesta predicha y garantiza que el contexto recuperado incluya la respuesta. - Optimizador específico (Teleprompter): El compilador de DSPy incorpora múltiples teleprompters diseñados para optimizar tus programas de manera efectiva.
from dspy.teleprompt import BootstrapFewShot
# Validation logic: check that the predicted answer is correct.
# Also check that the retrieved context does 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 teleprompter, which will compile our RAG program.
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)
# Compile!
compiled_rag = teleprompter.compile(rag, trainset=trainset)
# Now compiled_rag is optimized and ready to answer your new question!
Ahora, evaluemos el programa RAG compilado.
score = evaluate_on_hotpotqa(compiled_rag, metric=metric)
print(score)
print('compile_rag:', score)
# The result:
# compile_rag: 52.0
La puntuación de evaluación ha aumentado de su valor anterior de 50.0 a 52.0, lo que indica una mejora en la calidad de las respuestas.
Resumen
DSPy marca un salto en las interacciones con modelos de lenguaje a través de su interfaz programable, que facilita la optimización algorítmica y automatizada de los prompts y pesos del modelo. Al aprovechar DSPy para la implementación de RAG, la adaptabilidad a distintos modelos de lenguaje o conjuntos de datos se vuelve muy sencilla, reduciendo drásticamente la necesidad de intervenciones manuales tediosas.
Además, DSPy introduce un módulo recuperador MilvusRM dentro de su flujo de trabajo mediante la integración de la base de datos vectorial Milvus. Con esta nueva integración, los desarrolladores pueden automatizar la optimización de prompts y los ajustes de parámetros del modelo dentro de aplicaciones RAG para mejorar la calidad de las respuestas. Si quieres obtener más información, consulta la guía detallada de MilvusRM en la documentación de DSPy.
Referencias
Página de GitHub de DSPy: https://github.com/stanfordnlp/dspy
Artículo de DSPy: https://arxiv.org/pdf/2310.03714
Documentación de DSPy: https://dspy-docs.vercel.app/quick-start/installation/
Guía de MilvusRM: https://dspy-docs.vercel.app/docs/deep-dive/retrieval_models_clients/MilvusRM
Documentación de Milvus: https://milvus.io/docs
Sigue leyendo

Build Multimodal Search for 3D Assets with Tripo and Zilliz Cloud
Generate 3D assets with Tripo, then search them by text, image, and metadata with multimodal embeddings and Zilliz Cloud.

How to Install and Run OpenClaw (Previously Clawdbot/Moltbot) on Mac
Turn your Mac into an AI gateway for WhatsApp, Telegram, Discord, iMessage, and more — in under 5 minutes.

Why Deepseek is Waking up AI Giants Like OpenAI And Why You Should Care
Discover how DeepSeek R1's open-source AI model with superior reasoning capabilities and lower costs is disrupting the AI landscape and challenging tech giants like OpenAI.



