> LangChain: LCEL (LangChain Expression Language)
~/posts/langchain:-lcel-(langchain-expression-language).md
O que é LCEL?
LCEL (LangChain Expression Language) é a sintaxe declarativa do LangChain para compor cadeias. Usa o operador | (pipe) para conectar componentes, similar ao pipe do Unix.
cadeia = componente1 | componente2 | componente3
Por que usar LCEL?
- Streaming - Tokens são enviados assim que disponíveis
- Async - Suporte nativo a operações assíncronas
- Batch - Processa múltiplos inputs em paralelo
- Retry - Retentativas automáticas com backoff
- Fallbacks - Alternativas quando algo falha
Runnables: Os blocos de construção
Todo componente LCEL implementa a interface Runnable:
# Métodos principais de um Runnable
runnable.invoke(input) # Síncrono
await runnable.ainvoke(input) # Assíncrono
runnable.batch([inputs]) # Múltiplos inputs
runnable.stream(input) # Streaming
Exemplo completo
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template(
"Você é um poeta. Escreva um haiku sobre {tema}."
)
llm = ChatOpenAI(model="gpt-4o-mini")
parser = StrOutputParser()
# Composição com LCEL
cadeia = prompt | llm | parser
# Invoke
resultado = cadeia.invoke({"tema": "programação"})
print(resultado)
RunnablePassthrough
Passa o input adiante sem modificação. Útil para construir dicionários:
from langchain_core.runnables import RunnablePassthrough
cadeia = (
{"tema": RunnablePassthrough(), "estilo": lambda _: "minimalista"}
| prompt
| llm
| parser
)
resultado = cadeia.invoke("café")
RunnableLambda
Transforma qualquer função em um Runnable:
from langchain_core.runnables import RunnableLambda
def processar(texto: str) -> str:
return texto.strip().lower()
cadeia = (
prompt
| llm
| parser
| RunnableLambda(processar)
)
RunnableParallel
Executa múltiplos runnables em paralelo:
from langchain_core.runnables import RunnableParallel
analise = RunnableParallel(
resumo=prompt_resumo | llm | parser,
keywords=prompt_keywords | llm | parser,
sentimento=prompt_sentimento | llm | parser
)
# Retorna dict com todas as chaves
resultado = analise.invoke({"texto": "..."})
Branching com RunnableBranch
Lógica condicional baseada no input:
from langchain_core.runnables import RunnableBranch
roteador = RunnableBranch(
(lambda x: "código" in x["pergunta"], cadeia_tecnica),
(lambda x: "receita" in x["pergunta"], cadeia_culinaria),
cadeia_geral # fallback
)
resultado = roteador.invoke({"pergunta": "Como fazer bolo?"})
Configuração dinâmica com configurable
from langchain_core.runnables import ConfigurableField
llm_configuravel = ChatOpenAI(model="gpt-4o-mini").configurable_fields(
temperature=ConfigurableField(id="temp")
)
cadeia = prompt | llm_configuravel | parser
# Usa temperatura padrão
cadeia.invoke({"tema": "sol"})
# Configura temperatura diferente
cadeia.with_config(configurable={"temp": 0.9}).invoke({"tema": "sol"})
Bind: Passando argumentos extras
from langchain_core.tools import tool
@tool
def pesquisar(query: str) -> str:
"""Pesquisa na web."""
return f"Resultados para: {query}"
# Bind anexa tools ao modelo
llm_com_tools = llm.bind_tools([pesquisar])
cadeia = prompt | llm_com_tools
Assign: Adicionando chaves ao contexto
from langchain_core.runnables import RunnablePassthrough
cadeia = (
RunnablePassthrough.assign(
tamanho=lambda x: len(x["texto"]),
maiusculo=lambda x: x["texto"].upper()
)
| prompt
| llm
)
# Input: {"texto": "hello"}
# Passa: {"texto": "hello", "tamanho": 5, "maiusculo": "HELLO"}
Debugging com callbacks
from langchain_core.callbacks import StdOutCallbackHandler
cadeia.invoke(
{"tema": "python"},
config={"callbacks": [StdOutCallbackHandler()]}
)
Resumo dos Runnables
| Runnable | Uso |
|---|---|
RunnablePassthrough |
Passa input sem modificar |
RunnableLambda |
Função → Runnable |
RunnableParallel |
Execução paralela |
RunnableBranch |
Lógica condicional |
.bind() |
Anexar argumentos |
.assign() |
Adicionar chaves |
.configurable_fields() |
Config dinâmica |
LCEL é a base de tudo no LangChain moderno. Dominar essa sintaxe abre portas para RAG, Agents e aplicações complexas.