06-01-01 — LangChain: filosofia, LCEL, runnables
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)
Por que Python/JS e não C#? LangChain não tem suporte oficial para .NET. Para stack Microsoft, o caminho é Semantic Kernel (ver 06-03-01). LangChain é a escolha quando seu time já é Python-first ou quando precisa de ecossistema de integrações pronto.
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?"})
AgentExecutor vs LangGraph: AgentExecutor é um loop ReAct simples, sem controle de estado avançado. Se o agente precisa de memória persistente entre sessões, bifurcações, retry ou checkpointing, use LangGraph diretamente.