SQL es uno de los idiomas clave ampliamente utilizados en todas las empresas, y requiere una comprensión de las bases de datos y los metadatos de la tabla. Esto puede ser abrumador para los usuarios no técnicos que carecen de competencia en SQL. Hoy, IA generativa Puede ayudar a cerrar esta brecha de conocimiento para que los usuarios no técnicos generen consultas SQL mediante el uso de una aplicación de texto a SQL. Esta aplicación permite a los usuarios hacer preguntas en lenguaje natural y luego genera una consulta SQL para la solicitud del usuario.
Modelos de idiomas grandes (LLMS) están capacitados para generar consultas SQL precisas para Instrucciones del lenguaje natural. Sin embargo, los LLM listales no se pueden usar sin alguna modificación. En primer lugar, los LLM no tienen acceso a bases de datos empresariales, y los modelos deben personalizarse para comprender la base de datos específica de una empresa. Además, la complejidad aumenta debido a la presencia de sinónimos para columnas y métricas internas disponibles.
La limitación de los LLM en la comprensión de los conjuntos de datos empresariales y el contexto humano se puede abordar utilizando Generación aumentada de recuperación (TRAPO). En esta publicación, exploramos usando Roca madre de Amazon Para crear una aplicación de texto a SQL usando RAG. Usamos Soneto Claude 3.5 de Anthrope modelo para generar consultas SQL, Amazon Titan en Amazon Bedrock para la incrustación de texto y la roca madre de Amazon para acceder a estos modelos.
Amazon Bedrock es un servicio totalmente administrado que ofrece una selección de alto rendimiento modelos de base (FMS) de compañías líderes de IA como AI21 Labs, Anthrope, Cohere, Meta, Mistral AI, Stability AI y Amazon a través de una sola API, junto con un amplio conjunto de capacidades que necesita para construir aplicaciones generativas de IA con seguridad, privacidad y IA responsable.
Descripción general de la solución
Esta solución se basa principalmente en los siguientes servicios:
- Modelo fundamental – Utilizamos el soneto Claude 3.5 de Anthrope en Amazon Bedrock como nuestro LLM para generar consultas SQL para las entradas de los usuarios.
- Incruscaciones vectoriales – Usamos Amazon Titan Text Increddings v2 en Amazon Bedrock para incrustaciones. La incrustación es el proceso mediante el cual el texto, las imágenes y el audio tienen representación numérica en un espacio vectorial. La incrustación generalmente es realizada por un aprendizaje automático (Ml) modelo. El siguiente diagrama proporciona más detalles sobre los incrustaciones.
- TRAPO – Utilizamos RAG para proporcionar más contexto sobre el esquema de tabla, los sinónimos de columnas y las consultas de muestra al FM. RAG es un marco para construir aplicaciones de IA generativas que pueden utilizar fuentes de datos empresariales y bases de datos vectoriales para superar las limitaciones de conocimiento. RAG funciona mediante el uso de un módulo Retriever para encontrar información relevante de un almacén de datos externo en respuesta al mensaje de un usuario. Estos datos recuperados se usan como contexto, combinados con el aviso original, para crear un mensaje ampliado que se pasa a la LLM. El modelo de idioma luego genera una consulta SQL que incorpora el conocimiento empresarial. El siguiente diagrama ilustra el marco RAG.

- Racionalizar – Esta biblioteca Python de código abierto hace que sea sencillo crear y compartir hermosas aplicaciones web personalizadas para ML y ciencia de datos. En solo unos minutos, puede crear potentes aplicaciones de datos utilizando solo Python.
El siguiente diagrama muestra la arquitectura de la solución.

Necesitamos actualizar los LLM con una base de datos específica de la empresa. Esto se asegura de que el modelo pueda comprender correctamente la base de datos y generar una respuesta adaptada al esquema y tablas de datos basados en la empresa. Hay múltiples formatos de archivo disponibles para almacenar esta información, como JSON, PDF, TXT y YAML. En nuestro caso, creamos archivos JSON para almacenar esquema de tabla, descripciones de tabla, columnas con sinónimos y consultas de muestra. El formato inherentemente estructurado de JSON permite una representación clara y organizada de datos complejos como esquemas de tabla, definiciones de columnas, sinónimos y consultas de muestra. Esta estructura facilita el análisis rápido y la manipulación de los datos en la mayoría de los lenguajes de programación, reduciendo la necesidad de lógica de análisis personalizado.
Puede haber múltiples tablas con información similar, lo que puede reducir la precisión del modelo. Para aumentar la precisión, clasificamos las tablas en cuatro tipos diferentes en función del esquema y creamos cuatro archivos JSON para almacenar diferentes tablas. Hemos agregado un menú desplegable con cuatro opciones. Cada opción representa una de estas cuatro categorías y está alineada a archivos JSON individuales. Después de que el usuario selecciona el valor del menú desplegable, el archivo JSON relevante se pasa a Amazon Titan Text Increddings V2, que puede convertir el texto en incrustaciones. Estas integridades se almacenan en una base de datos vectorial para una recuperación más rápida.
Agregamos la plantilla de solicitud al FM para definir los roles y responsabilidades del modelo. Puede agregar información adicional, como qué motor SQL debe usarse para generar las consultas SQL.
Cuando el usuario proporciona la entrada a través de la solicitud de chat, usamos búsqueda de similitud Para encontrar los metadatos de tabla relevantes de la base de datos Vector para la consulta del usuario. La entrada del usuario se combina con metadatos de tabla relevantes y la plantilla de solicitud, que se pasa a la FM como una sola entrada en conjunto. El FM genera la consulta SQL en función de la entrada final.
Para evaluar la precisión del modelo y rastrear el mecanismo, almacenamos cada entrada y salida del usuario en Servicio de almacenamiento simple de Amazon (Amazon S3).
Requisitos previos
Para crear esta solución, complete los siguientes requisitos previos:
- Regístrese para un Cuenta de AWS Si aún no tienes uno.
- Habilitar el acceso al modelo para Amazon Titan Text Increddings v2 y Soneto Claude 3.5 de Anthrope en Amazon Bedrock.
- Cree un cubo S3 como ‘SimplesQL-Logs-****‘, reemplazar ‘****‘Con su identificador único. Los nombres de los cubos son únicos a nivel mundial en todo el servicio de Amazon S3.
- Elija su entorno de prueba. Recomendamos que pruebe en Amazon Sagemaker Studioaunque puede usar otros entornos locales disponibles.
- Instale las siguientes bibliotecas para ejecutar el código:
pip install streamlit
pip install jq
pip install openpyxl
pip install "faiss-cpu"
pip install langchain
Procedimiento
Hay tres componentes principales en esta solución:
- Los archivos JSON almacenan el esquema de la tabla y configure el LLM
- Indexación vectorial con roca madre de Amazon
- Apreciado para la interfaz de usuario front-end
Puede descargar Los tres componentes y fragmentos de código proporcionados en la siguiente sección.
Generar el esquema de la tabla
Utilizamos el formato JSON para almacenar el esquema de la mesa. Para proporcionar más entradas al modelo, agregamos un nombre de tabla y su descripción, columnas y sus sinónimos, y consultas de muestra en nuestros archivos JSON. Cree un archivo json como table_schema_a.json copiando el siguiente código en él:
{
"tables": [
{
"separator": "table_1",
"name": "schema_a.orders",
"schema": "CREATE TABLE schema_a.orders (order_id character varying(200), order_date timestamp without time zone, customer_id numeric(38,0), order_status character varying(200), item_id character varying(200) );",
"description": "This table stores information about orders placed by customers.",
"columns": [
{
"name": "order_id",
"description": "unique identifier for orders.",
"synonyms": ["order id"]
},
{
"name": "order_date",
"description": "timestamp when the order was placed",
"synonyms": ["order time", "order day"]
},
{
"name": "customer_id",
"description": "Id of the customer associated with the order",
"synonyms": ["customer id", "userid"]
},
{
"name": "order_status",
"description": "current status of the order, sample values are: shipped, delivered, cancelled",
"synonyms": ["order status"]
},
{
"name": "item_id",
"description": "item associated with the order",
"synonyms": ["item id"]
}
],
"sample_queries": [
{
"query": "select count(order_id) as total_orders from schema_a.orders where customer_id = '9782226' and order_status="cancelled"",
"user_input": "Count of orders cancelled by customer id: 978226"
}
]
},
{
"separator": "table_2",
"name": "schema_a.customers",
"schema": "CREATE TABLE schema_a.customers (customer_id numeric(38,0), customer_name character varying(200), registration_date timestamp without time zone, country character varying(200) );",
"description": "This table stores the details of customers.",
"columns": [
{
"name": "customer_id",
"description": "Id of the customer, unique identifier for customers",
"synonyms": ["customer id"]
},
{
"name": "customer_name",
"description": "name of the customer",
"synonyms": ["name"]
},
{
"name": "registration_date",
"description": "registration timestamp when customer registered",
"synonyms": ["sign up time", "registration time"]
},
{
"name": "country",
"description": "customer's original country",
"synonyms": ["location", "customer's region"]
}
],
"sample_queries": [
{
"query": "select count(customer_id) as total_customers from schema_a.customers where country = 'India' and to_char(registration_date, 'YYYY') = '2024'",
"user_input": "The number of customers registered from India in 2024"
},
{
"query": "select count(o.order_id) as order_count from schema_a.orders o join schema_a.customers c on o.customer_id = c.customer_id where c.customer_name="john" and to_char(o.order_date, 'YYYY-MM') = '2024-01'",
"user_input": "Total orders placed in January 2024 by customer name john"
}
]
},
{
"separator": "table_3",
"name": "schema_a.items",
"schema": "CREATE TABLE schema_a.items (item_id character varying(200), item_name character varying(200), listing_date timestamp without time zone );",
"description": "This table stores the complete details of items listed in the catalog.",
"columns": [
{
"name": "item_id",
"description": "Id of the item, unique identifier for items",
"synonyms": ["item id"]
},
{
"name": "item_name",
"description": "name of the item",
"synonyms": ["name"]
},
{
"name": "listing_date",
"description": "listing timestamp when the item was registered",
"synonyms": ["listing time", "registration time"]
}
],
"sample_queries": [
{
"query": "select count(item_id) as total_items from schema_a.items where to_char(listing_date, 'YYYY') = '2024'",
"user_input": "how many items are listed in 2024"
},
{
"query": "select count(o.order_id) as order_count from schema_a.orders o join schema_a.customers c on o.customer_id = c.customer_id join schema_a.items i on o.item_id = i.item_id where c.customer_name="john" and i.item_name="iphone"",
"user_input": "how many orders are placed for item 'iphone' by customer name john"
}
]
}
]
}
Configure el LLM e inicialice la indexación vectorial utilizando Amazon Bedrock
Cree un archivo Python como biblioteca.py siguiendo estos pasos:
- Agregue las siguientes declaraciones de importación para agregar las bibliotecas necesarias:
import boto3 # AWS SDK for Python
from langchain_community.document_loaders import JSONLoader # Utility to load JSON files
from langchain.llms import Bedrock # Large Language Model (LLM) from Anthropic
from langchain_community.chat_models import BedrockChat # Chat interface for Bedrock LLM
from langchain.embeddings import BedrockEmbeddings # Embeddings for Titan model
from langchain.memory import ConversationBufferWindowMemory # Memory to store chat conversations
from langchain.indexes import VectorstoreIndexCreator # Create vector indexes
from langchain.vectorstores import FAISS # Vector store using FAISS library
from langchain.text_splitter import RecursiveCharacterTextSplitter # Split text into chunks
from langchain.chains import ConversationalRetrievalChain # Conversational retrieval chain
from langchain.callbacks.manager import CallbackManager
- Inicializar el cliente de Amazon Bedrock y configurar Anthrope’s Claude 3.5 Puede limitar el número de tokens de salida para optimizar el costo:
# Create a Boto3 client for Bedrock Runtime
bedrock_runtime = boto3.client(
service_name="bedrock-runtime",
region_name="us-east-1"
)
# Function to get the LLM (Large Language Model)
def get_llm():
model_kwargs = { # Configuration for Anthropic model
"max_tokens": 512, # Maximum number of tokens to generate
"temperature": 0.2, # Sampling temperature for controlling randomness
"top_k": 250, # Consider the top k tokens for sampling
"top_p": 1, # Consider the top p probability tokens for sampling
"stop_sequences": ["\n\nHuman:"] # Stop sequence for generation
}
# Create a callback manager with a default callback handler
callback_manager = CallbackManager([])
llm = BedrockChat(
model_id="anthropic.claude-3-5-sonnet-20240620-v1:0", # Set the foundation model
model_kwargs=model_kwargs, # Pass the configuration to the model
callback_manager=callback_manager
)
return llm
- Cree y devuelva un índice para el tipo de esquema dado. Este enfoque es una forma eficiente de filtrar tablas y proporcionar una entrada relevante al modelo:
# Function to load the schema file based on the schema type
def load_schema_file(schema_type):
if schema_type == 'Schema_Type_A':
schema_file = "Table_Schema_A.json" # Path to Schema Type A
elif schema_type == 'Schema_Type_B':
schema_file = "Table_Schema_B.json" # Path to Schema Type B
elif schema_type == 'Schema_Type_C':
schema_file = "Table_Schema_C.json" # Path to Schema Type C
return schema_file
# Function to get the vector index for the given schema type
def get_index(schema_type):
embeddings = BedrockEmbeddings(model_id="amazon.titan-embed-text-v2:0",
client=bedrock_runtime) # Initialize embeddings
db_schema_loader = JSONLoader(
file_path=load_schema_file(schema_type), # Load the schema file
# file_path="Table_Schema_RP.json", # Uncomment to use a different file
jq_schema=".", # Select the entire JSON content
text_content=False) # Treat the content as text
db_schema_text_splitter = RecursiveCharacterTextSplitter( # Create a text splitter
separators=["separator"], # Split chunks at the "separator" string
chunk_size=10000, # Divide into 10,000-character chunks
chunk_overlap=100 # Allow 100 characters to overlap with previous chunk
)
db_schema_index_creator = VectorstoreIndexCreator(
vectorstore_cls=FAISS, # Use FAISS vector store
embedding=embeddings, # Use the initialized embeddings
text_splitter=db_schema_text_splitter # Use the text splitter
)
db_index_from_loader = db_schema_index_creator.from_loaders([db_schema_loader]) # Create index from loader
return db_index_from_loader
- Use la siguiente función para crear y devolver la memoria para la sesión de chat:
# Function to get the memory for storing chat conversations
def get_memory():
memory = ConversationBufferWindowMemory(memory_key="chat_history", return_messages=True) # Create memory
return memory
- Use la siguiente plantilla de solicitud para generar consultas SQL en función de la entrada del usuario:
# Template for the question prompt
template = """ Read table information from the context. Each table contains the following information:
- Name: The name of the table
- Description: A brief description of the table
- Columns: The columns of the table, listed under the 'columns' key. Each column contains:
- Name: The name of the column
- Description: A brief description of the column
- Type: The data type of the column
- Synonyms: Optional synonyms for the column name
- Sample Queries: Optional sample queries for the table, listed under the 'sample_data' key
Given this structure, Your task is to provide the SQL query using Amazon Redshift syntax that would retrieve the data for following question. The produced query should be functional, efficient, and adhere to best practices in SQL query optimization.
Question: {}
"""
- Use la siguiente función para obtener una respuesta del modelo de chat de trapo:
# Function to get the response from the conversational retrieval chain
def get_rag_chat_response(input_text, memory, index):
llm = get_llm() # Get the LLM
conversation_with_retrieval = ConversationalRetrievalChain.from_llm(
llm, index.vectorstore.as_retriever(), memory=memory, verbose=True) # Create conversational retrieval chain
chat_response = conversation_with_retrieval.invoke({"question": template.format(input_text)}) # Invoke the chain
return chat_response['answer'] # Return the answer
Configurar a Streamlit para la interfaz de usuario front-end
Cree el archivo App.py siguiendo estos pasos:
- Importar las bibliotecas necesarias:
import streamlit as st
import library as lib
from io import StringIO
import boto3
from datetime import datetime
import csv
import pandas as pd
from io import BytesIO
- Inicializar el cliente S3:
s3_client = boto3.client('s3')
bucket_name="simplesql-logs-****"
#replace the 'simplesql-logs-****’ with your S3 bucket name
log_file_key = 'logs.xlsx'
- Configurar Strewlit para UI:
st.set_page_config(page_title="Your App Name")
st.title("Your App Name")
# Define the available menu items for the sidebar
menu_items = ["Home", "How To", "Generate SQL Query"]
# Create a sidebar menu using radio buttons
selected_menu_item = st.sidebar.radio("Menu", menu_items)
# Home page content
if selected_menu_item == "Home":
# Display introductory information about the application
st.write("This application allows you to generate SQL queries from natural language input.")
st.write("")
st.write("**Get Started** by selecting the button Generate SQL Query !")
st.write("")
st.write("")
st.write("**Disclaimer :**")
st.write("- Model's response depends on user's input (prompt). Please visit How-to section for writing efficient prompts.")
# How-to page content
elif selected_menu_item == "How To":
# Provide guidance on how to use the application effectively
st.write("The model's output completely depends on the natural language input. Below are some examples which you can keep in mind while asking the questions.")
st.write("")
st.write("")
st.write("")
st.write("")
st.write("**Case 1 :**")
st.write("- **Bad Input :** Cancelled orders")
st.write("- **Good Input :** Write a query to extract the cancelled order count for the items which were listed this year")
st.write("- It is always recommended to add required attributes, filters in your prompt.")
st.write("**Case 2 :**")
st.write("- **Bad Input :** I am working on XYZ project. I am creating a new metric and need the sales data. Can you provide me the sales at country level for 2023 ?")
st.write("- **Good Input :** Write an query to extract sales at country level for orders placed in 2023 ")
st.write("- Every input is processed as tokens. Do not provide un-necessary details as there is a cost associated with every token processed. Provide inputs only relevant to your query requirement.")
- Generar la consulta:
# SQL-AI page content
elif selected_menu_item == "Generate SQL Query":
# Define the available schema types for selection
schema_types = ["Schema_Type_A", "Schema_Type_B", "Schema_Type_C"]
schema_type = st.sidebar.selectbox("Select Schema Type", schema_types)
- Use lo siguiente para la generación SQL:
if schema_type:
# Initialize or retrieve conversation memory from session state
if 'memory' not in st.session_state:
st.session_state.memory = lib.get_memory()
# Initialize or retrieve chat history from session state
if 'chat_history' not in st.session_state:
st.session_state.chat_history = []
# Initialize or update vector index based on selected schema type
if 'vector_index' not in st.session_state or 'current_schema' not in st.session_state or st.session_state.current_schema != schema_type:
with st.spinner("Indexing document..."):
# Create a new index for the selected schema type
st.session_state.vector_index = lib.get_index(schema_type)
# Update the current schema in session state
st.session_state.current_schema = schema_type
# Display the chat history
for message in st.session_state.chat_history:
with st.chat_message(message["role"]):
st.markdown(message["text"])
# Get user input through the chat interface, set the max limit to control the input tokens.
input_text = st.chat_input("Chat with your bot here", max_chars=100)
if input_text:
# Display user input in the chat interface
with st.chat_message("user"):
st.markdown(input_text)
# Add user input to the chat history
st.session_state.chat_history.append({"role": "user", "text": input_text})
# Generate chatbot response using the RAG model
chat_response = lib.get_rag_chat_response(
input_text=input_text,
memory=st.session_state.memory,
index=st.session_state.vector_index
)
# Display chatbot response in the chat interface
with st.chat_message("assistant"):
st.markdown(chat_response)
# Add chatbot response to the chat history
st.session_state.chat_history.append({"role": "assistant", "text": chat_response})
- Registre las conversaciones al cubo S3:
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
try:
# Attempt to download the existing log file from S3
log_file_obj = s3_client.get_object(Bucket=bucket_name, Key=log_file_key)
log_file_content = log_file_obj['Body'].read()
df = pd.read_excel(BytesIO(log_file_content))
except s3_client.exceptions.NoSuchKey:
# If the log file doesn't exist, create a new DataFrame
df = pd.DataFrame(columns=["User Input", "Model Output", "Timestamp", "Schema Type"])
# Create a new row with the current conversation data
new_row = pd.DataFrame({
"User Input": [input_text],
"Model Output": [chat_response],
"Timestamp": [timestamp],
"Schema Type": [schema_type]
})
# Append the new row to the existing DataFrame
df = pd.concat([df, new_row], ignore_index=True)
# Prepare the updated DataFrame for S3 upload
output = BytesIO()
df.to_excel(output, index=False)
output.seek(0)
# Upload the updated log file to S3
s3_client.put_object(Body=output.getvalue(), Bucket=bucket_name, Key=log_file_key)
Prueba la solución
Abra su terminal e invoque el siguiente comando para ejecutar la aplicación Streamlit.
streamlit run app.py
Para visitar la aplicación utilizando su navegador, navegue al localhost.
Para visitar la aplicación con Sagemaker, copie su URL de cuaderno y reemplace ‘predeterminado/laboratorio’ en la url con ‘predeterminado/proxy/8501/’ . Debería parecerse a lo siguiente:
https://your_sagemaker_lab_url.studio.us-east-1.sagemaker.aws/jupyterlab/default/proxy/8501/
Elegir Generar consultas SQL Para abrir la ventana de chat. Pruebe su aplicación haciendo preguntas en lenguaje natural. Probamos la aplicación con las siguientes preguntas y generó consultas SQL precisas.
¿Conteo de pedidos realizados de la India el mes pasado?
Escriba una consulta para extraer el recuento de pedidos cancelados para los artículos que se enumeraron este año.
Escriba una consulta para extraer los 10 nombres principales de elementos que tienen el más alto orden para cada país.
Consejos de resolución de problemas
Use las siguientes soluciones para abordar los errores:
Error – Un error planteado por punto final de inferencia significa que ocurrió un error (AccessDeniedException) al llamar a la operación de Invokemodel. No tiene acceso al modelo con la ID del modelo especificado.
Solución – Asegúrese de tener acceso al FMS en Amazon Bedrock, Amazon Titan Text Increddings V2 y el soneto Claude 3.5 de Anthrope.
Error – App.py no existe
Solución – Asegúrese de que su archivo JSON y los archivos de Python estén en la misma carpeta y esté invocando el comando en la misma carpeta.
Error – No hay módulo llamado Streamlit
Solución – Abra el terminal e instale el módulo de transmisión ejecutando el comando pip install streamlit
Error – Se produjo un error (nosuchbucket) al llamar a la operación getObject. El cubo especificado no existe.
Solución – Verifique el nombre de su cubo en el archivo App.py y actualice el nombre en función de su nombre de cubo S3.
Limpiar
Limpie los recursos que creó para evitar incurrir en cargos. Para limpiar su cubo S3, consulte Vaciar un balde.
Conclusión
En esta publicación, mostramos cómo se puede usar el rock de Amazon para crear una aplicación de texto a SQL basada en conjuntos de datos específicos de la empresa. Utilizamos Amazon S3 para almacenar las salidas generadas por el modelo para las entradas correspondientes. Estos registros se pueden utilizar para probar la precisión y mejorar el contexto proporcionando más detalles en la base de conocimiento. Con la ayuda de una herramienta como esta, puede crear soluciones automatizadas que sean accesibles para usuarios no técnicos, lo que les permite interactuar con los datos de manera más eficiente.
¿Listo para comenzar con Amazon Bedrock? Empiece a aprender con estos talleres interactivos.
Para obtener más información sobre la generación SQL, consulte estas publicaciones:
Recientemente lanzamos un módulo NL2SQL administrado para recuperar datos estructurados en Conocimiento en la roca de Amazon . Para obtener más información, visite Las bases de conocimiento de Amazon Bedrock ahora admiten la recuperación de datos estructurados.
Sobre el autor
Rajendra Choudhary es analista de negocios Sr. en Amazon. Con 7 años de experiencia en el desarrollo de soluciones de datos, posee una profunda experiencia en visualización de datos, modelado de datos e ingeniería de datos. Le apasiona apoyar a los clientes al aprovechar soluciones generativas basadas en AI. Fuera del trabajo, Rajendra es un ávido entusiasta de la comida y la música, y le gusta nadar y caminar.