====== Memoria ======
El modo en que se gestiona la memoria en este apartado a través de langchain, está obsoleto //Deprecated//. \\
Se debe de hacer a través de //LangGraph//, pero como esto escapa al objetivo actual (aprender a manejar langchain), se hará de este modo. \\
Si a un modelo le hacemos varias consultas seguidas, al responder cada una, no recuerda qué respondió las anteriores, por lo que es complicado realizar con él una conversación coherente.
from langchain_ollama import ChatOllama
chat = ChatOllama(
model = "llama3.2",
temperature = 0.0,
verbose = False
)
respuesta = chat.invoke("Hola, soy Alberto")
print(respuesta.content)
respuesta = chat.invoke("¿Sabes cómo me llamo?")
print(respuesta.content)
===== Buffer de conversación =====
Cuando instanciamos la clase **ConversationBufferMemory**, en ésta se guarda todo el historial de conversación. \\
Si le pasamos esta información con una plantilla de prompt en cada iteración, le estaremos proporcionando al modelo una memoria a corto plazo a costa de una gran cantidad de tokens.
from langchain_ollama import ChatOllama
from langchain.memory import ConversationBufferMemory
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
chat = ChatOllama(
model = "llama3.2",
temperature = 0.0,
verbose = False
)
# Definimos el prompt con una plantilla, en el prompt especificaremos el historial
# de la conversación (transcripción) que pasaremos en cada nueva llamada
prompt = PromptTemplate(
input_variables=["historial", "input"],
template="{historial}\nUser: {input}\nAssistant:",
)
# Creamos la memoria de la conversación
memoria = ConversationBufferMemory(memory_key="historial", return_messages=True)
# Cadena LLMChain con el modelo, el prompt y la memoria, hay que hacerlo así
chat_chain = LLMChain(
llm = chat,
prompt=prompt,
memory=memoria,
verbose=False
)
# Obtenemos las respuestas del modelo
respuesta = chat_chain.invoke("Hola, soy Alberto")
#print(respuesta)
respuesta = chat_chain.invoke("¿Cuánto es 1+1?")
#print(respuesta)
respuesta = chat_chain.invoke("¿Cómo me llamo?")
#print(respuesta)
# Podemos añadir contexto a la memoria
memoria.save_context(
{"input":"Hola"},
{"output":"Qué pasa"}
)
# Muestro la conversación completa
print(memoria.buffer_as_str)
===== Ventana del Buffer de conversación =====
Podemos seleccionar el número de interacciones (pregunta-respuesta) que queremos que el modelo "recuerde" en el buffer instanciando la clase **ConversationBufferWindowMemory**.
from langchain.memory import ConversationBufferWindowMemory
# Instanciamos la memoria con una ventana de contexto de 2 iteraciones: de las tres que hay, no recordará la primera
memoria = ConversationBufferWindowMemory(k = 2)
# En lugar de preguntar a un modelo, le introducimos las interacciones directamente en memoria
memoria.save_context(
{"input":"Hola"},
{"output":"Cómo lo llevas"}
)
memoria.save_context(
{"input":"Colgando, ligeramente a la izquierda"},
{"output":"Eso está bien"}
)
memoria.save_context(
{"input":"Qué hay de tu vida"},
{"output":"Sobreviviendo, cuando me dejan"}
)
print(memoria.load_memory_variables({}))
===== Ventana de tokens del buffer de conversación =====
Del mismo modo que hicimos anteriormente, podemos limitar la cantidad de información que recuerda el modelo, pero limitando el número de //tokens//. \\
De esta manera se recordarán los últimos tokens en el número definido en la clase **ConversationTokenBufferMemory**
# CUARTO EJEMPLO: Definimos el número máximo de tokens a recordar
# Se necesita instalar el módulo "tiktoken": pip install tiktoken
# Tembién he tenido que instalar el módulo "transformers": pip install transformers
from langchain.memory import ConversationTokenBufferMemory
from langchain_ollama import ChatOllama
chat = ChatOllama(
model = "llama3.2",
temperature = 0.0,
verbose = False
)
# Definimos la memoria, indicando el modelo y el número máximo de tokens a recordar
memoria = ConversationTokenBufferMemory(llm=chat, max_token_limit=25)
memoria.save_context (
{"input":"¿Qué es la IA?"},
{"output":"¡La IA mola!"}
)
memoria.save_context (
{"input":"¿Tiene memoria?"},
{"output":"En eso estamos..."}
)
memoria.save_context (
{"input":"¿Recordarás?"},
{"output":"Si no se me olvida"}
)
print(memoria.load_memory_variables({}))
{{gallery>:inteligencia_artificial}}
===== Resumen de conversación =====
Con el fin de "gastar" menos tokens evitando "arrastrar" toda la conversación de una interacción a otra con el modelo, la clase **ConversationSummaryBufferMemory** nos permite guardar en un buffer un resumen de la conversación, cuyo tamaño en tokens podemos especificar.
from langchain_ollama import ChatOllama
from langchain.memory import ConversationSummaryBufferMemory
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
# Definimos el chat del modelo
chat = ChatOllama(
model = "llama3.2",
temperature = 0.0,
verbose = False # Podemos añadir como parámetro 'num_ctx' para cambiar el nº de tokens de contexto, por defecto 2048. El modelo Llama 3.2 de 3B (3 mil millones de parámetros), tiene una ventana total de 128k.
)
# Texto con el que vamos a trabajar
with open('articulo_eureka_pequeño.txt', 'r') as articulo:
texto = articulo.read()
# Definimos la memoria
memoria = ConversationSummaryBufferMemory(llm=chat, max_token_limit=100) # Si no se especifica max_token_limit, éste es de 2000
# Añadimos contexto a la conversación, incluído el artículo a resumir
memoria.save_context (
{"input":"Hola, cómo estás"},
{"output":"Bien, gracias"}
)
memoria.save_context (
{"input":"Me gustan las cosas del espacio:"},
{"output":"También a mí"}
)
memoria.save_context (
{"input":"Podrías darme el contenido del artículo del blog 'Eureka':"},
{"output":f"{texto}"}
)
#print(memoria.load_memory_variables({}))
#print("---")
# Creamos el prompt sólo con la entrada
prompt = PromptTemplate(
input_variables=["input"],
template="{input}"
)
# Cadena (chain) de conversación
conversacion = LLMChain(
llm = chat,
prompt = prompt,
memory=memoria,
verbose=True
)
respuesta = conversacion.invoke("¿Qué problema producen las megaconstelaciones de satélites?")
print(respuesta)
#print("---")
#print(memoria.load_memory_variables({}))