Blog.

Task APIs: Escribir, Resumir y Corregir con Precisión

Task APIs: Escribir, Resumir y Corregir con Precisión
15 min read

La Prompt API es extremadamente flexible: puedes hacer prácticamente cualquier tarea con el prompt correcto. Pero esa flexibilidad tiene un costo: modelos más grandes, mayor consumo de recursos, y la necesidad de gestionar tokens, contexto y prompts cuidadosamente.

Para tareas específicas y bien definidas, Chrome ofrece Task APIs: modelos afinados (fine-tuned) que sacrifican flexibilidad por eficiencia, precisión y simplicidad de uso.

¿Por qué Task APIs en lugar de Prompt API?

Las Task APIs están optimizadas para casos de uso concretos. La diferencia fundamental es que mientras la Prompt API es como una conversación abierta donde mantienes un historial completo, las Task APIs son llamadas stateless: ejecutas una operación, obtienes el resultado, y no hay contexto persistente.

AspectoPrompt APITask APIs
Tamaño del modeloModelo general completoVersiones más ligeras/cuantizadas
CalidadDepende del prompt engineeringAfinadas para la tarea específica
APIRequiere diseño de promptsParámetros declarativos simples
Gestión de estadoConversaciones multi-turno (stateful)Stateless (sin historial)
MemoriaAlta (mantiene contexto)Baja (libera después de cada call)
LatenciaVariable según contextoPredecible y optimizada
Uso típicoChatbots, RAG, tareas complejasResumen, reescritura, corrección

Regla de oro: Si existe una Task API para tu necesidad, úsala. Ahorrarás recursos, batería y complejidad.

Configuración del Entorno

Las Task APIs comparten los mismos requisitos de hardware y configuración que la Prompt API. Si ya configuraste tu entorno, estás listo. Si no:

  1. Chrome Canary o Dev (versión 137+)
  2. Flags necesarios en chrome://flags:
    • Enables optimization guide on device: Enabled BypassPerfRequirement
    • Prompt API for Gemini Nano: Enabled
  3. Verificar componentes en chrome://components: Actualizar "Optimization Guide On Device Model"

Patrón Común de Uso

Todas las Task APIs (Summarizer, Writer, Rewriter, Proofreader) siguen el mismo patrón de uso:

// 1. Verificar soporte del navegador
if (!('Summarizer' in self)) {
  // API no soportada, usar fallback
  return;
}

// 2. Verificar disponibilidad del modelo
const availability = await Summarizer.availability();

if (availability === 'unavailable') {
  // Hardware insuficiente, usar cloud API
  return;
}

// 3. Crear instancia con opciones
const summarizer = await Summarizer.create({
  type: 'key-points',
  length: 'medium',
});

// 4. Usar la API
const result = await summarizer.summarize(text);

// 5. Limpiar recursos
summarizer.destroy();

Los estados de disponibilidad son los mismos que en Prompt API:

  • unavailable: Hardware insuficiente
  • downloadable: Requiere descarga (primera vez, requiere user activation)
  • downloading: Descarga en progreso
  • available: Listo para usar

Conceptos Compartidos

Como ya vimos en los artículos sobre Prompt API, estos conceptos aplican también a Task APIs:

  • User Activation: La descarga del modelo requiere interacción del usuario (click, keydown)
  • Download Monitoring: Usa el parámetro monitor para mostrar progreso
  • Streaming: Todas las APIs tienen versión *Streaming() para resultados progresivos
  • Cleanup: Siempre llama a destroy() para liberar recursos
  • Error Handling: Manejar QuotaExceededError cuando el input excede límites

La única diferencia importante es que las Task APIs no mantienen historial entre llamadas, a diferencia de Prompt API donde cada prompt() acumula contexto.

1. Summarizer API: Extracción Inteligente de Insights

La Summarizer API está optimizada para extraer información relevante de textos largos. A diferencia de pedirle a Prompt API "resume este texto", aquí defines qué tipo de resumen quieres a través de parámetros declarativos.

Tipos de Resumen

const summarizer = await Summarizer.create({
  type: 'key-points', // 'key-points' | 'tldr' | 'teaser' | 'headline'
  format: 'markdown', // 'markdown' | 'plain-text'
  length: 'medium', // 'short' | 'medium' | 'long'
  sharedContext: '', // Contexto compartido para múltiples documentos
});

Cada type está diseñado para un caso de uso específico:

  • key-points: Lista de puntos clave. Ideal para artículos técnicos, documentación, o cuando necesitas escanear rápidamente el contenido. El modelo extrae las ideas principales en formato de lista.

  • tldr: Resumen ultra-conciso de 1-2 oraciones. Perfecto para previews rápidos, notificaciones, o cuando el espacio es limitado (cards, tooltips).

  • teaser: Introducción que incentiva a leer más. Diseñado para generar engagement, útil en feeds de contenido, newsletters, o sugerencias de artículos.

  • headline: Título descriptivo del contenido. Usa esto para generar títulos automáticos de secciones, categorizar documentos, o crear índices.

Shared Context: El Contexto Sin Contaminar

El parámetro sharedContext es particularmente útil cuando resumes múltiples documentos relacionados. A diferencia de incluir contexto en cada texto, sharedContext se define una sola vez al crear la instancia y aplica a todas las llamadas posteriores sin contar contra el límite de tokens de cada documento.

const summarizer = await Summarizer.create({
  type: 'tldr',
  sharedContext:
    'Estos son comentarios de usuarios sobre la nueva versión 2.0 de nuestra app',
});

// Procesar múltiples reviews sin repetir el contexto
for (const review of customerReviews) {
  const summary = await summarizer.summarize(review);
  console.log(summary);
}

Esto es especialmente poderoso cuando procesas lotes de documentos similares: reportes financieros, tickets de soporte, feedback de usuarios, etc.

Escalando Más Allá del Contexto: Summary of Summaries

El contexto de Gemini Nano (~4K tokens o ~3,000 palabras) puede ser insuficiente para documentos extensos. La técnica de "summary of summaries" divide el documento en chunks, resume cada parte, y luego resume los resúmenes.

Es importante dividir por límites semánticos (párrafos, secciones) en lugar de por caracteres, para mantener coherencia. El trade-off es claro: cada nivel de recursión distancia el resumen del contenido original, pero permite procesar documentos de cualquier tamaño.

async function summarizeLargeDocument(text) {
  const summarizer = await Summarizer.create({
    type: 'tldr',
    format: 'plain-text',
    length: 'long',
  });

  // Verificar si cabe en el contexto
  const estimatedTokens = await summarizer.measureInputUsage(text);
  if (estimatedTokens <= summarizer.inputQuota) {
    return await summarizer.summarize(text);
  }

  // Dividir por párrafos (semántico)
  const chunks = text.split(/\n\n+/).reduce((acc, paragraph) => {
    const maxChunkSize = summarizer.inputQuota * 3; // ~3 chars por token
    if (
      acc.length === 0 ||
      acc[acc.length - 1].length + paragraph.length > maxChunkSize
    ) {
      acc.push(paragraph);
    } else {
      acc[acc.length - 1] += '\n\n' + paragraph;
    }
    return acc;
  }, []);

  // Resumir chunks y luego resumir los resúmenes
  const summaries = await Promise.all(chunks.map(c => summarizer.summarize(c)));
  return await summarizer.summarize(summaries.join('\n\n'));
}

2. Writer API: Generación de Contenido Asistida

Writer API genera contenido desde cero. La diferencia clave con Prompt API es que Writer está específicamente entrenada para creación de texto, no para conversación o razonamiento complejo.

Control de Tono y Formato

const writer = await Writer.create({
  tone: 'neutral', // 'formal' | 'neutral' | 'casual'
  format: 'markdown', // 'markdown' | 'plain-text'
  length: 'medium', // 'short' | 'medium' | 'long'
  sharedContext: 'Eres asistente de servicio al cliente de TechCorp',
});

const response = await writer.write(
  'Generar respuesta sobre política de devoluciones',
  {
    context:
      'El cliente compró hace 15 días. Política: 30 días para devoluciones.',
  }
);

La combinación de sharedContext (definido en create()) y context (por llamada) te permite:

  • sharedContext: Define el "rol" o contexto global que se mantiene para todas las generaciones
  • context: Información específica de cada petición que cambia dinámicamente

Esto es más eficiente que repetir el contexto global en cada llamada, y te permite reutilizar la misma instancia de Writer para múltiples generaciones relacionadas.

Casos de Uso Típicos

  • Respuestas predefinidas: Generar variaciones de respuestas comunes en sistemas de soporte
  • Autocompletado inteligente: Sugerir continuaciones de texto basadas en contexto
  • Plantillas dinámicas: Crear contenido personalizado (emails, notificaciones) sin templates rígidos
  • Reformulación: Expresar la misma idea de diferentes maneras

3. Rewriter API: Transformación de Contenido

Rewriter API toma texto existente y lo transforma. Es el caso de uso más común en interfaces de usuario: el usuario escribe algo informal y quiere profesionalizarlo, o viceversa.

Parámetros de Transformación

const rewriter = await Rewriter.create({
  tone: 'more-formal', // 'more-formal' | 'as-is' | 'more-casual'
  format: 'markdown', // 'as-is' | 'markdown' | 'plain-text'
  length: 'shorter', // 'shorter' | 'as-is' | 'longer'
});

Nota: Los valores de tone son direccionales (more-formal, more-casual) a diferencia de Writer que usa estados absolutos (formal, casual). Esto es porque Rewriter transforma texto existente, no genera desde cero.

Patrones de Uso

1. Botón "Mejorar" en formularios:

// Inicializar una vez
const rewriter = await Rewriter.create({
  tone: 'more-formal',
  length: 'as-is',
});

// Usar en múltiples campos
document.querySelector('#enhance-btn').addEventListener('click', async () => {
  const textarea = document.querySelector('#message');
  textarea.value = await rewriter.rewrite(textarea.value);
});

2. Condensar texto manteniendo información esencial:

const rewriter = await Rewriter.create({ tone: 'as-is', length: 'shorter' });
const concise = await rewriter.rewrite(verbosoText);

3. Convertir formato (plain text → markdown):

const rewriter = await Rewriter.create({ tone: 'as-is', format: 'markdown' });

La API es particularmente útil porque no requieres diseñar prompts específicos como "haz este texto más formal pero mantén la misma longitud". Los parámetros declarativos manejan esto automáticamente.

4. Proofreader API: Corrección Contextual

Proofreader API va más allá de un corrector ortográfico tradicional. Entiende gramática compleja, contexto, y puede explicar cada error detectado. Es la API más ligera de todas, optimizada para latencia mínima.

Estructura de Respuesta

const proofreader = await Proofreader.create({
  includeCorrectionTypes: true, // Clasificar errores
  includeCorrectionExplanations: true, // Generar explicaciones
  expectedInputLanguages: ['en'],
  correctionExplanationLanguage: 'es',
});

const result = await proofreader.proofread('I seen him yesterday at the store');

console.log(result.correctedInput);
// "I saw him yesterday at the store."

console.log(result.corrections);
// [{
//   startIndex: 2,
//   endIndex: 6,
//   correction: 'saw',
//   type: 'grammar',
//   explanation: 'El verbo "see" en pasado simple es "saw", no "seen"...'
// }]

Tipos de Error Detectados

La API clasifica errores en categorías específicas, lo que te permite:

  • spelling: Errores ortográficos (typos, palabras mal escritas)
  • grammar: Errores gramaticales (tiempo verbal, concordancia)
  • punctuation: Puntuación incorrecta o faltante
  • capitalization: Uso incorrecto de mayúsculas
  • preposition: Preposiciones incorrectas
  • missing-words: Palabras omitidas que afectan comprensión

Esto permite implementar UX sofisticadas: mostrar diferentes íconos por tipo de error, filtrar errores por severidad, o aplicar correcciones selectivamente.

Ventajas vs Correctores Tradicionales

Los correctores ortográficos tradicionales funcionan con diccionarios y reglas. Proofreader API entiende contexto:

  • Detecta errores que dependen del significado, no solo de la gramática formal
  • Sugiere correcciones que mantienen la intención original
  • Puede explicar POR QUÉ algo es incorrecto (valioso para aprendizaje)

La trade-off es latencia: un corrector basado en reglas es instantáneo, Proofreader API requiere inferencia del modelo (aunque está optimizada para ser la más rápida de las Task APIs).

Comparativa: ¿Cuándo Usar Qué?

TareaPrompt APITask API RecomendadaRazón
Chatbot conversacional✅ Sí❌ NoRequiere contexto multi-turno
Resumir artículo⚠️ PosibleSummarizerModelos más ligeros, tipos de resumen configurables
Generar respuesta predefinida⚠️ PosibleWriterOptimizado para creación, no conversación
Cambiar tono de mensaje⚠️ PosibleRewriterTransformación específica, parámetros declarativos
Corregir gramática/ortografía⚠️ PosibleProofreaderMás ligero, errores tipados, explicaciones
Extracción de datos (JSON)✅ Sí❌ NoRequiere JSON Schema (solo Prompt API)
RAG con múltiples pasos✅ Sí❌ NoRequiere contexto persistente

Estrategias de Implementación

1. Progressive Enhancement

No asumas que todos tus usuarios tendrán Built-in AI disponible. Implementa detección y fallback:

async function enhanceText(text) {
  if ('Rewriter' in self) {
    try {
      const availability = await Rewriter.availability();
      if (availability !== 'unavailable') {
        const rewriter = await Rewriter.create({ tone: 'more-formal' });
        const result = await rewriter.rewrite(text);
        rewriter.destroy();
        return { result, source: 'local' };
      }
    } catch (error) {
      console.warn('Local AI failed:', error);
    }
  }

  // Fallback a Cloud API
  return { result: await cloudEnhance(text), source: 'cloud' };
}

2. Lazy Loading con Cleanup Automático

Para funcionalidades secundarias, carga la API solo cuando el usuario la necesita:

class LazyRewriter {
  constructor() {
    this.instance = null;
    this.lastUsed = Date.now();
  }

  async rewrite(text) {
    if (!this.instance) {
      this.instance = await Rewriter.create({ tone: 'more-formal' });
    }
    this.lastUsed = Date.now();
    this.scheduleCleanup();
    return await this.instance.rewrite(text);
  }

  scheduleCleanup() {
    clearTimeout(this.timer);
    this.timer = setTimeout(
      () => {
        if (Date.now() - this.lastUsed > 5 * 60 * 1000) {
          // 5 min inactivo
          this.instance?.destroy();
          this.instance = null;
        }
      },
      5 * 60 * 1000
    );
  }
}

3. Batch Processing con sharedContext

Cuando procesas múltiples documentos similares, aprovecha sharedContext para eficiencia:

const summarizer = await Summarizer.create({
  type: 'tldr',
  sharedContext: 'Feedback de usuarios sobre la versión beta',
});

// Procesar lote sin repetir contexto
const summaries = await Promise.all(
  feedbackList.map(f => summarizer.summarize(f))
);

Consideraciones de Producción

Requisitos de Hardware

Las Task APIs comparten las mismas restricciones que Prompt API:

  • Almacenamiento: Mínimo 22GB libres
  • GPU: >4GB VRAM, o CPU con 16GB RAM + 4+ núcleos
  • Sistema Operativo: Windows 10+, macOS 13+, Linux, ChromeOS

En producción, Chrome solo activará las APIs en hardware compatible. Por eso el fallback no es opcional, es crítico.

UX de Descarga

Si el modelo no está descargado, la primera llamada a create() requiere user activation (click del usuario). Implementa una UX clara:

const availability = await Rewriter.availability();

if (availability === 'downloadable') {
  showDownloadButton('Habilitar mejora de texto (descarga única)', async () => {
    await Rewriter.create({
      monitor: m =>
        m.addEventListener('downloadprogress', e =>
          updateProgress(Math.round(e.loaded * 100))
        ),
    });
  });
}

Streaming para UX Responsive

Todas las APIs soportan streaming (summarizeStreaming(), writeStreaming(), rewriteStreaming()). Para operaciones que toman más de 1-2 segundos, streaming mejora significativamente la percepción de velocidad:

const stream = summarizer.summarizeStreaming(longDocument);
for await (const chunk of stream) {
  outputElement.textContent += chunk; // Texto aparece progresivamente
}

Conclusión

Las Task APIs representan un balance ideal entre potencia y especialización:

  • Summarizer: 4 tipos de resumen configurables (key-points, tldr, teaser, headline) con manejo de contexto compartido
  • Writer: Generación de contenido con control fino de tono, formato y longitud
  • Rewriter: Transformación de texto existente con parámetros direccionales
  • Proofreader: Corrección con clasificación de errores y explicaciones pedagógicas

La diferencia fundamental con Prompt API es que estas APIs son stateless y están afinadas para tareas específicas. Esto se traduce en modelos más ligeros, mejor calidad en su dominio, y APIs más simples de usar.

Úsalas cuando la tarea encaje perfectamente en su especialización. Usa Prompt API cuando necesitas flexibilidad, contexto persistente, o capacidades que las Task APIs no ofrecen (JSON Schema, Tool Use, conversaciones multi-turno).

Con estas herramientas, puedes construir experiencias de escritura asistida, resumen inteligente y corrección automática completamente client-side, manteniendo privacidad total y disponibilidad offline.

Comments

Share your thoughts and join the discussion


Related Posts