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ápsula | Tema | Lo que aprenderás |
|---|---|---|---|
| 01 | Introducción | Un prompt no basta | Principios de composición |
| 02 | Prompt chaining | Output → Input | Sequential, conditional, parallel |
| 03 | Decomposition | Framework para descomponer | Identificar sub-tareas, interfaces |
| 04 | Pipelines multi-etapa | Orchestration, state, retry | PipelineState, manejo de errores |
| 05 | Context window management | Summarization, sliding window | Procesar documentos largos |
| 06 | Multi-turn strategies | Memoria, pruning | Conversaciones largas |
| 07 | Routing por complejidad | Modelo económico vs potente | Optimización de costos |
| 08 | Proyecto | Multi-Stage Analysis Pipeline | Sistema 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:
- Divide en 4 sub-tareas
- Define el schema de output de cada una (como Python dict)
- 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 chaining | Sí (Cápsulas 02-03) | Este módulo |
| Pipelines multi-etapa con state y retry | Sí (Cápsula 04) | Este módulo |
| Context window management | Sí (Cápsula 05) | Este módulo |
| Multi-turn memory strategies | Sí (Cápsula 06) | Este módulo |
| Routing por complejidad | Sí (Cápsula 07) | Este módulo |
| Evaluación de calidad por etapa | No | Módulo 07 (Evaluation) |
| Caching entre etapas de pipeline | No | Módulo 08 (Production) |
| Frameworks como LangChain o LlamaIndex | No | Se 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
- Least-to-Most Prompting (Zhou et al., 2022) - Decomposition sistemática
- LangChain LCEL Documentation - Framework para chaining
- OpenAI Cookbook - Building production systems
- Pydantic Documentation - Validación de outputs
- Python asyncio documentation - Para ejecución paralela
- Prompt Engineering Guide - Chaining