Pylarion Logo Pylarion Logo Pylarion
DESARROLLO WEB
13 MIN READ

Tutorial para crear una aplicación RAG con Nuxt y Gemini File Search

Pylarion Pylarion

Pylarion

Equipo de Pylarion. Construimos software confiable donde la tecnología no puede fallar. • 29 de junio de 2026

Tutorial para crear una aplicación RAG con Nuxt y Gemini File Search

Tutorial completo para construir una aplicación RAG con Nuxt y la API Gemini File Search de Google

La inteligencia artificial generativa ha transformado radicalmente la forma en que las aplicaciones interactúan con el conocimiento. Sin embargo, uno de sus límites más evidentes es la dependencia de datos de entrenamiento estáticos y genéricos, lo que dificulta obtener respuestas precisas sobre documentación interna, bases de conocimiento propietarias o información actualizada. Para superar esta barrera, surge la técnica conocida como RAG (Retrieval-Augmented Generation), que combina la recuperación semántica de información con la capacidad generativa de modelos como Gemini. En este tutorial, construiremos una aplicación RAG de extremo a extremo utilizando el framework Nuxt y la API Gemini File Search de Google.

A diferencia de los enfoques tradicionales donde el modelo responde exclusivamente con lo aprendido durante su entrenamiento, una arquitectura RAG permite indexar documentos propios en un almacén vectorial y, en tiempo de consulta, recuperar únicamente los fragmentos más relevantes para enriquecer el contexto que recibe el modelo. El resultado es una IA que responde con precisión quirúrgica sobre el corpus de información que tú mismo defines, reduciendo drásticamente las alucinaciones y aumentando la trazabilidad de las respuestas. Este paradigma resulta especialmente valioso en entornos empresariales donde la confidencialidad y la exactitud son requisitos no negociables.

Nuxt, el meta-framework basado en Vue.js, ofrece un entorno ideal para este tipo de aplicaciones gracias a su capacidad de manejar tanto el frontend como el backend dentro de un único proyecto cohesionado. Su sistema de server routes permite exponer endpoints HTTP con mínima configuración, mientras que su arquitectura basada en módulos facilita la integración con servicios externos. Combinado con la robustez de la API de Gemini, que incluye funcionalidades nativas de búsqueda semántica sobre archivos indexados, el resultado es una solución poderosa, escalable y sorprendentemente accesible para equipos de desarrollo web.

A lo largo de este artículo se detallará cada capa de la solución: la configuración inicial del proyecto, el diseño de los endpoints del backend, la lógica de indexación de documentos, el mecanismo de consulta al modelo y la interfaz de usuario que permite ejercitar el flujo completo. El objetivo no es únicamente mostrar código funcional, sino explicar las decisiones de diseño detrás de cada componente para que el lector pueda adaptar la arquitectura a sus propios casos de uso.

Antes de entrar en el código, es importante establecer un glosario conceptual claro, ya que muchos de los términos involucrados provienen de disciplinas distintas y suelen emplearse con imprecisión. Comprender con exactitud qué es un almacén de búsqueda, qué implica indexar un documento o cómo funciona la recuperación semántica es fundamental para tomar decisiones arquitectónicas sólidas durante el desarrollo.

Conceptos clave: RAG, almacenes vectoriales e indexación semántica

RAG (Retrieval-Augmented Generation) es una arquitectura de IA que divide el proceso de respuesta en dos fases distintas: una fase de recuperación (retrieval), donde se buscan los fragmentos de texto más relevantes para la consulta del usuario dentro de un corpus indexado, y una fase de generación (generation), donde el modelo de lenguaje recibe esos fragmentos como contexto adicional y produce una respuesta coherente y fundamentada. Esta separación de responsabilidades permite actualizar el conocimiento del sistema sin necesidad de reentrenar el modelo.

Un almacén de búsqueda (search store o vector store) es la estructura de datos que persiste los fragmentos de texto junto con sus representaciones vectoriales, también llamadas embeddings. Estos vectores codifican el significado semántico del texto en un espacio matemático de alta dimensión, de forma que dos fragmentos conceptualmente similares tendrán vectores próximos entre sí. La API Gemini File Search abstrae la complejidad de gestionar esta infraestructura, exponiendo operaciones de alto nivel para crear almacenes, añadir documentos y ejecutar búsquedas semánticas.

La indexación es el proceso mediante el cual un texto es fragmentado en unidades manejables (chunks), transformado en embeddings y almacenado en el vector store junto con sus metadatos originales. La calidad de la indexación tiene un impacto directo en la precisión de las respuestas finales: una fragmentación demasiado granular puede perder contexto, mientras que fragmentos excesivamente grandes pueden introducir ruido irrelevante en el prompt del modelo.

Configuración inicial del proyecto Nuxt

El primer paso es crear un nuevo proyecto Nuxt e instalar las dependencias necesarias. Asegúrate de tener Node.js 18 o superior instalado en tu entorno de desarrollo.

# Crear el proyecto Nuxt
npx nuxi@latest init nuxt-rag-app
cd nuxt-rag-app

# Instalar el SDK oficial de Google Generative AI
npm install @google/generative-ai

# Instalar dependencias adicionales
npm install @google/genai

Una vez creado el proyecto, es necesario configurar la clave de API de Gemini como variable de entorno. Crea un archivo .env en la raíz del proyecto con el siguiente contenido:

GEMINI_API_KEY=tu_clave_de_api_aqui
NUXT_SECRET_KEY=clave_secreta_para_el_servidor

A continuación, configura el archivo nuxt.config.ts para exponer las variables de entorno al runtime del servidor y habilitar las funcionalidades necesarias:

// nuxt.config.ts
export default defineNuxtConfig({
  devtools: { enabled: true },
  runtimeConfig: {
    geminiApiKey: process.env.GEMINI_API_KEY,
    public: {}
  },
  nitro: {
    experimental: {
      asyncContext: true
    }
  }
})

Arquitectura del backend: endpoints para gestionar el ciclo RAG completo

El backend de la aplicación se estructura en torno a cuatro endpoints principales, cada uno responsable de una operación específica dentro del ciclo RAG. Nuxt utiliza el directorio server/api/ para definir rutas HTTP que se ejecutan exclusivamente en el servidor, garantizando que la clave de API nunca quede expuesta al cliente.

  • POST /api/stores: Crea un nuevo almacén de búsqueda con un nombre identificador.
  • POST /api/stores/[id]/documents: Carga e indexa uno o varios documentos de texto en un almacén existente.
  • GET /api/stores/[id]/status: Verifica el estado de indexación de los documentos cargados.
  • POST /api/stores/[id]/query: Ejecuta una consulta semántica contra el almacén y obtiene una respuesta generada por Gemini.

El endpoint de creación de almacenes interactúa directamente con la API de Gemini para instanciar un nuevo corpus de búsqueda. La implementación en Nuxt es la siguiente:

// server/api/stores.post.ts
import { GoogleGenAI } from '@google/genai'

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()
  const body = await readBody(event)
  
  const genAI = new GoogleGenAI({ apiKey: config.geminiApiKey })
  
  try {
    const corpus = await genAI.files.createCorpus({
      displayName: body.name,
      description: body.description || ''
    })
    
    return {
      success: true,
      storeId: corpus.name,
      displayName: corpus.displayName,
      createTime: corpus.createTime
    }
  } catch (error: any) {
    throw createError({
      statusCode: 500,
      statusMessage: `Error al crear el almacén: ${error.message}`
    })
  }
})

El endpoint de carga de documentos recibe el texto en el cuerpo de la petición, lo fragmenta en chunks manejables y los indexa dentro del corpus indicado. La API de Gemini File Search gestiona internamente la generación de embeddings, por lo que el desarrollador únicamente necesita proporcionar el texto y los metadatos asociados:

// server/api/stores/[id]/documents.post.ts
import { GoogleGenAI } from '@google/genai'

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()
  const storeId = getRouterParam(event, 'id')
  const body = await readBody(event)
  
  const genAI = new GoogleGenAI({ apiKey: config.geminiApiKey })
  
  // Fragmentación del documento en chunks de 1000 caracteres con solapamiento
  const chunkSize = 1000
  const overlap = 200
  const chunks: string[] = []
  
  for (let i = 0; i < body.content.length; i += chunkSize - overlap) {
    chunks.push(body.content.slice(i, i + chunkSize))
  }
  
  const documents = await Promise.all(
    chunks.map((chunk, index) => 
      genAI.files.addDocument({
        corpusName: storeId,
        document: {
          displayName: `${body.filename}-chunk-${index}`,
          documentPassages: [{ content: { parts: [{ text: chunk }] } }]
        }
      })
    )
  )
  
  return {
    success: true,
    chunksIndexed: documents.length,
    documentIds: documents.map(d => d.name)
  }
})

El endpoint de consulta: orquestando recuperación y generación

El endpoint de consulta es el núcleo de la arquitectura RAG y donde ocurre la magia real del sistema. Su funcionamiento puede dividirse en tres fases secuenciales: primero realiza una búsqueda semántica en el corpus para recuperar los fragmentos más relevantes para la pregunta del usuario; segundo, construye un prompt enriquecido que incluye esos fragmentos como contexto; y tercero, invoca al modelo Gemini para generar una respuesta fundamentada exclusivamente en la información recuperada.

// server/api/stores/[id]/query.post.ts
import { GoogleGenAI } from '@google/genai'

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig()
  const storeId = getRouterParam(event, 'id')
  const body = await readBody(event)
  
  const genAI = new GoogleGenAI({ apiKey: config.geminiApiKey })
  
  // Fase 1: Recuperación semántica
  const retrievalResult = await genAI.files.queryCorpus({
    corpusName: storeId,
    query: body.question,
    metadataFilters: [],
    pageSize: 5
  })
  
  const relevantPassages = retrievalResult.relevantChunks
    ?.map(chunk => chunk.chunk?.data?.chunkData?.stringValue || '')
    .filter(Boolean)
    .join('\n\n---\n\n') || ''
  
  // Fase 2: Construcción del prompt aumentado
  const augmentedPrompt = `
    Eres un asistente especializado. Responde la siguiente pregunta 
    basándote ÚNICAMENTE en el contexto proporcionado. Si la información 
    no está en el contexto, indícalo explícitamente.
    
    CONTEXTO RECUPERADO:
    ${relevantPassages}
    
    PREGUNTA DEL USUARIO:
    ${body.question}
    
    RESPUESTA:
  `
  
  // Fase 3: Generación con Gemini
  const model = genAI.getGenerativeModel({ model: 'gemini-1.5-pro' })
  const result = await model.generateContent(augmentedPrompt)
  
  return {
    answer: result.response.text(),
    sourcesCount: retrievalResult.relevantChunks?.length || 0,
    retrievedContext: relevantPassages
  }
})

Un aspecto crítico de este endpoint es el diseño del prompt de sistema. La instrucción explícita de responder únicamente con el contexto recuperado es fundamental para evitar que el modelo mezcle su conocimiento de entrenamiento con la información indexada, lo cual podría producir respuestas híbridas difíciles de auditar. En entornos productivos, es recomendable añadir también instrucciones sobre el formato de la respuesta y el nivel de detalle esperado según el dominio de aplicación.

Interfaz de usuario: diseño del flujo de experiencia completo

La interfaz de usuario de la aplicación debe permitir ejercitar el ciclo RAG de forma secuencial e intuitiva. Se estructura en cuatro bloques funcionales que se corresponden exactamente con los cuatro endpoints del backend: creación de almacén, carga de documentos, verificación de estado y consulta interactiva.

<!-- pages/index.vue -->
<template>
  <div class="rag-app">
    <!-- Sección 1: Crear almacén -->
    <section class="store-creator">
      <h2>1. Crear Almacén de Búsqueda</h2>
      <input v-model="storeName" placeholder="Nombre del almacén" />
      <button @click="createStore" :disabled="isCreating">
        {{ isCreating ? 'Creando...' : 'Crear Almacén' }}
      </button>
      <p v-if="currentStoreId" class="success">
        ✓ Almacén creado: {{ currentStoreId }}
      </p>
    </section>
    
    <!-- Sección 2: Cargar documentos -->
    <section class="document-loader" v-if="currentStoreId">
      <h2>2. Cargar Documentos</h2>
      <textarea 
        v-model="documentContent" 
        placeholder="Pega aquí el contenido del documento..."
        rows="10"
      />
      <input v-model="documentName" placeholder="Nombre del documento" />
      <button @click="uploadDocument" :disabled="isUploading">
        {{ isUploading ? 'Indexando...' : 'Cargar e Indexar' }}
      </button>
    </section>
    
    <!-- Sección 3: Consulta -->
    <section class="query-interface" v-if="currentStoreId">
      <h2>3. Consultar al Modelo</h2>
      <input v-model="userQuestion" placeholder="¿Qué deseas saber?" />
      <button @click="executeQuery" :disabled="isQuerying">
        {{ isQuerying ? 'Consultando...' : 'Consultar' }}
      </button>
      <div v-if="queryResult" class="result-display">
        <h3>Respuesta:</h3>
        <p>{{ queryResult.answer }}</p>
        <details>
          <summary>Contexto recuperado ({{ queryResult.sourcesCount }} fragmentos)</summary>
          <pre>{{ queryResult.retrievedContext }}</pre>
        </details>
      </div>
    </section>
  </div>
</template>

La sección de visualización de contexto recuperado, implementada mediante el elemento <details>, es especialmente valiosa desde el punto de vista del debugging y la auditoría. Al permitir al usuario comparar la respuesta generada con los fragmentos exactos que el modelo recibió como contexto, se facilita la identificación de problemas de fragmentación, indexación deficiente o consultas mal formuladas. Esta transparencia en el flujo de datos es una práctica recomendada en cualquier sistema RAG destinado a entornos productivos.

Consideraciones de rendimiento y mejoras arquitectónicas

Una vez validado el flujo básico, existen varias optimizaciones que marcan la diferencia entre un prototipo funcional y una aplicación lista para producción. A continuación se enumeran las más relevantes:

  1. Caché de resultados de recuperación: Preguntas similares pueden generar las mismas consultas al vector store. Implementar una capa de caché con Redis o una solución en memoria puede reducir significativamente la latencia y el coste de las llamadas a la API.
  2. Estrategia de chunking adaptativa: En lugar de fragmentar por número fijo de caracteres, considera estrategias semánticas que respeten párrafos, secciones o unidades de información lógicas del documento original.
  3. Reranking de resultados: Los fragmentos recuperados en la fase de búsqueda semántica pueden reordenarse mediante un modelo de reranking secundario para maximizar la relevancia antes de construir el prompt final.
  4. Gestión de múltiples formatos: Ampliar el soporte de ingesta para procesar PDF, DOCX o Markdown, extrayendo el texto limpio antes de la indexación.
  5. Monitorización de métricas RAG: Implementar evaluaciones automáticas de faithfulness (fidelidad al contexto) y answer relevancy para detectar degradaciones en la calidad de las respuestas a lo largo del tiempo.

"La arquitectura RAG no es simplemente una técnica de optimización de prompts; es un cambio de paradigma que separa el conocimiento del razonamiento, permitiendo que los modelos de lenguaje sean herramientas de inferencia aplicables a cualquier corpus de información sin necesidad de reentrenamiento."

La combinación de Nuxt y la API Gemini File Search demuestra que implementar una arquitectura RAG completa no requiere infraestructura compleja ni conocimientos profundos en aprendizaje automático. El ecosistema de herramientas disponible en 2024 permite a equipos de desarrollo web abordar este tipo de soluciones con las mismas habilidades y patrones que ya utilizan en sus proyectos cotidianos. La clave está en comprender el flujo de datos, diseñar cuidadosamente la estrategia de indexación y construir una capa de evaluación que permita iterar sobre la calidad del sistema de forma continua y sistemática.

0
Pylarion Pylarion

Pylarion

Desarrollo Web Expert

Equipo de Pylarion. Construimos software confiable donde la tecnología no puede fallar.

Blog / Desarrollo Web / Tutorial para crear una aplicación RAG con Nuxt y Gemini File Search

Comentarios

(0)
Categoría: Desarrollo Web

Artículos Recomendados

Creando un editor colaborativo con Nuxt UI, Jazz e IA
Desarrollo Web
3
0
0

Creando un editor colaborativo con Nuxt UI, Jazz e IA

El autor comparte su experiencia desarrollando un editor de texto enriquecido colaborativo en tiempo real utilizando Nuxt UI y Jazz, asistido en gran medida por inteligencia artificial. Inicialmente planeado como un tutorial paso a paso, el artículo evoluciona hacia una reflexión sobre cómo la IA facilita la programación, una práctica conocida como vibe coding. Se detalla la motivación de construir una solución propia dentro del ecosistema Nuxt para mantener el control completo del código, superando así las limitaciones de varias opciones prefabricadas. El proyecto resultante incluye características clave como soporte multiusuario, comentarios contextuales estilo Notion, carga de imágenes y resolución de respuestas. Además de proporcionar el código base de código abierto para que la comunidad lo clone, el autor ofrece importantes lecciones sobre el desarrollo guiado por agentes de IA, destacando la necesidad de forzarlos a verificar iterativamente su trabajo mediante el navegador.

Leer artículo
Construyendo una aplicación RAG con Nuxt y Gemini File Search
Desarrollo Web
5
0
0

Construyendo una aplicación RAG con Nuxt y Gemini File Search

Este artículo es un tutorial técnico paso a paso para construir una aplicación de Generación Aumentada por Recuperación (RAG) utilizando el framework Nuxt y la API Gemini File Search de Google. Explica cómo indexar documentos propios, recuperar el contexto más relevante en fragmentos y generar respuestas precisas y fundamentadas por inteligencia artificial. El proyecto abarca la creación de un backend en Nuxt con utilidades y endpoints para interactuar con Gemini, gestionar los procesos de indexación y solicitar información. También describe una interfaz de usuario completa para probar el flujo integrado, permitiendo cargar textos, visualizar almacenes de datos y leer los estados del sistema. Además, el contenido define conceptos esenciales sobre la tecnología RAG y detalla exactamente la configuración inicial del proyecto, la gestión de dependencias y el manejo de variables de entorno.

Leer artículo
Gestión de Estado en Vue: Composables, Provide/Inject y Pinia
Desarrollo Web
2
0
0

Gestión de Estado en Vue: Composables, Provide/Inject y Pinia

Esta guía práctica explica cómo elegir la herramienta adecuada para compartir estado y lógica en aplicaciones Vue.js, evitando arquitecturas complejas. Destaca tres enfoques clave: Los Composables, que utilizan la Composition API para encapsular y reutilizar comportamiento donde cada consumidor obtiene su propio estado independiente, ideales para lógica local como validaciones o fetch de datos. Provide/Inject resulta útil para pasar o inyectar estado a lo largo de un árbol de componentes descendente sin necesidad de recurrir al tedioso paso de props múltiples ('prop drilling'). Por último, Pinia es la solución estándar recomendada para gestionar el estado global y centralizado de la aplicación (como sesiones de usuario o datos del carrito de compras), ya que vive fuera de la jerarquía de los componentes y ofrece integración completa con Devtools.

Leer artículo