🌐 Try the deployed app:
https://tripmates-ai.netlify.app/
A hands-on learning repository documenting my journey through Agentic AI — from foundational state management and graph-based workflows to a fully deployed multi-agent travel planning system with a Supervisor, MCP integrations, Guardrails, and Human-in-the-Loop approval.
- Overview
- What This Repository Covers
- Projects & Implementations
- Concept Matrix
- Architecture
- Technology Stack
- Project Structure
- Getting Started
- Configuration
- Running the Projects
- API Reference
- Learning Journey
- Key Learnings
- Future Roadmap
- Security
- Contributing
- License
- Author
This repository is a structured, implementation-first learning journey through Agentic AI engineering. Every file here represents a concept learned and then immediately built — not just read about.
The progression moves from understanding how LangGraph state works, through increasingly complex graph topologies (sequential, parallel, conditional, iterative), all the way to a production-style multi-agent system that orchestrates five specialist AI agents, integrates three external MCP servers, enforces input guardrails, and requires human approval before finalizing a travel plan.
The goal is simple: learn by building real things, understand why each pattern exists, and develop the intuition to design agentic systems from scratch.
- State definition using TypedDict, Pydantic, dataclasses, and MessagesState
- Graph nodes, edges, and the START/END lifecycle
- Sequential execution pipelines
- Parallel branch execution with custom reducers
- Conditional routing based on state
- Iterative loops with tool calling and exit conditions
- PDF document loading and chunking
- HuggingFace sentence-transformer embeddings
- FAISS vector store retrieval
- Query classification and conditional RAG routing
- Context-aware response generation
- Human-in-the-Loop with
interrupt()andCommand(resume=...) - In-memory checkpointing with
MemorySaver - Persistent checkpointing with PostgreSQL
- Multi-agent orchestration with a Supervisor
- Input guardrails using LLM-based validation
- MCP (Model Context Protocol) server and client integration
- Dynamic agent selection based on query intent
File: states.py
Explores the four main approaches to defining state in LangGraph:
- TypedDict — the most common approach, simple key-value state
- Pydantic BaseModel — adds runtime type validation and field validators
- Python dataclass — standard dataclass with default factories
- MessagesState — LangGraph's built-in state that includes the
add_messagesreducer, extended with custom fields
from langgraph.graph import MessagesState
class State(MessagesState):
user_name: str
language: strThis file is the conceptual foundation for everything else in the repository.
File: sequential_base.py
A three-stage content pipeline that demonstrates how to chain nodes in a strict linear order.
What it does: Takes raw text input → cleans grammar and tone (Editor) → transforms it into a YouTube-style video script (Scriptwriter) → converts the script into natural Hinglish for the Indian market (Translator).
Graph topology:
START → editor → scriptwriter → translator → END
Key concepts demonstrated:
- Defining a pipeline state with typed fields
- Writing focused single-responsibility nodes
- Connecting nodes with
add_edgefor strict sequential execution - Using
llama-3.3-70b-versatilevia Groq for each stage
File: parallel_reducers.py
A content safety analyzer that runs three independent analysis branches simultaneously and merges their results into a single state field using a custom reducer.
What it does: Takes a text sample and simultaneously scores it for:
- Toxicity and hate speech
- Copyright and originality risk
- Regional and cultural sensitivity
Graph topology:
START → toxicity_node ─┐
START → copyright_check ─┼→ END
START → culture_node ─┘
Key concept — custom reducer:
def merge_score_dicts(existing: dict, new_update: dict) -> dict:
if existing is None:
return new_update
return {**existing, **new_update}
class AnalyzerState(TypedDict):
raw_text: str
safety_scores: Annotated[dict[str, int], merge_score_dicts]Each parallel branch writes to the same safety_scores key. The reducer merges all three sub-dictionaries into one without overwriting.
File: iterative_tools.py
A LinkedIn post generator that loops between a writer agent and a reviewer agent until the post is approved or the maximum attempt limit is reached.
What it does:
- Writer drafts a LinkedIn post (optionally using Tavily web search for fresh data)
- Reviewer scores the draft against strict criteria
- If rejected, the writer rewrites with the feedback
- Loop continues until approved or 3 attempts are exhausted
Graph topology:
START → writer → [tools if needed] → extract_draft → reviewer
↓
approved? → END
rejected? → writer (loop)
Key concepts demonstrated:
- Conditional edges for tool-call detection (
should_use_tool) - Conditional edges for loop control (
should_stop_looping) ToolNodefor automatic tool executionbind_toolsto give the LLM access to Tavily search- Two different LLMs in one graph: GPT-4o-mini (writer) + LLaMA 3.3 (reviewer)
File: humanintheloop.py
The same LinkedIn post generator as iterative_tools.py, but the automated reviewer is replaced by a real human. The graph pauses mid-execution and waits for human input before continuing.
What it does:
- Writer drafts a LinkedIn post
- Graph pauses and presents the draft to the human
- Human types
approvedor provides revision feedback - Graph resumes from the exact pause point
- If feedback was given, writer rewrites; if approved, workflow ends
Key concepts demonstrated:
interrupt()to pause graph execution and surface data to the callerCommand(resume=...)to inject human input and resumeMemorySavercheckpointer to persist state across the pause- Thread-based session management with
configurable: {thread_id: ...}
human_response = interrupt({
"draft": state["draft"],
"instruction": "Type 'approved' to accept, or type your feedback."
})File: conditional_RAG.py
A college student assistant that classifies each query and routes it to the appropriate knowledge source before generating a response.
What it does: A student asks a question. The system classifies it as academic, fee, or general, then:
academic→ retrieves fromacademics_handbook.pdfvia FAISSfee→ retrieves fromfee_structure.pdfvia FAISSgeneral→ answers directly from the LLM without retrieval
Graph topology:
START → classifier → route_query()
↓
academic_rag / fee_rag / general
↓
response → END
RAG pipeline:
- PDF loading with
PyPDFLoader - Chunking with
RecursiveCharacterTextSplitter(800 chars, 100 overlap) - Embeddings:
sentence-transformers/all-MiniLM-L6-v2via HuggingFace - Vector store: FAISS (top-4 retrieval)
- LLM:
llama-3.3-70b-versatilevia Groq
File: app.py
A Streamlit web application wrapping the same conditional RAG graph from conditional_RAG.py with a proper chat interface.
Features:
- Programme selection sidebar (BCA, BBA, B.Com H)
- Persistent multi-turn chat history
- Query-type badges (ACADEMIC / FEE / GENERAL) on each response
- Cached resource loading so the vector stores are built only once
- Clear chat button
Run it:
streamlit run app.pyDirectory: Multi-Agent-System-using-LangGraph-MCP-Supervisor-Guardrails-HITL-main/
The most complete project in this repository. TripMate AI is a full-stack multi-agent travel planning application built with FastAPI, LangGraph, and three MCP server integrations.
What it does: A user describes a trip in natural language. The system validates the request, dynamically selects the right specialist agents, gathers live flight/hotel/weather/budget data, drafts an itinerary, pauses for human review, and then generates a polished final travel plan.
User Request (HTTP POST /api/travel)
↓
Supervisor Agent
├── Input Guardrail (LLM-based validation)
├── Agent selection (dynamic, based on query)
└── Trip constraint extraction
↓
[Selected Specialist Agents — run in order]
├── Flight Agent → AviationStack MCP (airports, airlines)
├── Hotel Agent → Tavily MCP (live web search)
├── Weather Agent → Custom Weather MCP (OpenWeatherMap)
└── Budget Agent → LLM analysis of all gathered data
↓
Itinerary Agent (synthesizes all results into a draft)
↓
Human Approval (graph pauses — HITL via interrupt())
├── Approved → Final Agent polishes and returns plan
└── Rejected → Final Agent applies feedback and revises
↓
Final Response (HTTP POST /api/travel/approve)
| Agent | Data Source | Responsibility |
|---|---|---|
flight_agent |
AviationStack MCP (list_airports, list_airlines) |
Airports, airlines, routes, airfare estimates |
hotel_agent |
Tavily MCP (tavily_search) |
Live hotel and accommodation search |
weather_agent |
Custom Weather MCP (get_current_weather, get_forecast) |
Current weather + 5-entry forecast |
budget_agent |
LLM synthesis of all above | Cost categories, risk areas, money-saving tips |
itinerary_agent |
All specialist results | Draft day-by-day travel plan |
Three MCP servers are connected via langchain-mcp-adapters:
- Tavily MCP —
streamable_httptransport tomcp.tavily.com - AviationStack MCP —
stdiotransport viauvx aviationstack-mcp - Custom Weather MCP —
stdiotransport, runscustom_weather_mcp_server.pyas a subprocess using OpenWeatherMap API
The Supervisor runs an LLM-based input guardrail before any agent is invoked. It returns a JSON verdict (allowed: true/false) and blocks requests unrelated to travel planning. On parser failure, it fails open to preserve the travel workflow.
State is persisted across the HITL pause using PostgreSQL via langgraph-checkpoint-postgres. Each conversation is identified by a thread_id, allowing the /api/travel/approve endpoint to resume the exact paused graph state.
A vanilla HTML/CSS/JavaScript single-page app served by FastAPI via Jinja2 templates:
- Travel request input with quick-prompt buttons
- Supervisor workflow panel showing selected agents and guardrail status
- Draft itinerary display with Markdown rendering
- Human approval panel with feedback textarea
- Copy to clipboard and PDF download (html2pdf.js)
| Concept | Implementation | Key Technology | What It Demonstrates |
|---|---|---|---|
| State Definition | states.py |
TypedDict, Pydantic, MessagesState | Four approaches to LangGraph state |
| Sequential Workflow | sequential_base.py |
LangGraph, Groq | Linear node chaining, pipeline design |
| Parallel Execution | parallel_reducers.py |
LangGraph, Annotated reducers | Fan-out branches, state merging |
| Iterative Loop | iterative_tools.py |
LangGraph, ToolNode, Tavily | Conditional loops, tool calling, multi-LLM |
| Human-in-the-Loop | humanintheloop.py |
interrupt(), MemorySaver |
Graph pause/resume, human feedback injection |
| Conditional RAG | conditional_RAG.py |
FAISS, HuggingFace, LangGraph | Query routing, PDF retrieval, context-aware generation |
| RAG Web UI | app.py |
Streamlit, LangGraph | Wrapping a graph in a chat interface |
| Supervisor Pattern | backend.py |
LangGraph, Groq | Dynamic agent selection, guardrails |
| MCP Integration | mcp_client.py |
MCP, langchain-mcp-adapters | Multi-server MCP client, tool invocation |
| Custom MCP Server | custom_weather_mcp_server.py |
FastMCP, OpenWeatherMap | Building and exposing MCP tools |
| PostgreSQL Checkpointing | backend.py |
langgraph-checkpoint-postgres | Persistent state across HTTP requests |
| Full-Stack Agent App | TripMate AI | FastAPI, LangGraph, HTML/JS | End-to-end agentic application |
flowchart TD
A[User Input] --> B[State Initialization]
B --> C[Graph Entry Node]
C --> D{Conditional Router}
D -->|Path A| E[Node A]
D -->|Path B| F[Node B]
D -->|Path C| G[Node C]
E --> H[Merge / Next Node]
F --> H
G --> H
H --> I{Loop or End?}
I -->|Loop| C
I -->|End| J[Final Output]
flowchart TD
U[User Travel Request] --> S[Supervisor Agent]
S --> GR{Guardrail Check}
GR -->|Blocked| GB[Guardrail Blocked Response]
GR -->|Allowed| AG[Dynamic Agent Selection]
AG --> FA[Flight Agent - AviationStack MCP]
AG --> HA[Hotel Agent - Tavily MCP]
AG --> WA[Weather Agent - Custom MCP]
FA --> BA[Budget Agent]
HA --> BA
WA --> BA
BA --> IA[Itinerary Agent - Draft]
IA --> HI[Human Approval - interrupt]
HI -->|Approved| FIN[Final Agent - Polish]
HI -->|Rejected + Feedback| FIN
FIN --> R[Final Travel Plan]
flowchart TD
Q[Student Query] --> CL[Classifier Node]
CL --> RT{Route Query}
RT -->|academic| AR[Academic RAG - FAISS]
RT -->|fee| FR[Fee RAG - FAISS]
RT -->|general| GN[General Node - No Retrieval]
AR --> RS[Response Node]
FR --> RS
GN --> RS
RS --> ANS[Answer]
- LangGraph
1.2.2— graph-based agent orchestration, state management, HITL - LangChain
1.3.2— LLM abstraction, document loaders, text splitters - langchain-groq
1.1.3— Groq LLM integration - langchain-mcp-adapters
0.3.0— MCP server connections - MCP
1.28.1— Model Context Protocol, FastMCP server
- LLaMA 3.3 70B Versatile (via Groq) — primary LLM across all projects
- GPT-4o-mini (via OpenAI) — writer LLM in iterative and HITL workflows
- sentence-transformers —
all-MiniLM-L6-v2embeddings - FAISS (
faiss-cpu) — local vector store - PyPDF — PDF document loading
- langchain-text-splitters — recursive character chunking
- FastAPI
0.136.3— REST API for TripMate AI - Uvicorn
0.48.0— ASGI server - Jinja2
3.1.6— HTML templating - psycopg
3.3.4— PostgreSQL driver - langgraph-checkpoint-postgres
3.1.0— persistent graph checkpointing
- Vanilla HTML, CSS, JavaScript
marked.js— Markdown renderinghtml2pdf.js— PDF export
- Groq API — LLM inference
- Tavily API — web search (via MCP and direct)
- AviationStack API — airport and airline data (via MCP)
- OpenWeatherMap API — current weather and forecast (via custom MCP server)
- Docker — containerized deployment for TripMate AI
- PostgreSQL — persistent checkpoint storage
- Streamlit — web UI for College Assistant
Agentic-AI-Learning/
│
├── states.py # LangGraph state definition patterns
├── sequential_base.py # Sequential 3-stage content pipeline
├── parallel_reducers.py # Parallel content safety analyzer
├── iterative_tools.py # Iterative LinkedIn post generator (auto-review)
├── humanintheloop.py # LinkedIn post generator with human review
├── conditional_RAG.py # Conditional RAG college assistant (CLI)
├── app.py # Streamlit UI for the college assistant
│
├── academics_handbook.pdf # RAG knowledge source — academic rules
├── fee_structure.pdf # RAG knowledge source — fee information
│
├── requirements.txt # Root-level Python dependencies
│
└── Multi-Agent-System-using-LangGraph-MCP-Supervisor-Guardrails-HITL-main/
│
├── app.py # FastAPI application, API endpoints
├── backend.py # LangGraph multi-agent graph, all agent logic
├── mcp_client.py # MCP client — Tavily, AviationStack, Weather
├── custom_weather_mcp_server.py # Custom FastMCP weather server
│
├── templates/
│ └── index.html # Single-page frontend UI
├── static/
│ ├── script.js # Frontend logic, API calls, approval flow
│ └── style.css # UI styling
│
├── requirements.txt # TripMate-specific dependencies
├── Dockerfile # Docker image for TripMate AI
├── .dockerignore
└── .gitignore
- Python 3.10 or higher
- Git
- A Groq API key (free tier available at console.groq.com)
- For
iterative_tools.pyandhumanintheloop.py: an OpenAI API key - For
conditional_RAG.pyandapp.py: no external API keys (uses local FAISS + HuggingFace) - For TripMate AI: Groq, Tavily, AviationStack, OpenWeatherMap API keys + a PostgreSQL database URL
- For TripMate AI MCP AviationStack:
uvinstalled (pip install uv) - Docker (optional, for containerized TripMate deployment)
git clone https://github.com/SadiqCodex/Agentic-AI-Learning.git
cd Agentic-AI-LearningCreate and activate a virtual environment:
Windows:
python -m venv .venv
.venv\Scripts\activateLinux / macOS:
python -m venv .venv
source .venv/bin/activateInstall root dependencies:
pip install -r requirements.txtFor TripMate AI, install its own dependencies:
cd Multi-Agent-System-using-LangGraph-MCP-Supervisor-Guardrails-HITL-main
pip install -r requirements.txtGROQ_API_KEY=your_groq_api_key_here
OPENAI_API_KEY=your_openai_api_key_here
TAVILY_API_KEY=your_tavily_api_key_hereOPENAI_API_KEY is required only for iterative_tools.py and humanintheloop.py.
TAVILY_API_KEY is required only for iterative_tools.py.
GROQ_API_KEY is required for all other root-level scripts.
GROQ_API_KEY=your_groq_api_key_here
TAVILY_API_KEY=your_tavily_api_key_here
AVIATION_STACK_API_KEY=your_aviationstack_api_key_here
OPENWEATHER_API_KEY=your_openweathermap_api_key_here
DATABASE_URL=postgresql://user:password@host:port/dbnameDATABASE_URL must point to a PostgreSQL instance. The checkpointer will create its own tables automatically on first run.
python states.pypython sequential_base.pypython parallel_reducers.pypython iterative_tools.pypython humanintheloop.pypython conditional_RAG.pystreamlit run app.pyFrom inside the TripMate directory:
cd Multi-Agent-System-using-LangGraph-MCP-Supervisor-Guardrails-HITL-main
python app.pyOr with uvicorn directly:
uvicorn app:app --reload --host 127.0.0.1 --port 8000Then open http://127.0.0.1:8000 in your browser.
cd Multi-Agent-System-using-LangGraph-MCP-Supervisor-Guardrails-HITL-main
docker build -t tripmate-ai .
docker run -p 8000:8000 --env-file .env tripmate-aiStart a new travel planning session.
Request:
{
"message": "Plan a 7-day Japan trip from Dhaka under 2 lakhs",
"thread_id": null
}Response (requires approval):
{
"success": true,
"thread_id": "user_abc123",
"answer": "...",
"requires_approval": true,
"approval_request": "Please review the draft itinerary...",
"itinerary": "...",
"flight_results": "...",
"hotel_results": "...",
"weather_results": "...",
"budget_results": "...",
"selected_agents": ["flight_agent", "hotel_agent", "weather_agent", "budget_agent", "itinerary_agent"],
"supervisor_reasoning": "...",
"guardrail_allowed": true
}Resume the paused graph after human review.
Request:
{
"thread_id": "user_abc123",
"approved": true,
"feedback": ""
}Request (revision):
{
"thread_id": "user_abc123",
"approved": false,
"feedback": "Reduce hotel costs and add one free day for exploration"
}Response:
{
"success": true,
"thread_id": "user_abc123",
"answer": "Final polished travel plan...",
"requires_approval": false,
"approved": true
}{
"status": "ok",
"message": "TripMate AI API is running",
"features": ["supervisor_agent", "input_guardrail", "human_in_the_loop"]
}State Management (TypedDict, Pydantic, MessagesState)
↓
Sequential Graph Workflows (nodes + edges)
↓
Parallel Execution with Custom Reducers
↓
Iterative Loops with Tool Calling
↓
Human-in-the-Loop (interrupt / resume)
↓
Conditional RAG (query routing + FAISS retrieval)
↓
Streamlit UI wrapping a LangGraph agent
↓
Multi-Agent Supervisor Architecture
↓
MCP Integration (client + custom server)
↓
Input Guardrails
↓
PostgreSQL Persistent Checkpointing
↓
Full-Stack Agentic Application (FastAPI + LangGraph + MCP)
Each step builds directly on the previous one. The repository evolves as new concepts are learned and implemented.
- State is everything in LangGraph. Choosing the right state shape — and the right reducer — determines how complex your graph can become.
- Reducers enable parallelism. Without a custom reducer, parallel branches would overwrite each other's results. The
Annotated[dict, merge_score_dicts]pattern solves this cleanly. interrupt()is not an exception. It is a first-class LangGraph primitive that serializes state, pauses execution, and waits for external input — enabling real human-in-the-loop workflows over HTTP.- Conditional routing makes graphs intelligent. A classifier node that sets a
query_typefield, combined with a router function, turns a static pipeline into a dynamic decision-making system. - MCP decouples tools from agents. Instead of hardcoding tool logic inside agents, MCP servers expose tools over a standard protocol. The agent just calls the tool by name.
- The Supervisor pattern scales multi-agent systems. A single supervisor that reads the user query, selects agents, and extracts constraints means adding a new specialist agent requires no changes to the routing logic.
- Guardrails belong at the entry point. Validating input before any agent runs prevents wasted LLM calls and keeps the system focused on its intended domain.
- PostgreSQL checkpointing enables stateful HTTP APIs. Without it, the HITL pause would be lost between the
/api/traveland/api/travel/approverequests.
- State management patterns
- Sequential workflows
- Parallel execution with reducers
- Iterative loops with tool calling
- Human-in-the-loop
- Conditional RAG
- Multi-agent supervisor architecture
- MCP server and client integration
- Input guardrails
- PostgreSQL persistent checkpointing
- Full-stack agentic application
- Hybrid search (dense + sparse retrieval)
- Reranking retrieved documents
- Long-term agent memory
- Agent evaluation and tracing (LangSmith)
- Multi-modal agents (image + text)
- Agent-to-agent communication
- Rate limiting and authentication for deployed agents
- Automated test coverage for agent workflows
Automated test coverage is currently being expanded as part of the learning process. To experiment with any implementation, run the scripts directly or interact with the web UIs as described in the Running the Projects section.
- Never commit
.envfiles or API keys to version control — both.gitignorefiles in this repository exclude them - Use environment variables or a
.envfile for all secrets - The TripMate guardrail validates user input before any agent or external API is invoked
- Validate and sanitize any user-provided input before passing it to external services
- Protect your
DATABASE_URL— it contains credentials for your PostgreSQL instance - MCP server subprocesses inherit only the environment variables they need
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-concept - Implement your changes
- Verify the implementation runs correctly
- Open a pull request with a clear description
New learning implementations are welcome. Each new concept should include a clear explanation of what it demonstrates, either in the code comments or in an update to this README.
This project is licensed under the MIT License. See the LICENSE file for details.
Sadik Mohammad
GitHub: @SadiqCodex
If this repository helped you understand Agentic AI concepts, consider giving it a star. It helps others find it and motivates continued learning and documentation.
TripMate AI is live on Netlify — try the full multi-agent travel planner here:
https://tripmates-ai.netlify.app/
This repository is actively maintained and grows as new Agentic AI concepts are explored and implemented.