# Laboratorio: Construcción de un evaluador de productos con IA


Construye una canalización (pipeline) completa de análisis de comentarios para un producto de IA ficticio
llamado Jarvis. Escribirás código en Node.js que ejecute LLMs locales y modelos de incrustación
(embeddings) a través de Docker Model Runner; sin claves de API, sin suscripciones a la nube y
sin que los datos salgan de tu máquina.

## Iniciar el laboratorio













<ol>
<li>
<p>Inicia el labspace:</p>
<div
  data-pagefind-ignore
  x-data
  x-ref="root"
  class="group mt-2 mb-4 flex w-full scroll-mt-2 flex-col items-start gap-4 rounded bg-gray-50 p-2 outline outline-1 outline-offset-[-1px] outline-gray-200 dark:bg-gray-900 dark:outline-gray-800"
>
  
  <div class="relative w-full">
    
    
    <div class="syntax-light dark:syntax-dark not-prose w-full">
      <button
        x-data="{ code: 'JCBkb2NrZXIgY29tcG9zZSAtcCBsYWJzcGFjZSAtZiBvY2k6Ly9kb2NrZXJzYW1wbGVzL2xhYnNwYWNlLWNyZWF0aW5nLWFpLXByb2R1Y3QtcmV2aWV3ZXIgdXAgLWQ=', copying: false }"
        class="
          top-1
         absolute right-2 z-10 text-gray-300 dark:text-gray-500"
        title="copiar"
        @click="window.navigator.clipboard.writeText(atob(code).replaceAll(/^[\$>]\s+/gm, ''));
      copying = true;
      setTimeout(() => copying = false, 2000);"
      >
        <span
          :class="{ 'group-hover:block' : !copying }"
          class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"/>
  <path d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"/>
</svg>
</span
        >
        <span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clip-rule="evenodd"/>
</svg>
</span
        >
      </button>
      
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> docker compose -p labspace -f oci://dockersamples/labspace-creating-ai-product-reviewer up -d
</span></span></code></pre></div>
      
    </div>
  </div>
</div>
</li>
<li>
<p>Abre tu navegador en <a class="link" href="http://localhost:3030" rel="noopener">http://localhost:3030</a>.</p>
</li>
<li>
<p>Cuando hayas terminado, elimina el labspace:</p>
<div
  data-pagefind-ignore
  x-data
  x-ref="root"
  class="group mt-2 mb-4 flex w-full scroll-mt-2 flex-col items-start gap-4 rounded bg-gray-50 p-2 outline outline-1 outline-offset-[-1px] outline-gray-200 dark:bg-gray-900 dark:outline-gray-800"
>
  
  <div class="relative w-full">
    
    
    <div class="syntax-light dark:syntax-dark not-prose w-full">
      <button
        x-data="{ code: 'JCBkb2NrZXIgY29tcG9zZSAtcCBsYWJzcGFjZSBkb3du', copying: false }"
        class="
          top-1
         absolute right-2 z-10 text-gray-300 dark:text-gray-500"
        title="copiar"
        @click="window.navigator.clipboard.writeText(atob(code).replaceAll(/^[\$>]\s+/gm, ''));
      copying = true;
      setTimeout(() => copying = false, 2000);"
      >
        <span
          :class="{ 'group-hover:block' : !copying }"
          class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path d="M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 0 1 3.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0 1 21 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 0 1 7.5 16.125V3.375Z"/>
  <path d="M15 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 17.25 7.5h-1.875A.375.375 0 0 1 15 7.125V5.25ZM4.875 6H6v10.125A3.375 3.375 0 0 0 9.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 0 1 3 20.625V7.875C3 6.839 3.84 6 4.875 6Z"/>
</svg>
</span
        >
        <span :class="{ 'group-hover:block' : copying }" class="icon-svg hidden"
          ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
  <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clip-rule="evenodd"/>
</svg>
</span
        >
      </button>
      
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> docker compose -p labspace down
</span></span></code></pre></div>
      
    </div>
  </div>
</div>
</li>
</ol>



## Qué aprenderás

Al final de este Labspace, habrás completado lo siguiente:

- Ejecutar LLMs localmente a través de la API compatible con OpenAI de Docker Model Runner.
- Conectar una aplicación Node.js a Docker Model Runner usando el SDK de OpenAI y la integración de `models:` en Compose.
- Realizar análisis de sentimientos utilizando clasificación LLM a baja temperatura.
- Usar embeddings y similitud del coseno para agrupar comentarios relacionados semánticamente.
- Extraer datos estructurados de un LLM usando `response_format: { type: 'json_object' }`.
- Generar respuestas contextuales a las reseñas basadas en las características del producto extraídas.

## Módulos

| #   | Módulo                              | Descripción                                                                        |
| --- | ----------------------------------- | ---------------------------------------------------------------------------------- |
| 1   | Introducción                        | Descripción general de la canalización y configuración de Docker Model Runner                             |
| 2   | Configuración del proyecto y Docker Model Runner | Explorar el proyecto inicial y conectar la integración del modelo en Compose                  |
| 3   | Generación de comentarios sintéticos       | Usar el LLM para generar reseñas de productos realistas como datos de prueba                     |
| 4   | Análisis de sentimientos                  | Clasificar las reseñas como positivas, negativas o neutras con generación a baja temperatura |
| 5   | Embeddings y agrupamiento semántico    | Agrupar reseñas relacionadas usando embeddings vectoriales y similitud del coseno                |
| 6   | Características y respuestas                | Extraer características procesables y generar respuestas contextuales a las reseñas            |
| 7   | Cierre                             | Resumen de técnicas e ideas para extender la canalización                         |

