APIs de IA integradas: recomendaciones y precauciones

Fecha de publicación: 30 de abril de 2026

Con la IA integrada, tu sitio web o aplicación web puede realizar tareas potenciadas por IA sin necesidad de implementar, administrar ni alojar modelos por tu cuenta. Es posible que te resulte difícil pasar de una demostración a una función lista para producción. En este documento, se abordan consideraciones técnicas y de UX para ayudarte a evitar errores comunes.

Prepara el modelo con anticipación

Se aplica a: todas las APIs, por ejemplo, Summarizer, Translator y Writer.

Haz lo siguiente: Inicializa la sesión en cuanto reconozcas la intención del usuario. Como se requiere la activación del usuario para inicializar una sesión, puedes usar cualquier interacción, por ejemplo, un clic en cualquier lugar de la página que ofrece una función potenciada por IA. Esto prepara el modelo y el tiempo de ejecución mientras el usuario interactúa con la IU. Cuando sea pertinente, inicia la siguiente tarea de IA más probable en cuanto comiences a renderizar el resultado.

No hagas lo siguiente: No esperes hasta que el usuario haga clic en "Generar" para inicializar la sesión. Esto genera un retraso de inicio en frío de varios segundos, ya que el modelo primero debe cargarse en la memoria y preparar su canalización de ejecución.

Configura las instrucciones iniciales durante la creación

Se aplica a: API de Prompt.

Haz lo siguiente: Proporciona instrucciones del sistema durante la inicialización de la sesión para mejorar la velocidad de la primera instrucción.

No hagas lo siguiente: No comiences con una sesión vacía y envíes instrucciones del sistema como parte de la primera llamada a prompt(). Esto aumenta la latencia porque obliga al modelo a procesar esas instrucciones en el último momento.

// ✅ DO: Create the session as early as possible (tip on warming up the model early) and use initialPrompts for system instructions in the create call
const session = await LanguageModel.create({
  initialPrompts: [
    { role: 'system', content: 'You are a helpful assistant specialized in code reviews.' }
  ]
});

// A few moments later, when the user triggers the AI feature
const review = await session.prompt(`Review the following code:\n\n${code}`);

// ❌ DON'T: Send instructions using prompt() after creation
// const slowerSession = await LanguageModel.create();
// await slowerSession.prompt(`You are a helpful assistant specialized in code reviews.\n\nReview the following code:\n\n${code}`); // Higher latency

Clona sesiones para tareas repetitivas

Se aplica a: API de Prompt.

En el caso de la API de Prompt, cada sesión hace un seguimiento del contexto de la conversación, y tiene en cuenta todas las interacciones anteriores. Como un clon hereda todo de su sesión superior, incluidas las instrucciones iniciales y todo el historial de interacciones hasta el punto de clonación, estructura tu uso para heredar solo lo que necesitas.

Haz lo siguiente:

  • Crea una sesión base: Para controlar las tareas no relacionadas de manera eficiente, crea una sesión base que contenga solo las instrucciones del sistema y ningún contexto conversacional anterior.
  • Clona la línea de base: Usa clone() en esa sesión base para las tareas nuevas para guardar la sobrecarga de volver a analizar instrucciones pesadas del sistema. Esto te permite crear conversaciones paralelas o restablecer una tarea a su línea de base.

No hagas lo siguiente:

  • No reutilices la misma sesión para tareas no relacionadas y evita clonar cualquier sesión que ya contenga un historial de interacciones innecesario. Ambos patrones pueden hacer que el contexto anterior no relacionado interfiera con tu tarea actual.
  • No llames a create() de forma repetida con instrucciones idénticas y pesadas del sistema. En su lugar, usa el patrón de clonación para optimizar el rendimiento.
// ✅ DO: Create a baseline session and clone it for each new task
const baseSession = await LanguageModel.create({
  initialPrompts: [{
    role: 'system',
    content: 'You are a technical editor...',
  }],
});

// Clone the base session once for the first task
const task1 = await baseSession.clone();
const response1 = await task1.prompt("Review this first draft...");
// ... Repeat the cloning pattern for subsequent independent tasks
// Each task starts fresh from the baseline system instructions

// ❌ DON'T:
// Bad performance pattern: repeated create() calls for identical tasks.
// This forces the model to re-parse instructions every time, increasing latency.
// const sessionA = await LanguageModel.create({ initialPrompts: [...] });
// await sessionA.prompt("Task 1...");
// const sessionB = await LanguageModel.create({ initialPrompts: [...] });
// await sessionB.prompt("Task 2...");
// Bad quality pattern: reusing the same session for unrelated tasks.
// const session = await LanguageModel.create();
// await session.prompt("Analyze this financial report...");
// Unrelated task in the same session:
// await session.prompt("Now write a children's story...");

Destruye las sesiones no utilizadas

Se aplica a: todas las APIs.

Haz lo siguiente: Llama de forma explícita a destroy() en las sesiones que ya no necesites para liberar memoria cuando una función ya no esté en uso. Si usas un patrón de clonación, conserva la sesión base y destruye los clones que ya no necesites.

No hagas lo siguiente: No mantengas activas varias sesiones grandes. Cada sesión consume memoria, lo que crea un uso innecesario de recursos y podría convertirse en un problema. El recolector de elementos no utilizados limpiará las sesiones de forma natural, pero llamar a destroy() libera memoria más rápido.

// ✅ DO: Use the clone and destroy it immediately after
const clone = await baseSession.clone();
const response = await clone.prompt("Quick task...");
// Free memory right away: destry the clone, keep the baseSession
clone.destroy();

Renderiza respuestas de transmisión de forma segura y eficiente

Se aplica a: todas las APIs con compatibilidad con transmisión (Prompt, Summarizer, Writer, Rewriter y Translator).

Haz lo siguiente: Trata toda la salida de LLM como contenido no confiable. Desinfecta la salida combinada completa, no solo los fragmentos, ya que el código malicioso podría dividirse en varias actualizaciones. Antes de renderizar, usa la Sanitizer API cuando sea compatible. Para evitar una disminución en el rendimiento, usa un analizador de Markdown de transmisión como streaming-markdown.

No hagas lo siguiente: No configures innerHTML directamente en cada actualización de fragmento. Esto es lento, en especial con formatos complejos como el resaltado de sintaxis, y vulnerable a la inyección.

import * as smd from "streaming-markdown";
// Set up virtual buffer and Sanitizer API
const sanitizer = new Sanitizer({
  allowElements: ['figure', 'figcaption', 'p', 'br', 'strong', 'em', 'img', 'a'],
  allowAttributes: {
    'loading': ['img'], 'decoding': ['img'], 'src': ['img'], 'href': ['a']
  }
});

// Create an off-screen fragment so the parser doesn't cause flicker
// or trigger XSS in the live DOM during the building process.
const buffer = new DocumentFragment();
const parser = smd.parser_new(buffer);

// Use sanitizer as a gatekeeper / cleaner function so we can combine it with the streaming Markdown parser
function syncSanitized(target, sourceFragment) {
  // .sanitize() returns a fresh, clean DocumentFragment
  const cleanFragment = sanitizer.sanitize(sourceFragment);
  // replaceChildren is the modern high-performance way to swap DOM content
  target.replaceChildren(cleanFragment);
}

// Streaming Logic
// `chunks` keeps track of the raw string (useful for logs/debug)
chunks += chunk;
// Let the parser build the DOM incrementally in the buffer.
// This is high-performance because the buffer is not live
smd.parser_write(parser, chunk);
// Use the Sanitizer API to port the content safely to the container.
syncSanitized(container, buffer);

Optimiza la entrada para obtener velocidad

Se aplica a: todas las APIs.

Haz lo siguiente: Solo pasa al modelo lo que sea estrictamente necesario. Quita todo lo que no sea pertinente para la tarea en cuestión. En el caso de conjuntos de datos grandes, proporciona una breve descripción general y una pequeña selección de elementos pertinentes.

No hagas lo siguiente: No envíes texto sin procesar, metadatos innecesarios, etiquetas HTML ni listas grandes sin filtrar a las APIs. La latencia aumenta de manera significativa con el tamaño de la entrada, lo que puede hacer que la función de IA parezca dañada en muchos dispositivos.

// ✅ DO: Send only relevant text
const cleanText = document.querySelector('#article').innerText;
const summary = await Summarizer.summarize(cleanText);

// ❌ DON'T: Send the entire DOM structure
// const dirtyText = document.querySelector('#article').innerHTML;

Usa una salida estructurada para obtener resultados predecibles

Se aplica a: API de Prompt.

Haz lo siguiente: Cuando necesites que el modelo muestre datos en un formato específico, usa una salida estructurada proporcionando un campo responseConstraint para proporcionar un esquema JSON. Esto garantiza que el resultado sea predecible y evita que necesites un procesamiento posterior complejo o un análisis manual.

No hagas lo siguiente: No te bases solo en instrucciones de lenguaje natural (como "solo salida JSON") solo. Los modelos pueden incluir relleno conversacional que rompa tu analizador.

// ✅ DO: Use a JSON Schema for predictable results
const schema = {
  type: "object",
  properties: {
    isTopicCats: { type: "boolean" }
  }
};

const result = await session.prompt(`Is this post about cats?\n\n${post}`, {
  responseConstraint: schema,
});
console.log(JSON.parse(result).isTopicCats);

Desvincula la generación de las restricciones de longitud

Se aplica a: la API de Prompt, ya que es la única API que admite esquemas de salida estructurados.

Haz lo siguiente: Permite que el modelo genere su respuesta de forma natural y, luego, usa la lógica del cliente para truncar el texto y adaptarlo a tu IU.

No hagas lo siguiente: No apliques límites estrictos de caracteres como maxLength: 125 con esquemas de salida estructurados. Cuando la respuesta de un modelo es más larga que el límite que estableces, el modelo puede cambiar a tokens de alta densidad, como idiomas extranjeros o emojis, para comprimir el significado, lo que genera una salida sin sentido.

/*  DO: Handle overflow using CSS */
.result {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis; /* Displays '…' */
}
// ❌ DON'T: Force length in the prompt
const result = await session.prompt("Write a bio in exactly 50 characters.");

Administra la paciencia del usuario

Se aplica a: todas las APIs.

Haz lo siguiente: Usa animaciones y técnicas de IU para administrar la paciencia del usuario. El enfoque óptimo depende de tu caso de uso y de la longitud esperada de la salida de la API. Algunas ideas:

  • Transmisión para contenido largo: En el caso de los resúmenes o el chat, la transmisión crea un efecto de máquina de escribir por token de forma predeterminada. Esto puede parecer natural y proporcionar comentarios inmediatos.
  • No transmitir para tareas cortas (o tareas asíncronas largas): En el caso de salidas cortas, por ejemplo, texto alternativo, la no transmisión puede crear una IU más refinada. También proporciona tiempo para preparar de forma especulativa la siguiente tarea de IA mientras se renderiza la actual. Este enfoque también funciona para tareas asíncronas o en segundo plano más largas. Si el usuario no está bloqueado en el resultado para continuar su recorrido, no es necesario producir el resultado de forma urgente a medida que sucede. Indica que el proceso está en curso en la IU.
  • Transiciones visuales para actualizaciones: Cuando traduzcas o vuelvas a escribir texto, usa animaciones, por ejemplo, la transformación de palabras.

No hagas lo siguiente: No actualices la IU sin indicadores visuales.

Alinea con el modelo mental del usuario sobre el tiempo y el trabajo

Se aplica a: todas las APIs.

Haz lo siguiente: Considera un retraso artificial de uno o dos segundos si una respuesta es casi instantánea. Paradójicamente, los usuarios pueden considerar que los resultados son más confiables cuando perciben un proceso de generación que se alinea con la dificultad percibida de la tarea. Usa animaciones para indicar que se produjo un proceso de IA.

No hagas lo siguiente: No sorprendas a los usuarios con reemplazos instantáneos de la IU.

Permite que los usuarios naveguen rápidamente y deshagan las ediciones de IA

Se aplica a: todas las APIs.

Haz lo siguiente: Equipa tu IU con un selector o un historial de navegación que permita a los usuarios explorar diferentes resultados con confianza y deshacer rápidamente las ediciones de IA. Esto garantiza que las diferentes versiones sigan estando disponibles con facilidad.

No hagas lo siguiente: No sobrescribas el borrador anterior del usuario ni un resultado de IA que le haya gustado sin una forma de volver, revertir o comparar versiones.

Elemento de la IU de pasos que muestra el historial de navegación.
Patrón de IU: Rechazar o aceptar sugerencia (Documentos de Google)
Botón para deshacer todas las ediciones del agente en una IU de Google Antigravity.
Patrón de IU: Deshacer todas las ediciones del agente (Google Antigravity)
Botones para rechazar o aceptar sugerencias en Documentos de Google.
Patrón de IU: Selector (demostración de texto alternativo)

Permite el control y las anulaciones del usuario

Se aplica a: todas las APIs.

Haz lo siguiente: Siempre permite que el usuario tenga la última palabra. Proporciona una forma de anular las sugerencias de forma manual. Es posible que las APIs produzcan resultados incorrectos.

No hagas lo siguiente: No fuerces un resultado generado por IA como la única opción.

Almacena en caché los resultados de tareas repetidas

Se aplica a: todas las APIs.

Haz lo siguiente: Implementa una caché de resultados local (por ejemplo, con sessionStorage o IndexedDB) para entradas o consultas repetidas. Normaliza la entrada recortando los espacios en blanco y convirtiendo a minúsculas para aumentar los aciertos de caché. En el caso de entradas pesadas, por ejemplo, imágenes, genera un hash para usarlo como clave de caché. Establece un tiempo de actividad (TTL) conservador para tu caché (o muestra resultados almacenados en caché mientras los actualizas en segundo plano). Permite que el usuario active una inferencia nueva si el resultado no es satisfactorio.

No hagas lo siguiente: No vuelvas a ejecutar la misma inferencia para una consulta de búsqueda repetida o una entrada de datos idéntica, por ejemplo, cuando un usuario navega hacia atrás y hacia adelante entre los resultados de la búsqueda. Si bien la inferencia integrada en el dispositivo es gratuita en términos de costos de la nube, es costosa en términos de tiempo del usuario y duración de la batería.

// ✅ DO: Check a local cache before running inference
async function getAiResponse(userInput, forceRefresh = false) {
  // Normalize the query to increase cache hits
  const query = userInput.trim().toLowerCase();
  const cacheKey = `ai_results_${query}`;
  const TTL_MS = 3600000; // 1 hour conservative TTL

  if (!forceRefresh) {
    const itemStr = localStorage.getItem(cacheKey);
    if (itemStr) {
      const item = JSON.parse(itemStr);
      const now = Date.now();

      // Check if the item has expired
      if (now < item.expiry) {
        // Lightweight safety check before rendering
        if (isValid(item.value)) return item.value;
      } else {
        // Delete the stale entry if the TTL has passed
        localStorage.removeItem(cacheKey);
      }
    }
  }

  // Fallback: Run inference if no valid cache exists
  const session = await LanguageModel.create();
  const response = await session.prompt(userInput);

  // Store the result for future use (with an expiration)
  const cacheData = {
    value: response,
    expiry: Date.now() + TTL_MS
  };
  localStorage.setItem(cacheKey, JSON.stringify(cacheData));

  return response;
}