Ejemplos de encadenamiento de prompts (con y sin LangChain)

Ejemplos copiables de encadenamiento de prompts en TypeScript: triaje de currículums y contenido, primero y luego con LangChain.

Colaboradores: Ivan Garcia Villar

Ejemplos de encadenamiento de prompts (con y sin LangChain)

Encadenar prompts es coger una tarea grande y partirla en varias llamadas al LLM (el modelo de lenguaje, como Claude o ChatGPT) puestas en fila: lo que devuelve un paso entra como input del siguiente. Aquí tienes ejemplos copiables, primero en TypeScript y después con LangChain.

Antes de empezar: te basta con saber qué es un LLM y haber escrito algo de TypeScript. La teoría completa del porqué (cómo dividir bien, qué es un gate) vive en la guía de prompt chaining; este post es el banco de ejemplos.

Ejemplo 1: triaje de currículums, paso a paso

El caso más claro es procesar los currículums que llegan a una oferta. Lo partimos en tres llamadas, y cada una recibe solo el dato limpio de la anterior, no el documento de tres páginas.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic(); // usa la variable de entorno ANTHROPIC_API_KEY

// Helper: manda un prompt y devuelve el texto que responde el modelo
async function llamarLLM(prompt: string): Promise<string> {
  const respuesta = await client.messages.create({
    model: "claude-haiku-4-5-20251001", // modelo rápido, ideal para pasos simples
    max_tokens: 300,                     // tope de tokens (trozos de texto) generados
    messages: [{ role: "user", content: prompt }],
  });
  const bloque = respuesta.content[0];
  if (!bloque || bloque.type !== "text") throw new Error("El modelo no devolvió texto");
  return bloque.text;
}

Con ese helper, la cadena son tres prompts seguidos. Fíjate en qué se pasa a cada paso:

async function triarCV(cv: string) {
  // Paso 1: extraer solo la experiencia laboral del documento entero
  const experiencia = await llamarLLM(
    `Extrae únicamente la experiencia laboral de este CV:\n\n${cv}`
  );

  // Paso 2: clasificar usando SOLO ese extracto, no el CV completo
  const nivel = await llamarLLM(
    `Clasifica este perfil como "Junior", "Mid" o "Senior":\n\n${experiencia}`
  );

  // Paso 3: redactar el email usando SOLO la etiqueta del paso 2
  const email = await llamarLLM(
    `Redacta un email de seguimiento breve para un candidato ${nivel}.`
  );

  return { nivel, email };
}

El paso 3 no necesita leer el CV. Solo recibe la palabra Senior y trabaja con eso. Pasar menos es más barato y deja menos margen para que el modelo se líe.

Ejemplo 2: redactar contenido en tres prompts

La misma idea sirve para escribir un artículo. La cadena tiene tres responsabilidades distintas, una por llamada:

  1. Esquema → “Dame un esquema de 5 secciones para un artículo sobre X.”
  2. Redacción → “Redacta el artículo siguiendo este esquema: {esquema}.”
  3. Revisión de tono → “Reescribe este texto en un tono cercano y directo: {borrador}.”

No hace falta volcar todo el código otra vez. El esqueleto es idéntico al del ejemplo anterior: cada llamarLLM recibe el resultado del paso previo entre llaves, nada más. Un ticket de soporte funcionaría igual (resumir → clasificar urgencia → enrutar al equipo). Cambia el dominio, no el patrón.

El patrón que se repite

Mira los dos ejemplos y verás siempre lo mismo: una responsabilidad por llamada, pasar contexto mínimo y limpio entre pasos, y comprobar el resultado antes de seguir. Esa comprobación es el gate (una puerta que valida el output de un paso antes de dejarle avanzar), y es lo que evita que un error del paso 1 se arrastre hasta el final. Por qué importa tanto y cómo escribirlo bien lo desarrolla la guía de prompt chaining. Aquí me quedo en el cómo se ve.

Los mismos ejemplos con LangChain

LangChain hace exactamente esto, pero con piezas reutilizables que se componen. Su forma de encadenar se llama LCEL (LangChain Expression Language): conectas componentes con el método .pipe(), como tuberías de Unix. Esta es la primera mitad del Ejemplo 1 reescrita:

import { ChatAnthropic } from "@langchain/anthropic";
import { PromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";

const modelo = new ChatAnthropic({ model: "claude-haiku-4-5-20251001" });
const parser = new StringOutputParser(); // extrae el texto plano de la respuesta

// Un paso = plantilla .pipe(modelo) .pipe(parser que devuelve string)
const extraer = PromptTemplate
  .fromTemplate("Extrae únicamente la experiencia laboral de este CV:\n\n{cv}")
  .pipe(modelo)
  .pipe(parser);

Para encadenar varios pasos usas RunnableSequence.from([...]). Entre paso y paso metes una función que coge el texto de salida y lo mapea al input que espera el siguiente:

import { RunnableSequence } from "@langchain/core/runnables";

const clasificar = PromptTemplate
  .fromTemplate('Clasifica este perfil como "Junior", "Mid" o "Senior":\n\n{experiencia}')
  .pipe(modelo)
  .pipe(parser);

// La cadena completa: extraer → mapear el texto al input → clasificar
const cadena = RunnableSequence.from([
  extraer,
  (experiencia: string) => ({ experiencia }), // texto del paso 1 → variable del paso 2
  clasificar,
]);

const nivel = await cadena.invoke({ cv: "..." }); // ejecuta toda la secuencia

La función (experiencia) => ({ experiencia }) hace lo que en la versión sin framework hacíamos a mano: coger la salida limpia de un paso y dársela al siguiente. StringOutputParser está ahí para que entre pasos circule texto, no el objeto de respuesta completo.

¿Vanilla o LangChain?

Las dos versiones hacen lo mismo. La diferencia es cuántas abstracciones quieres encima.


(SDK Anthropic)LangChain (LCEL)
Cadenas cortas (2-4 pasos)Más simple, menos dependenciasAñade capas que no necesitas
Muchas cadenas componiblesAcabas repitiendo pegamentoReutilizas Runnables
Cambiar de proveedor o modeloReescribes las llamadasCambias la clase del modelo
Streaming, reintentos, retrieversLo montas túViene de serie

Para los ejemplos de este post, hacerlo con el sdk gana en claridad. LangChain empieza a compensar cuando tienes muchas cadenas que recombinar, quieres streaming o reintentos sin escribirlos, o necesitas intercambiar de modelo sin tocar la lógica. Si solo tienes una cadena de tres pasos, las dependencias extra rara vez valen la pena.

Cuando quieras pasar de copiar ejemplos a construir tus propios sistemas agénticos, el curso de patrones agénticos es donde practicarlos.

Preguntas Frecuentes

¿Necesito LangChain para encadenar prompts?

No. Un par de funciones en TypeScript que se pasan el resultado entre ellas hacen lo mismo, y en cadenas de pocos pasos se leen y se depuran mejor que cualquier framework.

¿Puedo usar Claude con LangChain?

Sí. Importas ChatAnthropic de @langchain/anthropic y le pasas el modelo en el constructor: new ChatAnthropic({ model: "claude-haiku-4-5-20251001" }). A partir de ahí lo encadenas igual que cualquier otro modelo de LangChain.

¿Qué es LCEL?

LCEL es LangChain Expression Language, la forma de componer pasos en LangChain. Conectas componentes (un Runnable) con el método .pipe(), de modo que la salida de uno entra en el siguiente. prompt.pipe(modelo).pipe(parser) es una cadena de un paso.

¿Cuándo NO conviene LangChain?

Cuando la tarea es atómica (“traduce esta frase”) o la cadena es muy corta. Ahí el framework solo añade dependencias y capas de abstracción que tendrás que entender para depurar. Empieza y muévete a LangChain cuando el número de cadenas que recombinas lo justifique.