{"id":16352,"date":"2024-09-23T14:08:57","date_gmt":"2024-09-23T21:08:57","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=16352"},"modified":"2025-06-13T16:36:40","modified_gmt":"2025-06-13T23:36:40","slug":"ai-powered-recommendation-engine-llm-rag","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/ai-powered-recommendation-engine-llm-rag\/","title":{"rendered":"Del concepto al c\u00f3digo: LLM + RAG con Couchbase"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Las tecnolog\u00edas GenAI son sin duda un elemento de tendencia en 2023 y 2024, y como trabajo para\u00a0 <\/span><a href=\"https:\/\/tikalk.com\/\"><span style=\"font-weight: 400;\">Tikal<\/span><\/a><span style=\"font-weight: 400;\">que publica su propio informe anual <\/span><a href=\"https:\/\/tikalk.com\/radar\/\"><span style=\"font-weight: 400;\">radar tecnol\u00f3gico y tendencias<\/span><\/a><span style=\"font-weight: 400;\"> report, LLM y genAI no escaparon a mi atenci\u00f3n. Como desarrollador, a menudo consulto chatbots de IA generativa para que me ayuden a resolver todo tipo de errores de TypeScript y misteriosos problemas de linting, utilizo herramientas de asistencia de genAI en mi IDE y para mejorar mis PR. Esta tecnolog\u00eda puede cambiarnos la vida.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Como t\u00e9cnicos y, en definitiva, como desarrolladores de software, esta nueva tendencia nos brinda la oportunidad de integrar estas capacidades en todos los proyectos en los que trabajamos, y veo que mis amigos y colegas exploran estas opciones, lo que me llev\u00f3 a tomar la decisi\u00f3n: \u00a1yo tambi\u00e9n deber\u00eda hacerlo!<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Y ten\u00eda justo el proyecto:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">A menudo me pregunto c\u00f3mo pueden los artistas aficionados explorar el amplio mundo de los eventos culturales locales y mundiales para llegar a conseguir esa deseada invitaci\u00f3n para actuar. No tenemos los recursos, las conexiones y el conocimiento de todo lo disponible. Claro que hay motores de b\u00fasqueda y sitios web especializados, pero hay que saber qu\u00e9 y c\u00f3mo buscar, as\u00ed que decid\u00ed utilizar genAI para obtener recomendaciones.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Paso 1 - \u00bfSe puede hacer?<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Comprobar la viabilidad de un motor de recomendaci\u00f3n utilizando uno de los LLM, inclu\u00eda abrir cuentas en varios servicios de chat genAI y hacerles la misma pregunta:<\/span><\/p>\n<p><i><span style=\"font-weight: 400;\">Somos una <\/span><\/i><b><i>aficionado<\/i><\/b> <b><i>Danza folcl\u00f3rica israel\u00ed<\/i><\/b><i><span style=\"font-weight: 400;\"> grupo, incluidos bailarines en <\/span><\/i><b><i>sillas de ruedas<\/i><\/b><i><span style=\"font-weight: 400;\">. Buscamos <\/span><\/i><b><i>cultural <\/i><\/b><i><span style=\"font-weight: 400;\">y<\/span><\/i><b><i> folclore<\/i><\/b> <b><i>eventos<\/i><\/b><i><span style=\"font-weight: 400;\"> y <\/span><\/i><b><i>festivales<\/i><\/b><i><span style=\"font-weight: 400;\"> en <\/span><\/i><b><i>Europa<\/i><\/b><i><span style=\"font-weight: 400;\"> la posibilidad de que nos inviten a actuar, siempre y cuando <\/span><\/i><b><i>cubrir nuestros gastos<\/i><\/b><i><span style=\"font-weight: 400;\">. \u00bfPodr\u00eda recomendarme algunos?<\/span><\/i><\/p>\n<p><span style=\"font-weight: 400;\">Los resultados en H1 de 2024 variaron entre los distintos servicios de chat:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Me remitieron a sitios web especializados que pod\u00eda consultar para obtener resultados<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Me dio resultados reales<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">De entre los que devolvieron resultados, califiqu\u00e9 la calidad de los resultados por su relevancia y precisi\u00f3n, y acab\u00e9 con <\/span><b>OpenAI<\/b><span style=\"font-weight: 400;\"> GPT-<\/span><b>3<\/b><span style=\"font-weight: 400;\"> como opci\u00f3n.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Paso 2 - \u00bfEs suficiente?<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Recordando que incluso uno de los asistentes de chat del paso 1 me sugiri\u00f3 que consultara otros sitios web, \u00bfqu\u00e9 pasar\u00eda si pudiera incluir algunos de esos datos en los resultados?<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Teniendo en cuenta que tambi\u00e9n dependo de qui\u00e9n y cu\u00e1ndo se entren\u00f3 el modelo, quer\u00eda que mis recomendaciones se basaran en m\u00e1s fuentes de datos y sab\u00eda que se pod\u00eda hacer con RAG. En primer lugar, \u00bfqu\u00e9 es RAG?<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Generaci\u00f3n de Recuperaci\u00f3n Aumentada (RAG)<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">RAG es el proceso de enriquecer y optimizar los resultados que recibe de LLM a\u00f1adiendo datos \"externos\". Si puedo a\u00f1adir resultados basados en la misma b\u00fasqueda en fuentes de datos externas (de sitios web dedicados) puedo ampliar la variedad de los resultados que proporcionar\u00e1 mi aplicaci\u00f3n.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Para ello necesitar\u00e1s:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Fuentes de datos externas - Para mi experimento cre\u00e9 una cuenta de prueba para <\/span><a href=\"https:\/\/www.predicthq.com\/events\/upcoming-events\"><span style=\"font-weight: 400;\">API de eventos de predictHQ<\/span><\/a><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Almacenar mis datos externos es un motor que permite la b\u00fasqueda por similitud y no una coincidencia exacta<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4><span style=\"font-weight: 400;\">Accesibilidad de los datos para el GAR<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Una vez que haya terminado de examinar los datos, su aspecto y las caracter\u00edsticas que contienen, es hora de que seleccione las caracter\u00edsticas de los datos que le gustar\u00eda utilizar y hacerlas utilizables para el GAR.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Para permitir una b\u00fasqueda de similitudes, tendr\u00edamos que transformar nuestros datos en un formato que permita realizar b\u00fasquedas y <\/span><b>comparable.<\/b><span style=\"font-weight: 400;\"> Dado que no buscamos coincidencias exactas, sino coincidencias similares, existen dos t\u00e9cnicas muy comunes para ello:<\/span><\/p>\n<table style=\"border: 1px solid black;\">\n<tbody>\n<tr>\n<td><b>T\u00e9cnica RAG<\/b><\/td>\n<td><b>Detalles<\/b><\/td>\n<\/tr>\n<tr>\n<td>B\u00fasqueda vectorial (tambi\u00e9n conocida como RAG com\u00fan)<\/td>\n<td>Los datos y la pregunta se transforman en <b>vectores<\/b> de n\u00fameros (puntos flotantes).<\/p>\n<p>Se utilizan c\u00e1lculos matem\u00e1ticos para determinar la similitud entre la pregunta y los datos.<\/td>\n<\/tr>\n<tr>\n<td>GraphRAG<\/td>\n<td>Los datos y la pregunta se transforman en <b>gr\u00e1fico<\/b> v\u00e9rtices y aristas.<\/p>\n<p>Las relaciones gr\u00e1ficas se comparan por similitud<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400;\">El proceso de creaci\u00f3n de la representaci\u00f3n de los datos se denomina <\/span><b>incrustaci\u00f3n<\/b><span style=\"font-weight: 400;\">En este art\u00edculo nos centraremos en la b\u00fasqueda vectorial.<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">M\u00e9trica de similitud<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Hay 3 opciones comunes (en pocas palabras):<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Producto de puntos: C\u00e1lculo de la similitud a partir del producto de los valores de cada vector.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Coseno: Basado en el \u00e1ngulo entre los vectores<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">L2_norm: Distancia euclidiana entre los vectores, basada en el \u00e1ngulo entre los vectores y la longitud de cada vector.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">M\u00e1s informaci\u00f3n <a href=\"https:\/\/www.couchbase.com\/blog\/es\/vector-similarity-search\/\">opciones de similitud vectorial<\/a>.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Paso 3 - \u00bfC\u00f3mo lo hago?<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Antes de sumergirnos en c\u00f3mo vamos a hacer esto y en algo de c\u00f3digo real y capturas de pantalla, veamos c\u00f3mo se construir\u00eda tal arquitectura, y c\u00f3mo Couchbase entra en escena:<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-16356 aligncenter\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image4-1.jpg\" alt=\"\" width=\"673\" height=\"682\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image4-1.jpg 673w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image4-1-296x300.jpg 296w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image4-1-65x65.jpg 65w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image4-1-50x50.jpg 50w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image4-1-300x304.jpg 300w\" sizes=\"auto, (max-width: 673px) 100vw, 673px\" \/><br style=\"font-weight: 400;\" \/><br style=\"font-weight: 400;\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Lo que esto significa en la pr\u00e1ctica es:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Ingesti\u00f3n app to:<\/span>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Obtener datos de la API externa<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Crear incrustaciones vectoriales<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Cargar datos en una colecci\u00f3n Couchbase<\/span><\/li>\n<\/ol>\n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Crear un \u00edndice de b\u00fasqueda vectorial en Couchbase<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Solicitud inmediata a:<\/span>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Pedir resultados a los datos de Couchbase<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">A\u00f1adir los resultados de la b\u00fasqueda vectorial a la consulta LLM como contexto<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Devolver los resultados cohesionados a los usuarios<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3><span style=\"font-weight: 400;\">Aplicaci\u00f3n por ingesti\u00f3n<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Este proceso fue probablemente el m\u00e1s largo, pas\u00e9 tiempo creando incrustaciones en distintos campos y formatos. Por simplicidad, al final opt\u00e9 por utilizar \u00fanicamente la informaci\u00f3n geogr\u00e1fica que hab\u00eda recopilado:<\/span><\/p>\n<pre class=\"nums:false lang:python decode:true\">from langchain_openai import OpenAIEmbeddings\r\nembeddings_model = OpenAIEmbeddings(model=\"text-embedding-3-small\")\r\ntext = f\"Geo Info: {row['geo_info']}\"\r\n\r\nembedding = embeddings_model.embed_query(text)<\/pre>\n<p><span style=\"font-weight: 400;\">Para crear la incrustaci\u00f3n eleg\u00ed utilizar incrustaciones textuales como punto de partida, es decir, \"comparar\" representaci\u00f3n de texto con representaci\u00f3n de texto. La incrustaci\u00f3n en s\u00ed incluye aproximadamente 1500 n\u00fameros (que es el peque\u00f1o).<\/span><\/p>\n<p><span style=\"font-weight: 400;\">El c\u00f3digo en s\u00ed no es extremadamente complejo, sin embargo puede llevar mucho tiempo, crear 1 incrustaci\u00f3n para 5000 eventos me llev\u00f3 aproximadamente 1 hora en mi MacBook pro M1 de 16 GB.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">El c\u00f3digo completo utilizando pandas2 puede encontrarse en <\/span><a href=\"https:\/\/github.com\/sshahar1\/TikalMeetup2024Ingestion\"><span style=\"font-weight: 400;\">este<\/span><\/a><span style=\"font-weight: 400;\"> repositorio.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Colecci\u00f3n Couchbase e \u00edndice de b\u00fasqueda<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Para poder buscar datos similares entre la pregunta y los resultados que hemos preparado bas\u00e1ndonos en una API externa, vamos a...<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Crear una colecci\u00f3n Couchbase<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Sube los datos preparados a una colecci\u00f3n de Couchbase <\/span><b>incluidas las incrustaciones<\/b><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Crear un \u00edndice de b\u00fasqueda en los campos de incrustaci\u00f3n eligiendo el algoritmo de similitud vectorial para comparar vectores.<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<h4><span style=\"font-weight: 400;\">Nueva colecci\u00f3n Couchbase<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Para mi aplicaci\u00f3n eleg\u00ed utilizar el servicio alojado Couchbase - Capella, la configuraci\u00f3n es muy f\u00e1cil. Me registr\u00e9, eleg\u00ed el servicio Cloud y cre\u00e9 un nuevo proyecto.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-16354\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image2-4-1024x118.png\" alt=\"\" width=\"900\" height=\"104\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image2-4-1024x118.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image2-4-300x35.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image2-4-768x89.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image2-4-1536x177.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image2-4-1320x153.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image2-4.png 1999w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Al hacer clic en mi proyecto y navegar hasta la pesta\u00f1a Herramientas de datos, ahora puedo crear una nueva colecci\u00f3n para los datos que he preparado:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-16353\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image1-4-893x1024.png\" alt=\"\" width=\"893\" height=\"1024\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image1-4-893x1024.png 893w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image1-4-262x300.png 262w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image1-4-768x880.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image1-4-300x344.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image1-4.png 1284w\" sizes=\"auto, (max-width: 893px) 100vw, 893px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Para subir los datos que prepar\u00e9 hay varias opciones: como el tama\u00f1o del archivo era bastante grande opt\u00e9 por utilizar la opci\u00f3n <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/tools\/cbimport.html\"><span style=\"font-weight: 400;\">cbimport<\/span><\/a><span style=\"font-weight: 400;\"> utilidad de hacerlo.<\/span><\/p>\n<pre class=\"nums:false wrap:true lang:default decode:true\">.\/cbimport json --cluster couchbases:\/\/&lt;yourcluster&gt; --username &lt;your user&gt; --password &lt;your password&gt; --bucket &lt;bucket&gt; --scope-collection-exp \"&lt;scope&gt;.&lt;collection&gt;\" --dataset for_collection.json --generate-key '%id%' --cacert &lt;path to couchbase certificate&gt; --format lines<\/pre>\n<p><span style=\"font-weight: 400;\">Observe que he elegido el <em>ID<\/em> de los documentos JSON para que sea el documento <em>clave<\/em> en la colecci\u00f3n.<\/span><\/p>\n<p><b>Recuerde<\/b><span style=\"font-weight: 400;\"> que antes de hacerlo, es necesario:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Cree un usuario\/contrase\u00f1a de acceso a la base de datos con privilegios de escritura como m\u00ednimo<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Abrir el cluster para llamadas desde su host<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Descargar un certificado para el cl\u00faster<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">El esquema del documento inferido muestra que el <\/span><b>incrustaci\u00f3n<\/b><span style=\"font-weight: 400;\"> con el tipo de matriz de n\u00fameros:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-16355\" style=\"border: 1px solid black;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image3-2.png\" alt=\"\" width=\"648\" height=\"296\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image3-2.png 648w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image3-2-300x137.png 300w\" sizes=\"auto, (max-width: 648px) 100vw, 648px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Para permitir la b\u00fasqueda por similitud vectorial, creemos el \u00edndice de b\u00fasqueda accediendo a la pesta\u00f1a B\u00fasqueda.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Obviamente debemos seleccionar el campo de incrustaci\u00f3n para el \u00edndice de b\u00fasqueda, pero observe que hay m\u00e1s par\u00e1metros que configurar:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-16357\" style=\"border: 1px solid black;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image5-1-1024x311.png\" alt=\"\" width=\"900\" height=\"273\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image5-1-1024x311.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image5-1-300x91.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image5-1-768x233.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image5-1-1536x467.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image5-1-1320x401.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image5-1.png 1842w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Ya hemos discutido lo que la m\u00e9trica de similitud es, s\u00f3lo tenga en cuenta que Couchbase apoyo l2_norm (es decir, la distancia euclidiana) y el producto punto, eleg\u00ed \"<\/span><b>producto punto\"<\/b><span style=\"font-weight: 400;\">que puede ser m\u00e1s beneficioso para mi sistema de recomendaci\u00f3n.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">El siguiente paso consiste en elegir campos adicionales de los documentos que se devolver\u00edan siempre que se aten\u00fae un vector similar a la pregunta:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-16358\" style=\"border: 1px solid black;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image6-1-1024x372.png\" alt=\"\" width=\"900\" height=\"327\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image6-1-1024x372.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image6-1-300x109.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image6-1-768x279.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image6-1-1536x558.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image6-1-1320x479.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image6-1.png 1999w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Si no a\u00f1ade al menos un campo, su aplicaci\u00f3n fallar\u00e1 porque no habr\u00e1 ning\u00fan dato devuelto.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Ah\u00ed est\u00e1, la selecci\u00f3n de campos \u00edndice:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-16359\" style=\"border: 1px solid black;\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image7-1-1024x517.png\" alt=\"\" width=\"900\" height=\"454\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image7-1-1024x517.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image7-1-300x152.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image7-1-768x388.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image7-1-1536x776.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image7-1-1320x667.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image7-1.png 1999w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Hemos llegado a un punto crucial en nuestro proyecto, ahora podemos empezar a ejecutar la b\u00fasqueda de similitud en los datos que hemos preparado, pero puede que no tengas una b\u00fasqueda de similitud que funcione en tu primer intento. Le dar\u00e9 algunos consejos para obtener resultados de su b\u00fasqueda de similitud o para comprobar por qu\u00e9 no obtiene resultados:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Aseg\u00farese de que su t\u00e9cnica de incrustaci\u00f3n, al crear los datos y preparar una b\u00fasqueda son id\u00e9nticos<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Comience con un formato sencillo y predecible para la informaci\u00f3n que desea comparar. Por ejemplo , , .<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Aseg\u00farese de que no tiene informaci\u00f3n adicional que se a\u00f1ade accidentalmente a los datos que est\u00e1 creando incrustaciones para (por ejemplo, tuve saltos de l\u00ednea)<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Aseg\u00farese de que la b\u00fasqueda de coincidencia exacta funciona:<\/span>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">B\u00fasqueda de los datos exactos para los que cre\u00f3 incrustaciones<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Compare el vector de incrustaci\u00f3n para asegurarse de que se crean incrustaciones id\u00e9nticas en la parte de generaci\u00f3n y b\u00fasqueda (la depuraci\u00f3n ser\u00e1 \u00fatil aqu\u00ed). Si hay alguna diferencia, vuelva a los pasos 1-3.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Una vez que tenga una b\u00fasqueda por similitud que funcione, a\u00f1ada gradualmente m\u00e1s campos, cambie formatos, incrustaciones y cualquier otra cosa que considere que falta.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Recuerde que cualquier cambio en las incrustaciones significa:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Recrear las incrustaciones<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Carga de los datos de los cambios en una colecci\u00f3n truncada<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Cambiar el \u00edndice de b\u00fasqueda si es necesario<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Es necesario cambiar el c\u00f3digo<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">Estos pasos pueden llevar mucho tiempo, especialmente la creaci\u00f3n de incrustaciones, por lo que es posible que desee comenzar con:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Una peque\u00f1a parte de sus documentos<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Una t\u00e9cnica de incrustaci\u00f3n peque\u00f1a\/r\u00e1pida<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3><span style=\"font-weight: 400;\">LLM y solicitud de RAG<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Lo que nuestra aplicaci\u00f3n necesita hacer es:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Pedir a Couchbase que encuentre resultados similares a la pregunta del usuario<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">A\u00f1ade los resultados al contexto de la pregunta al LLM<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Haz una pregunta al LLM<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">Para simplificar he creado este c\u00f3digo en Python como un cuaderno Jupyter que se puede encontrar en este <\/span><a href=\"https:\/\/github.com\/sshahar1\/TikalMeetup2024\"><span style=\"font-weight: 400;\">repositorio<\/span><\/a><span style=\"font-weight: 400;\">. Para ello he utilizado las siguientes bibliotecas:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><a href=\"https:\/\/pypi.org\/project\/couchbase\/\"><span style=\"font-weight: 400;\">Couchbase<\/span><\/a><span style=\"font-weight: 400;\">: Conectar y autenticar a mi cl\u00faster Capella<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><a href=\"https:\/\/www.langchain.com\/langchain\"><span style=\"font-weight: 400;\">Cadena LangChain<\/span><\/a><span style=\"font-weight: 400;\">un marco para el desarrollo de aplicaciones basadas en grandes modelos ling\u00fc\u00edsticos (LLM), para:<\/span>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Incrustaciones<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">Uso de Couchbase como almac\u00e9n de vectores<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">\"Chateando\" con OpenAI<\/span><\/li>\n<\/ol>\n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><a href=\"https:\/\/www.langchain.com\/langgraph\"><span style=\"font-weight: 400;\">LangGraph<\/span><\/a><span style=\"font-weight: 400;\">: Un marco para la construcci\u00f3n de aplicaciones LLM con estado y multiactores, para la creaci\u00f3n de un flujo de la aplicaci\u00f3n LLM.<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">Si has estado leyendo sobre, e incluso intentando construir tu propia aplicaci\u00f3n LLM probablemente est\u00e9s algo familiarizado con LangChain, es un conjunto de librer\u00edas que te permiten escribir, construir, desplegar y monitorizar una aplicaci\u00f3n, tiene muchos agentes y extensiones que te permiten integrar diferentes partes en tu c\u00f3digo, como una API de terceros, una base de datos, una b\u00fasqueda web y muchas m\u00e1s.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00daltimamente, tambi\u00e9n aprend\u00ed sobre LangGraph del hogar de LangChain, que te permite como desarrollador construir topolog\u00edas m\u00e1s complejas de la aplicaci\u00f3n LLM con condiciones, bucles (\u00a1el grafo no tiene que ser un DAG!), interacci\u00f3n del usuario, y quiz\u00e1s la caracter\u00edstica m\u00e1s buscada: Mantener el estado.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Antes de ver el c\u00f3digo echemos un vistazo al archivo de entorno (.env) para ver qu\u00e9 credenciales y otros datos confidenciales necesitamos:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">LANGSMITH_KEY=langsmithkey\r\nOPENAI_API_KEY=openaikey\r\nLANGCHAIN_PROJECT=myproject\r\nCOUCHBASE_CONNECTION_STRING=couchbase:\/\/mycluster.com\r\nCOUCHBASE_USER=myuser\r\nCOUCHBASE_PASS=mypass\r\nCOUCHBASE_BUCKET=mybucket\r\nCOUCHBASE_SCOPE=myscope\r\nCOUCHBASE_COLLECTION=mycollection\r\nCOUCHBASE_SEARCH_INDEX=mysearchindex\r\nLANGCHAIN_API_KEY=langchainapikey<\/pre>\n<p><span style=\"font-weight: 400;\">El estado de cada nodo del grafo es:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">from langgraph.graph import add_messages, StateGraph\r\nfrom typing_extensions import TypedDict\r\nfrom typing import Annotated\r\nfrom langgraph.checkpoint.sqlite import SqliteSaver\r\n\r\nclass State(TypedDict):\r\n\u00a0 # Messages have the type \"list\". The `add_messages` function\r\n\u00a0 # in the annotation defines how this state key should be updated\r\n\u00a0 # (in this case, it appends messages to the list, rather than overwriting them)\r\n\u00a0 messages: Annotated[list, add_messages]\r\n\u00a0 event_type: str\r\n\u00a0 location: str\r\n\u00a0 labels: str\r\n\u00a0 \r\ngraph_builder = StateGraph(State)<\/pre>\n<p><span style=\"font-weight: 400;\">Es importante tener en cuenta que a menos que se defina un reductor el estado se sobrescribir\u00e1 entre cada nodo del gr\u00e1fico, el miembro messages de la clase state tiene un reductor que a\u00f1adir\u00e1 los nuevos mensajes a la lista.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Para conectarnos a Couchbase y usarlo como almac\u00e9n de vectores para la aplicaci\u00f3n LLM, nos autenticamos en el cluster, y pasamos la conexi\u00f3n del cluster al objeto LangChain para el almac\u00e9n de vectores:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">from langchain_openai import OpenAIEmbeddings\r\nimport os\r\nfrom couchbase.cluster import Cluster\r\nfrom couchbase.options import ClusterOptions\r\nfrom couchbase.auth import PasswordAuthenticator\r\nfrom langchain_couchbase import CouchbaseVectorStore\r\n\r\nCOUCHBASE_CONNECTION_STRING = os.environ[\"COUCHBASE_CONNECTION_STRING\"]\r\nCOUCH_USER = os.environ[\"COUCHBASE_USER\"]\r\nCOUCH_PASS = os.environ[\"COUCHBASE_PASS\"]\r\nBUCKET_NAME = os.environ[\"COUCHBASE_BUCKET\"]\r\nSCOPE_NAME = os.environ[\"COUCHBASE_SCOPE\"]\r\nCOLLECTION_NAME = os.environ[\"COUCHBASE_COLLECTION\"]\r\nSEARCH_INDEX_NAME = os.environ[\"COUCHBASE_SEARCH_INDEX\"]\r\n\r\nauth = PasswordAuthenticator(COUCH_USER, COUCH_PASS)\r\noptions = ClusterOptions(auth)\r\ncluster = Cluster(COUCHBASE_CONNECTION_STRING, options)\r\nembedding = OpenAIEmbeddings(model=\"text-embedding-3-small\")\r\n\r\nvector_store = CouchbaseVectorStore(\r\n\u00a0 cluster=cluster,\r\n\u00a0 bucket_name=BUCKET_NAME,\r\n\u00a0 scope_name=SCOPE_NAME,\r\n\u00a0 collection_name=COLLECTION_NAME,\r\n\u00a0 embedding=embedding,\r\n\u00a0 index_name=SEARCH_INDEX_NAME,\r\n)<\/pre>\n<p><span style=\"font-weight: 400;\">Hay dos detalles importantes a tener en cuenta:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">La integraci\u00f3n en la aplicaci\u00f3n <\/span><b>debe<\/b><span style=\"font-weight: 400;\"> ser id\u00e9ntico al utilizado en la parte de ingesti\u00f3n<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">El nombre por defecto del campo de incrustaci\u00f3n es 'incrustaci\u00f3n', si el nombre del campo respectivo es diferente en su \u00edndice de b\u00fasqueda necesita establecerlo durante la instanciaci\u00f3n de CouchbaseVectorStore (embedding_key)<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">En este momento, est\u00e1s listo para escribir tu aplicaci\u00f3n LangGraph y usar Couchbase como almac\u00e9n de vectores. Vamos a montarlo: cada grafo necesita nodos, punto de inicio y aristas dirigidas.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Nuestro gr\u00e1fico obtendr\u00e1 datos del almac\u00e9n de vectores y continuar\u00e1 a\u00f1adiendo esta informaci\u00f3n al contexto de la solicitud LLM.<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">from langchain_core.prompts import ChatPromptTemplate\r\nfrom langchain_core.output_parsers import StrOutputParser\r\nfrom langchain_openai import ChatOpenAI\r\n\r\nllm = ChatOpenAI(model=\"gpt-3.5-turbo\")\r\ntemplate = \"\"\"You are a helpful bot that serves the purpose of finding events for artists looking for venues in the USA. If you cannot answer based on the context provided, respond with a generic\r\n\u00a0 answer. Answer the question as truthfully as possible using the context below: {context}\r\nPlease also format the result in Markdown format.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Question: {question}\"\"\"\r\n\r\nprompt = ChatPromptTemplate.from_template(template)\r\n\r\ngeneration_chain = prompt | llm | StrOutputParser()\r\n\r\n\r\ndef chatbot(state: State):\r\n\u00a0 response = generation_chain.invoke({\"context\": state['messages'], \"question\": f\"We are a {state['event_type']} amateur group looking for {state['labels']} festivals in {state['location']}, can you please recommend some for us to reach out to?\"})\r\n\u00a0 state['messages'].append(response)\r\n\u00a0 return state\r\n\r\ndef search_couchbase(state: State):\r\n\u00a0 query = f\"Geo Info: {state['location']}\"\r\n\u00a0 \r\n\u00a0 retriever = vector_store.as_retriever()\r\n\u00a0 results = retriever.invoke(query)\r\n\u00a0 for result in results:\r\n\u00a0 \u00a0 \u00a0 text = f\"Title: {result.metadata['title']}\/{result.metadata['alternate_titles_flat']} - {result.metadata['description']} from {result.metadata['start']} to {result.metadata['end']}, location {result.metadata['geo_info']}. Labels {result.metadata['labels_flat']}, category {result.metadata['category']}\"\r\n\u00a0 \u00a0 \u00a0 state['messages'].append(text)\r\n\u00a0 return state\r\n\r\ngraph_builder.add_node(\"vector_search\", search_couchbase)\r\ngraph_builder.add_node(\"chatbot\", chatbot)\r\ngraph_builder.set_entry_point(\"vector_search\")\r\ngraph_builder.add_edge(\"vector_search\", \"chatbot\")\r\ngraph_builder.set_finish_point(\"chatbot\")\r\n\r\nmemory = SqliteSaver.from_conn_string(\":memory:\")\r\ngraph = graph_builder.compile(checkpointer=memory)<\/pre>\n<p><span style=\"font-weight: 400;\">Se traduce en el c\u00f3digo anterior a dos nodos:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">vector_search (punto de entrada)<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">chatbot (punto final)<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">Como una imagen vale m\u00e1s que mil palabras, he utilizado el siguiente c\u00f3digo para visualizar el gr\u00e1fico:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">from IPython.display import Image, display\r\nfrom langchain_core.runnables.graph import CurveStyle, MermaidDrawMethod, NodeStyles\r\n\r\ndisplay(\r\n\u00a0 Image(\r\n\u00a0 \u00a0 \u00a0 graph.get_graph().draw_mermaid_png(\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 draw_method=MermaidDrawMethod.API,\r\n\u00a0 \u00a0 \u00a0 )\r\n\u00a0 )\r\n)<\/pre>\n<p><span style=\"font-weight: 400;\">Lo que dio lugar al siguiente dibujo:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16360 size-medium\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image8-186x300.png\" alt=\"\" width=\"186\" height=\"300\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image8-186x300.png 186w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image8-300x483.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/image8.png 370w\" sizes=\"auto, (max-width: 186px) 100vw, 186px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Para m\u00e1s opciones de visualizaci\u00f3n en langGraph, v\u00e9ase <\/span><a href=\"https:\/\/github.com\/langchain-ai\/langgraph\/blob\/main\/examples\/visualization.ipynb\"><span style=\"font-weight: 400;\">este<\/span><\/a><span style=\"font-weight: 400;\"> Cuaderno Jupyter de LangGraph.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Preguntar al almac\u00e9n vectorial significa buscar datos con una ubicaci\u00f3n similar, puede observar que el formato de la consulta es el mismo que en el texto incrustado, los resultados se a\u00f1aden al estado para ser utilizados en el siguiente nodo.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">El nodo del chatbot toma la informaci\u00f3n de los mensajes y la incrusta en la pregunta dirigida al LLM.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Tenga en cuenta que el estado se guarda en la base de datos en memoria sqlite. Para utilizar el gr\u00e1fico no dude en utilizar el siguiente ejemplo:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">from random import randint\r\nfrom IPython.core.display import Markdown\r\n\r\nsession_id = randint(1, 10000)\r\nconfig = {\"configurable\": {\"thread_id\": session_id}}\r\n\r\ninput_location = \"kansas\"\r\ninput_category = \"jaz\"\r\ninput_labels = \"grange\"\r\n\r\n# Stream the graph, each output will be printed when ready\r\nfor event in graph.stream({\"event_type\": input_category, \"location\": input_location, \"labels\": input_labels}, config):\r\n\u00a0 for value in event.values():\r\n\u00a0 \u00a0 \u00a0 if len(value['messages']) &gt; 0:\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 display(Markdown(value['messages'][-1]))<\/pre>\n<p><span style=\"font-weight: 400;\">Y ya est\u00e1, has creado una aplicaci\u00f3n LLM para recomendar eventos culturales a grupos de aficionados a los que pedir invitaciones.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Resumen<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Comenzar con las aplicaciones LLM es emocionante y, en mi humilde opini\u00f3n, como una rampa divertida, emocionante y factible debido a su pronta naturaleza, sin embargo, hacer que nuestra aplicaci\u00f3n sea mejor y m\u00e1s robusta esconde m\u00e1s desaf\u00edos.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">En este art\u00edculo, me centr\u00e9 en el reto de aprovechar el conocimiento de nuestro modo con datos externos a trav\u00e9s de la t\u00e9cnica o RAG y c\u00f3mo se puede aprovechar Couchbase para hacerlo.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Es importante recordar que la creaci\u00f3n de incrustaciones que la aplicaci\u00f3n LLM encontrar\u00e1 en la b\u00fasqueda vectorial, puede no funcionar en su primer intento. Compruebe el formato, intente empezar con incrustaciones sencillas y utilice la depuraci\u00f3n en la medida de lo posible.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Tambi\u00e9n demostr\u00e9 las capacidades de LangGraph de LangChain que permite crear decisiones y flujos complejos en la aplicaci\u00f3n LLM.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Disfruta de tu viaje con las solicitudes de LLM.<\/span><\/p>\n<p><br style=\"font-weight: 400;\" \/><br style=\"font-weight: 400;\" \/><\/p>","protected":false},"excerpt":{"rendered":"<p>GenAI technologies are definitely a trending item in 2023 and 2024, and because I work for\u00a0 Tikal, which publishes its own annual technology radar and trends report, LLM and genAI did not escape my attention. As a developer myself, I [&hellip;]<\/p>","protected":false},"author":85526,"featured_media":16398,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[10122,1815,2225,9973,9139,9937],"tags":[9963,9870],"ppma_author":[10032],"class_list":["post-16352","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-artificial-intelligence-ai","category-best-practices-and-tutorials","category-cloud","category-generative-ai-genai","category-python","category-vector-search","tag-langchain","tag-llms"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>From Concept to Code: LLM + RAG with Couchbase<\/title>\n<meta name=\"description\" content=\"Learn how to build a generative AI recommendation engine using LLM, RAG, and Couchbase integration. Step-by-step guide for developers.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/ai-powered-recommendation-engine-llm-rag\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"From Concept to Code: LLM + RAG with Couchbase\" \/>\n<meta property=\"og:description\" content=\"Learn how to build a generative AI recommendation engine using LLM, RAG, and Couchbase integration. Step-by-step guide for developers.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/ai-powered-recommendation-engine-llm-rag\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-09-23T21:08:57+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-13T23:36:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1340\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Sigal Shaharabani - Technical Leader, Tikal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sigal Shaharabani - Technical Leader, Tikal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/\"},\"author\":{\"name\":\"Sigal Shaharabani - Technical Leader, Tikal\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/eaa4f519f1bdafc253d366c93f115114\"},\"headline\":\"From Concept to Code: LLM + RAG with Couchbase\",\"datePublished\":\"2024-09-23T21:08:57+00:00\",\"dateModified\":\"2025-06-13T23:36:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/\"},\"wordCount\":2271,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg\",\"keywords\":[\"langchain\",\"LLMs\"],\"articleSection\":[\"Artificial Intelligence (AI)\",\"Best Practices and Tutorials\",\"Couchbase Capella\",\"Generative AI (GenAI)\",\"Python\",\"Vector Search\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/\",\"name\":\"From Concept to Code: LLM + RAG with Couchbase\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg\",\"datePublished\":\"2024-09-23T21:08:57+00:00\",\"dateModified\":\"2025-06-13T23:36:40+00:00\",\"description\":\"Learn how to build a generative AI recommendation engine using LLM, RAG, and Couchbase integration. Step-by-step guide for developers.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg\",\"width\":2560,\"height\":1340},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"From Concept to Code: LLM + RAG with Couchbase\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/eaa4f519f1bdafc253d366c93f115114\",\"name\":\"Sigal Shaharabani - Technical Leader, Tikal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/6bf412a23dbadb2c7664e454e6195c40\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/unnamed.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/unnamed.jpg\",\"caption\":\"Sigal Shaharabani - Technical Leader, Tikal\"},\"description\":\"I am a Technical Leader and a Group Leader in Tikal, with a great passion for backend and data systems. In my spare time I enjoy swimming and Israeli folk dancing.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/sigalshaharabani\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Del concepto al c\u00f3digo: LLM + RAG con Couchbase","description":"Aprende a construir un motor de recomendaci\u00f3n de IA generativa usando LLM, RAG e integraci\u00f3n con Couchbase. Gu\u00eda paso a paso para desarrolladores.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/ai-powered-recommendation-engine-llm-rag\/","og_locale":"es_MX","og_type":"article","og_title":"From Concept to Code: LLM + RAG with Couchbase","og_description":"Learn how to build a generative AI recommendation engine using LLM, RAG, and Couchbase integration. Step-by-step guide for developers.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/ai-powered-recommendation-engine-llm-rag\/","og_site_name":"The Couchbase Blog","article_published_time":"2024-09-23T21:08:57+00:00","article_modified_time":"2025-06-13T23:36:40+00:00","og_image":[{"width":2560,"height":1340,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg","type":"image\/jpeg"}],"author":"Sigal Shaharabani - Technical Leader, Tikal","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Sigal Shaharabani - Technical Leader, Tikal","Est. reading time":"12 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/"},"author":{"name":"Sigal Shaharabani - Technical Leader, Tikal","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/eaa4f519f1bdafc253d366c93f115114"},"headline":"From Concept to Code: LLM + RAG with Couchbase","datePublished":"2024-09-23T21:08:57+00:00","dateModified":"2025-06-13T23:36:40+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/"},"wordCount":2271,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg","keywords":["langchain","LLMs"],"articleSection":["Artificial Intelligence (AI)","Best Practices and Tutorials","Couchbase Capella","Generative AI (GenAI)","Python","Vector Search"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/","url":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/","name":"Del concepto al c\u00f3digo: LLM + RAG con Couchbase","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg","datePublished":"2024-09-23T21:08:57+00:00","dateModified":"2025-06-13T23:36:40+00:00","description":"Aprende a construir un motor de recomendaci\u00f3n de IA generativa usando LLM, RAG e integraci\u00f3n con Couchbase. Gu\u00eda paso a paso para desarrolladores.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/From-Concept-to-Code-LLM-RAG-with-Couchbase_V2-scaled.jpg","width":2560,"height":1340},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/ai-powered-recommendation-engine-llm-rag\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"From Concept to Code: LLM + RAG with Couchbase"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/eaa4f519f1bdafc253d366c93f115114","name":"Sigal Shaharabani - Responsable t\u00e9cnico, Tikal","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/6bf412a23dbadb2c7664e454e6195c40","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/unnamed.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/unnamed.jpg","caption":"Sigal Shaharabani - Technical Leader, Tikal"},"description":"Soy L\u00edder T\u00e9cnico y L\u00edder de Grupo en Tikal, con una gran pasi\u00f3n por los sistemas backend y de datos. En mi tiempo libre disfruto nadando y bailando folclore israel\u00ed.","url":"https:\/\/www.couchbase.com\/blog\/es\/author\/sigalshaharabani\/"}]}},"authors":[{"term_id":10032,"user_id":85526,"is_guest":0,"slug":"sigalshaharabani","display_name":"Sigal Shaharabani - Technical Leader, Tikal","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/unnamed.jpg","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/09\/unnamed.jpg"},"author_category":"","last_name":"Shaharabani - Technical Leader, Tikal","first_name":"Sigal","job_title":"","user_url":"","description":"Soy L\u00edder T\u00e9cnico y L\u00edder de Grupo en Tikal, con una gran pasi\u00f3n por los sistemas backend y de datos. En mi tiempo libre disfruto nadando y bailando folclore israel\u00ed."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/16352","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/85526"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=16352"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/16352\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/16398"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=16352"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=16352"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=16352"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=16352"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}