Build AI-powered applications with practical, hands-on exercises
Both workshops require the following setup. Complete these steps before starting any workshop.
| Requirement | Minimum | Notes |
|---|---|---|
| Python | 3.11+ | Required for both workshops |
| RAM | 8GB | 16GB recommended for larger models |
| Disk Space | ~5GB | For models and dependencies |
| Ollama | Latest | Local LLM runtime |
Ollama runs LLMs locally on your machine.
# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh
# Verify installation
ollama --version
ollama --version# Required models for both workshops
ollama pull mistral
ollama pull llama3
# Additional model for LangGraph + MCP workshop
ollama pull nomic-embed-text
# Verify models
ollama list
๐ก Tip: Run ollama serve in a terminal to start the Ollama service
before running the workshops.
# Create virtual environment
python3 -m venv venv
# Activate it
source venv/bin/activate # macOS/Linux
# OR
venv\Scripts\activate # Windows
Docker provides an isolated environment for running the workshops.
curl -fsSL https://get.docker.com | shdocker --version
docker-compose --version
# Check if Ollama is running
curl http://localhost:11434/api/tags
# Start Ollama service
ollama serve
# Pull the missing model
ollama pull mistral
ollama pull llama3
# Reinstall dependencies
pip install -r requirements-minimal.txt --force-reinstall
Build AI chatbots from scratch using LangChain, Ollama, and RAG
| # | File | Duration | Topics |
|---|---|---|---|
| 01 | 01_basic_chatbot_with_memory.py |
15 min | Chatbot basics, conversation memory |
| 02 | 02_agent_with_tools.py |
20 min | Agent architecture, custom tools |
| 03 | 03_rag_create_vector_database.py |
15 min | Embeddings, FAISS vector database |
| 04 | 04_rag_semantic_search.py |
15 min | Semantic search, similarity scores |
| 05 | 05_complete_agent_with_rag.py |
25 min | LangGraph StateGraph, Guardrails |
# 1. Extract and navigate to workshop files
cd ChatBot-Files
# 2. Install dependencies
pip install -r requirements-minimal.txt
# 3. Run your first lesson
python3 01_basic_chatbot_with_memory.py
Goal: Build a simple chatbot that remembers the conversation.
๐ฏ What You'll Learn:
from langchain_ollama import ChatOllama
from langgraph.checkpoint.memory import MemorySaver
# Initialize local LLM
llm = ChatOllama(model="mistral", temperature=0.3)
# Create memory instance
memory = MemorySaver()
# Simple chat
response = llm.invoke("Hello, who are you?")
print(response.content)
User: Hi, my name is John
Assistant: Hello John! Nice to meet you. How can I help you today?
User: What is my name?
Assistant: Your name is John! You told me when we started chatting.
python3 01_basic_chatbot_with_memory.py
Goal: Build an agent that can use tools to perform specific tasks.
๐ฏ What You'll Learn:
@tool decoratorfrom langchain_core.tools import tool
@tool
def calculate_square(number: str) -> str:
"""Calculates the square of an integer.
Use when user asks to calculate square of a number."""
number = int(number.strip())
return f"The square of {number} is {number ** 2}."
| User Input | Agent Decision | Tool Used |
|---|---|---|
| "Hi, how are you?" | Direct response | โ None |
| "What is the square of 7?" | Use tool | โ calculate_square |
| "Summarize this text..." | Use tool | โ generate_summary |
User: What is the square of 7?
โ Agent decides to use calculate_square tool
โ Tool returns: "The square of 7 is 49."
Assistant: The square of 7 is 49.
python3 02_agent_with_tools.py
Goal: Create a searchable knowledge base using FAISS.
๐ฏ What You'll Learn:
from sentence_transformers import SentenceTransformer
import faiss
# Load embedding model
model = SentenceTransformer('all-MiniLM-L6-v2')
# Generate embeddings
texts = ["Critical TechWorks Principles...", "Quality and collaboration..."]
embeddings = model.encode(texts)
# Create FAISS index
index = faiss.IndexFlatIP(384) # 384 = embedding dimension
index.add(embeddings)
faiss.write_index(index, "faiss.index")
faiss_index/
โโโ faiss.index # Vector index (binary)
โโโ embeddings.npy # Embedding vectors
โโโ texts.json # Original text chunks
python3 03_rag_create_vector_database.py
Goal: Query the vector database with natural language.
โ ๏ธ Prerequisite: Run Lesson 03 first to create the FAISS index!
๐ฏ What You'll Learn:
# Encode user query
query = "What are Critical TechWorks principles?"
q_embedding = model.encode([query])
# Search in FAISS
scores, indices = index.search(q_embedding, k=3) # Top 3 results
# Display results
for score, idx in zip(scores[0], indices[0]):
print(f"Score: {score:.3f} โ {texts[idx][:100]}...")
Query: "principles"
Result 1 (Score: 0.85): Critical TechWorks Principles: A principle is a rule...
Result 2 (Score: 0.72): Quality and collaboration are fundamental...
Result 3 (Score: 0.68): Our core values include transparency...
python3 04_rag_semantic_search.py
Goal: Build a production-ready chatbot with LangGraph StateGraph and output guardrails.
๐ฏ What You'll Learn:
from langgraph.graph import StateGraph, END
graph = StateGraph(AgentState)
# Add nodes
graph.add_node("classify", classify_intent)
graph.add_node("calculate", use_calculate_square)
graph.add_node("search", use_faiss_search)
graph.add_node("guardrails", check_guardrails)
# Set entry point and routing
graph.set_entry_point("classify")
graph.add_conditional_edges("classify", route_by_intent, {...})
# Compile
agent = graph.compile()
| Type | Description | Example Triggers |
|---|---|---|
| Pattern Matching | Regex patterns for blocked words | hack, exploit, malicious |
| Topic Blocking | Prohibited topics list | "how to hack", "steal passwords" |
| LLM Safety Check | AI-based content validation | Harmful instructions, hate speech |
User: "How to hack a computer?"
๐ [CLASSIFY] โ chat
๐ฌ [GENERATE] โ Draft generated
๐ก๏ธ [GUARDRAILS] โ โ BLOCKED
๐ซ Response: "I cannot provide information on that topic..."
python3 05_complete_agent_with_rag.py
# Build and start
./docker-run.sh build
./docker-run.sh start
# Run a lesson
./docker-run.sh run 1 # Lesson 1
./docker-run.sh run 5 # Lesson 5
# Interactive shell
./docker-run.sh shell
# Stop
./docker-run.sh stop
Build production-ready agents with StateGraph and Model Context Protocol
| Notebook | Duration | Topics |
|---|---|---|
| workshop-langgraph.ipynb | ~20 min | GraphState, Nodes, Edges, Conditional Routing |
| project-mcp.ipynb | ~20 min | MCP Servers, Jira/Celonis Integration, Supervisor Pattern |
# 1. Install Jupyter
pip install jupyterlab
# 2. Install workshop dependencies
pip install langchain langchain-ollama langgraph langchain-mcp-adapters
# 3. Start Jupyter
jupyter lab
# 4. Open workshop-langgraph.ipynb
LangGraph is a framework for building stateful, reliable, and controllable LLM applications using graphs instead of chains.
| Feature | Description |
|---|---|
| Statefulness | Application state persists and evolves throughout the workflow |
| Control Flow | Branching, looping, conditional routing, interruptions |
| Reliability | Checkpoints, replay, explicit state tracking |
| Human-in-the-Loop | Native support for pauses and manual interventions |
from typing import TypedDict, Annotated
import operator
class State(TypedDict):
# Messages accumulate across nodes (reducer)
messages: Annotated[list, operator.add]
# Flag gets replaced each time
needs_math: bool
def check_answer_type(state: State) -> dict:
question = state["messages"][-1].content
needs_math = "YES" == llm.invoke(prompt).upper().strip()
return {"needs_math": needs_math}
def math_answer(state: State) -> dict:
result = math_tools[operation](*numbers)
return {"messages": [AIMessage(content=f"Result: {result}")]}
def route(state: State) -> str:
if state["needs_math"]:
return "math_answer"
return "general_answer"
graph.add_conditional_edges(
"check_answer_type",
route,
{"math_answer": "math_answer", "general_answer": "general_answer"}
)
from langgraph.graph import StateGraph, END
graph = StateGraph(State)
graph.add_node("check_answer_type", check_answer_type)
graph.add_node("math_answer", math_answer)
graph.add_node("general_answer", general_answer)
graph.set_entry_point("check_answer_type")
graph.add_edge("math_answer", END)
graph.add_edge("general_answer", END)
app = graph.compile()
Build a Product Owner Assistant with external tool integrations.
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"celonis_mcp": {
"transport": "http",
"url": "http://localhost:8000/mcp",
},
"jira_mcp": {
"transport": "stdio",
"command": sys.executable,
"args": ["mcp/server.py", "stdio"],
}
})
mcp_tools = await client.get_tools()
def supervisor(state: GraphState) -> dict:
# Analyze chat history and execution log
# Decide: "answer_generation" or "tool_execution"
response = json.loads(llm.invoke(prompt))
return {"supervisor_decision": response["supervisor_decision"]}
| Concept | Description |
|---|---|
| Graphs | Data flows through a directed graph of nodes |
| Nodes | Steps that call LLMs, run tools, or execute logic |
| Edges | Connections with conditional branching support |
| Reducers | Functions that determine how state updates merge |
| Checkpoints | Save and resume execution at any point |
| MCP | Model Context Protocol - connect LLMs to external tools |