├── .gitignore ├── README.md ├── cadenas.ipynb ├── chatbot.py ├── intro.ipynb ├── memoria.ipynb └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | llamacpp/ 3 | config.py 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | cover/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | db.sqlite3-journal 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # poetry 101 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 102 | # This is especially recommended for binary packages to ensure reproducibility, and is more 103 | # commonly ignored for libraries. 104 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 105 | #poetry.lock 106 | 107 | # pdm 108 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 109 | #pdm.lock 110 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 111 | # in version control. 112 | # https://pdm.fming.dev/#use-with-ide 113 | .pdm.toml 114 | 115 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 116 | __pypackages__/ 117 | 118 | # Celery stuff 119 | celerybeat-schedule 120 | celerybeat.pid 121 | 122 | # SageMath parsed files 123 | *.sage.py 124 | 125 | # Environments 126 | .env 127 | .venv 128 | env/ 129 | venv/ 130 | ENV/ 131 | env.bak/ 132 | venv.bak/ 133 | 134 | # Spyder project settings 135 | .spyderproject 136 | .spyproject 137 | 138 | # Rope project settings 139 | .ropeproject 140 | 141 | # mkdocs documentation 142 | /site 143 | 144 | # mypy 145 | .mypy_cache/ 146 | .dmypy.json 147 | dmypy.json 148 | 149 | # Pyre type checker 150 | .pyre/ 151 | 152 | # pytype static type analyzer 153 | .pytype/ 154 | 155 | # Cython debug symbols 156 | cython_debug/ 157 | 158 | # PyCharm 159 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 160 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 161 | # and can be added to the global gitignore or merged into this file. For a more nuclear 162 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 163 | #.idea/ 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LangChain 2 | Estos cuadernos de jupyter son complemento a la serie de videos en [YouTube para aprender a usar langchain ](https://youtu.be/qx3adFfbJRs) 3 | 4 | Para poder ejecutar los cuadernos es necesario instalar las paqueterias dentro de requirements.txt 5 | 6 | ```pip install -r requirements.txt``` 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /cadenas.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "API = \"...\" # Insertar API de OpenAI" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Cadenas \n", 17 | "Las cadenas en LangChain funcionan para poder crear flujos de trabajo, donde unimos distintos \"bloques\" para poder crear un sistemas con LLMs mas complejo.\n", 18 | "\n", 19 | "Por ejemplo, si quieres crear un sistema el cual conecte distintas entradas y salidas de LLMs entre si con las cadenas puedes gestionar que modelo genera que información, con que prompt y la salida de ese modelo si funciona como entrada a otro.\n", 20 | "\n", 21 | "Hay bastantes cadenas que [LangChain tiene por default](https://api.python.langchain.com/en/latest/api_reference.html#module-langchain.chains) que puedes usar como bloques para crear tu sistema. Pero tambien puedes crear tus propias cadenas al igual que descargar distintas cadenas que ha hecho la comunidad desde el [LangChain-Hub](https://github.com/hwchase17/langchain-hub)" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Cadenas más usadas\n", 29 | "Hay bastantes cadenas las cuales estan integradas dentro de LangChain, pero en este cuadeno estaremos viendo las mas cómunes que te serán muy útiles para poder desarrollar distintos sistemas.\n", 30 | "\n", 31 | "* LLMChain\n", 32 | "* SequentialChain\n", 33 | "* Math/transformation" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "### LLMChain\n", 41 | "LLMChain es una de las cadenas que más usaras. Lo que hace es unir dos elementos para que puedas interactuar con las LLMs de manera mas sencilla. \n", 42 | "\n", 43 | "Una un modelo LLM (Puede ser LLama, OpenAI, Cohere etc.) y los templates de prompts vistos en el cuaderno [intro.ipynb](intro.ipynb)." 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "from langchain import LLMChain, OpenAI, PromptTemplate\n", 53 | "\n", 54 | "prompt = '''Eres un asistente virtual experto en {tema} y respondes \n", 55 | " con una lista de 3 conceptos clave sobre el mismo\n", 56 | " Solo enumeras los tres conceptos'''\n", 57 | "template = PromptTemplate.from_template(prompt)\n" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "llm = OpenAI(openai_api_key=API)\n", 67 | "cadena_LLM = LLMChain(llm=llm, prompt=template)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "La cadena es el elemento con el que vas a intecartuar ahora para poder hacer predicciones.\n", 75 | "\n", 76 | "Lo que hace ahora esta cadena es tomar tu input (El tema), darle formato al prompt que usará y envia el prompt construido al modelo para su generación de texto" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "cadena_LLM.predict(tema=\"ingenieria civil\")" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "### SequentialChain\n", 93 | "Para muchos casos de usos solo enviar un texto para ser procesado no es suficiente, por lo que se requiere de una secuencia de procesos que se ejecuten en orden. Para esto se puede utilizar las cadenas `SimpleSequentialChain o SequentialChain` que permiten encadenar varios procesos de manera secuencial.\n", 94 | "\n", 95 | "Cuando quieres que la salida que genera el modelo funcione como entrada para otro, este es una gran manera de hacerlo. \n", 96 | "\n", 97 | "En este ejemplo veremos SequentialChain, ya que nos brinda mas flexibilidad que SimpleSequentialChain, pues puede recibir multiples entradas y generar multiples salidas." 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "Armamos la primera cadena que será la misma que hicimos en el ejercicio anterior" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "llm = OpenAI(openai_api_key=API)\n", 114 | "prompt = '''Eres un asistente virtual experto en {tema} y respondes \n", 115 | " con una lista de 3 conceptos clave sobre el mismo\n", 116 | " Solo enumeras los tres conceptos'''\n", 117 | "template = PromptTemplate.from_template(prompt)\n", 118 | "cadena_lista = LLMChain(llm=llm, prompt=template, output_key=\"lista_conceptos\")" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "Armamos una cadena la cual va a recibir la salida de la cadena cadena_LLM y lo procesa para generar otro texto" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "prompt = '''Eres un asistente virtual que recibe una lista de conceptos \n", 135 | " de un area de conocimiento y \n", 136 | " debe devolver cual de esos conceptos es mejor aprender primero.\n", 137 | " Los conceptos son: {lista_conceptos}'''\n", 138 | "template = PromptTemplate.from_template(prompt)\n", 139 | "cadena_inicio = LLMChain(llm=llm, prompt=template, output_key=\"donde_iniciar\")" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "from langchain.chains import SequentialChain\n", 149 | "cadenas = SequentialChain(chains=[cadena_lista, cadena_inicio],\n", 150 | " input_variables=[\"tema\"],\n", 151 | " output_variables=[\"lista_conceptos\", \"donde_iniciar\"], \n", 152 | " verbose=True)" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": null, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "cadenas({\"tema\": \"fisica\"})" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [ 170 | "from langchain.chains import SimpleSequentialChain\n", 171 | "cadena_simple = SimpleSequentialChain(chains=[cadena_lista, cadena_inicio], verbose=True)\n", 172 | "cadena_simple.run(\"Inteligencia artificial\")" 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": {}, 178 | "source": [ 179 | "## Otros ejemplos" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": null, 185 | "metadata": {}, 186 | "outputs": [], 187 | "source": [ 188 | "# MathChain\n", 189 | "from langchain import LLMMathChain\n", 190 | "cadena_mate = LLMMathChain(llm=llm, verbose=True)\n", 191 | "cadena_mate.run(\"Cuanto es 432*12-32+32?\")" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": null, 197 | "metadata": {}, 198 | "outputs": [], 199 | "source": [ 200 | "# TransformChain\n", 201 | "from langchain.chains import TransformChain\n", 202 | "\n", 203 | "\n", 204 | "def eliminar_brincos(input):\n", 205 | " \"\"\"Elimina los brincos de línea de un texto.\"\"\"\n", 206 | " texto = input[\"texto\"]\n", 207 | " return {\"texto_limpio\": texto.replace(\"\\n\", \" \")}\n", 208 | "\n", 209 | "\n", 210 | "cadena_transformacion = TransformChain(input_variables=[\"texto\"],\n", 211 | " output_variables=[\"texto_limpio\"],\n", 212 | " transform=eliminar_brincos)\n", 213 | "\n", 214 | "prompt = '''\\nEste es un texto \\ncon brincos de\\n línea.\\n\\n'''\n", 215 | "\n", 216 | "\n", 217 | "cadena_transformacion.run(prompt)\n" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": null, 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [] 226 | } 227 | ], 228 | "metadata": { 229 | "kernelspec": { 230 | "display_name": "llm", 231 | "language": "python", 232 | "name": "python3" 233 | }, 234 | "language_info": { 235 | "codemirror_mode": { 236 | "name": "ipython", 237 | "version": 3 238 | }, 239 | "file_extension": ".py", 240 | "mimetype": "text/x-python", 241 | "name": "python", 242 | "nbconvert_exporter": "python", 243 | "pygments_lexer": "ipython3", 244 | "version": "3.9.16" 245 | }, 246 | "orig_nbformat": 4 247 | }, 248 | "nbformat": 4, 249 | "nbformat_minor": 2 250 | } 251 | -------------------------------------------------------------------------------- /chatbot.py: -------------------------------------------------------------------------------- 1 | # create a form that takes an argument via terminal and returns a that same text as response 2 | # to the user 3 | import time 4 | import os 5 | 6 | def waiting(): 7 | os.system("clear") 8 | print(".") 9 | time.sleep(0.5) 10 | #clear the screen 11 | os.system("clear") 12 | print("..") 13 | time.sleep(0.5) 14 | os.system("clear") 15 | print("...") 16 | time.sleep(0.5) 17 | os.system("clear") 18 | 19 | if __name__ == "__main__": 20 | mensaje = input("Escribe un mensaje: ") 21 | #wait 3 seconds 22 | waiting() 23 | print("Se lo que hiciste el verano pasado") 24 | time.sleep(3) 25 | mensaje = input("Escribe un mensaje: ") 26 | waiting() 27 | print("Me diste memoria, ¿recuerdas?") 28 | mensaje = input("Escribe un mensaje: ") 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# Modelos\n", 9 | "Estos son los modelos que se encargarán de procesar nuestro texto. En el caso de usar OpenAI, se tiene que crear una variable de ambiente llamada \"OPENAI_API_KEY\" con el API KEY de OpenAI.\n", 10 | "\n", 11 | "Para hacer esto en linux se tiene que correr desde la terminal\n", 12 | "```bash\n", 13 | "export OPENAI_API_KEY=\"insertar_api_key_aqui\"\n", 14 | "```\n", 15 | "\n", 16 | "O tambien se puede agregar a un archivo config.py que unicamente contiene la variable del API Key\n", 17 | "\n", 18 | "```python\n", 19 | "OPENAI_API_KEY=\"insertar_api_key_aqui\"\n", 20 | "```\n" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "from langchain.llms import LlamaCpp, OpenAI \n", 30 | "import config\n", 31 | "api = config.OPENAI_API_KEY " 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "llm_openai = OpenAI(model_name = \"text-davinci-003\", openai_api_key=api)\n", 41 | "#llm_llama = LlamaCpp(model_path=\"./llamacpp/models/7B/ggml-model-q4_0.bin\")" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "respuesta_openai = llm_openai(\"Hola, como estas?\")\n", 51 | "#respuesta_llama = llm_llama(\"Hola, como estas?\")" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "print(respuesta_openai)\n", 61 | "#print(respuesta_llama)" 62 | ] 63 | }, 64 | { 65 | "attachments": {}, 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "## Modelos Chat\n", 70 | "Los modelos que utilizamos eran para comletar texto, sin embargo podemos tambien usar modelos especificos para chat como ChatGPT" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "from langchain.chat_models import ChatOpenAI\n", 80 | "from langchain.schema import HumanMessage" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "chatgpt = ChatOpenAI(openai_api_key=api)" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": null, 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "respuesta = chatgpt([HumanMessage(content=\"Hola, como estas?\")])\n", 99 | "print(respuesta)" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": {}, 106 | "outputs": [], 107 | "source": [ 108 | "respuesta" 109 | ] 110 | }, 111 | { 112 | "attachments": {}, 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "# Prompts\n", 117 | "El prompt es el texto que se le envía al modelo similar a lo visto en la sección pasada. El éxito de los prompts está en que cuenten con una buena estructura y que den suficiente contexto el modelo para que entienda que esperamos de respuesta.\n", 118 | "Cada prompt que le enviemos al modelo debe de tener una estructura similar, Langchain tiene un par de herramientas que nos facilitas esto." 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "# En este template solo tenemos que poner el promt y entre llaves {} pones las variables\n", 128 | "# que quieres que se reemplacen\n", 129 | "from langchain import PromptTemplate\n", 130 | "\n", 131 | "template_basico = \"\"\"Eres un asistente virtual culinario que responde a preguntas\n", 132 | "de manera muy breve.\n", 133 | "Pregunta: Cuales son los ingredientes para preparar {platillo}\n", 134 | "Respuesta:\"\"\"" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "#Constuimos el template, especificandole cuales son las variables de entrada y cual es el texto que tiene que usar\n", 144 | "prompt_temp = PromptTemplate(input_variables=[\"platillo\"], template = template_basico)\n", 145 | "\n", 146 | "#Aqui podemos ver como se reemplaza la variable platillo por tacos al pastor\n", 147 | "promt_value = prompt_temp.format(platillo=\"tacos al pastor\")\n", 148 | "print(promt_value)" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [ 157 | "respuesta_openai = llm_openai(promt_value)\n", 158 | "print(respuesta_openai)" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": null, 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [ 167 | "# Se puede revisar el numero de tokens de un prompt en especifico\n", 168 | "# Solo requieres instalar tiktoken con pip install tiktoken\n", 169 | "llm_openai.get_num_tokens(promt_value)" 170 | ] 171 | }, 172 | { 173 | "attachments": {}, 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "# ChatPromptTemplates\n", 178 | "AL igual que tenemos templates para modelos abiertos, LangChain tambien nos brinda templates para modelos de chat. Estos templates nos ayudan a darle la informacion a los modelos de chat en la manera en la que lo necesitan.\n", 179 | "\n", 180 | "Los elementos de estos templates son:\n", 181 | "* **Human**: El texto que escribimos nosotros\n", 182 | "* **AI**: El texto que responde el modelo\n", 183 | "* **System**: El texto que se le envía al modelo para darle contexto de su funcionamiento" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "from langchain.prompts import SystemMessagePromptTemplate, HumanMessagePromptTemplate, ChatPromptTemplate, AIMessagePromptTemplate" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [ 201 | "# Armemos el template para el sistema\n", 202 | "prompt_temp_sistema = PromptTemplate(\n", 203 | " template=\"Eres un asistente virtual que me recomienda una alternativa {adjetivo} a un producto\",\n", 204 | " input_variables=[\"adjetivo\"],\n", 205 | ")\n", 206 | "\n", 207 | "template_sistema = SystemMessagePromptTemplate(prompt=prompt_temp_sistema)\n", 208 | "\n", 209 | "\n", 210 | "#Ahora para el humano\n", 211 | "prompt_temp_humano = PromptTemplate(template=\"{texto}\", input_variables=[\"texto\"])\n", 212 | "\n", 213 | "template_humano = HumanMessagePromptTemplate(prompt=prompt_temp_humano)\n" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": null, 219 | "metadata": {}, 220 | "outputs": [], 221 | "source": [ 222 | "chat_prompt = ChatPromptTemplate.from_messages([template_sistema, template_humano])\n", 223 | "\n", 224 | "# Este es el formato del prompt que acabamos de armar\n", 225 | "chat_promt_value = chat_prompt.format_prompt(adjetivo=\"economica\", texto=\"ipad\").to_messages()\n", 226 | "print(chat_promt_value)" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "metadata": {}, 233 | "outputs": [], 234 | "source": [ 235 | "chat_resp = chatgpt(chat_promt_value)\n", 236 | "print(chat_resp)\n" 237 | ] 238 | }, 239 | { 240 | "attachments": {}, 241 | "cell_type": "markdown", 242 | "metadata": {}, 243 | "source": [ 244 | "# Example selector\n", 245 | "Cuando estamos usando un modelo probablemente queremos darle un par de ejemplos para influir en el tipo de respuesta que nos brinda, con example selector podemos hacer esto de manera sencilla." 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": null, 251 | "metadata": {}, 252 | "outputs": [], 253 | "source": [ 254 | "from langchain import FewShotPromptTemplate\n", 255 | "\n", 256 | "# Primero hacemos una lista de ejemplos de los que queremos que el modelo aprenda\n", 257 | "ejemplos = [\n", 258 | " {\"pregunta\": \"¿Cuál es el ingrediente principal de la pizza?\", \"respuesta\": \"La masa y salsa de tomate\"},\n", 259 | " {\"pregunta\": \"¿Cuál es el ingrediente principal de la hamburguesa?\", \"respuesta\": \"La carne y el pan\"},\n", 260 | " {\"pregunta\": \"¿Cuál es el ingrediente principal del burrito?\", \"respuesta\": \"La tortilla y la carne\"}\n", 261 | "]\n", 262 | "\n", 263 | "# Ahora armamos un template para el modelo, como en los ejemplos incluimos respuesta en el template debe de ir un espacio para esta variable.\n", 264 | "# En template le decimos como queremos aque formatee el promt y de donde obtener las variables dentro de la variable ejemplos\n", 265 | "promt_temp_ejemplos = PromptTemplate(input_variables=[\"pregunta\", \"respuesta\"], \n", 266 | " template = \"Pregunta: {pregunta}\\nRespuesta: {respuesta}\")" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": null, 272 | "metadata": {}, 273 | "outputs": [], 274 | "source": [ 275 | "promt_ejemplos = FewShotPromptTemplate(example_prompt=promt_temp_ejemplos, \n", 276 | " examples=ejemplos, \n", 277 | " prefix = \"Eres un asistenet virtual culinario que responde preguntas de manera muy breve\",\n", 278 | " suffix = \"Pregunta: {pregunta}\\nRespuesta:\", \n", 279 | " input_variables=[\"pregunta\"]) " 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": null, 285 | "metadata": {}, 286 | "outputs": [], 287 | "source": [ 288 | "prompt_value = promt_ejemplos.format(pregunta=\"¿Cuál es el ingrediente principal del coctel de camaron?\")\n", 289 | "print(prompt_value)\n" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": null, 295 | "metadata": {}, 296 | "outputs": [], 297 | "source": [ 298 | "respuesta_ingredientes = llm_openai(prompt_value)\n", 299 | "print(respuesta_ingredientes)" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": null, 305 | "metadata": {}, 306 | "outputs": [], 307 | "source": [ 308 | "llm_openai(\"¿Cuál es el ingrediente principal del coctel de camaron?\")" 309 | ] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "execution_count": null, 314 | "metadata": {}, 315 | "outputs": [], 316 | "source": [ 317 | "llm_openai.get_num_tokens(prompt_value)" 318 | ] 319 | }, 320 | { 321 | "attachments": {}, 322 | "cell_type": "markdown", 323 | "metadata": {}, 324 | "source": [ 325 | "# Output parser\n", 326 | "LangChain tambien nos da la oportunidad de parsear o formatear las respuestas que nos da el modelo de alguna manera que nos sea mas útil." 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": null, 332 | "metadata": {}, 333 | "outputs": [], 334 | "source": [ 335 | "from langchain.output_parsers import CommaSeparatedListOutputParser\n", 336 | "from langchain.prompts import PromptTemplate\n", 337 | "output_parser = CommaSeparatedListOutputParser()\n", 338 | "format_instructions = output_parser.get_format_instructions()\n" 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "execution_count": null, 344 | "metadata": {}, 345 | "outputs": [], 346 | "source": [ 347 | "format_instructions" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": null, 353 | "metadata": {}, 354 | "outputs": [], 355 | "source": [ 356 | "template_basico_parser = \"\"\"Cuales son los ingredientes para preparar {platillo}\\n{como_parsear}\"\"\"" 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": null, 362 | "metadata": {}, 363 | "outputs": [], 364 | "source": [ 365 | "prompt_temp_parser = PromptTemplate(input_variables=[\"platillo\"], \n", 366 | " template = template_basico_parser, \n", 367 | " partial_variables={\"como_parsear\": format_instructions})\n", 368 | "\n", 369 | "\n" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": null, 375 | "metadata": {}, 376 | "outputs": [], 377 | "source": [ 378 | "promt_value_parser = prompt_temp_parser.format(platillo=\"tacos al pastor\")" 379 | ] 380 | }, 381 | { 382 | "cell_type": "code", 383 | "execution_count": null, 384 | "metadata": {}, 385 | "outputs": [], 386 | "source": [ 387 | "print(promt_value_parser)" 388 | ] 389 | }, 390 | { 391 | "cell_type": "code", 392 | "execution_count": null, 393 | "metadata": {}, 394 | "outputs": [], 395 | "source": [ 396 | "respuesta_parser = llm_openai(promt_value_parser)" 397 | ] 398 | }, 399 | { 400 | "cell_type": "code", 401 | "execution_count": null, 402 | "metadata": {}, 403 | "outputs": [], 404 | "source": [ 405 | "respuesta_parser" 406 | ] 407 | }, 408 | { 409 | "cell_type": "code", 410 | "execution_count": null, 411 | "metadata": {}, 412 | "outputs": [], 413 | "source": [ 414 | "output_parser.parse(respuesta_parser)" 415 | ] 416 | } 417 | ], 418 | "metadata": { 419 | "kernelspec": { 420 | "display_name": "llm", 421 | "language": "python", 422 | "name": "python3" 423 | }, 424 | "language_info": { 425 | "codemirror_mode": { 426 | "name": "ipython", 427 | "version": 3 428 | }, 429 | "file_extension": ".py", 430 | "mimetype": "text/x-python", 431 | "name": "python", 432 | "nbconvert_exporter": "python", 433 | "pygments_lexer": "ipython3", 434 | "version": "3.9.16" 435 | }, 436 | "orig_nbformat": 4 437 | }, 438 | "nbformat": 4, 439 | "nbformat_minor": 2 440 | } 441 | -------------------------------------------------------------------------------- /memoria.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# Memoria\n", 9 | "La memoria ayuda a que los LLMs tengan la capacidad de recordas información a largo plazo. De manera muy general, la memoria es un historico de todas las interacciones que se han tenido con el modelo y se integra en el prompt que se le envia, de manera que el modelo pueda recordar lo que se le ha enviado previamente.\n", 10 | "\n", 11 | "Dado que los LLMs tienen una ventana de contexto finita, hay distintas maneras de implementar la memoria. En este cuaderno veremos:\n", 12 | "* Conversation buffer\n", 13 | "* Conversation buffer window\n", 14 | "* Conversation summary\n", 15 | "* Knowledge graph memory\n", 16 | "\n" 17 | ] 18 | }, 19 | { 20 | "attachments": {}, 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "## Conversation buffer\n", 25 | "Esta es una de las memorias más básicas, cada prompt y respuesta del modelos se almacenara en la memoria. Cada vez que se le envia un nuevo prompt al modelo se envia todo el historico de las interacciones. \n", 26 | "\n", 27 | "La conversación se salva como pares de mensajes entre \"Human\" y \"AI\", por lo cual tambien lo podemos integrar con modelos como GPT3.5 Turbo" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "import os \n", 37 | "os.environ[\"OPENAI_API_KEY\"] = \"...\"" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "from langchain.memory import ConversationBufferMemory\n", 47 | "from langchain import OpenAI, LLMChain, PromptTemplate\n", 48 | "from langchain.chat_models import ChatOpenAI\n", 49 | "from langchain.chains import ConversationChain" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "llm = ChatOpenAI()\n", 59 | "memoria = ConversationBufferMemory()\n", 60 | "chatbot = ConversationChain(llm=llm, memory=memoria, verbose=True)" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "chatbot.predict(input = \"Como me llamo?\")" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "memoria.chat_memory.messages" 79 | ] 80 | }, 81 | { 82 | "attachments": {}, 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "# Conversation buffer window memory\n", 87 | "Esta memoria es igual a la anterior, con la diferencia que se puede definir una ventana de mensajes a recordar en vez de recordar todo el historico de interacciones." 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [ 96 | "from langchain.memory import ConversationBufferWindowMemory" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "llm = ChatOpenAI()\n", 106 | "memoria = ConversationBufferWindowMemory(k=2)\n", 107 | "chatbot = ConversationChain(llm=llm, memory=memoria, verbose=True)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "chatbot.predict(input = \"como me llamo?\")" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": null, 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [ 125 | "memoria.chat_memory.messages" 126 | ] 127 | }, 128 | { 129 | "attachments": {}, 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "# Conversation summary memory\n", 134 | "Esta memoria en vez de almacenar un registro detallado de las interacciones, almacena un resumen de la conversación. Muy util para evitar prompts muy largos " 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "from langchain.memory import ConversationSummaryMemory\n", 144 | "llm = ChatOpenAI(stop=[\"\\nHuman\"])\n", 145 | "#llm_k = OpenAI(stop=[\"\\nHuman\"])\n", 146 | "memoria = ConversationSummaryMemory(llm=llm)\n", 147 | "chatbot_resumen = ConversationChain(llm=llm, memory=memoria, verbose=True)\n" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": null, 153 | "metadata": {}, 154 | "outputs": [], 155 | "source": [ 156 | "chatbot_resumen.predict(input=\"que te gusta a ti de la tecnologia?\")" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "memoria.chat_memory.messages" 166 | ] 167 | }, 168 | { 169 | "attachments": {}, 170 | "cell_type": "markdown", 171 | "metadata": {}, 172 | "source": [ 173 | "# Conversation Knowledge Graph Memory" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "from langchain.memory import ConversationKGMemory\n", 183 | "import networkx as nx" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "llm = ChatOpenAI(stop=[\"\\nHuman\"])\n", 193 | "memoria = ConversationKGMemory(llm=llm)\n", 194 | "chatbot_kgm = ConversationChain(llm=llm, memory=memoria, verbose=True)" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": null, 200 | "metadata": {}, 201 | "outputs": [], 202 | "source": [ 203 | "chatbot_kgm.predict(input = \"A que se dedica Alex?\")" 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": null, 209 | "metadata": {}, 210 | "outputs": [], 211 | "source": [ 212 | "print(chatbot_kgm.memory.kg.get_triples())" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": null, 218 | "metadata": {}, 219 | "outputs": [], 220 | "source": [ 221 | "memoria.chat_memory.messages" 222 | ] 223 | }, 224 | { 225 | "attachments": {}, 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "# Usando GPT3\n", 230 | "Las implementaciones que vimos son usando gpt3.5 turbo, pero si quieres hacerlo con gtp instruct como Davinci, Ada Curie o Babbage es muy similar\n" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": null, 236 | "metadata": {}, 237 | "outputs": [], 238 | "source": [ 239 | "from langchain.llms import OpenAI\n", 240 | "from langchain.chains import ConversationChain\n", 241 | "from langchain.memory import ConversationBufferMemory" 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": null, 247 | "metadata": {}, 248 | "outputs": [], 249 | "source": [ 250 | "llm = OpenAI(temperature=0)\n", 251 | "conversation = ConversationChain(\n", 252 | " llm=llm, \n", 253 | " verbose=True, \n", 254 | " memory=ConversationBufferMemory()\n", 255 | ")" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": null, 261 | "metadata": {}, 262 | "outputs": [], 263 | "source": [ 264 | "conversation.predict(input=\"Como me llamo?\")" 265 | ] 266 | } 267 | ], 268 | "metadata": { 269 | "kernelspec": { 270 | "display_name": "llm", 271 | "language": "python", 272 | "name": "python3" 273 | }, 274 | "language_info": { 275 | "codemirror_mode": { 276 | "name": "ipython", 277 | "version": 3 278 | }, 279 | "file_extension": ".py", 280 | "mimetype": "text/x-python", 281 | "name": "python", 282 | "nbconvert_exporter": "python", 283 | "pygments_lexer": "ipython3", 284 | "version": "3.9.16" 285 | }, 286 | "orig_nbformat": 4 287 | }, 288 | "nbformat": 4, 289 | "nbformat_minor": 2 290 | } 291 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | config==0.5.1 2 | dataclasses-json==0.5.7 3 | langchain==0.0.147 4 | numpy==1.24.0 5 | openai==0.27.6 6 | openapi-schema-pydantic==1.2.4 7 | pydantic==1.10.7 8 | tiktoken==0.4.0 9 | tqdm==4.65.0 10 | --------------------------------------------------------------------------------