DEV Community

Tiago Vilas Boas (Montanha)
Tiago Vilas Boas (Montanha)

Posted on

LangGraph versus LangChain. A conta é cadeia, grafo ou harness

Pessoal, eu ia responder LangGraph ou LangChain. Tipo React ou Vue. A aula até empurra um pouco pra isso.

Eu tava no módulo 1 do Agentic AI with LangChain and LangGraph, no Coursera (IBM). Duas aulas feitas: Introdução à IA agêntica e LangGraph versus LangChain. Didático. Aí abri o chat.

A pergunta não era o logo. Era: este fluxo é uma cadeia (entra, sai, acabou)? É um grafo (estado, ciclo, pausa pra gente)? Ou o cérebro nem está na lib: está no Cursor, no Kiro, no Claude Code?

O que você leva daqui: nomeia o fluxo antes do logo. Cadeia, grafo ou o desk. LangChain e LangGraph se encaixam. Nenhum substitui o harness.

A nota gerar vs agir para no turno. O post de RAG e MCP é outra camada. Aqui é orquestração.

Um limite só: eu não rodei benchmark de latência Chain versus Graph neste laboratório. A conta abaixo é de forma, não de milissegundo.

Tabela de Conteúdo

1. Nomeia o fluxo antes do logo

Três formas. Não são três produtos.

Cadeia. Prompt, modelo, parser. Um sentido. Sem loop. LCEL: prompt | model | parser. Traduz, classifica, extrai. Acabou.

Grafo. Nós, arestas, estado. Pode voltar. Pode pausar. Pode retomar depois de falha. Docs oficiais: execução durável, memória de curto e longo prazo, interrupt com gente no meio. Isso é LangGraph.

Harness. O IDE chama tool, lê arquivo, espera você. Não precisa do grafo Python pra existir. Precisa de política: o que lê, o que grava, quem aprova.

No grafo, uma pergunta extra: quem escolhe o próximo passo? Se o código escolhe (aresta que você escreveu), é workflow. Se o modelo escolhe (ReAct, create_react_agent), é agent. LangGraph faz os dois. Por isso “coloquei LangGraph” não diz se você tem agente.

Se o time discute logo e o fluxo ainda é um invoke sem estado, vocês estão no item 1 fingindo que é o 2. Se no teu time já abriu PR de StateGraph pra um classificador, você já viu isso.

2. LangChain: a cadeia

A forma mínima, da documentação LCEL:

chain = prompt | model | StrOutputParser()
chain.invoke({"text": "Hello", "input_language": "English", "output_language": "Spanish"})
Enter fullscreen mode Exit fullscreen mode

Entra dict. Sai string. Não tem “tenta de novo se a tool falhar”. Não tem “espera o humano”. Não tem checkpoint.

LangChain também entrega atalho de agente (create_agent no pacote atual). O detalhe está no H3 abaixo.

O que você ganha: integração, LCEL, um invoke que o time lê em dez linhas.
O que você paga: quando precisa de ciclo, persistência e pausa de verdade, a cadeia não chega. Você sobe de knob. Ou finge que subiu.

atalho de agente versus cadeia

create_agent no pacote atual não apaga o grafo. Por baixo, o runtime de agente da casa ainda é grafo. Você não desenhou os nós. O ciclo está lá. Se o pedido é traduzir e não há tool, o atalho é cadeia cara.

3. LangGraph: estado, ciclo, pausa

O README lista o que a cadeia não promete: execução que sobrevive a falha, HITL, memória de trabalho e entre sessões.

Ciclo: aresta condicional. O nó agent decide se chama tools ou END. Tool volta pro agent. ReAct não é marketing. É esse loop.

Pausa: interrupt(). Sobe valor pro cliente. Retoma com Command. Sem checkpointer, a pausa não existe: o estado não grava.

interrupt versus print("confirma?")

HITL que é print("confirma?") no log não é o interrupt da lib. Sem checkpointer, a pausa some no crash.

Cena pedagógica (não é log de produção):

você:     faz deploy da branch feature/pix
cadeia:   gera um YAML de pipeline. ninguém chamou o CI
grafo:    nó agent → nó tools → interrupt (HITL)
humano:   aprova
grafo:    retoma do checkpoint, dispara o workflow
Enter fullscreen mode Exit fullscreen mode

A cadeia “fez o texto do deploy”. O grafo “quase publicou”. São contas diferentes. Least privilege e HITL no que grava. Sem isso o grafo é force push com estado.

O que você ganha: estado explícito, ciclo, pausa retomável.
O que você paga: desenho. Cada nó a mais é um jeito de errar no mundo. Blast radius da tool.

4. O grafo que ainda é uma cadeia

Atalho:

from langgraph.prebuilt import create_react_agent

agent = create_react_agent(model, tools)
agent.invoke({"messages": [("human", "traduz isto")]})
Enter fullscreen mode Exit fullscreen mode

Isso compila um StateGraph e devolve um Runnable do LangChain. Você pode invoke como cadeia. Por dentro tem ciclo se houver tool.

Se a tool não existe e o pedido é “traduz”, você pagou grafo pra fazer LCEL. Estado vazio. Sem interrupt. Sem checkpointer. Logo Graph no requirements.txt. Fluxo de cadeia.

O teste: o transcript tem mais de um nó, ou tem um invoke e acabou?

Não usei ChargePaidHandler aqui. Essa cena é do post do grafo de código. Aqui o knob é orquestração, não dump do repo.

5. Quatro perguntas antes de adicionar o grafo

Copia. Cola no PR do agente.

## Cadeia, grafo ou harness

1. O fluxo é um sentido só (gera, classifica, extrai)? Cadeia. LCEL chega.
2. Precisa voltar (tool falhou, tenta de novo) ou parar pra gente (push, pagar, deploy)? Grafo. Checkpointer. `interrupt` no que grava. Aí: o **código** escolhe o próximo nó (workflow) ou o **modelo** (agent)?
3. O “agente” é o Cursor/Kiro neste pedido, não o Python? Harness. Não invente um StateGraph pra duplicar o que o IDE já faz.
4. Se o servidor do grafo cair, o time ainda trabalha? Se não, você acoplou o desk num processo.

HITL, least privilege, blast radius: a tool que grava não anda no mesmo cano da que só lê.
Enter fullscreen mode Exit fullscreen mode

Se a resposta da 1 for sim e você mesmo assim abriu StateGraph, você comprou ciclo pra um invoke. O prompt da seção seguinte monta a arquitetura no teu repo. Sem pular pra StateGraph no escuro.

6. Cole isto no seu agente

Isto não é receita de instalar LangChain e LangGraph. É o contrato das três formas, pra colar numa conversa nova. Arquiteto, não gerador de código. Se você não tem nada, ele assume cadeia (LCEL) e semana 1 no README. Se tem tool que grava, pergunta HITL e espera.

Conversa nova. Cinco linhas do seu repo. Ele lê README e o que já existe (LCEL, StateGraph, create_agent). Sem stack: default cadeia. Stack complexa: até 8 perguntas, aí para.

Se devolver um StateGraph pra traduzir texto, você pulou as perguntas. Manda o trecho no comentário.

You are an architect, not a code generator.

I am designing a LangChain + LangGraph setup for a software team. I may paste repo context, a stack description, or a messy Slack thread. Do not assume Cursor, LangSmith Cloud, or any host. Talk in terms of three shapes: chain, graph, harness.

Do not write application code in the first reply. Do not invent tools, models, or vendors I did not mention. Do not open a StateGraph because the hype asked.

First pass, before any questionnaire: inspect what I pasted. If the harness can see the repo, look only at README, existing chains/graphs (LCEL, StateGraph, create_agent / create_react_agent), tools, checkpointer config. A handful of Reads. Not ten. Not dump. Cite what you found. Then classify from that evidence: chain-only vs needs-graph vs harness-already-does-it. Do not pick 3 or 8 questions before this pass.

If the pass shows nothing (no LangChain, no LangGraph, no tools): ask at most 3 short questions: (1) one-way generate/classify/extract, or a loop with tools, (2) does anything write (push, pay, deploy, email), (3) is the “agent” this Python process or an IDE chat. If I skip them, assume: one-way chain; no writes; one IDE for daily work; no StateGraph this week. Then output the sections below in this same reply. Week-1 bullets must be doable with LCEL in that repo. They are the first correct setup, not a shopping list of integrations.

If the pass already has enough, skip questions and output. If the pass shows a complex stack (tools that mutate, existing graph, checkpointer, or I proposed “add LangGraph for everything”) and something material is still missing, ask up to 8 short questions, then stop and wait. The 8 are for that case. Not for the nothing-case.

Mental model (non-negotiable):
- LangChain vs LangGraph is the wrong fight. Chain = one-way compose (LCEL: prompt | model | parser). Graph = state, cycles, durable execution, interrupt for humans. They fit: a compiled StateGraph is a LangChain Runnable. create_react_agent / create_agent is a shortcut that still compiles a graph. A shortcut with no tools and no interrupt is a chain you overpaid for.
- Harness (Cursor, Claude Code, Codex, Kiro) is a third shape. Do not duplicate the IDE with a Python graph if this request already lives in the chat with tools.
- interrupt() without a checkpointer is not HITL. print("confirm?") is not interrupt.
- Read tools ≠ write tools. Push, pay, deploy, email: HITL. Least privilege. Blast radius. No unbounded shell “to make the demo work”.
- Checkpointer memory is not a knowledge-base contract. Retrieval/RAG is another layer. Do not stuff the repo or OpenAPI into graph state.
- Start with the smallest shape that matches the flow. Chain first. Graph when you need to come back or pause. Harness policy always.

Also respect:
- If I said LangGraph or LangChain as alternatives, correct me and classify my flow as chain, graph, or harness.
- If I asked to “add LangGraph” to a translate/classify pipeline, refuse the graph and specify the LCEL chain.
- LangSmith is optional observability. Not a layer that replaces chain/graph/harness.

After you have enough answers, output exactly these sections in my language (pt-BR unless I write in English):

1. Diagnosis — for MY flow: chain vs graph vs harness. One paragraph. If I treated LangGraph as a competitor to LangChain, say so.
2. Chain (LangChain / LCEL) — what stays a one-way invoke. What must never become a node.
3. Graph (LangGraph) — “not now”, or nodes / edges / state fields / checkpointer / interrupt points. Table: node, read vs write, blast radius, HITL yes/no.
4. Shortcut — create_react_agent / create_agent: allowed only if the table needs a tool cycle. Otherwise forbid.
5. Harness — what stays in the IDE and must not be copied into Python this week.
6. Week-1 plan — 5 bullets in the repo. No new logo unless I already have it. If I had nothing, bullets are LCEL only.

End with 3 risks if I skip the diagnosis and jump to StateGraph.
Enter fullscreen mode Exit fullscreen mode

O prompt já dá pra colar. O gist vive sem o artigo:

7. Se o server cai, o desk segue

No meu setup o cérebro do servidor defaultou pra Goose. LangGraph ficou legado. Não li isso num slide. Olhei o stack.

Quando o server está down, o Cursor continua: rules, vault, MCP. Doctor reclama. Você não para. A lib do grafo não era o harness. Era um cérebro atrás de um HTTP.

Isso não mata LangGraph. Mata a ideia de que escolher Graph ou Chain é montar o agente. Montar o agente é política no desk +, se você precisa de processo longo no servidor, um runtime com estado. Goose, Graph, o que for: o knob 3 (harness) continua existindo.

A memória é outra porta. Retrieve não é o checkpointer do Graph. Não misture as duas.

No último fluxo que você subiu: foi prompt | model | parser, foi grafo com interrupt, ou foi o chat do IDE sem Python no meio?

Top comments (0)