LCEL es la forma correcta de construir cadenas en LangChain desde 2024. Esta guía cubre la sintaxis, los patrones de composición y los errores comunes que vemos en código de producción.
Todo en LCEL implementa la interfaz `Runnable`: un prompt, un modelo de chat, un parser de salida, un retriever, incluso una función de Python decorada. Esta interfaz garantiza cuatro métodos síncronos y sus equivalentes asíncronos: `invoke`, `batch`, `stream`, y sus versiones `a*`. El operador `|` no es azúcar sintáctica trivial: internamente construye un `RunnableSequence` que encadena la salida de un componente como entrada del siguiente.
Esto significa que puedes insertar lógica de negocio pura de Python en medio de una cadena de LLM sin envolturas artificiales.
El patrón más común en producción es recuperación + generación. Con LCEL se expresa de forma lineal y legible:
El diccionario de entrada se convierte automáticamente en un `RunnableParallel`: cada clave se ejecuta de forma concurrente, no secuencial, lo que reduce latencia cuando hay múltiples fuentes de datos independientes.
Cuando necesitas ejecutar varias sub-cadenas sobre la misma entrada —por ejemplo, generar un resumen y extraer entidades al mismo tiempo— `RunnableParallel` lo hace explícito:
Para lógica condicional simple (sin ciclos, que es terreno de LangGraph), `RunnableBranch` permite enrutar según el contenido de entrada, útil para clasificar la intención del usuario antes de elegir el prompt correcto.
Un beneficio directo de LCEL es que el streaming funciona de forma consistente en toda la cadena, no solo en la llamada final al modelo:
Esto es crítico para UX en aplicaciones conversacionales: el usuario ve la respuesta generarse en tiempo real en vez de esperar el bloque completo, incluso cuando hay pasos de recuperación antes del modelo.
LCEL expone `.with_retry()` y `.with_fallbacks()` directamente sobre cualquier `Runnable`, lo cual evita envolver llamadas en bloques try/except manuales:
En producción, combinamos esto con `with_fallbacks` apuntando a un segundo proveedor (por ejemplo, Anthropic) para tener resiliencia real ante caídas de API, algo que en la capa de agentes antigua requería código custom.
El más frecuente es mezclar `Runnable` con la vieja API de `Chain` en el mismo proyecto sin razón, lo que duplica patrones de manejo de errores. El segundo es no usar `.batch()` cuando se procesan lotes de documentos, dejando en su lugar un `for` con `.invoke()` secuencial, perdiendo el paralelismo interno que LangChain gestiona con un `ThreadPoolExecutor`. El tercero es no tipar la entrada de la cadena con `RunnableConfig` cuando se necesita pasar metadata (como `run_name` o `tags`) para trazabilidad en LangSmith, lo cual complica el debugging después.
Carlos Montiel es arquitecto de soluciones IA empresarial. Implementa LLMs, Agentes, RAG y orquestadores en empresas de Guatemala y Latinoamérica. Contáctalo para una consultoría.
Contactar a Carlos Montiel