Prompt Engineering para Desarrolladores

Utiliza el poder de los LLMs como parte de tus Aplicaciones

Ahora que ya cuentas con tu LLM en Local, como explicamos en el artículo “Instala un LLM en Local”, podemos encenderlo en modo Servidor y comenzar a jugar con él desde nuestro código python.

En este artículo usaremos una Jupyter Notebook que puedes ver y descargar desde GitHub y realizar las actividades de Prompt Engineering.

Vamos a comenzar explicando los conceptos más importantes a la hora de pedir tareas a un Gran Modelo del Lenguaje y veremos como iterar sobre diversos casos de uso para mejorar el resultado final. Por último plantearemos el código para crear un Chatbot que guíe al cliente en sus compras en un ecommerce.

Introducción

El término Prompt Engineer surgió cuando los primeros Grandes Modelos de Lenguaje cómo (GPT-2 en 2019, GPT-3 en 2020) comenzaban a aparecer y encerrar en su interior los misterios del lenguaje humano. Entonces hacer prompt Engineer trataba de “encontrar de forma artística” la mejor forma de obtener buenas respuestas de estos modelos. De hecho, la técnica muchas veces consistía en hackear al modelo, descubrir vulnerabilidades y fortalezas. De las diversas y a veces aleatorias fórmulas utilizadas por los usuarios de la comunidad, el Prompt Engineer gana fuerza como una tarea en sí misma (y no como un complemento) en donde el saber cómo realizar la petición al modelo tenía salidas precisas y concretas.

Los actuales grandes modelos (de 2024) tienen “billones” de parámetros y si bien tenemos algo más de comprensión sobre su comportamiento -sabemos que son modelos estadísticos- lo cierto es que aún no tenemos un mapa completo de cómo se comportan. Esto da lugar a que el Prompt Engineering (“cómo consultamos el LLM”) siga siendo una parte importante de nuestra tarea como científicos de datos o Ingenieros de datos.

Lo cierto es que ahora un LLM puede ser una pieza más del sistema, por lo que debemos poder fiarnos de que tendremos la respuesta apropiada (y en el formato buscado).

Modelo Fundacional vs Modelo de Instrucciones

Hagamos un mini repaso antes de empezar; hay dos tipos de LLMS, los “LLM Base” (fundacional) y los “LLM tuneados con Instrucciones” (en inglés Instruction Tuned LLM). Los primeros entrenados únicamente para predecir la siguiente palabra. Los tuneados en Instrucciones están entrenados sobre los Base; pero pueden seguir indicaciones, eso los vuelve mucho más útiles para poder llevar adelante una conversación. Además, al agregar el RLHF, es decir, un paso adicional luego de Tunearlos en donde mediante el feedback de personas humanas se mejora la redacción de respuestas penalizando o premiando al modelo. El RLHF también funciona como una capa de censura para ciertas palabras o frases no deseadas.

Estas LLMs que siguen instrucciones son ajustadas con el objetivo de ser “utiles, honestas e inofensivas” (en inglés Helpful, Honest, Harmless) intentan ser lo menos tóxicas posibles. De ahí la importancia de la limpieza del dataset inicial con el que fueron entrenadas las “LLM base”.

Ten esto en cuenta cuando descargues o elijas qué LLM utilizar. Para la mayoría de aplicaciones deberás seleccionar una version de LLM que sea de Instrucciones y no base. Por ejemplo para modelos Llama 2 encontrarás versiones “raw” o base, pero generalmente queremos utilizar las tuneadas en instrucciones. A veces se les denomina como “versión chat”.

Las dos reglas para lograr buenos Prompts

¿Qué es lo que tienes que hacer para lograr buenas respuestas con tu LLM?

Veamos los dos principios básicos:

  1. Escribir tareas claras y específicas.
  2. Darle al modelo “tiempo para pensar” (o reflexionar).

Requerimientos técnicos

Veamos como hacerlo con ejemplos en python; siguiendo una Jupyter Notebook.

Recuerda iniciar tu modelo en LM Studio, en mi caso, estoy utilizando laser-dolphin-mixtral en mi Mac.

Y tampoco olvides instalar el paquete de OpenAI ejecutando “pip install openai==1.13.3” en el ambiente de Python en el que te encuentres trabajando. Inicia en LM Studio el Servidor Local, para poder utilizar la API.

Empezamos con el Código!

Importamos las librerías que utilizaremos y creamos una función “get_completion” que nos facilitará la obtención del resultado del modelo. Como verás ponemos el valor de Temperatura a cero, eso nos proporciona menos “creatividad” por parte del modelo para poder reproducir resultados (de no hacerlo, podríamos obtener distintas respuestas cada vez que ejecutemos el mismo prompt). También notarás que definimos un rol de Sistema para lograr que el LLM nos responda siempre en español.

Recuerda: Si bien utilizamos el paquete de openai, estaremos haciendo las consultas a nuestro modelo local y gratuito

Volvamos al primer Principio “dar instrucciones claras y específicas”, esto mejorará las chances de que el modelo de respuestas erróneas o incorrectas. OJO, no confundir el dar respuestas cortas con “claras”. En la mayoría de casos, las respuestas largas proveen mejores explicaciones y detalle que respuestas cortas.

1. Prompts claros

Una buena ayuda para aclarar nuestros prompts es la de usar delimitadores como triple comillas o guiones. Veamos un ejemplo en donde en el prompt definimos un delimitador con el texto al que queremos que el LLM ponga atención:

Otra táctica es solicitar al modelo salida estructurada. Por ejemplo salidas JSON o HTML.

La salida puede ser usada directamente como un diccionario python, esto puede ser muy útil para nuestras apps! Esta es la salida que obtuve:

Los tiempos de Salida del modelo pueden variar, en mi caso en un ordenador sin GPU el tiempo de respuesta puede ser de 1 o dos minutos. Si cuentas con GPU el tiempo de respuesta podría ser de apenas segundos.

Si estás pensando en comprar una GPU… aquí te dejo algunos enlaces con precios de Amazon España:

La tercer táctica es pedir al modelo que revise si las condiciones son satisfactorias y si no se cumplen indicarlo con un mensaje explicito.

Tenemos como salida:

La cuarta técnica para prompts claros, será la de “Few shot prompting“. Esto consiste en proveer de ejemplos correctos del tipo de respuesta que buscamos antes de pedir una tarea.

Salida:

2. Piensa antes de hablar…

El segundo principio es el de “Darle tiempo al modelo a pensar (reflexionar)

Si las respuestas del modelo son incorrectas ante una tarea compleja, puede ser debido a que se apresura en responder, eso a veces nos pasa a los humanos que respondemos “lo primero que se viene a la mente” y no siempre es correcto. Lo que podemos hacer es decirle al LLM que realice una “cadena de pensamiento” (Chain of thought) o que <<piense atentamente>> antes de responder.

La primera técnica para conseguirlo es darle una lista detallada de los pasos que debe seguir para responder.

Salida (sólo copio la salida JSON, por ahorrar texto):

Técnica dos; Pedir al modelo que trabaje internamente la solución antes de apresurarse en dar una respuesta. Aquí le daremos un problema de matemáticas real, que tuvo mi hija de 10 años. Introduciré un error (a propósito) en la solución del estudiante, al usar el valor del IVA y el modelo deberá detectarlo y explicarnos la solución correcta.

A mi personalmente me parece impresionante que el modelo pueda detectar el fallo!, veamos la salida:

Advertencia, este modelo puede alucinar!

Tengamos en cuenta las alucinaciones! Este es un fenómeno que ¿sufren? los LLMS y hacen que se inventen datos, fechas y lugares de manera muy convincente. Hay que tener esto en cuenta al momento de obtener salidas, porque podríamos estar dandole a un cliente información falsa!.

Vemos un ejemplo en donde le pedimos al LLM que nos cuente sobre un producto que no existe, y sin embargo es capaz de darnos una descripción completa y convincente!!

Como verás, pedimos información sobre un producto que no existe y el Modelo es capaz de inventar una respuesta que parece real. Salida (acorto el texto, pero está completo en la Notebook):

Segunda vuelta

Además de los dos principios, deberás saber que la tarea de Prompt Engineering es una tarea iterativa, es decir, empezamos con un prompt y hacemos la prueba. Seguramente no saldrá el mejor resultado a la primera por lo que debemos refinar nuestro prompt; hacer leves variaciones, cambiar ciertas palabras e ir viendo como responde el modelo.

Debemos analizar porqué no funciona el prompt y corregir. Por ejemplo si el prompt retorna una salida muy larga podemos probar de acotarla con “Escribe máximo 50 palabras”. Otra opción podría ser “utiliza como máximo 3 oraciones”.

Prompts para Resumir texto

Uno de los casos de uso comunes es el de usar LLM para resumir textos; podemos pedir que nos haga un resumen diario de las noticias del día o del Feed de Twitter o de nuestras redes sociales.

Vemos un ejemplo. Primero podemos pedirle que lo haga “en como máximo 30 palabras”.

Salida:

Podemos refinarlo pidiendo que se centre en algún aspecto en particular de la review.

Salida:

Otra opción es en vez de pedirle de “resumir” decirle que “extraiga” el contenido. Pruébalo!

Tareas de NLP con tu LLM

Ahora veremos de usar al LLM para que realice tareas que antes realizábamos con modelos específicos de NLP. Es fabuloso que el LLM pueda resolver estas tareas como si “estuviera razonando” y entendiendo realmente el lenguaje Natural!

Veremos ejemplos en los que usamos al LLM para obtener el análisis de sentimiento, detección de Entidades y clasificación de textos/tópicos.

Análisis de Sentimiento

Primero, le pedimos análisis de sentimiento:

También podemos intentar detectar emociones, intentar entender si un cliente está enojado nos puede servir por si debemos actuar u ofrecerle un cupón de descuento antes de que abandone su suscripción…

Extracción de entidades

¿De qué trata el texto?

Podemos hacer que el LLM detecte temas, es decir, sobre qué trata un texto. Podemos pedirle una lista libre (a su criterio) o acotarlo a una lista de temas que le damos nosotros. Veamos un ejemplo utilizando un extracto de texto de la lista de correos sobre IA de Unai Martinez:

Tienes algunos ejemplos y usos adicionales en la Notebook!

LLM para traducción y corrección de textos

Los grandes modelos están entrenados con Millones y Millones de textos sacados de internet en distintos idiomas; por lo cual, sin haberlo hecho con ese propósito, el modelo aprendió a entender y traducir entre una variedad de lenguas.

Veamos ejemplos de traducción:

También podemos pedir que detecte un idioma:

Corrección de Textos

En este ejemplo vamos a pasarle un listado de oraciones con error y probar si el modelo es capaz de detecta errores de sintaxis o gramática. Si eres un profesor, esto podría ser útil para corregir textos antes de procesarlos (o limpieza de datos en un pipeline de ML).

Tengamos en cuenta que el modelo también puede fallar y no siempre detectar los errores. Puedes ver las salidas en la Notebook.

Crea un Chatbot para ecommerce con tu LLM

En nuestro último ejercicio vamos a crear un chatbot para que conteste a los clientes de una empresa ya existente. Será un ejemplo básico, pero verás lo potente que resulta. Sobre todo, no tener que programar paso a paso todo el chatbot, si no, que es simplemente darle las instrucciones en lenguaje natural al LLM.

Roles y memoria!

Antes de empezar debemos saber sobre la memoria de un LLM y sobre los roles.

Sobre los roles, tenemos 3 roles principales que gestionamos cuando enviamos los prompts al modelo:

  • System: se define 1 solo mensaje de sistema. Este mensaje define “quién es el LLM”, su identidad y cómo debe contestar.
  • User: aquí veremos TODOS los mensajes que va escribiendo el usuario que utiliza el LLM y sus consultas
  • Assistant: serán las respuestas que provee el LLM a las peticiones del usuario.

El Modelo de lenguaje no tiene memoria, esto quiere decir que si le pedimos algo al modelo, debemos tener en cuenta que el modelo no recuerda las respuesta anteriores. Esto es un inconveniente porque para poder tener una conversación resultará muy útil que el modelo recuerde todo lo que se habló previamente. Si en el primer mensaje le decimos al Asistente nuestro nombre y luego le preguntamos “¿Quién soy?” el modelo no tendrá ni idea!

Para resolver esto, es que debemos almacenar el historial de mensajes e ir enviándolo al modelo constantemente.

Para nuestro ejemplo, modificamos levemente la función de “get_completion()” y esta vez enviaremos el historial completo como una lista de mensajes python.

Para nuestro ejemplo, mantendremos todos los mensajes! Así que cuidado… si la conversación se extiende podrías llenar tu memoria… pero en próximos artículos del blog veremos estrategias para limitar la memoria del chat.

Antes de comenzar con el bot, hagamos un ejemplo enviando mensajes y limitando el historial para comprobar que el LLM no recuerda…

Aquí comprobaremos que en su salida no sabe nuestro nombre:

Sin embargo, si le pasamos el historial completo, el modelo puede recordar que mi nombre es Juan 🙂

Bien, ya sabemos cómo debemos hacer para que el chatbot conserve nuestro historial y pueda seguir una conversación.

Un Bot que sirve Pizzas

Vamos a crear un listado con todos los mensajes que se van produciendo y los vamos a incorporar al chat. En el primer mensaje de sistema, le indicaremos al LLM quién es, la información con la que cuenta, en este caso serán las pizzas y productos que ofrece y sus precios.

Con este código de muy pocas líneas podemos hacer que el bot trabaje para nosotros!; aquí copio la salida que obtuve:

Conclusiones

En este artículo podemos aprender a usar el LLM como una pieza de nuestras aplicaciones. Podemos contar con él como un motor de respuestas generales, o específicas para el caso de uso que abordemos.

Además si aprovechamos la capacidad de que responda en formatos como JSON, XML o HTML, podemos incorporar sus salidas para alimentar otras APIs, u otras funciones de nuestro código Python.

Los LLMs son muy potentes y resulta muy cómodo poder utilizar uno en Local y hacer este tipo de pruebas!

Espero que el artículo te resulte útil, cuentas con el código completo en la Jupyter notebook dentro de mi cuenta de Github.

En el próximo artículo veremos más ejemplos de uso del LLM y nuevas librerías python que surgieron para facilitarnos la vida!

Hasta la próxima.

Suscripción al Blog

Recibe los próximos artículos sobre Machine Learning, estrategias, teoría y código Python en tu casilla de correo!

NOTA: algunos usuarios reportaron que el email de confirmación y/o posteriores a la suscripción entraron en su carpeta de SPAM. Te sugiero que revises los “correos no deseados” y/o que agendes la dirección de remitente en tus contactos.

Leave a Reply