A beginner-friendly practice project for learning how to build Generative AI applications with LangChain.
This repo is built around small Jupyter notebooks. Each notebook teaches one idea at a time: calling chat models, using messages, getting structured output, giving tools to a model, and building simple agents.
By going through this project, you will understand:
- What LangChain is and why developers use it
- How to call LLMs from providers like Groq and Google Gemini
- How prompts and messages work
- How to keep conversation context
- How to make model output easier to use with structured output
- How tools let an AI model call Python functions or search the web
- How agents decide which tool to use and when
- How streaming and batching improve AI app behavior
- How LangChain is different from LangGraph
- When to use LangChain, LangGraph, chains, tools, and agents
LangChain is a framework for building applications that use language models.
A language model can answer questions and generate text, but a real application usually needs more than that. It may need prompts, chat history, tools, search, APIs, databases, structured output, and multi-step workflows.
LangChain gives you reusable building blocks for those tasks.
In simple words:
LangChain helps you connect an AI model with the rest of your application.
LangChain is useful when you want to:
- Call different AI models with similar code
- Write prompts in a clean way
- Build chatbots with message history
- Ask models to return structured data
- Give models access to tools
- Build AI workflows step by step
- Stream responses to the user
- Build agents that can decide which tool to use
You can call an LLM API directly without LangChain. That is fine for very small projects.
But as your app grows, you may need to solve common problems:
- Different model providers have different APIs
- Chat messages need roles like system, human, AI, and tool
- Tool calling needs a clean loop
- Model output often needs parsing and validation
- Long workflows need clear steps
- Agents need a way to manage tools and decisions
LangChain gives structure to these problems so you do not write everything from scratch every time.
Most LangChain apps follow this flow:
User question
-> Prompt or messages
-> Chat model
-> Optional tools
-> Optional structured format
-> Final answer
LangChain helps connect these parts together in a clean way.
Without LangChain, you usually write separate code for every model provider, every message format, every tool call, and every output parser. LangChain gives you common building blocks so your code is easier to change and grow.
This project already includes the needed packages in requirements.txt.
Common packages used here:
langchain: main LangChain packagelangchain-core: core interfaces and message typeslangchain-groq: Groq model integrationlangchain-google-genai: Google Gemini integrationlangchain-tavily: Tavily search tool integrationlanggraph: graph-based agent/workflow frameworkpython-dotenv: loads API keys from.env
API keys are stored in .env.
Example:
GROQ_API_KEY=your_groq_key_here
GOOGLE_API_KEY=your_google_key_here
TAVILY_API_KEY=your_tavily_key_here
Then Python can load them using:
from dotenv import load_dotenv
load_dotenv()A chat model is the object you use to talk to the LLM.
Example with Groq:
from langchain.chat_models import init_chat_model
model = init_chat_model(
"llama-3.1-8b-instant",
model_provider="groq"
)Example with Gemini:
from langchain.chat_models import init_chat_model
model = init_chat_model("google_genai:gemini-2.5-flash-lite")response = model.invoke("Explain LangChain in simple words")
print(response.content)This is the most basic LangChain flow:
prompt -> model -> response
Messages let you give roles to the conversation.
from langchain.messages import SystemMessage, HumanMessage
messages = [
SystemMessage("You are a helpful AI teacher."),
HumanMessage("Explain RAG in simple words.")
]
response = model.invoke(messages)
print(response.content)Structured output is used when you want the model to return data in a fixed format.
from pydantic import BaseModel, Field
class Movie(BaseModel):
title: str = Field(..., description="Movie title")
director: str = Field(..., description="Movie director")
year: int = Field(..., description="Release year")
model_with_structure = model.with_structured_output(Movie)
response = model_with_structure.invoke("Give details about Inception")Now the response can be used like normal Python data.
A tool is a Python function that the model can ask to use.
from langchain.tools import tool
@tool
def get_weather(location: str) -> str:
"""Get the weather at a location."""
return f"It's sunny in {location}"
model_with_tools = model.bind_tools([get_weather])The model can request the tool, but your program executes it.
An agent combines a model with tools and lets the model decide what to do.
from langchain.agents import create_agent
agent = create_agent(
model=model,
tools=[get_weather]
)
response = agent.invoke({
"messages": [
{"role": "user", "content": "What is the weather in Bangalore?"}
]
})Use agents when the AI needs to choose a tool or decide the next step.
LangChain and LangGraph are related, but they solve different problems.
LangChain is best for common LLM app building blocks.
Use LangChain when you need:
- Prompting
- Chat models
- Messages
- Output parsing
- Structured output
- Tool calling
- Simple chains
- Basic agents
Think of LangChain as the toolkit.
LangGraph is used for graph-based AI workflows.
It helps when your app has multiple steps, branches, loops, state, memory, or agent-like behavior that must be controlled carefully.
Use LangGraph when you need:
- Multi-step workflows
- State management
- Conditional paths
- Loops
- Human approval steps
- More reliable agents
- Complex agent systems
- Workflows that can pause, resume, or inspect state
Think of LangGraph as the workflow engine.
LangChain = components for building LLM apps
LangGraph = graph/workflow system for controlling complex LLM apps
Use LangChain for:
User asks question -> model answers
Use LangGraph for:
User asks question
-> classify the task
-> choose search or calculator
-> call tool
-> check result
-> maybe ask human
-> generate final answer
Use LangChain first when you are learning or building a simple app.
Use LangGraph when your app starts needing clear control over many steps.
In real projects, they are often used together:
LangChain provides the model, tools, and messages.
LangGraph controls the workflow between them.
python -m venv .venvActivate it:
.\.venv\Scripts\Activate.ps1pip install -r requirements.txtCopy the example environment file:
copy .env.example .envThen open .env and add your keys:
GROQ_API_KEY=your_groq_key_here
GOOGLE_API_KEY=your_google_key_here
TAVILY_API_KEY=your_tavily_key_here
You do not need every key for every notebook:
- Groq key is used in most examples.
- Google key is used for Gemini examples.
- Tavily key is used for web search tool examples.
Open the generativeai folder in VS Code or Jupyter, then start with:
generativeai/langchainIntro.ipynb
Start here. This notebook introduces the basic LangChain flow:
- Import LangChain
- Create a chat model
- Send a prompt
- Read the model response
- Try different model providers
- Use streaming for live output
- Use batching for multiple independent requests
Key idea: a chat model is the AI engine. You send input to it, and it returns a response.
This notebook explains how LangChain represents conversations.
Important message types:
SystemMessage: tells the model how to behaveHumanMessage: represents the user's inputAIMessage: represents the model's responseToolMessage: represents the result returned by a tool
Key idea: messages are better than plain strings when you need roles, memory, instructions, tool calls, or conversation history.
Example:
System: You are a data science expert.
Human: Explain RAG applications.
AI: Here is an explanation...
Normal model responses are text. Text is easy for humans to read, but harder for programs to use.
Structured output asks the model to respond in a fixed shape, such as:
{
"title": "Inception",
"director": "Christopher Nolan",
"year": 2010,
"rating": 8.8
}This project uses Pydantic models to define the expected shape.
Key idea: structured output is useful when the AI response needs to be saved, validated, displayed in a UI, or passed to another function.
Tools are functions that a model can request to use.
A tool has two parts:
- A schema that tells the model what the tool does and what arguments it needs
- A function that actually runs in Python
Example:
@tool
def get_weather(location: str) -> str:
"""Get the weather at a location."""
return f"It's sunny in {location}"Key idea: the model does not magically know live data or run code by itself. It asks for a tool call, your program runs the tool, and then the result is sent back to the model.
Basic tool loop:
User asks a question
-> Model decides it needs a tool
-> Program executes the tool
-> Tool result goes back to the model
-> Model writes the final answer
An agent is a model plus tools plus a loop for deciding what to do next.
In a simple chain, you usually define the exact steps yourself.
In an agent, the model can choose:
- Whether it needs a tool
- Which tool to use
- What arguments to pass
- When it has enough information to answer
Key idea: agents are useful when the task is flexible and the model needs to make decisions.
This notebook expands the agent idea by giving it multiple tools:
- Tavily search for web information
- Calculator tool for math
Key idea: when an agent has multiple tools, it can choose the best tool for the task. For example, it can search the web for current information and use a calculator for arithmetic.
Note: the calculator example uses Python eval() for learning purposes. In real applications, avoid raw eval() with user input because it can run unsafe code.
A chat model is the AI model object you call from your code.
It receives prompts or messages and returns an AI response.
Example:
model.invoke("Explain AI")
The model is the brain of the application, but it does not automatically know your private data, run your code, or search the web unless you connect those abilities.
An LLM, or Large Language Model, is an AI model trained to understand and generate text.
Examples:
- Gemini
- Llama
- Qwen
- GPT-style models
In this project, the model is used through LangChain wrappers such as Groq and Google Gemini integrations.
A prompt is the instruction or question you send to the model.
Simple prompt:
Explain Newton's third law.
Prompts are best for one-time questions where you do not need conversation history or special roles.
Messages are a structured way to talk to chat models.
Instead of sending only a string, you send a list of role-based messages. This helps the model understand who is speaking and what each message means.
Use messages when:
- You want a system instruction
- You are building a chatbot
- You need conversation history
- You are using tools
- You need better control over behavior
A system message sets the behavior of the model.
Example:
You are a helpful teacher. Explain every answer in simple language.
The system message is useful because it guides the style, role, and rules for the model.
Structured output means asking the model to return data in a predictable format.
Instead of getting a paragraph, you can get fields like:
- name
- title
- year
- rating
- summary
This is important because software needs predictable data. A paragraph is flexible, but a schema is easier to validate and use.
A tool is a function that the model can ask your program to run.
Tools are useful when the model needs to:
- Search the web
- Look up private data
- Run calculations
- Call an API
- Read from a database
- Perform an action
The model chooses the tool call, but your Python code executes it.
An agent is an AI system that can reason about what step to take next.
An agent usually has:
- A model
- A list of tools
- Instructions
- A loop that continues until the task is done
Agents are powerful, but they should be used carefully. If your task has fixed steps, a normal chain is often simpler. If your task needs decision-making, an agent can be useful.
Streaming means showing the response while the model is still generating it.
Instead of waiting for the full answer, users see text appear gradually.
Streaming is useful for:
- Chatbots
- Long answers
- Better user experience
- Showing progress
Batching means sending many independent requests together.
This can be useful when you need answers for multiple prompts and they do not depend on each other.
Example:
Prompt 1: Explain AI.
Prompt 2: Explain parrots.
Prompt 3: Explain Newton's third law.
The model can process them more efficiently as a batch.
A chain is a fixed sequence of steps.
Example:
User input -> prompt template -> model -> output parser
Use a chain when you already know the exact order of work.
Chains are easier to understand than agents because the developer controls the flow.
In LangGraph, state is the shared data that moves through the workflow.
For example, state may contain:
- User question
- Chat messages
- Tool results
- Current step
- Final answer
Each graph node can read the state, update it, and pass it to the next node.
In LangGraph, a node is one step in the workflow.
Examples of nodes:
- Call the model
- Search the web
- Run a calculator
- Check if the answer is complete
- Ask a human for approval
An edge connects one node to another.
Edges decide where the workflow goes next.
There are two common types:
- Normal edge: always goes to the next step
- Conditional edge: chooses the next step based on the current state
A chain is best when the steps are predictable.
Input -> Model -> Output
Use a chain for simple tasks like summarization, classification, rewriting text, or extracting structured data.
An agent is best when the model needs to decide what to do.
Input -> Model decides -> Tool maybe runs -> Model answers
Use an agent when the task may require different tools depending on the user's question.
A graph is best when the workflow has multiple controlled steps.
Input -> Node A -> condition -> Node B or Node C -> Final answer
Use LangGraph when you need state, loops, branches, retries, human review, or more reliable control over an agent workflow.
LangChain is not the model. It is the framework that helps you use models.
Groq, Google Gemini, OpenAI, and others provide the actual models.
A prompt is usually a simple string.
A message has a role, content, and sometimes metadata. Messages are better for chat, tools, and multi-turn conversations.
The model creates a tool call request.
Your code executes the tool.
The model does not directly run your Python function by itself.
A chain follows steps you define.
An agent decides some steps by itself.
Use chains for predictable workflows. Use agents when the model needs to choose actions.
An agent can decide actions, but the flow can become hard to control as the task grows.
LangGraph helps you control that flow with nodes, edges, and state.
Use a basic agent for simple tool choice. Use LangGraph when the agent needs a more reliable workflow.
After finishing the notebooks, try these exercises:
- Change the system message and compare responses
- Create a tool that converts currency or units
- Create a structured output schema for books, products, or students
- Give an agent two tools and ask questions that require choosing between them
- Add error handling when an API key is missing
- Replace the fake weather tool with a real weather API
- Build a small chatbot that keeps message history
- Never commit your
.envfile. - Keep API keys private.
- Be careful with tools that run code, write files, call APIs, or spend money.
- Avoid using raw
eval()with user input in real projects. - Always validate structured output before trusting it in production.
Install packages:
pip install -r requirements.txtRun the simple Python file:
python main.pyStart Jupyter if needed:
jupyter notebookIf you are new, follow this order:
langchainIntro
-> messages
-> structuredOutput
-> tools
-> agentintro
-> agentsMultipleTools
Learn one concept, run the notebook, change a small part, and run it again. That is the fastest way to understand LangChain.