| 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.
Cada eslabón hace una conversión de tipo. Lo que viaja por la tubería cambia de forma tres veces:
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.
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.
| Método | Qué hace | Quié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 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.
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?
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.