Session 6· 00· 15 min

Why LangChain? (read this first)

What you'll learn
  • Understand what problems LangChain actually solves
  • Compare raw-SDK code (Session 5) with LangChain code for the same task
  • Know when LangChain is the right tool — and when it is not
Read this before writing any LangChain code
Session 5 already taught you to do tools, structured output, and everything else with the raw OpenAI SDK. Before you learn a new library, you should know WHY it exists and what it changes. This lesson is pure motivation — zero code to run.

The problem: you built it with raw SDKs, now what?

Imagine your boss walks over and says three things: "1) The OpenAI bill is high — can we try Claude for 30% of traffic? 2) We also want to try Gemini for long documents. 3) And by the way, we need streaming tokens for the UI." With raw SDKs, each of those is a rewrite — different client classes, different method names, different response shapes, different tool formats. Multiply that by three providers and your head hurts.

The raw-SDK pain — three providers, three codebases
OpenAI
openai.OpenAI()
Anthropic
anthropic.Anthropic()
Google
google.generativeai
3x maintenance
different APIs

The LangChain answer: one interface, many providers

LangChain is an abstraction layer. You write your code once against its common interface (invoke, stream, batch, bind_tools, with_structured_output) and swap the provider with a single line. Same code, same method names, same response shape — whether the underlying model is GPT, Claude, or Gemini.

Raw OpenAI SDK
Session 5
  • client = OpenAI(api_key=…)
  • client.chat.completions.create(…)
  • response.choices[0].message.content
  • tools parameter: JSON schema dict
  • response_format: json_schema dict
  • Swap provider = rewrite
LangChain
Session 6
  • model = init_chat_model("openai:gpt-4.1-mini")
  • model.invoke("hello")
  • result.content
  • @tool decorator + bind_tools([func])
  • with_structured_output(PydanticModel)
  • Swap provider = one string change

Side-by-side: the same feature in both eras

Look at structured output from Session 5 lesson 17 vs Session 6 lesson 08. Both return a typed Pydantic Movie object — but notice the provider-agnostic surface of the LangChain version.

Raw OpenAI SDK (Session 5)
from openai import OpenAI
from pydantic import BaseModel

class Movie(BaseModel):
    title: str
    year: int

client = OpenAI()
response = client.responses.parse(
    model="gpt-4o-2024-08-06",
    input=[{"role": "user", "content": "Favourite movie?"}],
    text_format=Movie,
)
movie = response.output_parsed
print(movie.title)
LangChain (Session 6)
from langchain.chat_models import init_chat_model
from pydantic import BaseModel

class Movie(BaseModel):
    title: str
    year: int

# Swap "openai:gpt-4.1-mini" to "anthropic:claude-sonnet-4-5"
# or "google_genai:gemini-2.0-flash" — nothing else changes.
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
movie = model.with_structured_output(Movie).invoke("Favourite movie?")
print(movie.title)
Notice what changed
The top imports. The rest — the Pydantic class, the invoke call, the attribute access — is identical shape. The raw-SDK version is tied to OpenAI; the LangChain version works with three providers via a one-string swap.

What LangChain actually gives you

1
Interface
invoke / stream / batch / ainvoke
10+
Providers
OpenAI, Anthropic, Google, Mistral, Groq, Ollama, Bedrock…
2x
Less boilerplate
for tool calling and structured output
  • Unified method surface — invoke(), stream(), batch(), with_structured_output(), bind_tools() are identical across providers
  • Tool definition from plain Python — the @tool decorator auto-generates schemas from type hints and docstrings (no hand-written JSON schema)
  • Pydantic everywhere — structured output, tool arguments, retrieval all accept Pydantic classes directly
  • Provider prefix init — init_chat_model("openai:…") / "anthropic:…" / "google_genai:…"
  • Large ecosystem — prompt templates, retrievers, memory, caching, callbacks, LangSmith tracing

When NOT to use LangChain

Honest trade-offs
LangChain is an abstraction. Abstractions have costs: extra dependencies, indirection when debugging, and sometimes the common interface cannot expose a brand-new provider feature on day one. Know when to drop down to raw SDKs.
Use LangChain when
  • You want to support multiple providers
  • You want quick tool calling and structured output with minimal boilerplate
  • You need retrievers, memory, prompt templates, or LangGraph agents
  • You value the ecosystem of integrations over full SDK control
Use raw SDK when
  • You are locked to a single provider anyway
  • You need a day-one feature LangChain has not wrapped yet
  • You want minimal dependencies and maximum debuggability
  • You are shipping a high-volume production system that needs fine-grained control

The Session 6 arc in one picture

00 · Why
you are here
01–04
Basics
05–07
Tools
08–09
Structured

The 10 exercises that follow all use the same init_chat_model("openai:…") entry point. Everything you learned in Session 5 transfers conceptually — you are just meeting the LangChain version of the same patterns.

Knowledge check

Knowledge Check
Which problem does LangChain primarily solve?
Code Check
In init_chat_model("openai:gpt-4.1-mini"), what does the "openai:" prefix do?
Knowledge Check
When should you reach for the raw provider SDK instead of LangChain?
Recap — what you just learned
  • LangChain is an abstraction layer that gives you ONE interface across many LLM providers
  • Same code runs on OpenAI, Anthropic, and Google with a one-string change
  • Structured output and tool calling get 2x shorter with decorators and with_structured_output
  • Use raw SDKs when you are locked to one provider or need brand-new features
  • Every Session 6 exercise from here on uses init_chat_model("openai:…") as the starting point
Next up: 00 — Provider Smoke Tests