LangChain Essentials — The Only Things You Need Before LangGraph A developer outlines the minimal LangChain concepts needed before learning LangGraph, focusing on LLM setup, prompt templates with LCEL, structured output via Pydantic, and tool calling. The guide demonstrates using ChatOpenAI with Groq for free inference and emphasizes that LangGraph automates the tool-calling loop. Note:This article was written in July 2026 using LangChain 0.3.x. APIs may change in future versions — check the LangChain docs if something doesn't work. When I started learning LangChain, I got overwhelmed. There are chains, agents, memory, retrievers, output parsers — dozens of abstractions. Then I realized: most of them are deprecated. LangGraph by the same team has replaced the orchestration layer. But you still need LangChain's core building blocks inside LangGraph nodes. So I figured out the minimum you actually need to learn. Here's everything, in one file. | | Topic | Why It Matters for LangGraph | |---|---|---| | 1 | LLM Setup | You need to talk to a model | | 2 | Prompt Templates + LCEL | The LCEL pipe syntax carries over | | 3 | Structured Output | Pydantic models replace the old output parsers | | 4 | Tool Calling | This is the big one — LangGraph agents are built around the tool-calling loop | Let's walk through each one. python from langchain openai import ChatOpenAI llm = ChatOpenAI model="llama-3.3-70b-versatile", temperature=0.0, api key=os.environ "GROQ API KEY" , base url="https://api.groq.com/openai/v1", ChatOpenAI works with any OpenAI-compatible API. Here I'm using Groq for free, fast inference with Llama 3.3. python from langchain core.prompts import ChatPromptTemplate template string = """Translate the text that is delimited by triple backticks \ into a style that is {style}. text: {text} """ prompt template = ChatPromptTemplate.from template template string chain = prompt template | llm response = chain.invoke {"style": "formal English", "text": "yo what's up"} The pipe | syntax is called LCEL LangChain Expression Language . It replaces the old LLMChain , SequentialChain , etc. Simple and composable. The old way required ResponseSchema , StructuredOutputParser , and injecting format instructions into your prompt. The new way is just Pydantic: python from pydantic import BaseModel, Field class ReviewInfo BaseModel : """Information extracted from a product review.""" gift: bool = Field description="Was the item purchased as a gift?" delivery days: int = Field description="How many days to arrive? -1 if unknown." price value: list str = Field description="Sentences about value or price." structured llm = llm.with structured output ReviewInfo, method="function calling" result = prompt | structured llm .invoke {"text": review} print result.gift True a real bool, not the string "true" print result.delivery days 2 a real int Who does what: | Step | Who | |---|---| | Converting Pydantic → JSON schema | LangChain | | Understanding schema & producing JSON | The LLM | | Parsing JSON back into Pydantic obj | LangChain | No more format instructions in your prompt. The LLM never sees "return JSON" — it uses function calling under the hood. This is what LangGraph automates. Understanding it manually first makes LangGraph click instantly. Define tools — just Python functions with the @tool decorator: python from langchain core.tools import tool @tool def get current weather city: str - str: """Get the current weather for a given city.""" return {"berlin": "17°C, cloudy"}.get city.lower , "No data" @tool def get population city: str - int: """Get the approximate population of a city.""" return {"berlin": 3 700 000}.get city.lower , -1 The @tool decorator transforms these into BaseTool objects. The docstring becomes the description the LLM reads to decide when to call it. Bind tools and call: tools = get current weather, get population llm with tools = llm.bind tools tools messages = HumanMessage "What's the weather and population in Berlin?" ai response = llm with tools.invoke messages print ai response.tool calls {"name": "get current weather", "args": {"city": "Berlin"}, "id": "..."}, {"name": "get population", "args": {"city": "Berlin"}, "id": "..."} The LLM does not execute the tools. It returns a structured request asking you to run them. Execute tools and send results back: tool map = {t.name: t for t in tools} messages.append ai response for tc in ai response.tool calls: result = tool map tc "name" .invoke tc "args" messages.append ToolMessage content=str result , tool call id=tc "id" final response = llm with tools.invoke messages print final response.content "The weather in Berlin is 17°C and cloudy, with a population of 3.7 million." This loop — LLM decides → you execute → send result back → repeat — is exactly what LangGraph's ToolNode automates. If you're heading to LangGraph, don't bother learning these legacy LangChain abstractions: LLMChain → replaced by LCEL prompt | llm SequentialChain → replaced by LCEL pipes RouterChain → replaced by LangGraph branching ConversationChain → replaced by LangGraph state AgentExecutor → replaced by LangGraph agent loopLangGraph is not a replacement for LangChain — it builds on top of it: LangGraph came in early 2024 because LangChain's original agent/chain abstractions were too rigid — hard to customize, no support for cycles or branching, and memory was bolted on rather than built in. The entire thing is one file: github.com/santanu2908/langchain-essentials git clone https://github.com/santanu2908/langchain-essentials.git cd langchain-essentials uv sync add your GROQ API KEY to .env uv run main.py Next up: LangGraph. If this helped you, follow along — I'll be sharing that journey too. I'm Santanu Mohanta — connect with me on LinkedIn https://www.linkedin.com/in/santanu29/ or check out my projects on GitHub https://github.com/santanu2908 .