Prompt Chaining: cómo dividir una tarea compleja en pasos simples
Aprende a dividir tareas difíciles en llamadas LLM secuenciales. Con código TypeScript comentado línea a línea y sin frameworks externos.
Colaboradores: Manu Rubio
La primera vez que intenté hacer algo útil con un LLM en código, le pedí todo de golpe: “analiza esta reseña, extrae las emociones principales, clasifícala y devuelve el resultado en JSON”. El modelo lo intentó, pero en algún punto del proceso perdió el hilo, mezcló pasos y el JSON final no servía para nada. La solución no era un modelo mejor. Era dividir el problema.
Antes de empezar: para seguir este post necesitas saber qué es un LLM (un modelo de lenguaje como ChatGPT o Claude, que genera texto a partir de instrucciones) y haber escrito algo de TypeScript o JavaScript. Con eso basta.
El problema: pedirle todo de golpe
Imagínate ir al supermercado y que, justo al cruzar la puerta, alguien te grite una lista de 10 cosas distintas sin darte tiempo a anotarlas. Seguramente comprarás bien el pan y la leche, pero acabarás olvidando la mitad o comprando el producto equivocado. A los modelos de IA les pasa igual.
Cuando en un solo prompt (tu instrucción) le pides que lea, resuma, clasifique y responda, el modelo tiene que hacer malabares con demasiada información. Tarde o temprano se le cae una “pelota”, comete un error, y ese error arrastra a todo lo demás.
La solución es simple: dividir la lista. Un paso, una llamada.
Cómo funciona el encadenamiento
Piensa en el prompt chaining como una carrera de relevos. En lugar de obligar a la IA a hacer todo el esfuerzo de golpe, divides la tarea. Cada llamada a la IA hace una sola parte del trabajo y le pasa el “testigo” (su respuesta) a la siguiente llamada para que continúe. Así, paso a paso, se llega a la meta sin cometer errores.
Un ejemplo concreto. Quieres procesar los currículums que llegan a tu empresa:
-
Llamada 1: “Extrae únicamente la experiencia laboral de este documento.”
-
Llamada 2: “Calcula los años totales de experiencia basándote en ese extracto.”
-
Llamada 3: “Clasifica el perfil como Junior, Mid o Senior según esos años.”
-
Llamada 4: “Redacta un correo de seguimiento para el candidato basándote en esa clasificación.”
Cada llamada tiene una sola responsabilidad. El modelo del paso 4 no necesita leer todo el currículum de tres páginas: solo recibe la etiqueta limpia (“Senior”) del paso 3 y trabaja con eso.
Este patrón es el Pipe & Filter (tuberías y filtros). Los datos fluyen por una cadena de transformaciones simples, en lugar de pedirle a una sola IA que haga todo el trabajo pesado de golpe, lo que reduce los errores y ahorra costes.
¿Cuándo tiene sentido usarlo?
Tiene sentido en proyectos por fases. Escribir un artículo SEO requiere poner cimientos (el esquema), levantar muros (redactar) y pintar (revisar el tono). Además, te permite hacer control de calidad: si los cimientos fallan en el paso 1, paras la obra y no gastas dinero en los pasos siguientes.
También tiene sentido cuando necesitas verificar resultados intermedios. Si el paso 1 extrae entidades de un texto y el resultado llega vacío, no tiene sentido gastar dinero en los pasos 2 y 3. Puedes parar ahí.
Cuándo no usarlo es igual de importante. Si la tarea es directa (“resume esto en tres puntos”, “traduce esta frase”), un solo prompt bien escrito lo resuelve. Añadir pasos solo suma latencia y coste. Antes de diseñar un pipeline, pregúntate: ¿puedo resolverlo con una sola llamada bien estructurada? Si la respuesta es sí, hazlo así. El post sobre prompt engineering para desarrolladores cubre los patrones básicos para construir esos prompts efectivos.
El gate: cómo evitar que los errores se multipliquen
En cualquier cadena de prompts, es obligatorio validar los datos entre un paso y el siguiente. A esto lo llamamos un gate (puerta o barrera): un bloque de código que comprueba si el resultado del modelo es correcto antes de dejarle avanzar.
Sin gates ocurre esto: el paso 1 genera un texto con el formato incorrecto (lo que se llama alucinación cuando el modelo inventa o deforma la respuesta esperada). El paso 2 recibe eso como entrada y produce algo peor. El paso 3 recibe lo del paso 2. Para cuando llegas al output final, el error original se ha multiplicado y es imposible saber dónde empezó.
El gate más sencillo es una función que devuelve true o false. Si devuelve false, aplicas un early exit: sales del pipeline antes de llegar al final, devuelves un mensaje de error claro, y no gastas más llamadas ni dinero.
Los guardarrailes en agentes IA son el concepto más amplio (los límites generales sobre lo que el sistema puede hacer), pero en un pipeline secuencial el gate es su versión más concreta y práctica.
Un pipeline en TypeScript, paso a paso
Aquí tienes un ejemplo funcional. Dos pasos con un gate entre ellos, sin ningún framework, solo el SDK oficial de Anthropic:
import Anthropic from "@anthropic-ai/sdk";
// Creamos el cliente (usa la variable de entorno ANTHROPIC_API_KEY)
const client = new Anthropic();
// Helper reutilizable: manda un prompt al LLM y devuelve el texto
async function llamarLLM(prompt: string): Promise<string> {
try {
const respuesta = await client.messages.create({
model: "claude-haiku-4-5-20251001", // modelo rápido, ideal para pasos simples
max_tokens: 300, // máximo de tokens que puede generar
messages: [{ role: "user", content: prompt }],
});
// Verificamos el tipo del bloque: la API puede devolver texto, imágenes u otros tipos
const bloque = respuesta.content[0];
if (!bloque || bloque.type !== "text") {
throw new Error("El modelo no devolvió un bloque de texto");
}
return bloque.text;
} catch (error) {
throw new Error(`Error llamando al LLM: ${error instanceof Error ? error.message : String(error)}`);
}
}
// Gate: comprueba que el resumen tiene una longitud razonable
// Este gate es deliberadamente simple. En producción los gates típicos incluyen:
// regex para verificar formato esperado (/^(positivo|negativo|neutral)$/.test(output)),
// JSON.parse() para outputs estructurados (try { JSON.parse(output) } catch { early exit }),
// o una segunda llamada LLM cuando la validación requiere criterio semántico.
function esResumenValido(resumen: string): boolean {
return resumen.trim().length > 10 && resumen.length < 300;
}
async function analizarResena(resena: string) {
// En producción: valida y limita el input del usuario antes de interpolarlo
// Paso 1: resumir la reseña
const resumen = await llamarLLM(
`Resume esta reseña de cliente en una sola frase:\n\n${resena}`
);
console.log("[paso 1] resumen:", resumen);
// Gate: si el resumen no es válido, salida temprana (early exit)
if (!esResumenValido(resumen)) {
return { error: "No se pudo generar un resumen válido. Revisa el input." };
}
// Paso 2: clasificar usando SOLO el resumen, no la reseña completa
const clasificacion = await llamarLLM(
`Clasifica este texto como "positivo", "negativo" o "neutral":\n\n${resumen}`
);
return { resumen, clasificacion };
}
Fíjate en el paso 2: le pasamos resumen, no resena. El modelo de clasificación no necesita leer el texto original completo. Pasarle menos es más barato y más rápido.
Aquí entra en juego la ventana de contexto (la cantidad de texto que puedes enviar a un modelo en una sola llamada, con un límite máximo). En pipelines largos, si no filtras lo que pasas en cada paso, el coste se dispara sin que el resultado mejore. El post sobre ventana de contexto y buenas prácticas entra en detalle sobre cómo gestionarla.
Errores que va a cometer todo el mundo
Demasiados pasos para muy poco
Un pipeline de seis pasos para algo que se resuelve en dos. Cada paso extra añade latencia y un punto de fallo nuevo. Empieza siempre con el número mínimo de pasos y añade solo si el resultado lo justifica.
Pasar todo el contexto a cada llamada
El error más caro. Los tokens son las unidades en que los modelos miden el texto (algo así como trozos de palabras). Las APIs de LLM cobran por token: tanto por lo que envías como por lo que recibes. Si en el paso 3 incluyes el historial completo de los pasos 1 y 2, ese coste se multiplica por el número de pasos. Pasa solo el dato limpio que ese paso necesita. El tradeoff inverso también existe: recortar demasiado puede debilitar el resultado del paso siguiente. No todo el historial, pero sí lo necesario para que ese paso tenga suficiente señal.
Llamadas sin gestión de errores
El error que más veces vi repetir, especialmente al principio: un pipeline sin gates donde el paso 1 falla silenciosamente y los pasos siguientes reciben datos incorrectos. El sistema falla en cascada, no sabes en qué punto ocurrió el error, y el usuario recibe un mensaje genérico sin contexto. Los gates no son una optimización: son lo que hace que el sistema sea usable.
Input de usuario sin validar
Si el pipeline procesa texto que viene del usuario (una reseña, un formulario, cualquier campo libre), ese texto se interpola directamente en el prompt. Un usuario puede inyectar instrucciones dentro del contenido y alterar el comportamiento del modelo. En producción, valida y limita el input antes de usarlo en un prompt: longitud máxima, caracteres permitidos, lo que tenga sentido para tu caso.
Usar prompt chaining para tareas atómicas
“Traduce esta palabra al inglés” no necesita un pipeline. Si te encuentras añadiendo pasos a una tarea que en el fondo es simple, da un paso atrás y pregúntate si el problema real está en el prompt, no en la arquitectura. La complejidad tiene un coste: más código, más puntos de fallo, más latencia.
Checklist de implementación
-
Cada paso del pipeline tiene una sola responsabilidad clara
-
Hay un gate de validación entre cada par de pasos
-
El gate implementa early exit con un mensaje de error que ayuda a depurar
-
Cada paso recibe solo el contexto que necesita, no el historial completo
-
El número de pasos es el mínimo necesario para la tarea
-
Los resultados de cada paso se loguean para facilitar la depuración
Preguntas Frecuentes
¿Qué diferencia hay entre prompt chaining y un agente de IA?
Un agente decide por sí mismo qué pasos dar, en qué orden y cuándo parar. El prompt chaining es una secuencia fija que tú defines de antemano. Si sabes exactamente los pasos que necesitas, usa prompt chaining: es más predecible y mucho más fácil de depurar cuando algo falla.
¿Necesito un framework como LangChain para construir un pipeline?
No. El ejemplo de este post no usa ningún framework. Para pipelines de dos o cuatro pasos, añadir un framework suma dependencias y capas de abstracción innecesarias. Un par de funciones en TypeScript hacen exactamente lo mismo con mucho menos complejidad.
¿Qué pasa si el modelo del paso 1 genera un formato incorrecto?
Para eso está el gate. Comprueba el formato antes de continuar y si el output no pasa la validación, el pipeline se detiene y devuelve un error claro. Sin gate, ese formato incorrecto se propaga y después es casi imposible rastrear el origen del fallo.
Si tu paso 1 devuelve JSON, el gate más directo es try { JSON.parse(output) } catch { return { error: "Formato inválido" } }. Si esperas un valor enumerado (“positivo” / “negativo” / “neutral”), un regex es suficiente: /^(positivo|negativo|neutral)$/i.test(output). Detectar el fallo aquí, antes del paso 2, es la diferencia entre un error claro y un debugging de 40 minutos.
El modelo del paso 2, ¿recuerda lo que hizo el paso 1?
No, a menos que tú le pases esa información explícitamente. Cada llamada al LLM empieza desde cero. No hay memoria entre llamadas. Si necesitas que el paso 2 sepa algo del paso 1, tienes que pasárselo tú en el prompt. Es una de las cosas que más confunde al principio, y es también por qué el diseño de qué información pasa entre pasos importa tanto.
¿Cuántos pasos es demasiado?
En la práctica, más de cuatro o cinco pasos para una sola tarea suele indicar que estás sobre-dividiendo el problema. Pregúntate si puedes fusionar algún paso sin perder el control sobre los resultados intermedios. Si la respuesta es sí, fusiónalo.