Hey! 👋 This repo is a hands-on, notebook-by-notebook walkthrough of how to build real things with LangChain and LangGraph — from your very first LLM call all the way to autonomous agents that query databases and search the web on their own.
No hand-wavy theory here — every notebook runs, every concept is shown in code, and everything builds on the previous one.
📚 Official docs:
Think of it in three layers:
┌────────────────────────────────────────────────┐
│ Layer 3 — Agents (LangGraph) │
│ Autonomous loops: Thought → Action → Observe │
├────────────────────────────────────────────────┤
│ Layer 2 — Chains (LCEL) │
│ Composable pipelines wired with | │
├────────────────────────────────────────────────┤
│ Layer 1 — Models & Messages │
│ Raw LLM calls, prompts, structured output │
└────────────────────────────────────────────────┘
The foundation. You send messages to a model, it sends one back. LangChain wraps OpenAI, Anthropic, Google etc. behind a unified interface so you swap providers without rewriting your app. You also learn to force the model to return validated JSON (with_structured_output) instead of free text.
LangChain Expression Language lets you compose steps with | — the pipe operator. Each step is a Runnable, and you can chain prompts, models, parsers, custom functions, and branches together like plumbing. Things like running two LLM calls in parallel or routing to different branches based on a condition all live here.
This is where it gets interesting. Instead of a fixed pipeline, you give the LLM a set of tools (web search, database queries, custom functions) and a graph (LangGraph) that runs in a loop. The model reasons about what it needs, calls a tool, reads the result, and keeps going until it has an answer. It's genuinely autonomous — you ask "what's the total sales value?" and it writes and executes the SQL itself.
Start here if you've never used LangChain before.
| Notebook | What you'll learn |
|---|---|
| 1 · LLM Call | Three ways to call an LLM: raw OpenAI SDK, ChatOpenAI, ChatAnthropic, and init_chat_model |
| 2 · Messages | SystemMessage, HumanMessage, AIMessage, multi-turn conversations, and ChatPromptTemplate |
| 3 · Structured Output | How to force an LLM to return validated JSON using Pydantic models and .with_structured_output() |
Why these matter: Every agent, chain, and pipeline you build later runs on top of these primitives. If you don't understand message types and structured output, debugging agents later is really painful.
Once you know how to call a model, you start composing steps into pipelines.
| Notebook | What you'll learn |
|---|---|
| 1 · First Chain | Your first ChatPromptTemplate | ChatOpenAI | StrOutputParser pipeline — the hello world of LCEL |
| 2 · Custom Runnable Chain | Chaining two LLM calls together — a NASA scientist generates a plan, an engineer executes it |
| 3 · Parallel Chains | RunnableParallel to fan out into two branches simultaneously (movie critic + Twitter post) |
| 4 · Conditional Chain | RunnableBranch to route to different outputs based on sentiment — LinkedIn vs Instagram post generator |
Why these matter: LCEL is how you build anything deterministic — RAG pipelines, document processors, multi-step workflows. The parallel and conditional patterns are used constantly in production apps.
This is the payoff. Agents that actually do stuff in the real world.
| Notebook | What you'll learn |
|---|---|
| 1 · ReAct Agent Intro | Build your first agent with web search (DuckDuckGo), Wikipedia, and a custom @tool — asks questions, searches the web, answers |
| 2 · SQL DB Agent | Agent that connects to a real SQLite database, figures out the schema on its own, writes SQL, validates it, and answers natural-language queries |
Why these matter: This is where LangGraph comes in. create_agent builds a LangGraph StateGraph with two nodes — model and tools — wired in a loop. The model keeps calling tools until it's confident in its answer. It's the backbone of copilots, AI assistants, and data agents.
┌─────────────────────────────────┐
│ CompiledStateGraph │
│ │
User ──► │ ┌──────────┐ ┌───────────┐ │ ──► Answer
question │ │ model │──►│ tools │ │
│ │ node │◄──│ node │ │
│ └──────────┘ └───────────┘ │
│ loops until no tool calls │
└─────────────────────────────────┘
- model node — the LLM sees the messages and either answers (done) or requests a tool call
- tools node — LangGraph runs the requested tool and appends a
ToolMessageto the state - back to model node — the model now sees the tool result and decides what to do next
- repeat until the model produces a plain
AIMessagewith no tool calls
The whole state is a list of messages. Every node reads from it and writes to it. stream_mode="values" lets you watch every step as it happens.
# clone
git clone [email protected]:EmiRoberti77/langchain_tutorial.git
cd langchain_tutorial
# install deps (uses uv)
uv sync
# or with pip
pip install langchain langchain-openai langchain-anthropic langchain-community python-dotenv
# add your keys
cp .env.example .env # then fill in your keys.env needs:
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
Then just open any notebook in VS Code or Jupyter and run the cells top to bottom.
CH-1/1 → CH-1/2 → CH-1/3
↓
CH-2/1 → CH-2/2 → CH-2/3 → CH-2/4
↓
CH-3/1 → CH-3/2
Each notebook is self-contained so you can jump around, but following the path means concepts build properly — structured output from CH-1/3 is used in CH-2/4, and the agent pattern from CH-3/1 is extended in CH-3/2.
- CH-3/3 — RAG agent (retrieval over your own documents)
- CH-4 — Memory and multi-turn agents
- CH-5 — Multi-agent systems
Built with ☕ and way too many LLM tokens.