Langchain 101: Prompts

Langchain 101: Prompts

Esta sección contiene todo lo relacionado con los prompts. Este valor puede ser un string (para LLMs) o una lista de mensajes (para Modelos de Chat)

Introducción

La nueva forma de programar modelos es mediante prompts. Un prompt se refiere a la entrada de datos al modelo. Esta entrada se construye a menudo a partir de múltiples componentes. Un PromptTemplate es responsable de la construcción de esta entrada. LangChain proporciona varias clases y funciones para facilitar la construcción y el trabajo con prompts.

Esta sección contiene todo lo relacionado con los prompts. Un prompt es el valor que se pasa al Modelo de Lenguaje. Este valor puede ser un string (para LLMs) o una lista de mensajes (para Modelos de Chat).

Los tipos de datos de estos prompts son bastante simples, pero su construcción es cualquier cosa menos eso. LangChain incluye:

  • Una interfaz estándar para prompts de cadena y prompts de mensaje.

  • Una interfaz estándar (para empezar) para plantillas de prompts de cadena y plantillas de prompts de mensajes

  • Example Selectors: métodos para insertar ejemplos en el prompt para el modelo de lenguaje a seguir

  • OutputParsers: métodos para insertar instrucciones en el prompt como el formato en el que el modelo de lenguaje debe mostrar la información, así como métodos para analizar esa cadena de salida en un formato.

Dispones de documentación detallada sobre tipos específicos de string prompts, tipos específicos de chat prompts, Example Selectors y OutputParsers, en las próximas guías o en su respectivo Notebook en el Github del curso.

A continuación, cubriremos una interfaz estándar para empezar a trabajar con prompts sencillos.

PromptTemplates

Los PromptTemplates son responsables de construir un prompt value ( La clase que representa una entrada a un modelo. ). Estos PromptTemplates pueden hacer cosas como formatear, seleccionar ejemplos y más. A un alto nivel, estos son básicamente objetos que exponen un método format_prompt para construir un prompt. Debajo del capó, puede pasar CUALQUIER COSA.

from langchain.prompts import PromptTemplate, ChatPromptTemplate
string_prompt = PromptTemplate.from_template("tell me a joke about {subject}")
chat_prompt = ChatPromptTemplate.from_template("tell me a joke about {subject}")
string_prompt_value = string_prompt.format_prompt(subject="soccer")
chat_prompt_value = chat_prompt.format_prompt(subject="soccer")

to_string

Esto es lo que se llama cuando se pasa a un LLM (que espera texto sin formato)

string_prompt_value.to_string()
'tell me a joke about soccer'
chat_prompt_value.to_string()
'Human: tell me a joke about soccer'

to_messages

Esto es lo que se llama cuando se pasa a un ChatModel (que espera una lista de mensajes)

string_prompt_value.to_messages()
[HumanMessage(content='tell me a joke about soccer', additional_kwargs={}, example=False)]
chat_prompt_value.to_messages()
[HumanMessage(content='tell me a joke about soccer', additional_kwargs={}, example=False)]

Prompt Templates: Primeros pasos

En este tutorial, aprenderemos sobre:

  • Qué es una plantilla de prompts y por qué es necesaria

  • Cómo crear una plantilla

  • Cómo pasar algunos ejemplos a una plantilla

  • Cómo seleccionar ejemplos para una plantilla

¿Qué es una Prompt Template?

Una plantilla de aviso es una forma reproducible de generar un prompt. Contiene una cadena de texto ("la plantilla"), que puede recibir un conjunto de parámetros del usuario final y generar un prompt.

La plantilla puede contener:

  • Instrucciones para el modelo lingüístico

  • Un conjunto de ejemplos para ayudar al modelo lingüístico a generar una mejor respuesta

  • Una pregunta al modelo lingüístico

El siguiente fragmento de código contiene un ejemplo de Prompt Template:

from langchain import PromptTemplate

template = """
I want you to act as a naming consultant for new companies.
What is a good name for a company that makes {product}?
"""

prompt = PromptTemplate(
    input_variables=["product"],
    template=template,
)
prompt.format(product="colorful socks")
'\nI want you to act as a naming consultant for new companies.\nWhat is a good name for a company that makes colorful socks?\n'

¿Cómo crear un Prompt Template?

Con la clase PromptTemplate se pueden crear prompts sencillos. Las plantillas de prompts pueden tomar cualquier número de variables de entrada y pueden formatearse para generar un prompt.

from langchain import PromptTemplate
# Ejemplo de solicitud sin variables de entrada
no_input_prompt = PromptTemplate(input_variables=[], template="Tell me a joke.")
no_input_prompt.format()
'Tell me a joke.'
# Un ejemplo con una variable de entrada
one_input_prompt = PromptTemplate(input_variables=["adjective"], template="Tell me a {adjective} joke.")
one_input_prompt.format(adjective="funny")
'Tell me a funny joke.'
multiple_input_prompt = PromptTemplate(
    input_variables=["adjective", "content"], 
    template="Tell me a {adjective} joke about {content}."
)
multiple_input_prompt.format(adjective="funny", content="chickens")
'Tell me a funny joke about chickens.'

Si no quieres especificar input_variables manualmente, también puedes crear una PromptTemplate utilizando el método de clase from_template. Langchain deducirá automáticamente las input_variables basándose en la plantilla pasada.

template = "Tell me a {adjective} joke about {content}."

prompt_template = PromptTemplate.from_template(template)
prompt_template.input_variables
['adjective', 'content']
prompt_template.format(adjective="funny", content="chickens")
'Tell me a funny joke about chickens.'

Puedes crear plantillas personalizadas que formateen el prompt de la manera que quieras.

Template formats

Por defecto, PromptTemplate tratará la plantilla proporcionada como una f-string de Python. Puedes especificar otro formato de plantilla mediante el argumento template_format:

In [22]:

# Asegúrate de que jinja2 está instalado antes de ejecutar esto
%pip install -U Jinja2
jinja2_template = "Tell me a {{ adjective }} joke about {{ content }}"
prompt_template = PromptTemplate.from_template(template=jinja2_template, template_format="jinja2")

prompt_template.format(adjective="funny", content="chickens")
'Tell me a funny joke about chickens'

Actualmente, PromptTemplate sólo soporta los formatos de plantillas jinja2 y f-string. Si hay algún otro formato de plantilla que te gustaría utilizar, puedes abrir una incidencia en la página de Github.

Validación de la plantilla

Por defecto, PromptTemplate validará el string de la plantilla comprobando si los input_variables coinciden con las variables definidas en la plantilla. Puede desactivar este comportamiento estableciendo validate_template en False.

template = "I am learning langchain because {reason}."

prompt_template = PromptTemplate(template=template, 
                                 input_variables=["reason", "foo"], # ValueError debido a variables adicionales
                                 validate_template=False) # No error

Serializar plantilla de prompt

Puedes guardar el PromptTemplate en un archivo en tu sistema de archivos local. langchain deducirá automáticamente el formato de archivo a través del nombre de la extensión del archivo. Actualmente, langchain soporta guardar plantillas en archivos YAML y JSON.

prompt_template.save("awesome_prompt.json") # Guardar en archivo JSON
from langchain.prompts import load_prompt
loaded_prompt = load_prompt("awesome_prompt.json")

assert prompt_template == loaded_prompt

langchain también soporta la carga de plantillas de prompts de LangChainHub, que contiene una colección de prompts útiles que puedes utilizar en tu proyecto. Puedes leer más sobre LangChainHub y los prompts disponibles aquí.

from langchain.prompts import load_prompt

prompt = load_prompt("lc://prompts/conversation/prompt.json")
prompt.format(history="", input="What is 1 + 1?")

Pasar few shot a una plantilla de prompts

Los ejemplos de few shot son un conjunto de ejemplos que pueden utilizarse para ayudar al modelo lingüístico a generar una respuesta mejor.

Para generar un prompt con ejemplos few shot, puedes utilizar FewShotPromptTemplate. Esta clase recibe un PromptTemplate y una lista de ejemplos few shot. Luego formatea la plantilla con los ejemplos.

En este ejemplo, crearemos un prompt para generar antónimos de palabras.

from langchain import PromptTemplate, FewShotPromptTemplate

# En primer lugar, elabora una lista con algunos ejemplos de tomas.
examples = [
    {"word": "happy", "antonym": "sad"},
    {"word": "tall", "antonym": "short"},
]

# A continuación, especificamos la plantilla para dar formato a los ejemplos que hemos proporcionado.
# Para ello utilizamos la clase `PromptTemplate`.
example_formatter_template = """Word: {word}
Antonym: {antonym}
"""

example_prompt = PromptTemplate(
    input_variables=["word", "antonym"],
    template=example_formatter_template,
)
# Por último, creamos el objeto `FewShotPromptTemplate`.
few_shot_prompt = FewShotPromptTemplate(
    # Estos son los ejemplos que queremos insertar en el prompt.
    examples=examples,
    # Así es como queremos formatear los ejemplos cuando los insertemos en el prompt.
    example_prompt=example_prompt,
    # El prefijo es un texto que va antes de los ejemplos en el prompt.
    # Suele consistir en instrucciones.
    prefix="Give the antonym of every input\n",
    # El sufijo es algún texto que va después de los ejemplos en el prompt.
    # Normalmente, aquí es donde irá la entrada del usuario
    suffix="Word: {input}\nAntonym: ",
    # Las variables de entrada son las variables que espera el indicador general.
    input_variables=["input"],
    # El example_selector es el string con la que uniremos el prefijo, los ejemplos y el sufijo.
    example_separator="\n",
)

# Ahora podemos generar un prompt utilizando el método `format`.
print(few_shot_prompt.format(input="big"))
Give the antonym of every input

Word: happy
Antonym: sad

Word: tall
Antonym: short

Word: big
Antonym:

Seleccionar ejemplos para una plantilla de prompts

Si dispones de un gran número de ejemplos, puedes utilizar el ExampleSelector para seleccionar un subconjunto de ejemplos que sean más informativos para el Modelo de Lenguaje. Esto te ayudará a generar un prompt que tenga más probabilidades de generar una buena respuesta.

A continuación, utilizaremos el LengthBasedExampleSelector, que selecciona ejemplos basados en la longitud de la entrada. Esto es útil cuando te preocupa construir un prompt que sobrepase la longitud de la ventana contextual. Para entradas más largas, seleccionará menos ejemplos a incluir, mientras que para entradas más cortas seleccionará más.

Continuaremos con el ejemplo de la sección anterior, pero esta vez utilizaremos el LengthBasedExampleSelector para seleccionar los ejemplos.

from langchain import PromptTemplate, FewShotPromptTemplate
from langchain.prompts.example_selector import LengthBasedExampleSelector

# Estos son muchos ejemplos de una tarea simulada de creación de antónimos.
examples = [
    {"word": "happy", "antonym": "sad"},
    {"word": "tall", "antonym": "short"},
    {"word": "energetic", "antonym": "lethargic"},
    {"word": "sunny", "antonym": "gloomy"},
    {"word": "windy", "antonym": "calm"},
]

# A continuación, especificamos la plantilla para dar formato a los ejemplos que hemos proporcionado.
# Para ello utilizamos la clase `PromptTemplate`.
example_formatter_template = """Word: {word}
Antonym: {antonym}
"""

example_prompt = PromptTemplate(
    input_variables=["word", "antonym"],
    template=example_formatter_template,
)

# Utilizaremos el `LengthBasedExampleSelector` para seleccionar los ejemplos.
example_selector = LengthBasedExampleSelector(
    # Estos son los ejemplos de los que dispone para elegir.
    examples=examples, 
    # Este es el PromptTemplate que se utiliza para dar formato a los ejemplos.
    example_prompt=example_prompt, 
    # Esta es la longitud máxima que deben tener los ejemplos formateados.
    # La longitud se mide con la función get_text_length que aparece a continuación.
    max_length=25
    # Esta es la función utilizada para obtener la longitud de una cadena, que se utiliza
    # para determinar qué ejemplos incluir. Se comenta en la documentación porque
    # es opcional. Si no se proporciona, se utiliza la longitud de la cadena.
    # get_text_length: Callable[[str], int] = lambda x: len(re.split("\n| ", x))
)

# Ahora podemos utilizar el `example_selector` para crear un `FewShotPromptTemplate`.
dynamic_prompt = FewShotPromptTemplate(
    # Proporcionamos un ExampleSelector en lugar de ejemplos.
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="Give the antonym of every input",
    suffix="Word: {input}\nAntonym:",
    input_variables=["input"],
    example_separator="\n\n",
)

# Ahora podemos generar un prompt utilizando el método `format`.
print(dynamic_prompt.format(input="big"))
Give the antonym of every input

Word: happy
Antonym: sad


Word: tall
Antonym: short


Word: energetic
Antonym: lethargic


Word: sunny
Antonym: gloomy


Word: big
Antonym:

Por el contrario, si proporcionamos una entrada muy larga, el LengthBasedExampleSelector` seleccionará menos ejemplos para incluir en el prompt.

long_string = "big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else"
print(dynamic_prompt.format(input=long_string))
Give the antonym of every input

Word: big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else
Antonym:

LangChain viene con algunos selectores de ejemplo que puedes utilizar. Los verás en el documento Prompts - ExampleSelectos - How-To Guides.ipynb (también puedes suscribirte a este Blog / Newsletter y no perderte el formato artículo)

Puedes crear selectores de ejemplo personalizados que seleccionen ejemplos basados en cualquier criterio que desees. Para más detalles sobre cómo hacerlo, consulta Prompts - ExampleSelectos - How-To Guides.ipynb.

Chat Prompt Templates

Los modelos de chat toman una lista de mensajes de chat como entrada - esta lista se conoce comúnmente como prompt. Estos mensajes de chat difieren de las cadenas de texto sin formato (que pasarías a un modelo LLM) en que cada mensaje está asociado a un rol.

Por ejemplo, en OpenAI Chat Completion API, un mensaje de chat puede asociarse con el rol de IA, humano o sistema. Se supone que el modelo sigue más de cerca las instrucciones del mensaje de chat del sistema.

LangChain proporciona varias plantillas de prompts para facilitar la construcción y el trabajo con prompts. Te animo a utilizar estas plantillas de prompts relacionados con el chat en lugar de PromptTemplate cuando consultes modelos de chat para explotar al máximo el potencial del modelo de chat subyacente.

from langchain.prompts import (
    ChatPromptTemplate,
    PromptTemplate,
    SystemMessagePromptTemplate,
    AIMessagePromptTemplate,
    HumanMessagePromptTemplate,
)
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)

Para crear una plantilla de mensaje asociada a un rol, se utiliza MessagePromptTemplate.

Por conveniencia, hay un método from_template expuesto en la plantilla. Si fueras a utilizar esta plantilla, este es el aspecto que tendría:

template="You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template="{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

Si quisieras construir el MessagePromptTemplate más directamente, podrías crear un PromptTemplate fuera y luego pasarlo, ej

prompt=PromptTemplate(
    template="You are a helpful assistant that translates {input_language} to {output_language}.",
    input_variables=["input_language", "output_language"],
)
system_message_prompt_2 = SystemMessagePromptTemplate(prompt=prompt)

assert system_message_prompt == system_message_prompt_2

Después, puedes construir un ChatPromptTemplate a partir de uno o más MessagePromptTemplates. Puedes usar el format_prompt de ChatPromptTemplate - esto devuelve un PromptValue, que puedes convertir en una string o en un objeto Message, dependiendo de si quieres usar el valor formateado como entrada a un modelo llm o chat.

chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])

# obtener una finalización de chat a partir de los mensajes formateados
chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_messages()
[SystemMessage(content='You are a helpful assistant that translates English to French.', additional_kwargs={}),
 HumanMessage(content='I love programming.', additional_kwargs={}, example=False)]

Formato de salida

La salida del método format está disponible como string, lista de mensajes y ChatPromptValue

como string

output = chat_prompt.format(input_language="English", output_language="Spanish", text="I love programming.")
output
'System: You are a helpful assistant that translates English to Spanish.\nHuman: I love programming.'
# o en su defecto
output_2 = chat_prompt.format_prompt(input_language="English", output_language="Spanish", text="I love programming.").to_string()
assert output == output_2

Como ChatPromptValue

chat_prompt.format_prompt(input_language="English", output_language="Spanish", text="I love programming.")
ChatPromptValue(messages=[SystemMessage(content='You are a helpful assistant that translates English to Spanish.', additional_kwargs={}), HumanMessage(content='I love programming.', additional_kwargs={}, example=False)])

Como lista de mensajes

chat_prompt.format_prompt(input_language="English", output_language="Spanish", text="I love programming.").to_messages()
[SystemMessage(content='You are a helpful assistant that translates English to Spanish.', additional_kwargs={}),
 HumanMessage(content='I love programming.', additional_kwargs={}, example=False)]

Diferentes tipos de MessagePromptTemplate

LangChain proporciona diferentes tipos de MessagePromptTemplate. Los más utilizados son AIMessagePromptTemplate, SystemMessagePromptTemplate y HumanMessagePromptTemplate, que crean un mensaje AI, un mensaje de sistema y un mensaje humano respectivamente.

Sin embargo, en los casos en los que el modelo de chat admite mensajes de chat con un rol arbitrario, puedes utilizar ChatMessagePromptTemplate, que permite al usuario especificar el nombre del rol.

from langchain.prompts import ChatMessagePromptTemplate

prompt = "May the {subject} be with you"

chat_message_prompt = ChatMessagePromptTemplate.from_template(role="Jedi", template=prompt)
chat_message_prompt.format(subject="force")
ChatMessage(content='May the force be with you', additional_kwargs={}, role='Jedi')

LangChain también proporciona MessagesPlaceholder, que le da el control total de los mensajes que se mostrarán durante el formateo. Esto puede ser útil cuando no estás seguro de qué papel debes utilizar para tus plantillas de mensajes o cuando deseas insertar una lista de mensajes durante el formateo.

from langchain.prompts import MessagesPlaceholder

human_prompt = "Summarize our conversation so far in {word_count} words."
human_message_template = HumanMessagePromptTemplate.from_template(human_prompt)

chat_prompt = ChatPromptTemplate.from_messages([MessagesPlaceholder(variable_name="conversation"), human_message_template])
human_message = HumanMessage(content="What is the best way to learn programming?")

chat_prompt.format_prompt(conversation=[human_message, ai_message], word_count="10").to_messages()
[HumanMessage(content='What is the best way to learn programming?', additional_kwargs={}, example=False),
 AIMessage(content='1. Choose a programming language: Decide on a programming language that you want to learn. \n\n2. Start with the basics: Familiarize yourself with the basic programming concepts such as variables, data types and control structures.\n\n3. Practice, practice, practice: The best way to learn programming is through hands-on experience', additional_kwargs={}, example=False),
 HumanMessage(content='Summarize our conversation so far in 10 words.', additional_kwargs={}, example=False)]

Guías prácticas

En la documentación oficial de Langchain hay "How To's" sobre Prompt Templates, Example Selector y ejemplos específicos de Output Parsers.

Si veo apoyo en el contenido y ⭐ el repo de Github iré trayendo esta semana los "How To's" en castellano.


Recursos Adicionales

Curso Langchain

Documentación oficial

Soy Samu Sarmiento, embajador de thirdweb y desarrollador de software. Mi experiencia incluye trabajar con TypeScript y frameworks populares como React, Next.js y Node.js, así como construir aplicaciones Web 3.0 usando thirdweb.

A Junio de 2023, llevo aproximadamente tres meses investigando el mundo de la inteligencia artificial, machine learning, deep learning, modelos de lenguaje, agentes autónomos.... Y de ahí nacen estas guías/tutoriales ;)

En los próximos días y semanas estaré trayendoles en mi Newsletter más notícias, actualizaciones, nuevos agentes o frameworks. Nuevos casos de uso. Y sobretodo muchos tutoriales y guías prácticas para que no pierdas mucho tiempo investigando y puedas poner en marcha tus ideas rápidamente.

Espero que les guste y la disfruten. Todo feedback es más que bienvenido, contacta conmigo en Twitter directamente ( @SamuSarmiento_ ).


¡Y eso es todo por hoy! Espero que hayas adquirido una comprensión superficial de las capacidades de LangChain. Si quieres seguir leyendo guías y tutoriales como este o el anterior, estar al día sobre AI, AGI, LLMs y productos potenciados por IA:

  1. Sígueme en Twitter

  2. Suscríbete a mi Newsletter para no perderte las últimas noticias sobre Agentes autónomos, LLMs y productos potenciados por IA.

  3. ⭐ el repo de Github mientras tanto para recibir actualizaciones.