Trail content
Fundamental

Choosing a stack

Escolhendo a stack

Choosing a stack is an AI engineering fundamental for people who work with LLMs. The layers of an LLM system, and when LangChain, LangGraph, a provider SDK, or another library earns its place.

Element
09/13
Level
Beginner
Read
4 min
Updated
On this page 5
  1. 01The situation
  2. 02The concept
  3. 03Try it
  4. 04What this changes
  5. 05Check your understanding
  6. ··Quick answers

The situation

You join a team and the README says “we use Claude”. At the last job the same order bot ran on OpenAI. A post tells you to throw LangChain out. A teammate says everything must be LangGraph. This week’s ticket is only this: classify the customer’s message and send billing to one prompt, orders to another.

The three folders implement the same design. What changes is who writes the sequence, the branch, and the retry. Learning a vendor’s name as if it were the job means you start over at every API change.

The concept

An LLM system has four layers. The library lives in one of them.

flowchart TD
  APP["1. Your product"]:::tool --> ORCH["2. Orchestration"]:::llm
  ORCH --> MODEL(["3. Model provider"]):::io
  ORCH --> SIDE["4. Retrieval, eval, and trace"]:::tool
  1. The product: routes, permission, money, the text the customer reads.
  2. Orchestration: call order, the branch, the loop, the pause. It can be a function you write, LangChain, LangGraph, a provider’s agent SDK, Pydantic AI, or the Vercel AI SDK.
  3. The provider: OpenAI, Anthropic, Google, or a model you host. All four expose the same operations: text, schema output, tools, and streaming.
  4. The neighbors: retrieval, eval, and trace. LlamaIndex when the index is the product. The eval stays yours. The trace can be LangSmith, Langfuse, or OpenTelemetry.

A catalog pattern describes layer 2. The Python tab’s SDK describes one shape of layer 3. Switching tabs does not switch the pattern.

Who writes the path

Before the library, pick the rung in Chains, agents, and workflows. A chain, a workflow, and an agent all fit in LangGraph. Using LangGraph does not turn ad moderation into an agent.

You need Write it yourself A library already wrote it
Two to four calls in a fixed order Functions LangChain, if you will swap providers
Branches, a loop, a human pause, resume A handful of functions LangGraph
A tool loop until it stops A while with a cap create_agent (LangChain 1.x, runs on LangGraph), the OpenAI Agents SDK, the Claude Agent SDK, or Pydantic AI
A chat UI with streaming Your API Vercel AI SDK
Questions over a document base Your retriever LlamaIndex, when the index is the product
Schema output Pydantic or Zod on the provider SDK with_structured_output, if the stack is already LangChain
A prompt that improves from a dataset Your eval DSPy, when the dataset is the spec

init_chat_model("anthropic:claude-haiku-4-5") and init_chat_model("openai:gpt-4o-mini") return the same kind of object. The prefix is the vendor. The rest of the function does not change. That is what the LangChain tab is showing on the pattern pages: the decision stays in your if, the model is a string.

What every provider does the same way

Text goes in. Text, a tool request, or a schema object comes out. Anthropic returns blocks in content and stop_reason. OpenAI returns choices[0].message and finish_reason. Google uses another envelope. None of those names should show up in the module that writes the invoice. The smell is Provider Format Leak.

LangChain and the Vercel AI SDK hide the envelope. A thin client you write does the same job when you only have two call sites. From the third one on, the abstraction starts to pay, because a model swap stops being a diff in every file.

When the library gets in the way

  • The task is one call. A graph with one node is a longer way to write a function.
  • You need to see the loop to find a blown budget. create_agent hides the turn. The Python tab on ReAct Loop is the one to read first.
  • LangGraph’s recursion_limit and the OpenAI Agents SDK’s max_turns count framework steps. Time, money, and an honest stop stay yours. See Stop Conditions.
  • A 2023 tutorial imports langchain.chains.LLMChain. That API moved to langchain-classic in 1.0. Read the pattern on this site and the import in the current docs, not the other way around.

Try it

Take the message “I need a second copy of the invoice for order 8831” and mark the layer of each piece. Five minutes.

Classify billing or orders        orchestration (workflow)
Call the small model              provider
The if that picks the route       your code
The billing prompt                your product
Anthropic or OpenAI SDK          adapter, not the rule

The same classification, two vendors, one function:

from typing import Literal

from langchain.chat_models import init_chat_model
from pydantic import BaseModel

class Route(BaseModel):
    kind: Literal["billing", "orders", "other"]
    confidence: float

# Change only this string. The shape is "provider:model".
MODEL = "openai:gpt-4o-mini"
# MODEL = "anthropic:claude-haiku-4-5"
# MODEL = "google_genai:gemini-2.5-flash"

router = init_chat_model(MODEL, temperature=0).with_structured_output(Route)

def classify(message: str) -> Route:
    return router.invoke([
        ("system", "Classify: billing, orders, or other."),
        ("human", message),
    ])

If your classify function still imports anthropic or openai in the middle of the business rule, the leak is there, not in the model you picked.

Check +20 XP on first tryThe team moderated ads with four fixed boxes, and someone wants to rewrite it in LangGraph with create_agent, 'because that is the right stack now'. What do you say?

What this changes

  • Routing keeps the decision in code in three shapes: an SDK, LangChain, and LangGraph.
  • Prompt Chaining uses LangGraph when the middle gate is an edge, not a loose if.
  • Structured Output shows the schema on the Anthropic SDK, the OpenAI SDK, and with_structured_output.
  • Tool Use and the ReAct Loop show the hand-written while and create_agent.
  • RAG leaves retrieval in your code. LlamaIndex comes in when the index is the product, not to hide the citation check.
  • Human-in-the-Loop uses LangGraph’s interrupt and a checkpointer when the wait can last for days.

Start with the rung. Pick the library that writes that rung in less code than you can still read on an incident Tuesday.

Check your understanding

Check +20 XP on first tryThe invoice extractor makes two calls, always in the same order, and the provider contract runs for a year. A teammate wants LangChain in place before the eval exists. What do you do?

Check +20 XP on first tryA payment over $500 waits for a human, sometimes until the next day. The in-memory loop dies when the process restarts. Which piece handles the wait?

Check +20 XP on first trybilling/emit.py imports Anthropic's ContentBlock type to read the tax id field. What is wrong, and would LangChain fix it by itself?

Check +20 XP on first tryYou found a RAG example using LangChain's RetrievalQA from 2023. This catalog's RAG page insists on checking cited ids in code. What do you copy?

Quick answers

What is Choosing a stack?

Choosing a stack is an AI engineering fundamental for people who work with LLMs. The layers of an LLM system, and when LangChain, LangGraph, a provider SDK, or another library earns its place.

Go further

Relations

Search