06-01-01 — LangChain: filosofia, LCEL, runnables
TL;DR
LangChain é o framework mais popular para construir aplicações com LLMs em Python e JavaScript. Sua principal contribuição é a LCEL (LangChain Expression Language) — uma sintaxe declarativa que compõe chains via operador | — e a interface Runnable, que padroniza invoke, stream e batch em qualquer componente. Ideal para RAG e chains simples; para agentes complexos com estado, prefira LangGraph.
O que é LangChain
Lançado em 2022 por Harrison Chase, LangChain nasceu como uma coleção de abstrações para conectar LLMs a ferramentas externas. Hoje cobre:
- langchain-core — primitivos: Runnable, PromptTemplate, BaseMessage
- langchain — chains, agents, memory de alto nível
- langchain-community — integrações com 300+ provedores (VectorStores, Tools, LLMs)
- langchain-openai / langchain-anthropic / … — pacotes de integração específicos
- LangSmith — observabilidade e tracing (SaaS)
LCEL — LangChain Expression Language
LCEL é uma DSL baseada em composição funcional. O operador | conecta Runnables em sequência. O resultado é uma chain lazy, que herda automaticamente streaming, batching e async.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Cada componente é um Runnable
prompt = ChatPromptTemplate.from_template("Explique {conceito} em uma frase.")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
parser = StrOutputParser()
# LCEL: composição via pipe
chain = prompt | llm | parser
# invoke: síncrono, retorna string
resultado = chain.invoke({"conceito": "RAG"})
print(resultado)
# stream: retorna generator de tokens
for chunk in chain.stream({"conceito": "embeddings"}):
print(chunk, end="", flush=True)
# batch: processa lista em paralelo
resultados = chain.batch([
{"conceito": "LLM"},
{"conceito": "vector store"},
{"conceito": "agente"}
])
Interface Runnable
Qualquer componente LangChain implementa a interface Runnable, que garante:
| Método | Retorno | Uso |
|---|---|---|
invoke(input) | objeto único | chamada síncrona simples |
stream(input) | Iterator de chunks | streaming de tokens para UI |
batch(inputs) | lista de resultados | processamento paralelo |
ainvoke / astream / abatch | async equivalentes | FastAPI, async frameworks |
Runnables utilitários
from langchain_core.runnables import RunnableParallel, RunnablePassthrough, RunnableLambda
# RunnableParallel: executa branches em paralelo e mescla resultados
parallel = RunnableParallel({
"resumo": prompt_resumo | llm | parser,
"keywords": prompt_keywords | llm | parser,
})
# RunnablePassthrough: passa input sem modificação (útil para injetar contexto)
chain_rag = (
RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
| prompt_rag
| llm
| parser
)
# RunnableLambda: envolve qualquer função Python como Runnable
formata = RunnableLambda(lambda x: x.upper())
chain_com_lambda = chain | formata
Agents em LangChain
LangChain suporta agents via create_tool_calling_agent + AgentExecutor. Para agentes simples (ReAct loop com ferramentas), funciona bem. Para lógica com estado, loops complexos ou múltiplos agentes, use LangGraph (próximo tópico).
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.tools import tool
@tool
def busca_web(query: str) -> str:
"""Busca informações na web."""
return f"Resultado da busca: {query}" # substituir por implementação real
agent = create_tool_calling_agent(llm, [busca_web], prompt_com_placeholder)
executor = AgentExecutor(agent=agent, tools=[busca_web], verbose=True)
executor.invoke({"input": "Qual é a capital da França?"})
Como isso se conecta
- 06-01-02 LangGraph — evolução natural: LangGraph usa os mesmos Runnables, mas em grafos de estado
- 06-02-01 LlamaIndex — complementar: LlamaIndex faz indexação/RAG melhor; LangChain orquestra o fluxo
- 06-03-01 Semantic Kernel — alternativa para stack .NET/Azure; filosofia similar de composição
- Módulo 05 (RAG) — LangChain é frequentemente usado para implementar pipelines RAG com LCEL