====== Modelos, plantillas y parsers ======
===== Modelos =====
En primer lugar hay que tener el modelo correspondiente instalado y ejecutándose. \\
Lo modelos disponibles para funcionar con langchain están en [[https://python.langchain.com/docs/integrations/chat/]] \\
En mi caso trabajo habitualmente con Ollama en local, usando el modelo Llama 3.2 de 3 mil millones de parámetros, uno de los modelos pequeños que no son multimodales. Por ello, haré los ejemplos usando éste. \\
# Cargamos las librerías de langchain del modelo
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
# Instanciamos el chat del modelo definiendo sus opciones
chat = ChatOllama(
model = "llama3.2",
temperature = 0.1
)
===== Plantillas =====
Las plantillas definen prompts por defecto que tienen algunas "variables" **{ entre llaves }**, a las que se les puede asignar diferentes valores. De este modo, puede usarse para tareas recurrentes.
prompt = """Quiero que sugieras una receta \
de cocina para {hora_comida} que tenga al menos \
los siguientes ingredientes: {ingredientes}"""
# Definimos la plantilla de prompt
plantilla_prompt = ChatPromptTemplate.from_template(prompt)
# Como el programa va de obtener recetas, vamos a incluir en las variables un código numérico
# que indique la fecha para la que estamos calculando la receta
hora_comida_111024 = "comer" # Otras posibilidades: cenar, almorzar, merendar, desayunar
ingredientes_111024 = "arroz, curry, pollo"
# Creamos el mensaje a pasar al modelo, indicando en la plantilla las variables correspondientes
mensaje = plantilla_prompt.format_messages(
hora_comida = hora_comida_111024,
ingredientes = ingredientes_111024)
# Obtenemos y visualizamos la receta
respuesta = chat.invoke(mensaje)
receta_111024 = respuesta.content
print(receta_111024)
===== Parseo de salida =====
Se entiende por //parser// la capacidad de devolver respuestas estructuradas, con las que python pueda trabajar en programación tradicional, por ejemplo en formato JSON o como listas o diccionarios. \\
Langchain tiene sus propios //parsers// que pueden consultarse en su documentación, por ejemplo para extraer información del formato JSON:
from langchain_core.prompts import ChatPromptTemplate
# En primer lugar podríamos hacer que el modelo nos diese directamente una cadena de
# texto //string// en formato JSON y convertirla a través de un parser predefinido para
# este tipo de archivos, en una variable de tipo diccionario
import json
plantilla_instrucciones = """\
De la siguiente receta extrae la siguiente información y no indiques nada más:
nombre: extrae el título de la receta.
ingredientes: extrae los ingredientes de la receta como una lista de python.
pasos: extrae el número de pasos necesarios para cocinar la receta.
comensales: extrae el número de comensales para los que está preparada la receta, si no se especifica, indicar -1.
Formatea la salida como JSON con las siguientes keys, sólo el contenido del JSON:
nombre
ingredientes
pasos
comensales
receta = {receta}
"""
# Suponemos que tenemos la variable receta_111024 del apartado anterior, copiarla para la realización del ejemplo.
# Trabajamos como vimos en el apartado anterior
plantilla_prompt = ChatPromptTemplate.from_template(plantilla_instrucciones)
mensaje = plantilla_prompt.format_messages(receta=receta_111024)
chat = ChatOllama (
model = "llama3.2",
temperature = 0.0
)
respuesta = chat.invoke(mensaje)
datos_json = respuesta.content
try:
dato_dict = json.loads(datos_json)
print(dato_dict)
print(type(dato_dict))
print(dato_dict["ingredientes"])
print(type(dato_dict["ingredientes"]))
except json.JSONDecodeError:
print("ERROR: No es un formato JSON válido")
except Exception as e:
print(f"Error inesperado: {e}")
Puede que en ocasiones necesitemos crear nuestros parsers personalizados, que se harían usando la biblioteca de langchain //output_parsers//
from langchain_core.prompts import ChatPromptTemplate
from langchain.output_parsers import ResponseSchema
from langchain.output_parsers import StructuredOutputParser
# De nuevo, suponemos que tenemos la variable receta_111024 del apartado anterior, copiarla para la realización del ejemplo.
# Definimos la estructura que tendrá el JSON, a patir de la información contenida en el texto de la receta
esquema_nombre = ResponseSchema(name = "nombre",
description = "Nombre de la receta.")
esquema_ingredientes = ResponseSchema(name = "ingredientes",
description = "Ingredientes necesarios para cocinar la receta.")
esquema_pasos = ResponseSchema(name = "pasos",
description = "Número de pasos necearios para cocinar la receta.")
esquema_comensales = ResponseSchema(name = "comensales",
description = "Número de comensales para los que está preparada la receta.\
Si no se especifican, el valor es -1.")
esquema_respuesta = [esquema_nombre,
esquema_ingredientes,
esquema_pasos,
esquema_comensales]
# Una vez tenemos el esquema del JSON definido, creamos el parser de salida
parser_de_salida = StructuredOutputParser.from_response_schemas(esquema_respuesta)
instrucciones_de_formato = parser_de_salida.get_format_instructions()
# Definimos las instrucciones para extraer la información, a partir del esquema que hemos hecho
plantilla_instrucciones = """\
De la siguiente receta extrae la siguiente información:
nombre: extrae el título de la receta.
ingredientes: extrae los ingredientes de la receta como una lista de python.
pasos: extrae el número de pasos necesarios para cocinar la receta.
comensales: extrae el número de comensales para los que está preparada la receta, si no se especifica, indicar -1.
receta = {receta}
{instrucciones_de_formato}
"""
# Creamos como hemos hecho antes, la plantilla del prompt y el mensaje a enviar al modelo
prompt = ChatPromptTemplate.from_template(template=plantilla_instrucciones)
mensaje = prompt.format_messages(receta=receta_111024, instrucciones_de_formato = instrucciones_de_formato)
respuesta = chat.invoke(mensaje)
# Por último pasamos a una variable el parseo de la respuesta obtenida, ya que gracias
# al esquema que hicimos en un principio, puede interpretar de la forma adecuada, que en
# este caso será un diccionario Python, en el que además el elemento "ingredientes" es una lista
diccionario_de_salida = parser_de_salida.parse(respuesta.content)
print(diccionario_de_salida)
print (type(diccionario_de_salida))
print(diccionario_de_salida.get("ingredientes"))
print(type(diccionario_de_salida.get("ingredientes")))