MÓDULO 4 · LANGCHAIN FUNDAMENTOS · 20 MIN

LCEL: la cadena mínima

El | de LCEL no es azúcar sintáctico para «llama a esto y luego a lo otro». Las tres piezas hablan el mismo interfaz —Runnable— y al unirlas obtienes otro Runnable. Por eso la cadena entera tiene invoke, batch y stream sin que escribas nada, y por eso puedes cambiar una pieza sin tocar las demás.
01 — Anatomía
Las tres piezas y lo que convierten

Cada eslabón hace una conversión de tipo. Lo que viaja por la tubería cambia de forma tres veces:

dict
ChatPromptTemplateRellena las variables y monta la lista de mensajes.
→ PromptValue
ChatOpenAILlama a la API y devuelve el mensaje con sus metadatos.
→ AIMessage
StrOutputParserSe queda solo con el texto.
→ str
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template("Traduce al {idioma}: {texto}")
parser = StrOutputParser()

cadena = prompt | model | parser

Sin el parser, cadena.invoke(...) te devuelve un AIMessage, no un string: tendrías que hacer .content a mano en cada sitio donde uses el resultado. El parser no «limpia» el texto: cambia el tipo de salida del pipeline.

02 — Composición
Qué hace el pipe realmente

a | b construye un RunnableSequence. Ese objeto es a su vez un Runnable, así que hereda el mismo trío de métodos que tenían sus piezas.

prompt | model | parser ⟶ RunnableSequence ⟶ también es un Runnable
MétodoQué haceQuién lo escribió
invoke(x)Una entrada, una salida.El interfaz
batch([x1, x2])Varias entradas, paralelizadas.El interfaz
stream(x)Devuelve los trozos según llegan.El interfaz

No hay tres implementaciones que escribir. Escribes la cadena una vez y los tres modos vienen puestos: esa es la razón práctica de usar LCEL en vez de llamar a la API a pelo. Y es también por lo que funciona la modularidad — si sustituyes ChatOpenAI por otro chat model que respete el mismo interfaz, el prompt y el parser no se enteran.

// la modularidad no es una promesa del framework: es una consecuencia del interfaz compartido
03 — Depuración
Dónde se rompe la ilusión

La abstracción tiene coste. Cuando algo falla, el traceback atraviesa el RunnableSequence y no siempre señala la pieza culpable. La técnica es partir la cadena e invocar los eslabones por separado:

prompt.invoke({"idioma": "italiano", "texto": "Hello"})   # ¿la plantilla rellena bien?
(prompt | model).invoke({...})                            # ¿el modelo responde?

Cada Runnable es invocable solo. Si la cadena entera falla pero prompt.invoke va bien, el problema no está en el prompt. Vas añadiendo eslabones hasta que reaparece el fallo.

Auditoría La guía usa ChatOpenAI(model="gpt-3.5-turbo") en sus siete lecciones. OpenAI anunció el 2026-04-22 el apagado de gpt-3.5-turbo y de su alias genérico para el 2026-10-23, con gpt-5.6-terra como reemplazo publicado (comprobado en la página oficial de deprecations el 2026-08-30). Si el modelo del que depende todo el material se apaga dentro de dos meses: ¿qué parte de lo que estás aprendiendo caduca con él y qué parte no? ¿Cambiar el string del modelo basta, o hay algo más en la cadena que dependa de ese modelo concreto?
Para hacer
Tres ejecuciones, una sola cadena

Monta la cadena mínima y, sin cambiar ni una línea de la cadena, ejecútala de tres formas: .invoke({...}), .batch([{...}, {...}]) y .stream({...}) recorrido en un for. Después quita el | parser y compara type() de lo que sale en cada caso.