Notice: La función wp_enqueue_script ha sido llamada de forma incorrecta. Los scripts y estilos no se deberían registrar o poner en cola hasta que se carguen los ganchos wp_enqueue_scripts, admin_enqueue_scripts y login_enqueue_scripts. Este aviso ha sido activado por la gestión de nfd_wpnavbar_setting. Por favor, ve depuración en WordPress para más información. (Este mensaje fue añadido en la versión 3.3.0). in /home1/spotsail/public_html/martra/wp-includes/functions.php on line 6078
Crear un SuperPrompt de conversión de Lenguaje Natural a SQL para OpenAI. – Pere Martra
No se han encontrado widgets en la barra lateral
Language natural, a SQL. prompt para OpenAI

Una de las cosas que más ha cambiado en estos últimos meses, desde el Boom de ChatGPT, ha sido la aparición de modelos de lenguaje inmensos, que son capaces de aprender a realizar tareas con tan solo dos o tres ejemplos. Esta capacidad, junto a la facilidad por interpretar las órdenes, ha facilitado la creación de una nueva técnica dentro del mundo de la IA: la ingeniería de prompts.

Utilizamos Ingeniería de Prompt para cambiar el comportamiento de estos modelos de grandes capacidades y conseguir que hagan las tareas que necesitamos.

En este artículo vamos a ver como crear un prompt para que los modelos GPT de OpenAI sean capaces de ejecutar tareas de NL2SQL. Es decir, traducir las peticiones hechas en el lenguaje del usuario a órdenes SQL que le devolverán los datos que pide.

Para ello partiremos de un paper de la universidad de Ohio: How to Prompt LLMs for Text-to-SQL: A Study in Zero-shot, Single-domain, and Cross-domain Settings. Y modificaremos lo que ya vimos en el segundo artículo del curso de Grandes Modelos de Lenguaje.

Estructura del Prompt.

El prompt va a contener cuatro secciones:

  • La estructura de las tablas. Con ejemplos de su contenido.
  • Instrucciones para guiar al modelo en cuanto al SQL a generar.
  • Los ejemplos de SQL correctos. Llamados Few Shot Samples.
  • La pregunta del usuario.

El prompt que vamos a crear es directamente el más completo. Va a contener varios ejemplos y con relaciones cruzadas entre las tablas. No siempre es necesario dar ejemplos de SQL al Modelo, si la tabla es sencilla y hemos dado información suficiente, el modelo será capaz de generar un SQL correcto. Pero estos ejemplos también nos permiten influenciar en el estilo y formato en el que queremos que sea devuelto el SQL.

La estructura de las tablas:

create table employees(
        ID_Usr INT primary key,
        name VARCHAR);
    /*3 example rows
    select * from employees limit 3;
    ID_Usr    name
    1344      George StPierre
    2122      Jon jones
    1265      Anderson Silva
    */

    create table salary(
        ID_Usr INT,
        year DATE,
        salary FLOAT,
        foreign key (ID_Usr) references employees(ID_Usr));
    /*3 example rows
    select * from salary limit 3
    ID_Usr    date          salary
    1344      01/01/2023    61000
    1344      01/01/2022    60000
    1265      01/01/2023    55000
    */

    create table studies(
        ID_study INT,
        ID_Usr INT,
        educational_level INT,  /* 5=phd, 4=Master, 3=Bachelor */
        Institution VARCHAR,
        Years DATE,
        Speciality VARCHAR,
        primary key (ID_study, ID_Usr),
        foreign key(ID_Usr) references employees (ID_Usr));
    /*3 example rows
    select * from studies limit 3
    ID_Study ID_Usr educational_level Institution    Years       Speciality
    2782     1344   3                 UC San Diego   01/01/2010  Bachelor of Science in Marketing
    2334     1344   5                 MIT            01/01/2023  Phd. Data Science.
    2782     2122   3                 UC San Diego   01/01/2010  Bachelor of Science in Marketing
    */

Como podéis ver, el formato en el que se indica la estructura es el mismo que usaríamos en SQL si quisiéramos crear las tablas. Podemos usar los comentarios para aumentar la información, como en el caso del campo educational_level de la tabla studies. Donde he indicado a qué nivel de estudios corresponde cada valor.

Debajo de la definición de la tabla, en un comentario de SQL, he puesto un ejemplo del contenido de la tabla. Este ejemplo se acompaña de la orden SQL que devolvería los datos.

Instrucciones.

/* Maintain the SQL order simple and efficient as you can, using valid SQL Lite, answer the following questions for the table provided above. */

En este caso las instrucciones son muy sencillas. GPT3.5-Turbo es un modelo muy potente que no necesita ser excesivamente guiado. Tan solo le decimos que haga un SQL simple, y que utilice la sintaxis de SQLLite. Podriamos indicarle si queremos usar o no alias para las tablas, usar otro formato de SQL.

Few Shot Samples.

Question: How Many employes we have with a salary bigger than 50000?
SELECT COUNT(*) AS total_employees
FROM employees e
INNER JOIN salary s ON e.ID_Usr = s.ID_Usr
WHERE s.salary > 50000;
  Question: Return the names of the three people who have had the highest salary increase in the last three years.
SELECT e.name
FROM employees e
JOIN salary s ON e.ID_usr = s.ID_usr
WHERE s.year >= DATE_SUB(CURDATE(), INTERVAL 3 YEAR)
GROUP BY e.name
ORDER BY (MAX(s.salary) - MIN(s.salary)) DESC
LIMIT 3;

Le estamos marcando al modelo, como le va a llegar la pregunta. Precedida por la palabra Question:. El SQL se devuelve justo después de la pregunta, como vemos lo formateamos en múltiples líneas para que sea más sencillo de leer.

Es importante que las ordenes SQL que pongamos como ejemplo sean correctas y tengan el estilo de SQL que se ha marcado en nuestra organización.

Una buena práctica es usar SQLs que estén funcionando en producción, y que el equipo de desarrollo las valide antes de usarlas como ejemplo en el prompt. El número de ejemplos a pasar puede variar entre 1 y 6. Si el modelo no ha aprendido con seis ejemplos es que algo no funciona.

Tenemos que tener en cuenta que estos ejemplos ocupan Tokens en el prompt y que se pasan en cada consulta, por lo que aumenta el coste y tiempo de respuesta de cada consulta al Modelo. Mi recomendación es mantener este número al mínimo.

En el primer ejemplo he usado tan solo los datos de una tabla, mientras que en el segundo sí que se necesitan relaciones entre tablas. Es recomendable mezclar los ejemplos y tener como mínimo uno de cada. De esta forma no tan solo aprende la estructura de las tablas, sino como queremos la forma del SQL.

La pregunta del usuario.

Question: Cual es el nombre del usuario mejor pagado?

Es tan sencillo como que la pregunta debe seguir el mismo patrón que se ha seguido en los ejemplos. En nuestro caso debemos ponerlo detrás de la palabra Question.

Con todos estos apartados tenemos que construir nuestro prompt completo.

create table employees(
        ID_Usr INT primary key,
        name VARCHAR);
    /*3 example rows
    select * from employees limit 3;
    ID_Usr    name
    1344      George StPierre
    2122      Jon jones
    1265      Anderson Silva
    */

    create table salary(
        ID_Usr INT,
        year DATE,
        salary FLOAT,
        foreign key (ID_Usr) references employees(ID_Usr));
    /*3 example rows
    select * from salary limit 3
    ID_Usr    date          salary
    1344      01/01/2023    61000
    1344      01/01/2022    60000
    1265      01/01/2023    55000
    */

    create table studies(
        ID_study INT,
        ID_Usr INT,
        educational_level INT,  /* 5=phd, 4=Master, 3=Bachelor */
        Institution VARCHAR,
        Years DATE,
        Speciality VARCHAR,
        primary key (ID_study, ID_Usr),
        foreign key(ID_Usr) references employees (ID_Usr));
    /*3 example rows
    select * from studies limit 3
    ID_Study ID_Usr educational_level Institution    Years       Speciality
    2782     1344   3                 UC San Diego   01/01/2010  Bachelor of Science in Marketing
    2334     1344   5                 MIT            01/01/2023  Phd. Data Science.
    2782     2122   3                 UC San Diego   01/01/2010  Bachelor of Science in Marketing
    */

-Maintain the SQL order simple and efficient as you can, using valid SQL Lite, answer the following questions for the table provided above. 
Question: How Many employes we have with a salary bigger than 50000?
SELECT COUNT(*) AS total_employees
FROM employees e
INNER JOIN salary s ON e.ID_Usr = s.ID_Usr
WHERE s.salary > 50000;
  Question: Return the names of the three people who have had the highest salary increase in the last three years.
SELECT e.name
FROM employees e
JOIN salary s ON e.ID_usr = s.ID_usr
WHERE s.year >= DATE_SUB(CURDATE(), INTERVAL 3 YEAR)
GROUP BY e.name
ORDER BY (MAX(s.salary) - MIN(s.salary)) DESC
LIMIT 3;
Question: Cual es el nombre del usuario mejor pagado.

El notebook de ejemplo.

Veamos cómo se usa este prompt con OpenAI.

Primero instalamos e importamos la librería de OpenAI que nos da acceso a su API.

!pip install openai
import openai
openai.api_key='your-api-key'

Para crear el prompt usaremos los roles de OpenAI. Las instrucciones de cómo debe trabajar y la estructura de la base de datos, así como los ejemplos los daremos de alta con el Rol de System, mientras que la pregunta la vamos a mandar con el rol de User.

context = [ {'role':'system', 'content':"""
    create table employees(
        ID_Usr INT primary key,
        name VARCHAR);
    /*3 example rows
    select * from employees limit 3;
    ID_Usr    name
    1344      George StPierre
    2122      Jon jones
    1265      Anderson Silva
    */

    create table salary(
        ID_Usr INT,
        year DATE,
        salary FLOAT,
        foreign key (ID_Usr) references employees(ID_Usr));
    /*3 example rows
    select * from salary limit 3
    ID_Usr    date          salary
    1344      01/01/2023    61000
    1344      01/01/2022    60000
    1265      01/01/2023    55000
    */

    create table studies(
        ID_study INT,
        ID_Usr INT,
        educational_level INT,  /* 5=phd, 4=Master, 3=Bachelor */
        Institution VARCHAR,
        Years DATE,
        Speciality VARCHAR,
        primary key (ID_study, ID_Usr),
        foreign key(ID_Usr) references employees (ID_Usr));
    /*3 example rows
    select * from studies limit 3
    ID_Study ID_Usr educational_level Institution    Years       Speciality
    2782     1344   3                 UC San Diego   01/01/2010  Bachelor of Science in Marketing
    2334     1344   5                 MIT            01/01/2023  Phd. Data Science.
    2782     2122   3                 UC San Diego   01/01/2010  Bachelor of Science in Marketing
    */
"""} ]

Ahora añadimos los ejemplos. Los he puesto en dos celdas diferentes, así podemos hacer pruebas con o sin ellos.

context.append( {'role':'system', 'content':"""
 --Maintain the SQL order simple and efficient as you can, using valid SQL Lite, answer the following questions for the table provided above. 
Question: How Many employes we have with a salary bigger than 50000?
SELECT COUNT(*) AS total_employees
FROM employees e
INNER JOIN salary s ON e.ID_Usr = s.ID_Usr
WHERE s.salary > 50000;
  Question: Return the names of the three people who have had the highest salary increase in the last three years.
SELECT e.name
FROM employees e
JOIN salary s ON e.ID_usr = s.ID_usr
WHERE s.year >= DATE_SUB(CURDATE(), INTERVAL 3 YEAR)
GROUP BY e.name
ORDER BY (MAX(s.salary) - MIN(s.salary)) DESC
LIMIT 3;
"""
}) 

Voy a crear una función que concatenará este prompt, con la pregunta del usuario, para pasársela a OpenAI, y que nos devolverá la respuesta del Modelo.

  #Functio to call the model.
def return_CCRMSQL(user_message, context):

    newcontext = context.copy()
    newcontext.append({'role':'user', 'content':"question: " + user_message})

    response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=newcontext,
            temperature=0,
        )

    return (response.choices[0].message["content"])

Como podemos ver la pregunta del usuario la estamos añadiendo al final del prompt con el rol user, así el modelo entiende que esta es una petición del usuario y no una instrucción de cómo debe funcionar.

Veamos un par de ejemplos:

#new
context_user = context.copy()
print(return_CCRMSQL("The name of the employee best paid", context_user))

`SELECT e.name FROM employees e JOIN salary s ON e.ID_Usr = s.ID_Usr ORDER BY s.salary DESC LIMIT 1;

print(return_CCRMSQL("Return the Institution with a higher average salary", context_user))

SELECT s.Institution, AVG(s.salary) AS average_salary FROM salary s JOIN studies st ON s.ID_Usr = st.ID_Usr GROUP BY s.Institution ORDER BY average_salary DESC LIMIT 1;

Conclusiones.

He usado esta estructura de prompt en varios proyectos para generar SQL desde lenguaje natural y su resultado siempre ha sido bastante bueno. Para bases de datos con una estructura sencilla quizas no hace falta poner los ejemplos del contenido de las tablas, pero si que recomiendo siempre darle un par de ejemplos de SQL generado.

Si tenéis acceso a una base de datos real, intentad replicar el prompt para obtener órdenes SQL con la estructura de vuestra base de datos. Así podéis probar vosotros mismos como funciona.

Usa una Base de datos Vectorial para optimizar tus prompts para grandes modelos de lenguaje.

En este artículo vamos a combinar dos de las tecnologías más en moda actualmente, las bases de datos vectoriales y Read more

Curso practico de IA sin Prerrequisitos.
Curso IA sin prerrequisitos

Introducción al apasionante mundo de la I.A. mediante Machine Learning, sin necesidad de tener conocimientos previos de Python o Algrebra. Read more

Preparando la certificación TensorFlow Developer by Google. 4-NLP Generación de texto predictivo.

Explico el notebook de Generación de texto predictivo que he usado para preparame el examen de TensorFlow Certificate.

Creación de un sistema de comentarios con LangChain y OpenAI.

Como disclaimer me gustaría indicar que este artículo es tan solo un ejemplo creado para ver como funciona la herramienta Read more

Por Martra

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *