Multi-query retrieval con LLMs
El multi-query retrieval es una técnica que mejora significativamente la cobertura de resultados al generar múltiples versiones parafraseadas de la consulta original del usuario. En lugar de realizar una única búsqueda, esta aproximación utiliza un LLM para crear variaciones semánticamente equivalentes de la pregunta, ejecuta búsquedas independientes para cada variante y combina los resultados para obtener una respuesta más completa.
Esta técnica resulta especialmente valiosa cuando las consultas de los usuarios contienen terminología ambigua o cuando diferentes formulaciones de la misma pregunta pueden activar documentos relevantes distintos en el vector store. Por ejemplo, una consulta sobre "machine learning" podría beneficiarse de variantes como "aprendizaje automático", "inteligencia artificial" o "algoritmos de ML".
Implementación básica con MultiQueryRetriever
LangChain proporciona la clase MultiQueryRetriever
que automatiza este proceso utilizando LCEL. La implementación básica requiere un retriever base y un modelo de lenguaje:
from langchain.retrievers import MultiQueryRetriever
from langchain_openai import ChatOpenAI
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# Configuración del modelo y vector store
llm = ChatOpenAI(model="gpt-4", temperature=0)
embeddings = OpenAIEmbeddings()
# Crear vector store (asumiendo documentos ya indexados)
vectorstore = FAISS.load_local("./vector_index", embeddings)
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# Crear multi-query retriever
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=base_retriever,
llm=llm
)
# Ejecutar búsqueda
query = "¿Cuáles son las mejores prácticas para optimizar modelos de deep learning?"
results = multi_query_retriever.invoke(query)
El MultiQueryRetriever
genera automáticamente entre 3 y 5 variaciones de la consulta original, ejecuta búsquedas independientes y elimina duplicados antes de devolver los resultados combinados.
Personalización del prompt de generación
Para casos específicos, puedes personalizar el prompt que utiliza el LLM para generar las variaciones de consulta:
from langchain.prompts import PromptTemplate
# Prompt personalizado para generar variaciones
QUERY_PROMPT = PromptTemplate(
input_variables=["question"],
template="""Eres un experto en reformular consultas técnicas.
Genera exactamente 4 versiones diferentes de la siguiente pregunta,
manteniendo el significado pero variando la terminología y estructura:
Pregunta original: {question}
Variaciones:
1."""
)
# Aplicar prompt personalizado
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=base_retriever,
llm=llm,
prompt=QUERY_PROMPT
)
Configuración avanzada con parámetros específicos
El MultiQueryRetriever
permite ajustar varios parámetros para optimizar el comportamiento según las necesidades específicas:
# Configuración detallada
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=base_retriever,
llm=llm,
include_original=True, # Incluir consulta original en los resultados
parser_key="lines" # Formato de parsing de las variaciones
)
# Configurar logging para ver las consultas generadas
import logging
logging.basicConfig()
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)
# Ejecutar con logging activo
results = multi_query_retriever.invoke(
"¿Cómo implementar autenticación JWT en aplicaciones web?"
)
Casos de uso donde multi-query mejora el retrieval
Esta técnica demuestra particular efectividad en varios escenarios comunes:
Consultas con terminología específica: Cuando los usuarios emplean jerga técnica que puede tener múltiples denominaciones en los documentos. Una consulta sobre "containerización" se beneficia de variantes como "Docker", "contenedores" o "virtualización ligera".
# Ejemplo con terminología técnica
technical_query = "¿Qué es la containerización en DevOps?"
results = multi_query_retriever.invoke(technical_query)
# El LLM generará variaciones como:
# - "¿Cómo funcionan los contenedores Docker en desarrollo?"
# - "¿Cuáles son los beneficios de la virtualización con contenedores?"
# - "¿Qué tecnologías de containerización existen para aplicaciones?"
Preguntas ambiguas o con múltiples interpretaciones: Cuando la consulta original puede entenderse de diferentes maneras, las variaciones ayudan a cubrir distintas interpretaciones posibles.
# Consulta ambigua
ambiguous_query = "¿Cómo mejorar el rendimiento?"
results = multi_query_retriever.invoke(ambiguous_query)
# Variaciones posibles:
# - "¿Cómo optimizar el rendimiento de aplicaciones web?"
# - "¿Qué técnicas mejoran el performance de bases de datos?"
# - "¿Cómo acelerar la ejecución de algoritmos?"
Integración con cadenas LCEL
El MultiQueryRetriever
se integra perfectamente con cadenas LCEL para crear flujos de procesamiento más complejos:
from langchain.schema.runnable import RunnablePassthrough
from langchain.prompts import ChatPromptTemplate
# Prompt para la respuesta final
answer_prompt = ChatPromptTemplate.from_template(
"""Basándote en el siguiente contexto, responde la pregunta de manera precisa:
Contexto: {context}
Pregunta: {question}
Respuesta:"""
)
# Cadena completa con multi-query retrieval
chain = (
{"context": multi_query_retriever, "question": RunnablePassthrough()}
| answer_prompt
| llm
)
# Ejecutar cadena completa
response = chain.invoke("¿Cuáles son las ventajas del edge computing?")
Esta aproximación multiplica la superficie de búsqueda sin requerir modificaciones en el vector store subyacente, proporcionando una mejora inmediata en la cobertura de resultados relevantes. La técnica resulta especialmente valiosa en dominios técnicos donde la misma información puede expresarse con terminología variada.
Query rewriting y step-back prompting
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
El query rewriting representa una evolución natural del multi-query retrieval, donde en lugar de generar múltiples variaciones paralelas, transformamos estratégicamente la consulta original para mejorar su capacidad de recuperación. Esta técnica resulta especialmente efectiva cuando las preguntas de los usuarios son demasiado específicas o contienen detalles que pueden limitar la búsqueda en el vector store.
El step-back prompting constituye una implementación particular del query rewriting que reformula preguntas específicas en consultas más abstractas y generales. Esta aproximación se basa en el principio de que las preguntas generales suelen activar documentos con información fundamental que posteriormente puede aplicarse a casos específicos.
Implementación de step-back prompting
Para implementar step-back prompting en LangChain, creamos una cadena LCEL que primero reformula la consulta y luego ejecuta la búsqueda:
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# Configuración inicial
llm = ChatOpenAI(model="gpt-4", temperature=0)
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.load_local("./vector_index", embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 6})
# Prompt para step-back prompting
stepback_prompt = ChatPromptTemplate.from_template(
"""Eres un experto en reformular consultas técnicas. Tu tarea es transformar
preguntas específicas en consultas más generales y abstractas que puedan
recuperar información fundamental relevante.
Pregunta específica: {question}
Reformula esta pregunta de manera más general, enfocándote en conceptos
fundamentales y principios subyacentes. Responde solo con la nueva consulta:"""
)
# Cadena para generar consulta step-back
stepback_chain = stepback_prompt | llm
Ejemplo práctico de transformación
Veamos cómo funciona la transformación step-back con ejemplos concretos:
# Consulta específica sobre un modelo particular
specific_query = "¿Cuál es la velocidad máxima del Tesla Model 3 Performance?"
# Generar consulta step-back
stepback_query = stepback_chain.invoke({"question": specific_query})
print(f"Consulta original: {specific_query}")
print(f"Consulta step-back: {stepback_query.content}")
# Resultado esperado:
# "¿Cuáles son las especificaciones de rendimiento de los vehículos eléctricos Tesla?"
La consulta transformada tiene mayor probabilidad de recuperar documentos con información técnica general sobre vehículos Tesla que pueden contener las especificaciones específicas del Model 3.
Implementación completa con retrieval dual
Una estrategia efectiva combina tanto la consulta original como la reformulada para maximizar la cobertura:
from langchain.schema.runnable import RunnableLambda
def dual_retrieval(inputs):
"""Ejecuta retrieval tanto con consulta original como step-back"""
original_query = inputs["question"]
stepback_query = inputs["stepback_query"]
# Recuperar documentos con ambas consultas
original_docs = retriever.invoke(original_query)
stepback_docs = retriever.invoke(stepback_query)
# Combinar y eliminar duplicados
all_docs = original_docs + stepback_docs
unique_docs = []
seen_content = set()
for doc in all_docs:
if doc.page_content not in seen_content:
unique_docs.append(doc)
seen_content.add(doc.page_content)
return unique_docs[:8] # Limitar a 8 documentos más relevantes
# Cadena completa con retrieval dual
dual_chain = (
{
"question": RunnablePassthrough(),
"stepback_query": stepback_chain
}
| RunnableLambda(dual_retrieval)
)
Casos específicos donde step-back mejora el retrieval
Preguntas sobre productos o versiones específicas: Cuando los usuarios preguntan sobre características de productos particulares, la reformulación hacia categorías generales mejora la recuperación:
# Ejemplo con software específico
specific_software_query = "¿Cómo configurar SSL en Apache 2.4.52?"
stepback_result = stepback_chain.invoke({"question": specific_software_query})
# Transformación esperada:
# "¿Cómo configurar certificados SSL en servidores web Apache?"
Consultas con fechas o números específicos: Las preguntas que incluyen datos temporales o numéricos específicos se benefician de abstracciones conceptuales:
# Ejemplo con datos temporales
temporal_query = "¿Qué cambios introdujo Python 3.11 en el manejo de excepciones?"
stepback_result = stepback_chain.invoke({"question": temporal_query})
# Transformación esperada:
# "¿Cómo funciona el manejo de excepciones en Python?"
Integración con cadenas de respuesta
Para crear un sistema completo, integramos el query rewriting con la generación de respuestas:
# Prompt para respuesta final
answer_prompt = ChatPromptTemplate.from_template(
"""Basándote en el contexto proporcionado, responde la pregunta específica
del usuario de manera precisa y detallada.
Contexto: {context}
Pregunta original: {question}
Proporciona una respuesta completa que aborde específicamente lo que pregunta el usuario:"""
)
# Cadena completa con step-back prompting
complete_chain = (
{
"context": dual_chain,
"question": RunnablePassthrough()
}
| answer_prompt
| llm
)
# Ejecutar sistema completo
response = complete_chain.invoke(
"¿Cuánta memoria RAM requiere entrenar un modelo BERT-large?"
)
Personalización avanzada del step-back prompting
Para dominios específicos, puedes personalizar el comportamiento del step-back prompting:
# Prompt especializado para consultas técnicas
technical_stepback_prompt = ChatPromptTemplate.from_template(
"""Como experto en {domain}, reformula la siguiente pregunta específica
en una consulta más general que capture los principios fundamentales:
Dominio: {domain}
Pregunta específica: {question}
Enfócate en conceptos, metodologías y principios generales del dominio.
Consulta reformulada:"""
)
# Cadena especializada
specialized_stepback = technical_stepback_prompt | llm
# Uso con dominio específico
domain_response = specialized_stepback.invoke({
"domain": "machine learning",
"question": "¿Qué learning rate usar para fine-tuning GPT-3.5 con LoRA?"
})
Esta técnica de reformulación estratégica complementa perfectamente el multi-query retrieval al abordar limitaciones diferentes: mientras que multi-query amplía la superficie de búsqueda con variaciones semánticas, el step-back prompting eleva el nivel de abstracción para capturar conocimiento fundamental que puede aplicarse a casos específicos.
Aprendizajes de esta lección
- Comprender el concepto y ventajas del multi-query retrieval con LLMs.
- Aprender a implementar y personalizar MultiQueryRetriever en LangChain.
- Conocer la técnica de query rewriting y su implementación mediante step-back prompting.
- Saber combinar consultas originales y reformuladas para optimizar la recuperación de documentos.
- Integrar estas técnicas en cadenas LCEL para crear sistemas de búsqueda y respuesta más efectivos.
Completa LangChain y certifícate
Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs