Agentic AI Course · Session Notes

Complete Agentic AI with LangChain

Focus: The Lang family, the Agent = Model + Harness model, and LLM models in depth Instructor: Mayank Scope: Part 1 of a planned 3–4 class LangChain series

This session builds the conceptual base for LangChain: what the "Lang family" of tools actually is, why an agent is nothing more than a model wrapped in a good harness, how LangChain evolved to version 1, and — in real depth — how models are wired up, from paid APIs to free OpenRouter routing to self-hosted open-source weights.

§ 00

Session at a glance

The class follows a deliberate teaching order: understand the tools, understand the core mental model, then go hands-on with the one component everything else depends on — the model. The instructor repeatedly stressed depth over speed, because "every student who got a job said the depth is what helped them in interviews."

ⓘ Prior knowledge assumed

Earlier sessions already covered LLMs, Python, and agents from scratch — the class had built agents without any framework, so everyone already knew what an agent is and how it differs from a plain LLM call. This session is where a framework (LangChain) enters to make that easier.

◆ What this session actually covered

The Lang family (LangGraph, LangChain, Deep Agents, LangSmith) → Agent = Model + Harness → LangChain's version history → why a framework matters → environment setup with uv and .env → and models in depth: init_chat_model, the response object, messages, free vs paid, open vs closed source, and OpenRouter. Messages, tools, and structured output were flagged as "next session."

§ 01

The Lang family: four offerings

LangChain (the company, San Francisco based) ships several products under one "Lang family." The instructor's framing: three of them build agents, one observes them.

▣ The four offerings

LangGraph, LangChain, and Deep Agents are all for building agents. LangSmith is for observing them — not for building. (LangFuse has "Lang" in its name but is an independent open-source project, not part of the family.)

The abstraction ladder

The three building tools sit at different levels of abstraction. Abstraction means hiding detail: lower level hides less and gives you more control; higher level hides more and gets you moving faster.

LangGraph LangChain Deep Agents Low level · most control "the load-bearing base" Middle · create_agent "the kitchen" ← we start here High level · batteries included "just order in" more abstraction → ← more control LangSmith · observes all
Deep Agents is built on LangChain, which is built on LangGraph. LangSmith watches whatever you build.
✦ Instructor analogy: the kitchen

"Starting directly with Deep Agents is like taking a job as a chef but all you know is how to order from Swiggy/Zomato. LangChain is the kitchen — you control the spice, the ingredients, the dish. LangGraph is one level lower still: you're even buying the vegetables. We master the kitchen first."

What LangSmith is for

You cannot understand an agent by reading its code, because at runtime an agent does many things — calls the LLM, reads/writes memory, invokes tools, talks to the user. LangSmith records the trace: when each step started, how long it took, how many tokens it used, where it failed.

▸ The instructor's picture of a trace

An agent's life = call AI → maybe call a tool the AI asked for → maybe save to memory → interact with the user. LangSmith is "the black box on a flight" — it captures the model calls, tool calls, and middleware around them so you can replay what happened. Very much like logging helps you understand ordinary code.

§ 02

Agent = Model + Harness

This is the load-bearing idea of the whole session, restated many times.

§ The core equation

Agent = Model + Harness. The model is the engine. On its own it is raw power that can reason about almost anything — but by itself it can do nothing: it's stateless, it doesn't remember you, it can't send an email, it doesn't know what tools exist. The harness turns that engine into a car that can actually drive.

LLM Model alone = engine powerful, but goes nowhere + LLM tools system prompt memory middleware guardrails Agent = the whole car
Frameworks like LangChain exist to build the harness around the engine.
▣ Harness engineering

A rising term: how well you harness your model. A capable model with a poor harness is useless; a modest model harnessed well can do a lot. The harness includes the system prompt, tools, middleware, guardrails, checkpoints, and memory. Products like Claude Code and ChatGPT are exactly this — a strong model plus connectors, skills, memory, and web search wrapped around it.

✦ Instructor insight

"The capability of your agent depends on the brain. Don't use the cheapest model and then complain the agent isn't smart — if you use Haiku but expect the smartest agent alive, you should have used a bigger model. It's all harness around the brain."

§ 03

The LangChain journey

LangChain has a long history by AI standards, and its shape changed dramatically with version 1. Knowing the timeline explains why online tutorials look so different from each other.

Oct 2022 · LangChain launches LLM abstraction + "chains" (predetermined steps) Early · ReAct agent First general-purpose agent (Reason + Act) Feb 2024 · LangGraph released The low-level orchestration layer that was missing Oct 2024 · LangGraph becomes default Old chains/agents marked deprecated Oct 2025 · LangChain v1 Major overhaul; built on LangGraph; agent-first. Old code → "LangChain Classic" 2026 · Deep Agents Batteries-included harness on top of LangChain agents
The pivot: LangChain went from LLM-centric to agent-centric, because "agent" only became the go-to word around mid-2025.
⚠ Watch out: version matters

Any tutorial you find must use LangChain v1.0+. Older code still runs but is now legacy ("LangChain Classic") — not maintained. The instructor's analogy: an iPhone 3 still charges, but nobody maintains it and Apple tells you to move on. Learn the latest, agent-first API only.

▣ Low level vs high level

A low-level tool gives little to no abstraction — more manual control (streaming, durable execution, short/long-term memory, human-in-the-loop). A high-level tool ("batteries included") hides the detail so you move fast but lose fine control. LangGraph is low; Deep Agents is high; LangChain sits in the productive middle.

§ 04

Why LangChain? The philosophy

The pain LangChain removes: every provider's SDK is different. To call Claude, Gemini, and OpenAI directly you write three genuinely different shapes of code.

Without LangChain client.messages.create() → Claude client.models.generate_content() → Gemini client.chat.completions.create() → OpenAI 3 SDKs, 3 message shapes, rewrite everything to switch With LangChain model.invoke(msg) OpenAIClaudeGemini … one interface; change one line to switch model
LangChain standardizes the call. Swapping OpenAI for Anthropic, OpenRouter, or Ollama is a one-line change.
◆ The philosophy, in the docs' words

LLMs are a powerful new technology; they're even better combined with external data and tools; and they will transform what applications look like. LangChain's job is to let you harness any model to its best without rewriting per-provider plumbing. The same idea recurs in every framework — CrewAI has the exact same "just tell me the model" abstraction, which is why mastering LangChain deeply makes the others quick to pick up.

✓ Practical tip from industry

Companies wrap this further. At one company the instructor worked at, an internal library exposed from mytical.ai.llm import calls — engineers just named the model, no keys, and LangChain + LangSmith in the backend tracked tokens and cost. That's the real-world pattern: a thin house wrapper over LangChain's invoke.

§ 05

Environment setup

Coding demos run on Google Colab (so a weak/office laptop is never a blocker and everyone runs the exact same shared link), while real projects are built locally in VS Code with a proper virtual environment. The instructor uses uv for environments over pip/venv.

Keeping keys safe

⚠ The classic mistake

Never hard-code API keys and never push them to GitHub. Put them in a .env file, add .env to .gitignore, and commit only a .env.example with placeholder values. "The real key never walks out."

Locally, load the key from .env; on Colab, use the Secrets panel via userdata. Either way LangChain reads it from the environment.

Exact · Colab secretslangchain_collab.ipynb
from google.colab import userdata
import os

OPENAI_API_KEY = userdata.get('OPENAI_API_KEY')
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
§ Rule: LangChain looks up keys by convention

LangChain expects the standard variable name for each provider: OPENAI_API_KEY, ANTHROPIC_API_KEY, etc. If you set OPENAI_API_KEY and then call an Anthropic model without setting ANTHROPIC_API_KEY, you get: "could not resolve authentication method…". Renaming it to OPENAI2 also breaks it — the name must match the convention.

The sanity check

To confirm the setup works, run the official create_agent example — a tiny agent with one tool. Details of every argument come later; here it's purely an environment test.

Exact · from the provided notebooklangchain_collab.py
from langchain.agents import create_agent

def get_weather(city: str) -> str:
    """Get weather for a given city."""
    return f"It's always sunny in {city}!"

agent = create_agent(
    model="openai:gpt-5.5",
    tools=[get_weather],
    system_prompt="You are a helpful assistant",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What's the weather in San Francisco?"}]}
)
print(result["messages"][-1].content_blocks)

If this runs on both Colab and VS Code, the environment is wired correctly. The point of the demo is the green light, not the arguments.

§ 06

Models in depth

The model is the core of any agent, so the session deep-dives here before touching agents further. In v1, agents are central and the LLM is a component of the agent — but you still master the model first.

Two ways to get a model

You can instantiate a provider class directly (e.g. ChatOpenAI), or use the newer, recommended init_chat_model, which gives one uniform entry point across providers.

Exact · init_chat_modellangchain_collab.py
from langchain.chat_models import init_chat_model

openai_model = init_chat_model("openai:gpt-5-mini")

response = openai_model.invoke("In one line, tell me what is Langchain?")
print(response.content)
✓ Which constructor to use

init_chat_model is the suggested default — fewer parameters, provider-agnostic. Reach for the specific class (ChatOpenAI) only when you need more control and provider-specific parameters. The reason to use init_chat_model over hard-wiring: you keep the ability to control and swap the model cleanly.

Sending structured messages

Beyond a bare string, you pass a list of typed message objects. This is where you actually control the model's behaviour — setting a role via a system message.

Exact · system + human messageslangchain_collab.py
from langchain_core.messages import SystemMessage, HumanMessage

messages = [
    SystemMessage(content="You are a pirate, answer everything in pirate language"),
    HumanMessage(content="What is the capital of France?")
]

response = openai_model.invoke(messages)
print(response.content)  # "Arrr, the capital o' France be Paris, matey!"
▣ System message

An initial set of instructions that primes the model's behaviour — sets tone, role, and response guidelines. SystemMessage, HumanMessage, and AIMessage come from langchain_core.messages. LangChain has split into submodules (like langchain_core) to keep things organized.

✓ A message list and a role-dict are equivalent

Passing [SystemMessage(...), HumanMessage(...)] and passing [{"role":"system","content":...},{"role":"user","content":...}] are effectively the same. Use whichever reads better — no behavioural difference.

The response object is rich

LangChain returns far more than text — and that extra data is what makes tracing and cost control possible "for the companies."

Exact · inspecting a responselangchain_collab.py
print("text:          ", response.text)
print("content_blocks:", response.content_blocks)
print("id:            ", response.id)
print("tool_calls:    ", response.tool_calls)

response.usage_metadata   # input_tokens, output_tokens, total_tokens, reasoning…
◆ Why this matters

Every response carries content, response_metadata (token usage, model name, finish reason), a unique id, and tool_calls. If a trace later shows a specific call id was expensive, you can find it. And it's standardized — the same shape whether the brain is OpenAI, Anthropic, or Ollama. LangChain "goes a lot beyond just calling your AI model."

§ 07

The model landscape

Any model is "a brain," and brains differ in capability — and in how you access them. Two independent axes were taught: free vs paid and closed vs open source. People constantly confuse the two, so keep them separate.

Closed source (no weights) Open source (weights out) Paid Free-ish OpenAI, Anthropic, Gemini (direct APIs) Self-host paid infra: DeepSeek, GPT-OSS via Ollama OpenRouter / Groq free tier (closed models, limited) Ollama / LM Studio "real free" if you own the box Key trap: "free" ≠ "open source"
OpenRouter can hand you closed-source models for free (with limits) — but you still can't run them yourself, because you don't have the weights.
▣ Closed vs open source

Closed source: you never see the weights/parameters — you can only use the model and pay the company (Claude, GPT-5.x). Like the Coca-Cola recipe. Open source: the company publishes the weights, so you can self-host on your own infra (DeepSeek R1, GPT-OSS) via Ollama or LM Studio. Weights and parameters are used interchangeably; more parameters (1.5B → 14B → 32B → 120B → 671B) means bigger size and heavier hardware.

⚠ "Free" is never truly free

Someone always pays. Free models usually cost you your data ("if it's free, you're the product") and come with hard limits — OpenRouter free tier is capped at ~50 requests/day and ~20/min. Self-hosting open-source is "real free" only in licensing — you still pay for infra, and a 120B model needs serious VRAM (e.g. an RTX 5090 / 32GB VRAM minimum). Smaller models are cheaper and faster but weaker.

OpenRouter: one key, many models

OpenRouter is like LangChain-for-endpoints: one account and key that fronts 100+ models from all providers, at (for common models) the same price as going direct. You call it exactly like any other model in LangChain.

Exact · OpenRouter via init_chat_modellangchain_collab.py
import os
from langchain.chat_models import init_chat_model

os.environ["OPENROUTER_API_KEY"] = "sk-or-v1-..."

# "auto" = OpenRouter picks a (possibly paid) model for you
model = init_chat_model("auto", model_provider="openrouter")

# A specific free model
free = init_chat_model("nvidia/nemotron-3-super-120b-a12b:free", model_provider="openrouter")

# "openrouter/free" = auto-route, but only across free models
free_auto = init_chat_model("openrouter/free", model_provider="openrouter")

response = model.invoke("Hello, which model are you?")
⚠ Don't rely on "auto" for routing logic

OpenRouter's auto is not intelligent task-based routing you can depend on — it routes on availability/latency/cost for their benefit, and the logic is their USP (undisclosed, changes often). It can silently pick a cheaper/weaker model or even fail. If you need real model routing, build your own logic (rule-based → classifier → LLM), don't outsource control to OpenRouter.

✓ When OpenRouter earns its place

Use it for experimentation — testing many models without juggling 10 keys and 10 billing accounts. For a single known model in production, call the provider directly for lower latency (OpenRouter may hop through Azure/Vertex, adding steps). Companies do use OpenRouter in production; just read the data-use terms, especially for free models, which log/train on your data.

✦ The same idea everywhere

Ollama and open-source weights plug into LangChain the same way; so does Azure AI Foundry, Bedrock, and Vertex. LangChain "just takes the brain" from any of them. The instructor's cloud preference: Bedrock (good connectivity, clearer pricing) over Vertex (harder pricing). Bedrock vs direct Anthropic differs mainly in latency and your company's contract/guardrails, not raw quality.

§ 08

Q&A highlights

The doubt session surfaced several ideas worth keeping — especially one very common misconception about tools.

QWhen a model "uses a tool," does the model run the tool itself?

No — and ~90% of people get this wrong. The model only decides that a tool should be called and returns the tool name + arguments in tool_calls. Your code executes the tool and passes the result back. Ask "should I take an umbrella to London?" and a good model reasons "let me check the weather" → requests the get_weather tool; it doesn't fetch weather on its own.

User Model(decides) YOUR coderuns the tool Model(answers) User tool_calls = [{name, args, id}] → you execute → ToolMessage back
The model proposes; your code disposes. This loop is the heart of tool use (covered in depth next session).
QWhy does the model give stale dates or currency values?

Because every model has a cut-off date — it only knows what it saw during training. Ask for today's date or an exchange rate and it answers from its cut-off (e.g. INR at whatever it last knew). The fix is a tool (a date/time or currency API) so the agent fetches live data instead of guessing.

QWhat exactly is "middleware"?

Everything that happens before and after the model call — logging/analytics, prompt transforming, tool selection, output formatting, and guardrails. Example: a user asks the chatbot to abuse them; middleware can block that before it reaches the model or before the response reaches the screen (a bad screenshot could tank your company's reputation). It can also stop PII (like an Aadhaar number) from ever hitting the model.

QAgent framework vs runtime vs harness — what's the difference?

Framework: the toolkit for building agents (LangChain, CrewAI, LangGraph, ADK). Runtime: the engine that actually runs your agent — checkpoints, session, state. Harness: everything around the runtime that gets the best out of the brain — tools, benchmarks, traceability, observability. They're distinct concepts, not just "tools."

QHow does prompt caching work?

Rather than reprocessing the full prompt each time, the transformer caches the KV values from the first pass and reuses them for subsequent messages in the same context — cutting cost and latency. Practically, cache the parts that stay constant: the system message, early context-setting messages, and uploaded reference material. You can't cache everything, and if your context is highly dynamic (changes every request), caching gains shrink.

QIs my data safe when calling these models?

Rule of thumb: closed-source paid models via enterprise/Azure/Bedrock contracts are generally production-safe and don't train on your data. Free models usually do train on your data. When in doubt, read the provider's terms (they change — especially after funding rounds), and inside a company just use whatever the company has approved rather than experimenting with other providers.

QAny production tip for LangChain's fast-moving versions?

LangChain has many interdependent packages (langchain, langchain-core, provider libs) under active development, so version clashes happen. For production, pin exact versions and use uv lock rather than loose >= ranges. If something breaks, the pragmatic fix is often to upgrade everything to the latest together.

✦ On "vibe coding" vs depth (interview reality)

"You're not competing with Claude Code — you're competing with another person using Claude Code, and whoever understands the code deeper wins." An interviewer told a student: in the age of copy-paste code, if you don't know the fundamentals you can't even find the bug. That's exactly why this course teaches every concept (open vs closed source, harness, tools) in depth.

§ 09

Active recall

Answer from memory before opening each one.

Explain "Agent = Model + Harness" to someone new.
The model is the engine — powerful but stateless and unable to act on its own. The harness (system prompt, tools, memory, middleware, guardrails) is the car built around it, letting the engine actually do useful work. Frameworks like LangChain exist to build that harness.
Name the four Lang-family offerings and which one is the odd one out.
LangGraph, LangChain, and Deep Agents build agents (low → high abstraction). LangSmith is the odd one out — it observes agents (traces, tokens, timing), it doesn't build them.
Why not just start with Deep Agents?
Because it hides too much for learning. Analogy: it's like being a chef who only knows how to order delivery. LangChain (the "kitchen") gives enough control to understand what's happening; Deep Agents becomes easy afterward.
When the model "calls a tool," what actually happens?
The model only decides and returns the tool name + arguments in tool_calls. Your own code executes the tool and feeds the result back as a ToolMessage; the model then produces the final answer.
What's the difference between "free" and "open source"?
Free = no upfront cost to call it (often paid with your data + rate limits), but the model can still be closed source, so you can't run it yourself. Open source = the weights are published, so you can self-host on your own infra (paying for that infra).
Why does a model return outdated facts, and how do you fix it?
It only knows up to its training cut-off date. Fix it by giving it a tool (API) that fetches live data — the agent then calls out instead of guessing.
What does response.usage_metadata give you and why care?
Token counts (input/output/total, plus reasoning). It's standardized across providers, so you can trace and control cost regardless of which brain you used.
§ 10

Quick revision

Session in 60 seconds

LangChain is a framework for building the harness around a model, so Agent = Model + Harness. The Lang family has three builders (LangGraph low-level, LangChain middle, Deep Agents high-level) plus LangSmith for observability. LangChain v1 (Oct 2025) made it agent-first; older code is "Classic." Its value: one interface for every provider — switch models in a line. Set keys via .env (never commit them). Master the model first: init_chat_model, system/human messages, and a rich standardized response. Models split on two axes: free vs paid and closed vs open source — and they're not the same thing. OpenRouter = one key for many models (great for testing, don't trust its auto-routing). The model decides to call a tool; you execute it.

Core ideas

  • Agent = Model + Harness
  • Harness engineering = how well you wrap the brain
  • Learn one framework deeply → others are easy
  • Docs are the source of truth

Key terms

  • Harness, trace, middleware, orchestration
  • ReAct = Reason + Act
  • Weights = parameters
  • Cut-off date

Code patterns

  • init_chat_model("openai:gpt-5-mini")
  • model.invoke(messages)
  • [SystemMessage(...), HumanMessage(...)]
  • response.content / .usage_metadata / .tool_calls

Watch-outs

  • Use LangChain v1.0+, not Classic
  • Never commit keys; use .env.example
  • Free ≠ open source
  • Don't depend on OpenRouter auto-routing
  • The model doesn't run the tool — you do

Instructor takeaways

  • Depth is what wins interviews
  • Pick the brain to match the task
  • Inside a company, use approved providers only
  • Pin versions with uv lock in prod

Coming next session

  • Messages in depth (AI/Tool messages)
  • Streaming & batch
  • Tools & tool execution loop
  • Structured output, parameters, middleware
ⓘ Reference notebook (not yet taught)

The shared Colab notebook (langchain_collab.py) also contains code for streaming (.stream()), .batch()/.batch_as_completed(), bind_tools(), with_structured_output() using Pydantic, and the full message-type family (AIMessage, ToolMessage). These were flagged for the next session — the instructor explicitly stopped at "messages and models" today — so they're here as a forward reference, not as material taught in this class.

✓ Resources referenced in class

LangChain docs — used live throughout as the source of truth (models, integrations, philosophy pages). OpenRouter (openrouter.ai/models) — browsing providers, free models, and the free "model router." Ollama / LM Studio — for downloading and self-hosting open-source weights. CrewAI docs — shown briefly to prove the "just name the model" abstraction is universal.