Renderz Studio
Academia
Proyectos
Servicios
Arsenal
Repo
Herramientas
Skills
El Oráculo
Guía Gratis
← El Arsenal
AutomatizaciónExperto50 min

Pipeline de Contenido Autónomo

Curación · Generación · QA · Publicación · sin tocar un botón

ContenidoPipelineAutonomía
✓ Guía gratuita · Acceso completo

Mapa rápido · salta al paso que te interese

Arquitectura del Pipeline

Las 5 etapas

Implementación completa

Código de cada etapa

QA automático

Filtros de calidad

01

Arquitectura del Pipeline: las 5 etapas

Un pipeline de contenido autónomo tiene 5 etapas. Cada una puede fallar sin tumbar el sistema. El contenido solo se publica si pasa todas las etapas.

Las 5 etapas

  1. 1. Curación: Buscar fuentes, filtrar por relevancia, extraer temas
  2. 2. Generación: Claude escribe el contenido con voz de marca
  3. 3. QA: Verificar calidad, detectar alucinaciones, validar facts
  4. 4. Formateo: Adaptar a cada dineroforma (blog, Twitter, newsletter)
  5. 5. Publicación: Postear, programar, notificar
EtapaTriggerOutputFallback
CuraciónCron 06:00 UTCLista de temasSkip día si no hay temas
GeneraciónDespués de curaciónDrafts en DBRetry 3x, luego skip
QADespués de generaciónDrafts aprobadosFlag para review manual
FormateoDespués de QAContenido formateadoUsar template default
PublicaciónCron 08:00 UTCPosts publicadosCola para retry
02

Implementación de cada etapa

Código completo de cada etapa del pipeline.

lib/pipeline/curation.ts
interface CuratedTopic {
  title: string
  source: string
  sourceUrl: string
  relevanceScore: number
  extractedAt: Date
}

const SOURCES = [
  { name: 'Hacker News', url: 'https://news.ycombinator.com/rss' },
  { name: 'TechCrunch AI', url: 'https://techcrunch.com/tag/artificial-intelligence/feed/' },
  { name: 'The Verge AI', url: 'https://www.theverge.com/ai-artificial-intelligence/rss/index.xml' },
]

export async function curateTopics(): Promise<CuratedTopic[]> {
  // 1. Fetch all feeds
  const allItems = await Promise.all(
    SOURCES.map(async (source) => {
      const feed = await fetchRSS(source.url)
      return feed.items.map(item => ({
        ...item,
        source: source.name,
      }))
    })
  )

  // 2. Flatten and dedupe
  const items = allItems.flat()
  const unique = dedupeByTitle(items)

  // 3. Score relevance with Claude
  const scored = await scoreRelevance(unique)

  // 4. Return top N
  return scored
    .filter(t => t.relevanceScore > 0.7)
    .slice(0, 5)
}

async function scoreRelevance(items: unknown[]): Promise<CuratedTopic[]> {
  const response = await anthropic.messages.create({
    model: 'claude-haiku-4-20250514', // Barato para scoring
    max_tokens: 2048,
    messages: [{
      role: 'user',
      content: `Evalúa estos títulos por relevancia para una audiencia de developers hispanohablantes interesados en IA.
Score de 0 a 1 (1 = muy relevante).

Títulos:
${items.map((i, idx) => `${idx + 1}. ${i.title}`).join('\n')}

Responde en JSON: [{ "index": 1, "score": 0.8 }, ...]`
    }]
  })

  const scores = JSON.parse(response.content[0].text)
  return items.map((item, idx) => ({
    ...item,
    relevanceScore: scores.find(s => s.index === idx + 1)?.score || 0,
    extractedAt: new Date(),
  }))
}
03

Orquestador del pipeline

lib/pipeline/orchestrator.ts
export async function runContentPipeline(): Promise<PipelineResult> {
  const results: PipelineResult = {
    curated: 0,
    generated: 0,
    qaPassed: 0,
    published: 0,
    errors: [],
  }

  try {
    // 1. Curate
    const topics = await curateTopics()
    results.curated = topics.length

    // 2. Generate
    const contents = await Promise.all(
      topics.map(t => generateContent(t).catch(e => {
        results.errors.push(`Generation failed: ${e.message}`)
        return null
      }))
    )
    const validContents = contents.filter(Boolean) as GeneratedContent[]
    results.generated = validContents.length

    // 3. QA
    const qaResults = await Promise.all(
      validContents.map(async c => ({
        content: c,
        qa: await qaContent(c),
      }))
    )
    const approved = qaResults.filter(r => r.qa.passed)
    results.qaPassed = approved.length

    // 4. Publish (only approved)
    for (const { content } of approved) {
      await publishContent(content)
      results.published++
    }

    return results

  } catch (error) {
    results.errors.push(`Pipeline failed: ${error.message}`)
    return results
  }
}

"Contenido consistente > contenido viral. Un pipeline que publica 3 piezas de calidad por semana le gana a publicar 1 hit seguido de 3 semanas de silencio."

— El Arsenal, Renderz Studio

Guías relacionadas

Agentes Autónomos

ORACLE + VERA en acción

Videos con Remotion

El componente visual

¿Quieres el sistema completo?

500+ páginas, 25 capítulos, código de producción, acceso a todas las guías del Arsenal.

Curso Completo · €29

PayPal · Acceso inmediato

¿Hablamos?