Introducción a LangChain

1

Desarrollo de aplicaciones con LLM utilizando LangChain

2

Estructura y módulos de LangChain

3

Uso de modelos Open Source de Hugging Face

4

Uso de modelos de OpenAI API

5

Prompt templates de LangChain

6

Cadenas en LangChain

7

Utility chains

8

RetrievalQA chain

9

Foundational chains

Quiz: Introducción a LangChain

Casos de uso de LangChain

10

Casos de uso de LangChain

11

¿Cómo utilizar LangChain en mi equipo?

Quiz: Casos de uso de LangChain

Manejo de documentos con índices

12

¿Cómo manejar documentos con índices en LangChain?

13

La clase Document

14

Document Loaders: PDF

15

Document Loaders: CSV con Pandas DataFrames

16

Document Loaders: JSONL

17

Document Transformers: TextSplitters

18

Proyecto de Chatbot: configuración de entorno para LangChain y obtención de datos

19

Proyecto de Chatbot: creación de documents de Hugging Face

Quiz: Manejo de documentos con índices

Embeddings y bases de datos vectoriales

20

Uso de embeddings y bases de datos vectoriales con LangChain

21

¿Cómo usar embeddings de OpenAI en LangChain?

22

¿Cómo usar embeddings de Hugging Face en LangChaing?

23

Chroma vector store en LangChain

24

Proyecto de Chatbot: ingesta de documents en Chroma

25

RetrievalQA: cadena para preguntar

26

Proyecto de Chatbot: cadena de conversación

27

Proyecto de Chatbot: RetrievalQA chain

Quiz: Embeddings y bases de datos vectoriales

Chats y memoria con LangChain

28

¿Para qué sirve la memoria en cadenas y chats?

29

Uso de modelos de chat con LangChain

30

Chat prompt templates

31

ConversationBufferMemory

32

ConversationBufferWindowMemory

33

ConversationSummaryMemory

34

ConversationSummaryBufferMemory

35

Entity memory

36

Proyecto de Chatbot: chat history con ConversationalRetrievalChain

Quiz: Chats y memoria con LangChain

Evolución del uso de LLM

37

LangChain y LLM en evolución constante

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso de LangChain

Curso de LangChain

Omar Espejel

Omar Espejel

Foundational chains

9/37
Recursos

Aportes 7

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Hola Este es mi aporte

Agregué solo la parte de la nueva cadena que resume y la definición de la cadena sequencial


## Plantilla para la cadena de resumen
## Decidí incluirle de nuevo el estilo para que mantenga la forma de hablar para generar el resumen

plantilla_resumen = """Resumir texto:

{texto_final}

En el estilo de una persona informal de {estilo}

resumen:
"""

# Definición del template con sus variables de entrada {texto_final} que viene de la cadena anterior de parafraseo
prompt_resumen = PromptTemplate(
    template= plantilla_resumen,
    input_variables= ["texto_final","estilo"]
)

## Instancia de la cadena que resumne
cadena_que_resume = LLMChain(
    llm=llm_gpt3_5,
    prompt=prompt_resumen,
    output_key='texto_resumido'
)

from langchain.chains import SequentialChain

# Cadena secuencial agregando la cadena que resume
cadena_secuencial = SequentialChain(
    chains=[cadena_que_limpia, cadena_que_cambia_estilo,cadena_que_resume],
    input_variables=["texto", "estilo"],
    output_variables=["texto_resumido"]
)

Me dió mucha pereza escribir el texto, así que le pedí al gpt-35-turbo que lo creara por mi especificando que quería urls y emojis para probar que funcionara la cadena de transformación:

Me costó un poco porque a este punto creí que debía usar una cadena de transformación, pero realmente requerimos usar un LLMChain con un nuevo template.

Antes de todo, cambié el output de la chain de estilo a “to_sum_text” y creé el template y el PromptTemplate.

summary_template = """Resume este texto lo más posible:

{to_sum_text}

Resumiendo: 
"""

prompt_summary = PromptTemplate(
    input_variables=["to_sum_text"],
    template=summary_template
)

luego creé la LLMChain con este nuevo prompt

summarize_chain = LLMChain(
    llm = llm_gpt_3_5,
    prompt=prompt_summary,
    output_key="final_text"
)

Y lo añadí a la cadena secuencial.

sequential_chain = SequentialChain(
    chains=[cleaning_chain, style_changer_chain, summarize_chain],
    input_variables =  ["text", "style"],
    output_variables = ["final_text"],
)

Al final redujo todo el entry a esto:

'final_text': 'Monterrey es una ciudad increíble, famosa por sus montañas imponentes, su cultura norteña y su Museo de Arte Contemporáneo. También es conocida por los partidos de fútbol de los Rayados y los Tigres. ¡Monterrey te espera con los brazos abiertos!'

Notemos que el prompt final se deshizo de los espacios extraños que había generado el cleaner, por lo que indirectamente aplicó otra capa de limpieza.

Cumpliendo el reto

Invertí el orden, primero limpia, luego resume y finalmente cambia el estilo.

cadena_que_limpia = TransformChain(
	input_variables=["texto"],
	output_variables=["texto_limpio"],
	transform=fn_limpiar_texto
)

############################################
# Cadena que resume
summarize_prompt = """Resumir el siente texto:
{texto_limpio}
Resumen:"""

summarize_chain = LLMChain(
	llm=llm_gpt3_5,
	prompt=PromptTemplate(
      input_variables=["texto_limpio"],
      template=summarize_prompt
      ),
	output_key="summary"
)

############################################
# Cadena que cambia de estilo
from langchain.chains import LLMChain
from langchain import PromptTemplate

plantilla = """Parafrasea este texto:
{summary}
En el estilo de una persona informal de {estilo}.
Parafraseado: """

prompt = PromptTemplate(
	input_variables=["summary","estilo"],
	template=plantilla
)

cadena_que_cambia_estilo = LLMChain(
	llm = llm_gpt3_5,
	prompt=prompt,
	output_key="texto_final"
)

# Cadena secuencial
from langchain.chains import SequentialChain

cadena_secuencial = SequentialChain(
	chains = [cadena_que_limpia, summarize_chain, cadena_que_cambia_estilo],
	input_variables=["texto", "estilo"],
	output_variables=["texto_final"]
)

El texto de entrada:

texto_entrada = """
Osaka es una ciudad vibrante y llena de vida en Japón 🏯🌸. Con su combinación 
única de tradición y modernidad, Osaka cautiva a sus visitantes. Puedes explorar 
el imponente castillo de Osaka, un verdadero símbolo histórico de la región 🏰🌳. 
Además, la deliciosa comida callejera en el distrito de Dotonbori te dejará con el 
estómago lleno y una sonrisa en el rostro 😋🍣.

La gente en Osaka es conocida por su amabilidad y hospitalidad, lo que hace que los 
viajeros se sientan bienvenidos desde el momento en que llegan ✨👋. Si eres un 
amante de las compras, la avenida Midosuji es el lugar perfecto para satisfacer tus 
deseos de compras y moda 👗🛍️.

Para obtener más información sobre los lugares para visitar en Osaka, puedes 
consultar el sitio web oficial de turismo: https://www.osaka-info.jp/en/ 🌐📲. 
¡No puedes perderte la oportunidad de experimentar la energía única y la cultura 
emocionante de Osaka!
"""

cadena_secuencial(
	{'texto': texto_entrada,
	 'estilo': 'Chile'}
)

El resultado:

 'texto_final': 'Osaka es una ciudad bacán y llena de vida en Japón, que mezcla la onda tradicional con la modernidad. Su castillo gigante y la comida rica en la calle en el barrio de Dotonbori son un must. La buena onda de la gente y la avenida Midosuji para ir de shopping son bien destacables. No te podís perder la oportunidad de vivir la energía y cultura emocionante de Osaka.'}

Dejo por aquí el patrón de emojis por si alguien no lo quiere transcribir o tomar del notebook.

emoji_pattern = re.compile(
      "["
      "\U0001F600-\U0001F64F" #emotes
      "\U0001F300-\U0001F5FF" #symbols and pictograms
      "\U0001F680-\U0001F6FF" #transport and map symbols
      "\U0001F1E0-\U0001F1FF" #flags (on iOS)
      "\U00002702-\U000027B0"
      "\U000024C2-\U0001F251"
      "]+", flags=re.UNICODE
  )

➡️ Secuencias (Secuencies)

ℹ️ Summary

Esta guía proporciona un caso de uso sobre Cadenas Secuenciales (Sequential Chain), sobre documentos combinados en cadenas, en un almacenamiento vectorial local.
.

🗂️ Background

Una LLMChain es una cadena simple que añade alguna funcionalidad alrededor de los modelos de lenguaje. La cual consiste en un PromptTemplate y un modelo de lenguaje (ya sea un LLM o un modelo de chat). Formatea el prompt template usando los valores de las claves de entrada proporcionadas (y también los valores de las claves de memoria, si están disponibles), pasa la cadena formateada al LLM y devuelve la salida del LLM.
.
Una secuencia es un tipo de Cadena Funcional (Functional Chain), que permiten conectar varias cadenas y componerlas en pipelines que ejecutan algún escenario específico. Existen dos tipos de cadenas secuenciales:
.

  • SimpleSequentialChain: La forma más simple de cadenas secuenciales, donde cada paso tiene una entrada/salida singular, y la salida de un paso es la entrada del siguiente.
  • SequentialChain: Una forma más general de cadenas secuenciales, que permite múltiples entradas/salidas.

.
En conjunto, permiten un túnel personalizado según los requerimientos de la aplicación.
.
Enlaces auxiliares:

.

🎯 Problem

Implementar una “Functional Chain” en LangChain utilizando TypeScript para implementar un flujo de tareas, por ejemplo, procesar y analizar datos textuales para proveer un formato preferido.
.

🚧 Solution

Una SimpleSequentialChain es una cadena que permite unir varias cadenas de una entrada y una salida en una sola cadena.

import { SimpleSequentialChain } from 'langchain/chains'

Dicha cadena, servirá para orquestar a los eslabones de cada proceso en conjunto. Por ejemplo, para obtener una entrada de QA y después darle formato según sea el requerimiento:

const actionitemsChain = new SimpleSequentialChain({
	chains: [retrievalQAChain, actionItemsFormatChain],
})

En ella, obtenemos una cadena que es provista de un almacenamiento vectorial.

const embeddings = new OpenAIEmbeddings({
	openAIApiKey: API_TOKEN,
})

const vectorStore = await HNSWLib.fromDocuments(docs, embeddings)
const retrievalQAChain = RetrievalQAChain.fromLLM(
	llm,
	vectorStore.asRetriever({ k: 1 })
)

Así mismo, se combina mediante una cadena para proveer de un formato. Dicho formato, puede ser soportada por Zod, una herramienta para gestionar estructura de datos bajo un determinando tipo.
.
Por lo que empleamos una prompt personalizado en combinación de LLMChain.

const prompt = new PromptTemplate({
	inputVariables: ['list'],
	template: `
	Given a numerical list with action items to be carried out by the team.
	Improve the content of each action item.
		
	{list}`,
})

const outParser = OutputFixingParser.fromLLM(
	llm,
	StructuredOutputParser.fromZodSchema(
		z.array(
			z.string()
				.describe('Action item to be carried out by the team'),
		).describe('Action items to be carried out by the team'),
	),
)


const actionItemsFormatChain = new LLMChain({
	llm,
	prompt,
	outputKey: 'records',
	outputParser: outParser,
})

🍻 Discussion

Las secuencias son personalizables en LangChain. Donde el caso de uso, permitirán generar “Functional Chains” para permitirnos generar un flujo completo de procesamiento.
Cada eslabón, en una secuencia se tiene que pensar en un filtro permisivo para poder refinar nuestra salida de información.

import { z } from 'zod'
import { LLMChain, RetrievalQAChain, SimpleSequentialChain } from 'langchain/chains'
import { HNSWLib } from 'langchain/vectorstores/hnswlib'
import { OpenAIEmbeddings } from 'langchain/embeddings/openai'
import { OpenAI } from 'langchain/llms/openai'
import { StructuredOutputParser, OutputFixingParser } from 'langchain/output_parsers'
import { PromptTemplate } from 'langchain/prompts'
import { TextLoader } from 'langchain/document_loaders/fs/text'

const API_TOKEN = // 👈 Enter the API Token from OpenAI

const loader = new TextLoader('tmp/conversation.txt')
const docs = await loader.load()

const llm = new OpenAI({
	maxTokens: -1,
	modelName: 'gpt-4',
	temperature: 0,
	openAIApiKey: API_TOKEN,
})

const embeddings = new OpenAIEmbeddings({
	openAIApiKey: API_TOKEN,
})
const vectorStore = await HNSWLib.fromDocuments(docs, embeddings)

const retrievalQAChain = RetrievalQAChain.fromLLM(
	llm,
	vectorStore.asRetriever({ k: 1 }),
)

const actionItemsFormatChain = new LLMChain({
	llm,
	prompt: new PromptTemplate({
	inputVariables: ['list'],
	template: `
		Given a numerical list with action items to be carried out by the team.
		Improve the content of each action item.
		
		{list}`,
	}),
	outputKey: 'records',
	outputParser: OutputFixingParser.fromLLM(
		llm,
		StructuredOutputParser.fromZodSchema(
			z.array(
				z.string()
					.describe('Action item to be carried out by the team'),
			).describe('Action items to be carried out by the team'),
		),
	),
})

const actionitemsChain = new SimpleSequentialChain({
	chains: [retrievalQAChain, actionItemsFormatChain],
})

const response = await actionitemsChain.run(
'Given a conversation between employees, obtain the action items to be carried out by the team.',
)

console.log(response)

En esta clase veremos como funcionan las cadenas Foundatinoal y como podemos unir varias de ellas para llevar procesos
más complejos a través de cadenas secuenciales SequentialChain.

Primero, vamos a construir una función personalizada para limpiar nuestros textos de URLs y emojis. Luego, utilizaremos esta función para crear una cadena en la que introduciremos nuestro texto y esperamos obtener un texto limpio como salida.

Debemos tener en cuenta que la función que hemos creado recibe como entrada un diccionario. En este diccionario, vamos a indicar los elementos que serán procesados por la cadena que estamos creando. El resultado que obtendremos de la cadena será el texto limpio.

Esto es el principio fundamental de las cadenas fundacionales, nos proporcionan un marco para llevar a cabo una serie de transformaciones de manera ordenada y estructurada.

Partimos de los antecedentes que ya conocemos:

# Antecedentes 1: Cargar el API KEY de OpenAI como una variable de sistema.
import os
from dotenv import load_dotenv

load_dotenv("../secret/keys.env")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
os.environ['OPENAI_API_KEY'] = OPENAI_API_KEY

# Antecedentes 2: Instanciar dos LLMs de OpenAI un GPT3.5 y un Davinci
from langchain.llms import OpenAI

llm_gpt3_5 = OpenAI(
    model_name="gpt-3.5-turbo",
    n=1,
    temperature=0.3
)

Vamos a empezar creando una función de limpieza de datos. La misma es una función que recibe un diccionario con una llave texto
que contiene el texto a limpiar y devuelve otro diccionario con la llave texto_limpio, el texto ya normalizado.

def limpiar_texto(entradas: dict) -> dict:
    texto = entradas["texto"]

    # Eliminamos los emojis utilizando un amplio rango unicode
    # Ten en cuenta que esto podría potencialmente eliminar algunos caracteres válidos que no son en inglés
    patron_emoji = re.compile(
        "["
        "\U0001F600-\U0001F64F"  # emoticonos
        "\U0001F300-\U0001F5FF"  # símbolos y pictogramas
        "\U0001F680-\U0001F6FF"  # símbolos de transporte y mapas
        "\U0001F1E0-\U0001F1FF"  # banderas (iOS)
        "\U00002702-\U000027B0"
        "\U000024C2-\U0001F251"
        "]+", flags=re.UNICODE,
    )
    texto = patron_emoji.sub(r'', texto)

    # Removemos las URLs
    patron_url = re.compile(r'https?://\S+|www\.\S+')
    texto = patron_url.sub(r'', texto)

    return {"texto_limpio": texto}

Con base en esta función de python podemos crear nuestro primer bloque de Cadena utilizando TransformChain:

from langchain.chains import TransformChain

cadena_que_limpia = TransformChain(
    input_variables=["texto"],
    output_variables=["texto_limpio"],
    transform=limpiar_texto
)

clean = cadena_que_limpia.run('Chequen está página https://twitter.com/home 🙈')
print(clean)

Respuesta esperada:

Chequen está página  

Ahora vamos a crear un par de cadenas más y finalmente las vamos a unir todas para un flujo de información completa.
Empecemos con una cadena de parafraseo de texto:

from langchain import PromptTemplate
from langchain.chains import LLMChain

# Empezamos creando nuestro prompt template que recibe como parámetro un 'texto_limpio' (salida de de la cadena de limpieza)
# y lo parafrasea con un estilo informa de una persona (estilo).
plantilla_parafrasea = """Parafrasea este texto:

{texto_limpio}

En el estilo de una persona informal de {estilo}.

Parafraseado: """

# Dado que nuestro Template tiene 2 variables, debemos indicarlas en el parámetro `input_variables
prompt_parafraseo = PromptTemplate(
    input_variables=["texto_limpio", "estilo"],
    template=plantilla_parafrasea 
)

# Ahora solo falta crear la cadena que cambia estilo utilizando como LLM a GPT3.5, esta cadena terminará creando una variable
# a la salida llamada `texto_final`
cadena_que_cambia_estilo = LLMChain(
    llm=llm_gpt3_5,
    prompt=prompt_parafraseo,
    output_key='texto_final'
)

Ahora siguiendo la misma estructura lógica, vamos a crear una nueva Chain que se encargue de parafrasear un texto de entrada:

# Texto_final es la variable de entrada, puesto que así la definimos en la cadena de parafraseo
plantilla_resumen = """Resume este texto:

{texto_final}

Resumen: """

prompt_resumen = PromptTemplate(
    input_variables=["texto_final"],
    template=plantilla_resumen
)

# Texto resumido será la variable final con la que termina nuestra secuencia de cadenas
cadena_que_resume = LLMChain(
    llm=llm_gpt3_5,
    prompt=prompt_resumen,
    output_key="texto_resumido"
)

Finalmente, para concluir vamos a unir todas nuestras cadenas entre ellas utilizando SequentialChain:

from langchain.chains import SequentialChain

cadena_secuencial = SequentialChain(
    chains=[cadena_que_limpia, cadena_que_cambia_estilo, cadena_que_resume],
    input_variables=["texto", "estilo"],
    output_variables=["texto_resumido"]
)

Nota:
Esta estructura de pensamiento es MUY similar a como PyTorch Organiza las capas de un modelo de DL.

Probemos entonces nuestra SequentialChain:

texto_entrada = """
¡Monterrey es una ciudad impresionante! 🏙️
Es conocida por su impresionante paisaje de montañas ⛰️ y su vibrante cultura norteña.
¡No olvides visitar el famoso Museo de Arte Contemporáneo (MARCO)!
🖼️ Si eres fanático del fútbol, no puedes perderte un partido de los Rayados o de los Tigres. ⚽
Aquí te dejo algunos enlaces para que puedas conocer más sobre esta maravillosa ciudad:
https://visitamonterrey.com, https://museomarco.org, https://rayados.com, https://www.tigres.com.mx.
¡Monterrey te espera con los brazos abiertos! 😃🇲🇽

Monterrey es la capital y ciudad más poblada del estado mexicano de Nuevo León, además de la cabecera del 
municipio del mismo nombre. Se encuentra en las faldas de la Sierra Madre Oriental en la región noreste de 
México. La ciudad cuenta según datos del XIV Censo de Población y Vivienda del Instituto Nacional de 
Estadística y Geografía de México (INEGI) en 2020 con una población de 3 142 952 habitantes, por lo cual 
de manera individual es la 9.ª ciudad más poblada de México, mientras que la zona metropolitana de Monterrey 
cuenta con una población de 5 341 175 habitantes, la cual la convierte en la 2.ª área metropolitana más 
poblada de México, solo detrás de la Ciudad de México.8​

La ciudad fue fundada el 20 de septiembre de 1596 por Diego de Montemayor y nombrada así en honor al castillo 
de Monterrey en España. Considerada hoy en día una ciudad global, es el segundo centro de negocios y finanzas 
del país, así como una de sus ciudades más desarrolladas, cosmopolitas y competitivas. Sirve como el 
epicentro industrial, comercial y económico para el Norte de México.9​ Según un estudio de Mercer Human 
Resource Consulting, en 2019, fue la ciudad con mejor calidad de vida en México y la 113.ª en el mundo.10​ 
La ciudad de Monterrey alberga en su zona metropolitana la ciudad de San Pedro Garza García, la cual es el 
área con más riqueza en México y América Latina.11​
"""

ans = cadena_secuencial({'texto': texto_entrada, 'estilo': 'ciudad de méxico'})
print(ans)

Respuesta esperada:

{'texto': 

'\n¡Monterrey es una ciudad impresionante! 🏙️\nEs conocida por su impresionante paisaje de montañas ⛰️ y su vibrante 
cultura norteña.\n¡No olvides visitar el famoso Museo de Arte Contemporáneo (MARCO)!\n🖼️ Si eres fanático del fútbol, no 
puedes perderte un partido de los Rayados o de los Tigres. ⚽\nAquí te dejo algunos enlaces para que puedas conocer más 
sobre esta maravillosa ciudad:\nhttps://visitamonterrey.com, https://museomarco.org, https://rayados.com, https://www.tigres.com.mx.
¡Monterrey te espera con los brazos abiertos! 😃🇲🇽\n\nMonterrey es la capital y ciudad más poblada del estado mexicano de 
Nuevo León, además de la cabecera del \nmunicipio del mismo nombre. Se encuentra en las faldas de la Sierra Madre Oriental en 
la región noreste de \nMéxico. La ciudad cuenta según datos del XIV Censo de Población y Vivienda del Instituto Nacional de 
\nEstadística y Geografía de México (INEGI) en 2020 con una población de 3 142 952 habitantes, por lo cual \nde manera 
individual es la 9.ª ciudad más poblada de México, mientras que la zona metropolitana de Monterrey \ncuenta con una población 
de 5 341 175 habitantes, la cual la convierte en la 2.ª área metropolitana más \npoblada de México, solo detrás de la Ciudad 
de México.8\u200b\n\nLa ciudad fue fundada el 20 de septiembre de 1596 por Diego de Montemayor y nombrada así en honor al 
castillo \nde Monterrey en España. Considerada hoy en día una ciudad global, es el segundo centro de negocios y finanzas 
\ndel país, así como una de sus ciudades más desarrolladas, cosmopolitas y competitivas. Sirve como el \nepicentro industrial, 
comercial y económico para el Norte de México.9\u200b Según un estudio de Mercer Human \nResource Consulting, en 2019, fue 
la ciudad con mejor calidad de vida en México y la 113.ª en el mundo.10\u200b \nLa ciudad de Monterrey alberga en su zona 
metropolitana la ciudad de San Pedro Garza García, la cual es el \nárea con más riqueza en México y América Latina.11\u200b\n', 

'estilo': 
'ciudad de méxico', 

'texto_resumido': '
Monterrey es una ciudad increíblemente hermosa y llena de vida, famosa por sus montañas y su cultura norteña. Es conocida 
por su Museo de Arte Contemporáneo y por los equipos de fútbol Rayados y Tigres. Es la capital y la ciudad más grande del 
estado de Nuevo León, con una población de más de 3 millones de habitantes. Es considerada una ciudad global y un importante 
centro de negocios y finanzas en México. También es una de las ciudades más desarrolladas y con mejor calidad de vida en 
el país. En resumen, Monterrey es una ciudad impresionante y llena de oportunidades.'}

Excelente, hemos podido aprender como unir varias cadenas entre ellas para crear un flujo de información efectivo a través
de SequentialChains

También dejo el input final.

entry = """
¡Monterrey es una ciudad impresionante!🏙️
Es conocida por su impresionante paisaje de montañas⛰️ y su vibrante cultura norteña.
¡No olvides visitar el famoso Museo de Arte Contemporáneo (MARCO)!
🖼️Si eres fanático del fútbol, no puedes perderte un partido de los Rayados o de los Tigres⚽
Aquí te dejo algunos enlaces para que puedas conocer más sobre esta maravillosa ciudad:
https://visitamonterrey.com, https://museomarco.org, https://rayados.com, https://www.tigres.com.mx.
¡Monterrey te espera con los brazos abiertos! 😃🇲🇽
"""