Contacto

Prompt Chaining: cuando un solo prompt no alcanza

prompt_chaining_b

Prompt Chaining: cuando un solo prompt no alcanza

Prompt Chaining (Pipeline Pattern) es una técnica que descompone tareas complejas en secuencias de prompts focalizados donde la salida de cada paso alimenta al siguiente. Resuelve instruction neglect, contextual drift y error propagation — los tres fallos sistémicos de los prompts monolíticos en LLMs.

Le pides a un modelo que extraiga datos, los transforme, los analice y redacte un resumen. Y obtienes una respuesta que hace bien la primera parte, mediocremente la segunda, y directamente ignora la tercera. No es un bug. Es lo que sucede cuando un generador autoregresivo intenta cumplir instrucciones concurrentes dentro de una misma ventana de contexto.

Descompones la tarea en pasos secuenciales. Cada paso tiene un prompt focalizado, un rol definido, y su salida alimenta al siguiente. La idea no es complicada; lo difícil es mantener el rigor entre pasos.


Lo que rompe en un prompt monolítico

Un prompt monolítico concentra múltiples instrucciones en una sola llamada. El modelo recibe: «extrae especificaciones, conviértelas a JSON, identifica tendencias, redacta un resumen». Y lo que ocurre después es predecible.

  • Instruction neglect: el modelo cumple mejor las instrucciones del principio y del final. Las del medio se degradan. Si tu prompt tiene cuatro tareas, las centrales son las primeras en sufrir.
  • Contextual drift: a medida que la respuesta crece, el modelo pierde el foco. La salida se vuelve progresivamente menos coherente con la instrucción original, especialmente cuando debe mantener múltiples contextos simultáneamente.
  • Error propagation: si la extracción de datos falla — un campo mal nombrado, un tipo incorrecto — la transformación y el análisis downstream también fallan, y el modelo no tiene mecanismo para detectar que su propia entrada intermedia es inválida.

Estos no son fallos aleatorios. Son consecuencias de la arquitectura: los LLMs completan patrones, no ejecutan instrucciones múltiples con validación intermedia.


Cómo funciona (en la práctica)

La descomposición sigue tres reglas que suenen obvias hasta que las rompes:

  • Un prompt, una operación. Si un paso requiere más de una operación semántica, se divide. Esto elimina la competencia entre instrucciones dentro del mismo prompt.
  • Handoff estructurado. La salida de cada paso es un objeto parseable, no texto libre. JSON en el 95% de los casos. XML solo compensa en entornos enterprise heredados o cuando necesitas validación XSD.
  • Roles por etapa. El primer paso es un «Analista de Extracción». El segundo, un «Transformador de Esquemas». El tercero, un «Analista de Tendencias». La asignación de roles mejora la focalización del modelo en cada etapa. No es un truco de prompt engineering — funciona porque cambia el espacio de activación del modelo.

El flujo resultante es lineal y determinista. Cada transición es explícita, validable y trazable. Y aquí es donde la teoría choca con la realidad: cada paso es una llamada al modelo, y cada llamada puede fallar de formas diferentes.


Salidas estructuradas: donde se gana o se pierde

El punto más frágil de cualquier cadena no es el razonamiento del modelo. Son las interfaces entre pasos.

Un modelo puede devolver un diccionario Python en lugar de JSON. Puede añadir comentarios narrativos alrededor de los datos. Puede cambiar cpu a processor entre ejecuciones. Variaciones que parecen menores pero rompen el consumidor downstream.

La solución es validación tipada. En Python, Pydantic permite definir esquemas y parsear directamente contra ellos, garantizando structured output entre pasos:

from pydantic import BaseModel, Field, ValidationError
import logging

logger = logging.getLogger(__name__)

class Specs(BaseModel):
    cpu: str
    memory_gb: int = Field(ge=1, le=512)
    storage_tb: float = Field(ge=0.1, le=20)

def validate_extraction(response: str) -> Specs:
    try:
        return Specs.model_validate_json(response)
    except ValidationError as e:
        logger.error(f"Extraction failed validation: {e}")
        raise

Cuando la validación falla, tienes tres opciones: reintentar con feedback del error, aplicar un fallback, o abortar. La elección depende de si el fallo es recuperable y de cuánto te importa ese dato en particular.

En producción, el mayor problema no suele ser el razonamiento del modelo sino la estabilidad de estas interfaces. He visto pipelines romperse durante días porque un modelo empezó a devolver null en lugar de string vacío tras una actualización silenciosa de la versión. Un cambio mínimo en un nombre de campo rompe silenciosamente todo el pipeline downstream. Los tests que cubren solo el caso happy path no detectan esto.


Patrones que realmente se usan

Existen varias formas de orquestar una cadena. En la práctica, la mayoría de pipelines útiles siguen siendo lineales. Los grafos complejos suelen introducir más problemas de observabilidad que beneficios reales.

  • Lineal: secuencia estricta. Extracción, transformación, análisis. Es fácil de depurar, fácil de monitorizar, y cada paso tiene un contrato claro. Cuando funciona, funciona.
  • Con validación intermedia: añade un paso de verificación entre cada etapa. Si falla, reintenta con el error como contexto. Añade latencia pero previene errores silenciosos. Útil cuando el costo de corregir downstream supera el costo de validar upstream.
  • Con paralelización: etapas independientes se ejecutan concurrente y convergen en un paso de síntesis. Parece atractivo hasta que aparecen inconsistencias semánticas entre ramas. Dos pasos paralelos pueden interpretar el mismo término técnico de forma distinta y romper la síntesis final. Úsalo solo cuando la independencia sea real, no aparente.

LangChain implementa paralelización con RunnableParallel. LangGraph lo modela como nodos independientes que convergen en un nodo de unión. Ambos funcionan. Elige según necesites estado compartido o no.


Lo que suele romperse en producción

Esta es la parte que los tutoriales no cubren.

  • JSON parcialmente válido. El modelo devuelve JSON sintácticamente correcto pero con campos faltantes o tipos incorrectos. model_validate_json() captura esto, pero muchos pipelines usan json.loads() y asumen que «si no explota, está bien». No lo está.
  • Retries infinitos. Un paso falla la validación, se reintenta, falla de nuevo, se reintenta… sin límite. El pipeline se queda en bucle consumiendo tokens y tiempo. Siempre establece un máximo de reintentos y un timeout global.
  • Schemas demasiado rígidos. Un esquema que exige exactamente 5 campos rompe cuando el modelo extrae 4 porque el quinto no estaba en el texto fuente. Los campos opcionales existen por una razón.
  • Context explosion. Cada paso añade tokens al contexto. Si no controlas el crecimiento, llegas al límite del modelo en el paso 4 de 6. La solución no es aumentar el contexto — es seleccionar qué datos realmente necesita cada paso.
  • Inconsistencia entre modelos. Un pipeline que funciona con GPT-4 puede fallar con Llama 3 8B. Los modelos pequeños son más propensos a errores de formato. Si usas chaining con modelos locales, valida más agresivamente entre pasos.
  • Prompts incompatibles entre versiones. Un prompt que funcionaba con una versión del modelo puede degradarse con la siguiente. La primera vez que esto te pasa en producción, tiendes a culpar al modelo. En realidad es un problema de versionado — los prompts necesitan los mismos tests de regresión que cualquier otro código.

Context Engineering

Gestionar qué información llega a cada paso es probablemente la parte más subestimada del diseño de pipelines. Un pipeline puede tener la arquitectura perfecta y romperse porque un paso recibe 12.000 tokens de contexto cuando solo necesitaba 200.

  • Selección mínima. Cada paso recibe solo lo que necesita, no todo el contexto acumulado. Los LLMs prestan más atención al inicio y final del prompt que al medio — el fenómeno «lost in the middle» — así que si un paso de análisis recibe 5.000 palabras de texto original junto con 200 palabras de datos extraídos, probablemente ignora los datos estructurados. La solución es extraer solo los campos relevantes antes de pasarlos al siguiente paso.
  • Compresión semántica. En lugar de pasar datos crudos entre pasos, puedes resumirlos semánticamente. Si un paso de extracción encuentra 50 entidades pero el siguiente solo necesita las 10 más relevantes, un paso intermedio de clasificación reduce el volumen sin perder información crítica. La compresión semántica consume tokens adicionales, pero preserva el significado. En la práctica, el trade-off vale la pena cuando la precisión downstream es prioritaria.
  • Aislamiento de contexto. Otra decisión arquitectónica es si los pasos comparten un pool de contexto o si cada paso tiene su propio contexto aislado. Compartido simplifica el diseño pero aumenta el riesgo de contaminación: un paso puede depender implícitamente de información que otro paso modificó. Aislado es más estricto pero más predecible. En producción, el aislamiento gana porque hace las dependencias explícitas y facilita la depuración: si un paso falla, sabes exactamente qué datos recibió.
  • Retrieval selectivo. Cuando un paso necesita información externa, no cargues todo. Recupera solo lo relevante para ese paso específico. Si el paso 2 necesita referencias de mercado pero el paso 3 necesita datos históricos, cada uno recupera de su propia fuente en lugar de cargar ambas al inicio. Esto reduce el consumo de tokens y evita que información irrelevante interfiera con el razonamiento del modelo.
  • Token budgeting. Cada paso consume tokens. Si no controlas el presupuesto, llegas al límite del modelo antes de terminar la cadena. Asigna un presupuesto por paso y monitoriza el consumo acumulado. LangChain lo hace con CallbacksHandler, LangGraph persiste el estado del grafo, y sin framework un logger estructurado con conteos de input/output tokens basta para detectar cuándo estás cerca del límite. Cuando lo estás, activa la compresión semántica o el truncamiento inteligente.
  • Context poisoning. Un riesgo silencioso es la contaminación del contexto: cuando un paso anterior introduce información incorrecta o irrelevante que los pasos posteriores heredan sin cuestionar. Especialmente problemático cuando un paso de generación narrativa consume datos extraídos con baja confianza. La mitigación es marcar la confianza de los datos en los metadatos y dejar que los pasos downstream ajusten su comportamiento. Si los datos son inciertos, el paso de narrativa lo señala explícitamente en su salida.
  • State persistence. En pipelines que se ejecutan en múltiples sesiones — un pipeline que se interrumpe y reanuda — el estado debe persistir entre ejecuciones. LangGraph lo hace nativamente con su sistema de estado serializable. Sin framework, un archivo JSON o una base de datos ligera con el estado de cada paso permite reanudar desde el último punto válido en lugar de reiniciar desde cero.

Registra entradas, salidas, tokens y tiempo por paso. Como metadatos externos, no dentro del contexto del modelo. Sin observabilidad, no sabes qué paso introdujo un error hasta que el pipeline termina — y para entonces, el contexto original ya no está disponible.


Chaining vs agentes: la verdad incómoda

Muchos workflows etiquetados como «AI agents» son realmente árboles de decisión con branding.

La diferencia real es quién controla el flujo. En chaining, es código determinista: defines cada paso y sus transiciones. En agentic workflows, es el modelo: genera un pensamiento, elige una herramienta, ejecuta, observa, repite. Patrones como ReAct son el backbone de esto.

Chaining gana en predictibilidad. Cada ejecución sigue el mismo camino, los fallos son reproducibles, el presupuesto de tokens es fijo. Los agentes ganan en flexibilidad — pueden adaptarse a situaciones no previstas o cambiar de estrategia a mitad del flujo — pero esa flexibilidad tiene un precio: bucles de razonamiento prolongados, costos impredecibles, y fallos que requieren registrar el trace completo de decisiones para depurar.

CriterioPrompt ChainingAgentes
Control de flujoCódigo deterministaModelo (ReAct)
PredictibilidadAltaBaja
Costo de tokensFijoVariable
FlexibilidadBajaAlta
ObservabilidadDirectaRequiere trace completo

La elección depende de la tarea. Flujo conocido y estable — extracción de datos, generación de reportes con estructura fija — chaining. Flujo dinámico — investigación abierta, diagnóstico con múltiples causas — agentes. Un enfoque híbrido es válido: chaining para la parte predecible, agente para la que necesita adaptación. He visto equipos invertir semanas en sistemas agénticos que resuelven el 10% de los casos, cuando un pipeline lineal cubría el 90%.

Sobre RAG: RAG añade conocimiento externo al contexto. Chaining estructura el flujo de procesamiento. Se combinan frecuentemente: paso 1 recupera documentos con RAG, paso 2 extrae datos, paso 3 genera análisis. No compiten.


Cuándo no usarlo

Cuando un solo prompt bien diseñado resuelve la tarea. Si un modelo capaz puede extraer, analizar y redactar en una invocación con resultados aceptables, añadir una cadena introduce latencia y complejidad innecesaria.

La señal de que necesitas chaining es clara: un prompt monolítico produce resultados inconsistentes, o la tarea requiere operaciones que el modelo no puede realizar con precisión en un solo paso.

Sobre la longitud: no hay un número mágico, pero cadenas de más de 7 pasos comienzan a sufrir. La métrica práctica no es el número de pasos, sino el tiempo total de ejecución y la tasa de errores por paso. Si necesitas más de 7, probablemente puedes fusionar pasos adyacentes o paralelizar los independientes.

Y sí, funciona con modelos pequeños. De hecho, es donde su ventaja es mayor: dividir una tarea compleja en pasos simples se alinea con las capacidades de modelos como Llama 3 8B o Qwen 2.5 7B. Solo valida más agresivamente entre pasos.


Preguntas frecuentes sobre Prompt Chaining

¿Cuándo usar Prompt Chaining en lugar de un solo prompt?

Cuando un prompt monolítico produce resultados inconsistentes, omite instrucciones intermedias (instruction neglect) o la tarea requiere más de 3 operaciones semánticas distintas. La señal clara es cuando el modelo cumple bien la primera y última instrucción pero falla las centrales.

¿Prompt Chaining funciona con modelos locales como Llama 3 o Qwen?

Sí, y es donde su ventaja es mayor. Los modelos pequeños (7B-8B parámetros) son más propensos a errores de formato en tareas complejas. Dividir la tarea en pasos simples se alinea con sus capacidades. Requiere validación más agresiva entre pasos con Pydantic o esquemas tipados.

¿Cuál es la diferencia entre Prompt Chaining y RAG?

Son ortogonales. RAG añade conocimiento externo al contexto recuperando documentos relevantes. Prompt Chaining estructura el flujo de procesamiento en pasos secuenciales. Se combinan frecuentemente: paso 1 recupera con RAG, paso 2 extrae datos, paso 3 genera análisis.

¿Cuántos pasos debe tener una cadena de prompts?

No hay un número absoluto, pero cadenas de más de 7 pasos comienzan a sufrir en latencia y mantenimiento. La métrica práctica es el tiempo total de ejecución y la tasa de errores por paso. Si necesitas más de 7, fusiona pasos adyacentes o paraleliza los independientes.

¿Qué framework usar para Prompt Chaining: LangChain o LangGraph?

LangChain (LCEL) es suficiente para pipelines lineales y paralelización básica con RunnableParallel. LangGraph es necesario cuando necesitas estado compartido entre pasos, bucles condicionales, o reanudación de pipelines interrumpidos. Para la mayoría de casos, LangChain es suficiente.

¿Cómo validar la salida de un LLM en Prompt Chaining?

Con esquemas tipados. En Python, Pydantic permite definir clases con anotaciones de tipo y usar model_validate_json() para parsear directamente la respuesta del modelo. Si la validación falla, captura ValidationError con información precisa sobre qué campo falló. Nunca uses solo json.loads() asumiendo que el JSON es válido.


Conclusión

Prompt Chaining no hace más inteligente al modelo. Hace más controlable el sistema. En producción, eso suele importar más.

El patrón es independiente de herramienta: funciona con llamadas secuenciales a cualquier API, validación con Pydantic o cualquier esquema tipado, y orquestación con código Python estándar. LangChain y LangGraph simplifican los prototipos, pero muchas implementaciones terminan reescribiendo partes críticas por problemas de complejidad y observabilidad.

Al final, lo que marca la diferencia no es el framework que elijas, sino como defines los contratos entre pasos y qué tan agresivamente validas las transiciones.

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *