Creación de un RAG Agentic para Aplicaciones de Texto a SQL

La combinación de generación aumentada por recuperación (RAG) y modelos de inteligencia artificial generativa ha traído cambios al procesamiento del lenguaje natural al mejorar las respuestas a las consultas. En el ámbito de RAG Agentic, este método convencional de depender de un modelo monolítico para tareas ha sido mejorado mediante la introducción de modularidad y autonomía. Al descomponer el proceso de resolución de problemas en herramientas integradas dentro de un agente, RAG Agentic proporciona beneficios como precisión, transparencia, escalabilidad y capacidades de depuración.

La Visión Detrás de RAG Agentic para Texto a SQL

Los sistemas RAG tradicionales a menudo recuperan documentos relevantes y dependen de un solo modelo monolítico para generar respuestas. Aunque este es un método efectivo en algunos casos, cuando se trata de salidas estructuradas como en el caso de generar SQL, este enfoque puede no ser el más efectivo. Ahí es donde podemos aprovechar el poder del marco RAG Agentic, donde:

  1. Dividimos las tareas en herramientas más pequeñas y manejables dentro de un agente
  2. Mejoramos la precisión asignando tareas a herramientas especializadas
  3. Mejoramos la transparencia rastreando el razonamiento y flujo de trabajo de cada herramienta
  4. Simplificamos la escalabilidad y depuración a través del diseño modular

Hablemos sobre cómo funciona esta herramienta y el papel que desempeña cada componente en transformar las preguntas de los usuarios en consultas SQL precisas.

Descripción General de la Arquitectura

La estructura comprende un agente que utiliza herramientas dentro del flujo de trabajo de texto a SQL. El proceso se puede resumir de la siguiente manera:

Consulta del usuario → Herramienta de Transformación de Consultas → Herramienta de Estímulo de Pocas Muestras → Herramienta de Búsqueda Híbrida → Herramienta de Reclasificación → Herramienta de Recuperación de Tablas → Herramienta de Construcción de Estímulos → Herramienta de Ejecución LLM → Herramienta de Ejecución SQL → Resultado Final

1. Herramienta de Transformación de Consultas de Usuario

Esta herramienta implicaría procesar la consulta del usuario para una mejor comprensión del LLM. Aborda ambigüedades, reformula preguntas de usuario, traduce abreviaturas a sus formas y proporciona contexto cuando es necesario.

Mejoras

  • Manejar referencias temporales. Mapear términos como “hasta la fecha de hoy” o “hasta ahora” a fechas explícitas.
  • Reemplazar palabras ambiguas. Por ejemplo, “reciente” podría ser reemplazado por “últimos 7 días.”
  • Conectar abreviaturas o siglas con sus nombres.

Ejemplo

Entrada: “Mostrar ventas recientes MTD.”

Consulta transformada: “Recuperar datos de ventas de los últimos 7 días (Mes hasta la Fecha).”

Python

 

from datetime import date, timedelta

def transform_query(user_query):
    # Manejar referencias temporales abiertas
    today = date.today()
    transformations = {
        "as of today": f"up to {today}",
        "till now": f"up to {today}",
        "recent": "last 7 days",
        "last week": f"from {today - timedelta(days=7)} to {today}",
    }
    
    for key, value in transformations.items():
        user_query = user_query.replace(key, value)

    # Mapear abreviaturas comunes
    abbreviations = {
        "MTD": "Month to Date",
        "YTD": "Year to Date",
    }
    for abbr, full_form in abbreviations.items():
        user_query = user_query.replace(abbr, full_form)

    return user_query

query_transform_tool = Tool(
    name="Query Transformer",
    func=transform_query,
    description="Refines user queries for clarity and specificity, handles abbreviations and open-ended terms."
)

2. Herramienta de Estímulo de Pocas Muestras

Esta herramienta hace una llamada al LLM para identificar la pregunta de un tipo de un conjunto (también podemos decir que coincide con la plantilla). La pregunta coincidente mejora el estímulo con una consulta SQL de ejemplo.

Flujo de trabajo de ejemplo

1. Pregunta de entrada: “Muéstrame las ventas totales por producto de los últimos 7 días.”

2. Plantillas predefinidas:

  • “Mostrar ventas agrupadas por región.” → Ejemplo SQL; SELECT región, SUM(ventas) …
  • “Mostrar ventas totales por producto.” → Ejemplo SQL; SELECT nombre_producto, SUM(ventas) …

3. Pregunta más similar: “Mostrar ventas totales por producto.”

4. Ejemplo de salida SQL: SELECT nombre_producto, SUM(ventas) FROM …

Python

 

from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(model="gpt-4")

predefined_examples = {
    "Show sales grouped by region": "SELECT region, SUM(sales) FROM sales_data GROUP BY region;",
    "Show total sales by product": "SELECT product_name, SUM(sales) FROM sales_data GROUP BY product_name;",
}

def find_similar_question(user_query):
    prompt = "Find the most similar question type for the following user query:\n"
    prompt += f"User Query: {user_query}\n\nOptions:\n"
    for example in predefined_examples.keys():
        prompt += f"- {example}\n"
    prompt += "\nRespond with the closest match."

    response = llm.call_as_function(prompt)
    most_similar = response['content']
    return predefined_examples.get(most_similar, "")

few_shot_tool = Tool(
    name="Few-Shot Prompting",
    func=find_similar_question,
    description="Finds the most similar question type using an additional LLM call and retrieves the corresponding example SQL."
)

3. Herramienta de Búsqueda Híbrida

Para una recuperación sólida, esta herramienta combina la búsqueda semántica, la búsqueda de palabras clave basada en BM25 y el mapeo basado en palabras clave. Los resultados de búsqueda de estos métodos de búsqueda se combinan utilizando fusión de rango recíproco.

¿Cómo se unen todos estos elementos?

Mapeo de Tabla de Palabras Clave

Este enfoque asigna las tablas a las palabras clave que se encuentran en la consulta. Por ejemplo:

  • La presencia de “ventas” resulta en la tabla de ventas siendo preseleccionada.
  • La presencia de “producto” resulta en la tabla de productos siendo preseleccionada. 

Mapeo de Superposición de Palabras Clave (BM25)

Este es un método de búsqueda basado en la superposición de palabras clave que preselecciona tablas en función de la relevancia. Para esto, aplicaremos la técnica BM25. Esto ordena los documentos en función de su relevancia para una búsqueda del usuario. Esta técnica de búsqueda considera la saturación de términos en vista, así como TF-IDF (Frecuencia de Término-Inversa de Frecuencia de Documento). 

La Frecuencia de Término (TF) ayuda a medir la frecuencia de un término en un documento dado. El enfoque de Frecuencia Inversa de Documento (IDF) subraya las palabras que aparecen en cada documento disminuyendo su importancia.

La normalización tiene en cuenta la longitud del documento para evitar cualquier sesgo hacia documentos más largos.

Dado:

  • datos_de_ventas: Contiene términos como “ventas,” “fecha,” “producto.”
  • productos: Contiene términos como “producto,” “categoría.”
  • pedidos: Contiene términos como “pedido,” “fecha,” “cliente.”
  • finanzas: Contiene términos como “ingresos,” “beneficio,” “gasto.”

Consulta del usuario: “Mostrar ventas totales por producto.”

  • Identificar términos en la consulta del usuario: [“ventas,” “producto”].
  • Ordenar cada documento (basado en la frecuencia y relevancia de estos términos) en DataBaseTable.

Relevancia de los documentos:

  • ventas: Alta relevancia debido a “ventas” y “producto.”
  • productos: Alta relevancia debido a “producto.”
  • pedidos: Baja relevancia debido a la presencia solo de “ventas.”
  • finanzas: No relevante.

Resultado:

Lista clasificada: [productos, datos_de_ventas, pedidos, finanzas]

Búsqueda Semántica

En este método de búsqueda, como su nombre indica, encontramos tablas semánticamente similares utilizando incrustaciones vectoriales. Logramos esto calculando un puntaje de similitud, como la similitud coseno, entre el documento (vectores de tabla) y los vectores de consulta del usuario.

Fusión de Rango Recíproco

Combina los resultados de búsqueda BM25 y semántica utilizando la estrategia de fusión de rango recíproco, que se explica un poco más en detalle a continuación:

Fusión de rango recíproco (RRF) combinando BM25 y búsqueda semántica:

RRF es un método para combinar resultados de múltiples algoritmos de clasificación (por ejemplo, BM25 y búsqueda semántica). Asigna una puntuación a cada documento basada en su rango en los métodos individuales, otorgando puntuaciones más altas a los documentos clasificados más alto en múltiples métodos.

Fórmula RRF:

RRF(d) = Σ(r ∈ R) 1 / (k + r(d))

Donde:

  • d es un documento
  • R es el conjunto de clasificadores (métodos de búsqueda)
  • k es una constante (típicamente 60)
  • r(d) es el rango del documento d en el método de búsqueda r

Ejemplo Paso a Paso

Datos de entrada.

1. Resultados de clasificación de BM25:

  • productos (Rango 1)
  • datos de ventas (Rango 2)
  • órdenes (Rango 3)

2. Resultados de clasificación de búsqueda semántica:

  • datos de ventas (Rango 1)
  • finanzas (Rango 2)
  • productos (Rango 3)

Fusión Paso a Paso

Para cada tabla, calcular la puntuación:

1. datos de ventas

  • Rango BM25 = 2, Rango Semántico = 1
  • Puntuación RRF = (1/60+2) + (1/60+1) = 0.03252

2. productos

  • Rango BM25 = 1, Rango Semántico = 3
  • Puntuación RRF = (1/60+1) + (1/60+3) = 0.03226

3. órdenes

  • BM25 Rank = 3, Rango Semántico = No Clasificado
  • Puntaje RRF = (1/60+3)= 0.01587

4. financieros

  • BM25 Rank = No Clasificado, Rango Semántico = 2
  • Puntaje RRF = (1/60+2)=0.01613

5. Ordenar por puntaje RRF

  • datos_ventas (puntaje más alto debido al rango superior en la búsqueda semántica).
  • productos (puntaje alto de BM25).
  • órdenes (relevancia menor en general).
  • financieros (superposición limitada).

Resultado final: [‘datos_ventas’, ‘productos,’ ‘financieros,’ ‘órdenes’]

Tablas recuperadas utilizando el mapeo de Tabla de Palabras Clave siempre se incluyen.

Python

 

from rank_bm25 import BM25Okapi

def hybrid_search(query):
    # Mapeo basado en palabras clave
    keyword_to_table = {
        "sales": "sales_data",
        "product": "products",
    }
    keyword_results = [table for keyword, table in keyword_to_table.items() if keyword in query.lower()]

    # Búsqueda BM25
    bm25 = BM25Okapi(["sales_data", "products", "orders", "financials"])
    bm25_results = bm25.get_top_n(query.split(), bm25.corpus, n=5)

    # Búsqueda Semántica
    semantic_results = vector_store.similarity_search(query, k=5)

    # Fusión de Rango Recíproco
    def reciprocal_rank_fusion(results):
        rank_map = {}
        for rank, table in enumerate(results):
            rank_map[table] = rank_map.get(table, 0) + 1 / (1 + rank)
        return sorted(rank_map, key=rank_map.get, reverse=True)

    combined_results = reciprocal_rank_fusion(bm25_results + semantic_results)

    return list(set(keyword_results + combined_results))

hybrid_search_tool = Tool(
    name="Hybrid Search",
    func=hybrid_search,
    description="Combines keyword mapping, BM25, and semantic search with RRF for table retrieval."
)

4. Herramienta de Reclasificación

Esta herramienta garantiza que las tablas más relevantes tengan prioridad.

Ejemplo

  • Tablas de entrada: [“datos_ventas,” “productos,” “financieros”]
  • Lógica de reordenamiento
    • Para cada tabla, calcular un puntaje de relevancia concatenando la consulta y la descripción de la tabla.
    • Ordenar por puntaje de relevancia.
  • Salida: [“datos_ventas,” “productos”]

Un poco más sobre la lógica de reordenación:

El codificadorenlazador calcula una puntuación de relevancia analizando la consulta concatenada y la descripción de la tabla como un par de entradas único. Este proceso implica:

  • Entrada de pares. La consulta y cada descripción de tabla se emparejan y se pasan como entrada al codificador enlazado.
  • Codificación conjunta. A diferencia de los codificadores separados (por ejemplo, bi-codificadores), el codificador enlazado codifica conjuntamente el par, lo que le permite capturar mejor el contexto y las dependencias entre la consulta y la descripción de la tabla.
  • Puntuación. El modelo genera una puntuación de relevancia para cada par, indicando qué tan bien se ajusta la tabla a la consulta.
Python

 

from transformers import pipeline

reranker = pipeline("text-classification", model="cross-encoder/ms-marco-TinyBERT-L-2")

def re_rank_context(query, results):
    scores = [(doc, reranker(query + " " + doc)[0]['score']) for doc in results]
    return [doc for doc, score in sorted(scores, key=lambda x: x[1], reverse=True)]

re_rank_tool = Tool(
    name="Re-Ranker",
    func=re_rank_context,
    description="Re-ranks the retrieved tables based on relevance to the query."
)

5. Herramienta de Construcción de Instrucciones

Esta herramienta construye una instrucción detallada para el modelo de lenguaje, incorporando la consulta refinada del usuario, el esquema recuperado y ejemplos de la Herramienta de Instrucciones de Pocas Muestras.

Supongamos que eres alguien que es competente en generar consultas SQL. Genera una consulta SQL para: Recuperar las ventas totales agrupadas por producto de los últimos 7 días.

Tablas relevantes:

  1. datos_ventas: Contiene las columnas [ventas, fecha, id_producto].
  2. productos: Contiene las columnas [id_producto, nombre_producto].

Ejemplo de SQL:

Plain Text

 

SELECT product_name, SUM(sales) FROM sales_data JOIN products ON sales_data.product_id = products.product_id GROUP BY product_name;

Alcance Futuro

Aunque este sistema utiliza un único agente con múltiples herramientas para simplificar la modularidad y reducir la complejidad, en el futuro se podría explorar un marco de trabajo multiagente. Posiblemente podríamos explorar lo siguiente:

  1. Agentes dedicados para la recuperación de contexto. Agentes separados para búsquedas semánticas y por palabras.
  2. Agentes específicos de tareas. Agentes especializados en validación u optimización de SQL.
  3. Colaboración entre agentes. Utilizando un agente de coordinación para gestionar la delegación de tareas.

Este enfoque podría mejorar la escalabilidad y permitir flujos de trabajo más sofisticados, especialmente en implementaciones a nivel empresarial.

Conclusión

RAG Agentic para aplicaciones de texto a SQL ofrece un enfoque escalable y modular para resolver tareas de consultas estructuradas. Al incorporar búsqueda híbrida, reordenamiento, indicaciones de poca muestra y construcción dinámica de indicaciones dentro de un marco de trabajo de un solo agente, este sistema garantiza precisión, transparencia y extensibilidad. Este flujo de trabajo mejorado demuestra un poderoso modelo para convertir preguntas en lenguaje natural en consultas SQL ejecutables.

Source:
https://dzone.com/articles/creating-an-agentic-rag-for-text-to-sql-applications