Módulo 6: Prompt Composition y Chaining

1. Introducción: Un Prompt No es Suficiente

Descripción

En módulos anteriores aprendiste técnicas avanzadas para hacer que un solo prompt sea más poderoso: Chain-of-Thought, Self-Consistency, ReAct. Pero hay una realidad fundamental que ninguna de esas técnicas puede resolver por sí sola: las tareas complejas del mundo real requieren múltiples pasos, múltiples perspectivas, y múltiples validaciones.

Este módulo introduce el concepto de Prompt Composition: el arte de diseñar sistemas donde múltiples prompts trabajan en conjunto, cada uno especializado en una parte del problema, conectados en pipelines que manejan el flujo de información de forma robusta.


Por Qué Un Prompt No Basta

Piensa en cómo resuelves un problema complejo como humano. No lo haces en un solo paso. Piensas, buscas información, sintetizas, escribes, revisas, reformateas. Cada etapa tiene su especialización.

Lo mismo aplica para los LLMs:

Razón 1: Límites del Context Window

Documento legal: 80,000 palabras (~120K tokens)
Context window gpt-4o-mini: 128K tokens
Context window gpt-4o: 128K tokens

PROBLEMA: 
- No puedes poner el documento completo + instrucciones + respuesta esperada en un solo prompt
- Incluso si cabes, el modelo pierde atención en partes lejanas del contexto (lost in the middle)
- Para documentos > 200K tokens: imposible sin procesamiento en etapas

SOLUCIÓN: Dividir en chunks, procesar cada uno, sintetizar resultados

Razón 2: Especialización por Etapa

Tarea: "Analiza este informe financiero y genera recomendaciones de inversión"

Un solo prompt intenta hacer TODO:
- Extraer métricas clave
- Entender contexto del sector
- Calcular ratios
- Comparar con benchmarks
- Generar recomendaciones
→ Resultado: análisis superficial, poco profundo en cada aspecto

Pipeline especializado:
- Prompt 1: Extrae datos numéricos (especializado en extracción)
- Prompt 2: Calcula ratios (especializado en cálculo financiero)
- Prompt 3: Interpreta tendencias (especializado en análisis)
- Prompt 4: Genera recomendaciones (especializado en síntesis)
→ Resultado: análisis más profundo, cada etapa optimizada

Razón 3: Validación Intermedia

# Sin validación intermedia:
resultado = un_prompt_enorme(documento)  # Si falla, no sabes dónde

# Con pipeline y validación:
extracto = extraer(documento)
assert extracto tiene_formato_correcto()

analisis = analizar(extracto)
assert analisis.score_confianza > 0.7

reporte = generar_reporte(analisis)
# Si falla en analizar, el error es claro y se puede reintentar solo esa etapa

Razón 4: Error Handling por Etapa

Sin pipeline: Si hay un error, todo el proceso falla y pierdes todo el trabajo.

Con pipeline: Si falla la etapa 3 de 5, retries solo en esa etapa,
              las etapas 1, 2 ya están completadas y cacheadas.
              
Esto es crítico para documentos largos donde cada etapa puede costar
$0.10 en llamadas API. No quieres perder el trabajo previo.

Decomposition: El Principio Central

La decomposition es el proceso de dividir una tarea compleja en sub-tareas manejables, cada una con:

  • Un input claro y bien definido
  • Un prompt especializado
  • Un output con schema validable
  • Dependencias explícitas con otras sub-tareas
Ejemplo: Sistema de análisis de artículos de noticias

Tarea compleja:
"Analiza este artículo y genera: resumen ejecutivo, análisis de sesgo,
 extracción de hechos verificables, e impacto potencial"

Decomposition en sub-tareas:

Sub-tarea 1: Extracción de entidades
  Input: Artículo completo
  Output: {personas, organizaciones, fechas, ubicaciones, cifras}
  Prompt: Especializado en NER (Named Entity Recognition)
  Independiente de: Nada
  
Sub-tarea 2: Resumen ejecutivo (puede correr en paralelo con 3 y 4)
  Input: Artículo completo
  Output: {titulo, puntos_clave: [str], longitud: "3 oraciones"}
  Prompt: Especializado en summarization
  Independiente de: Sub-tareas 3, 4
  
Sub-tarea 3: Análisis de sesgo
  Input: Artículo + entidades extraídas (de Sub-tarea 1)
  Output: {sesgo_detectado: bool, tipo_sesgo: str, evidencia: [str]}
  Prompt: Especializado en análisis crítico de medios
  Depende de: Sub-tarea 1

Sub-tarea 4: Verificación de hechos
  Input: Artículo + entidades + resumen
  Output: {hechos_verificables: [{hecho: str, verificable: bool}]}
  Depende de: Sub-tareas 1, 2
  
Sub-tarea 5: Síntesis final
  Input: Outputs de todas las sub-tareas anteriores
  Output: Reporte estructurado
  Depende de: Todas

Los Patrones de Composición

En este módulo aprenderás cuatro patrones fundamentales:

Patrón 1: Sequential Chaining (A → B → C)

El output de cada etapa es el input de la siguiente. Es el patrón más simple y común.

Input → [Extraer] → datos → [Analizar] → análisis → [Reportar] → Output

Cuándo usar: Cuando cada etapa depende del output de la anterior y no hay paralelización posible.

Patrón 2: Parallel Processing (A, B, C → síntesis)

Múltiples prompts se ejecutan simultáneamente sobre el mismo input, luego se combinan.

         ┌→ [Resumen] ─────────┐
Input ───┤→ [Análisis de sesgo] ├→ [Síntesis] → Output
         └→ [Extracción NER] ──┘

Cuándo usar: Cuando múltiples análisis son independientes entre sí. Reduce latencia significativamente.

Patrón 3: Conditional Branching (if/else)

El camino del pipeline se bifurca según el contenido del input.

Input → [Clasificar] → LARGO? → [Resumir] → [Analizar]
                     → CORTO? → [Analizar directamente]

Cuándo usar: Cuando distintos tipos de input requieren procesamiento diferente.

Patrón 4: Iterative Refinement (loop)

Un prompt se aplica repetidamente hasta alcanzar un criterio de calidad.

Input → [Generar] → [Evaluar] → score < 0.8? → [Refinar] → [Evaluar] → ...
                              → score ≥ 0.8? → Output

Cuándo usar: Cuando la calidad inicial es insuficiente y se puede mejorar iterativamente.


Roadmap del Módulo 6

#CápsulaTemaLo que aprenderás
01IntroducciónUn prompt no bastaPrincipios de composición
02Prompt chainingOutput → InputSequential, conditional, parallel
03DecompositionFramework para descomponerIdentificar sub-tareas, interfaces
04Pipelines multi-etapaOrchestration, state, retryPipelineState, manejo de errores
05Context window managementSummarization, sliding windowProcesar documentos largos
06Multi-turn strategiesMemoria, pruningConversaciones largas
07Routing por complejidadModelo económico vs potenteOptimización de costos
08ProyectoMulti-Stage Analysis PipelineSistema completo de análisis

Prerequisitos del Módulo

Antes de continuar, asegúrate de estar cómodo con:

  • Python async/await: Para parallel chaining con asyncio
  • Pydantic BaseModel: Para validar outputs entre etapas
  • try/except en Python: Para manejo de errores robusto
  • OpenAI SDK: from openai import OpenAI, AsyncOpenAI

Primer Experimento: Un Prompt vs Pipeline

Para que veas la diferencia de inmediato, compara estos dos enfoques para analizar un texto:

from openai import OpenAI

client = OpenAI()

texto = """La empresa XYZ reportó ingresos de $5.2M en Q3, un aumento del 34% 
respecto al año anterior. Sin embargo, los gastos operativos crecieron 45%, 
reduciendo el margen de beneficio a 12%. El CEO mencionó planes de expansión 
a mercados LATAM para Q1 del próximo año."""

# Enfoque 1: Un solo prompt (todo junto)
response_unico = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": f"""Analiza este texto y genera:
1. Datos clave extraídos
2. Análisis de tendencias
3. Recomendaciones accionables

Texto: {texto}"""}],
    temperature=0
)
print("=== UN SOLO PROMPT ===")
print(response_unico.choices[0].message.content[:300])

# Enfoque 2: Pipeline de 3 etapas
# Etapa 1: Extracción
extracto = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": f"Extrae SOLO los datos numéricos y hechos concretos:\n{texto}"}],
    temperature=0
).choices[0].message.content

# Etapa 2: Análisis (recibe solo los datos, no el texto original)
analisis = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": f"Analiza tendencias y riesgos en estos datos:\n{extracto}"}],
    temperature=0
).choices[0].message.content

# Etapa 3: Recomendaciones (recibe el análisis, no los datos crudos)
recomendaciones = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": f"Genera 3 recomendaciones accionables:\n{analisis}"}],
    temperature=0
).choices[0].message.content

print("\n=== PIPELINE 3 ETAPAS ===")
print(f"Extracto: {extracto[:100]}...")
print(f"Análisis: {analisis[:100]}...")
print(f"Recomendaciones: {recomendaciones[:100]}...")

Con un texto corto, ambos enfoques producen resultados similares. La diferencia se hace evidente con documentos largos, tareas complejas, o cuando necesitas validación intermedia.


Caso de Uso Real: Plataforma de Content Intelligence

Para dar contexto concreto, aquí hay un sistema real que usa todos los patrones del módulo:

Sistema de análisis de contenido para una empresa de media:

Módulo de ingesta:
  Input: Artículo, video transcript, o PDF
  
Pipeline de procesamiento:
  1. Classify (condicional): ¿Qué tipo de contenido es?
  2. Normalize (sequential): Convertir a formato estándar
  3. Parallel analysis:
     a. Extract entities (NER)
     b. Generate summary (3 niveles de longitud)
     c. Detect sentiment & tone
     d. Calculate readability scores
  4. Context enrichment (ReAct con búsqueda): Añadir contexto externo
  5. Quality check (Self-Refine): Verificar y mejorar si es necesario
  6. Format output (sequential): JSON estructurado para la API

Context management:
  - Artículos < 2K tokens: Procesar directamente
  - Artículos 2K-30K tokens: Sliding window
  - Artículos > 30K tokens: Hierarchical summarization

Ejercicios de Calentamiento

Ejercicio 1: Identificar el patrón correcto

Para cada uno de los siguientes sistemas, identifica qué patrón de composición usarías:

a) Transcribir un audio, traducirlo, y generar subtítulos b) Analizar simultáneamente el tono, las entidades, y el resumen de un email c) Procesar un documento que puede ser en inglés o español con flujos distintos d) Mejorar la calidad de un código hasta que pase todos los tests

Ver solución

a) Sequential chaining: Cada etapa depende de la anterior (primero transcribir, luego traducir, luego generar subtítulos).

b) Parallel processing: Tono, entidades, y resumen son análisis independientes del mismo input. Se pueden ejecutar simultáneamente con asyncio.

c) Conditional branching: Detectar el idioma primero, luego bifurcar hacia el flujo en inglés o español.

d) Iterative refinement: Generar código → ejecutar tests → si fallan, refinar → repetir hasta que pasen.

Ejercicio 2: Diseñar las interfaces

Para un pipeline de análisis de CVs que produce: clasificación por rol, score de idoneidad, puntos fuertes/débiles, y preguntas de entrevista sugeridas:

  1. Divide en 4 sub-tareas
  2. Define el schema de output de cada una (como Python dict)
  3. Especifica las dependencias entre sub-tareas
Ver solución
# Sub-tarea 1: Extracción de información
schema_extraccion = {
    "nombre": str,
    "años_experiencia": int,
    "skills": list[str],
    "educacion": list[dict],  # [{institucion, titulo, año}]
    "empresas_anteriores": list[dict]  # [{empresa, rol, duración}]
}
# Dependencias: ninguna

# Sub-tarea 2: Clasificación de rol (puede correr en paralelo con sub-tarea 1)
schema_clasificacion = {
    "rol_principal": str,   # "backend_dev", "data_scientist", etc.
    "nivel": str,           # "junior", "mid", "senior"
    "confianza": float      # 0-1
}
# Dependencias: ninguna (opera sobre el CV crudo)

# Sub-tarea 3: Score de idoneidad
schema_score = {
    "score_total": float,   # 0-100
    "score_tecnico": float,
    "score_experiencia": float,
    "puntos_fuertes": list[str],
    "puntos_debiles": list[str]
}
# Dependencias: Sub-tarea 1 (extracción), Sub-tarea 2 (clasificación)

# Sub-tarea 4: Preguntas de entrevista
schema_preguntas = {
    "preguntas_tecnicas": list[str],
    "preguntas_experiencia": list[str],
    "preguntas_red_flags": list[str]  # Para investigar puntos débiles
}
# Dependencias: Sub-tarea 1, Sub-tarea 3

Resumen

En este módulo aprenderás que los sistemas de IA más potentes no son los que tienen el prompt más inteligente, sino los que orquestan múltiples prompts especializados de forma robusta.

Los conceptos clave:

  • Decomposition: Dividir tareas complejas en sub-tareas con inputs/outputs claros
  • Sequential chaining: Output de A es input de B
  • Parallel processing: A, B, C se ejecutan simultáneamente sobre el mismo input
  • Conditional branching: El camino varía según el contenido
  • Iterative refinement: Loop hasta alcanzar calidad mínima
  • Context management: Estrategias para documentos que exceden el context window
  • Error handling: Retry por etapa, fallback, validación con Pydantic

Qué NO Cubre Este Módulo

Tema¿Se cubre?Dónde se ve
Sequential, parallel, conditional chainingSí (Cápsulas 02-03)Este módulo
Pipelines multi-etapa con state y retrySí (Cápsula 04)Este módulo
Context window managementSí (Cápsula 05)Este módulo
Multi-turn memory strategiesSí (Cápsula 06)Este módulo
Routing por complejidadSí (Cápsula 07)Este módulo
Evaluación de calidad por etapaNoMódulo 07 (Evaluation)
Caching entre etapas de pipelineNoMódulo 08 (Production)
Frameworks como LangChain o LlamaIndexNoSe usan APIs directas

Este módulo te enseña los fundamentos de composición usando Python puro y la API de OpenAI. Entender estos fundamentos es lo que te permite luego usar cualquier framework con comprensión profunda, en vez de ser dependiente de abstracciones que no entiendes.


Preguntas Frecuentes

¿Por qué no usar LangChain directamente? Porque LangChain abstrae los patrones que necesitas entender. Si sabes construir un pipeline manualmente con estado, retry y context management, puedes usar LangChain (o cualquier framework) de forma informada. Si no lo entiendes, estás atado a una abstracción que puede cambiar o romperse.

¿Cuándo vale la pena un pipeline vs. un solo prompt? Cuando la tarea tiene al menos una de estas características: (1) el input excede el 50% del context window, (2) la tarea tiene sub-tareas claramente diferenciadas, (3) necesitas validación intermedia, o (4) distintas partes se benefician de diferentes modelos o temperaturas.

¿Los pipelines son más lentos que un solo prompt? Sí en latencia total, pero son más confiables. Un pipeline de 4 etapas tarda más que un solo prompt, pero si una etapa falla, solo reintentas esa etapa. Con un solo prompt, si falla, pierdes todo el cómputo.

¿Puedo usar async para acelerar los pipelines? Sí. Las etapas independientes (parallel pattern) pueden ejecutarse con asyncio.gather(). La Cápsula 02 muestra cómo implementar esto.


Recursos adicionales

  1. Least-to-Most Prompting (Zhou et al., 2022) - Decomposition sistemática
  2. LangChain LCEL Documentation - Framework para chaining
  3. OpenAI Cookbook - Building production systems
  4. Pydantic Documentation - Validación de outputs
  5. Python asyncio documentation - Para ejecución paralela
  6. Prompt Engineering Guide - Chaining