A production-ready architectural boilerplate for building and automatically optimizing LangChain RAG applications using MLflow tracing and GEPA prompt optimization.
This project implements a three-layer architecture for systematic LLM app improvement:
Build (LangChain) → Measure (MLflow) → Optimize (GEPA) → Repeat
Components:
- LangChain (
src/app.py): Retrieval + generation orchestration with local keyword-based retrieval - MLflow (auto-integrated): Execution tracing, metrics, and experiment tracking
- GEPA (
src/optimize.py): Evolutionary prompt optimization with variant generation - MEGA (
src/optimize_mega.py): Workflow optimization for routing and tool selection
This boilerplate generalizes to any retrieval-augmented LLM application:
- Support/customer service agents
- Internal knowledge assistants (HR, IT, compliance)
- Developer documentation assistants
- Tool-using workflows with retrieval
- Q&A systems with fact-based responses
macOS/Linux:
python -m venv .venv
source .venv/bin/activateWindows (PowerShell):
python -m venv .venv
.venv\Scripts\Activate.ps1Windows (Command Prompt):
python -m venv .venv
.venv\Scripts\activate.batpip install -r requirements.txtCreate a .env file from .env.example:
macOS/Linux:
cp .env.example .env
# Edit .env and add your keys:
# GROQ_API_KEY=your-groq-api-key
# MLFLOW_TRACKING_URI=http://localhost:5000Windows (PowerShell):
Copy-Item .env.example .env
# Edit .env and add your keysWindows (Command Prompt):
copy .env.example .env
REM Edit .env and add your keysmlflow ui --host 0.0.0.0 --port 5000Then visit http://localhost:5000 in your browser to watch traces and experiments in real-time.
This boilerplate implements two complementary optimization layers:
-
Prompt Optimization (GEPA) — Improves what the agent says
- Better answer quality and relevance
- Fewer hallucinations
- More consistent tone and format
- Variant generation and evaluation
-
Workflow Optimization (MEGA) — Improves how the agent works
- Better routing decisions
- Optimal tool selection and ordering
- Trade-offs between retrieval and reasoning
- Block-level performance scoring
Run both for comprehensive improvement.
The fastest way to see the optimization system in action is with the included sample data:
Step 1: Measure Baseline Performance
macOS/Linux:
python -m demo.benchmarkWindows:
python -m demo.benchmarkThis shows baseline performance on 8 realistic test cases. You'll see ~62-65% answer match score, room for improvement.
Step 2: Optimize Prompts with GEPA
macOS/Linux:
python -m src.optimizeWindows:
python -m src.optimizeGEPA will:
- Generate prompt variants (base, detailed, concise, formal)
- Evaluate each on the demo eval set
- Select and register the best variant
- Return detailed metrics (~1-2 minutes)
Expected result: ~78% answer match score.
Step 3: (Optional) Optimize Workflow with MEGA
macOS/Linux:
python -m src.optimize_megaWindows:
python -m src.optimize_megaMEGA will:
- Generate workflow variants (high_retrieval, with_refinement, reasoning_heavy, balanced)
- Evaluate each on the demo eval set
- Select the best workflow configuration
- Return block-level performance scores (~2-3 minutes)
Expected result: ~81% answer match score (additional +3% over GEPA alone).
Step 4: Measure Improvements with Scores
macOS/Linux:
python -m demo.benchmarkWindows:
python -m demo.benchmarkThis re-runs the baseline benchmark to show how much optimization improved the scores:
- Before GEPA: ~62-65% match
- After GEPA: ~78% match
- After MEGA: ~81% match (+30% improvement)
Step 5: Try Interactive Demo (Optional)
macOS/Linux:
python -m src.appWindows:
python -m src.appInteractive mode to test the optimized system:
- Ask questions and see answers
- Experience improvements firsthand
- More accurate and grounded responses
Example questions:
- "How do I reset my password?"
- "What's your refund policy?"
- "Which authentication methods are available?"
Once you understand the system with the demo, replace the sample data:
-
Prepare your documents:
# my_data.py from langchain_core.documents import Document MY_DOCUMENTS = [ Document(page_content="Your document 1..."), Document(page_content="Your document 2..."), # ... more documents ]
-
Prepare your evaluation set:
MY_EVAL_SET = [ {"question": "Q1", "expected": "Expected answer 1"}, {"question": "Q2", "expected": "Expected answer 2"}, # ... more test cases ]
-
Run optimization on your data:
from src.ingest import build_retriever from src.eval import run_eval from my_data import MY_DOCUMENTS, MY_EVAL_SET # Build retriever with your documents retriever = build_retriever(MY_DOCUMENTS) # Run evaluation results = run_eval(MY_EVAL_SET) # Then run optimization # python -m src.optimize # python -m src.optimize_mega
gepa-langchain-lab/
├── src/ # Production code (no sample data)
│ ├── __init__.py
│ ├── app.py # Main RAG application (core logic)
│ ├── ingest.py # Configurable retriever (accepts documents)
│ ├── eval.py # Configurable evaluation (accepts eval set)
│ ├── optimize.py # GEPA prompt optimizer
│ ├── optimize_mega.py # MEGA workflow optimizer
│ └── prompts.py # Prompt templates
│
├── demo/ # Demo & learning materials
│ ├── __init__.py
│ ├── sample_data.py # 8 realistic sample documents
│ ├── eval_set.py # 8 test questions with expected answers
│ ├── benchmark.py # Baseline measurement tool
│ └── README.md # Demo quick start guide
│
├── docs/ # GitHub Pages website
│ ├── index.html
│ ├── preview.png
│ ├── og-image.svg
│ ├── _config.yml
│ └── .nojekyll
│
├── README.md # Main documentation (this file)
├── requirements.txt # Python dependencies
├── .env.example # Environment variable template
└── .gitignore # Git ignore rules
/src — Production Code
The src/ directory contains the core boilerplate with no sample data. Use this in production:
- app.py — Main RAG application. Your entry point.
- ingest.py —
build_retriever(documents)function. Pass your own documents. - eval.py —
run_eval(eval_set)function. Pass your own evaluation set. - optimize.py — GEPA prompt optimization. Works with any eval set.
- optimize_mega.py — MEGA workflow optimization. Works with any eval set.
- prompts.py — Prompt templates. Customize for your domain.
/demo — Demo & Learning Materials
The demo/ directory shows how to use the system with realistic sample data:
- sample_data.py — 8 realistic documents (SaaS support domain).
- eval_set.py — 8 test questions with expected answers.
- benchmark.py — Baseline performance measurement tool.
- README.md — Demo-specific instructions.
Key Design Principles:
- Separation of Concerns —
/srcis pure boilerplate;/demois learning material - Configuration Over Convention — Functions accept parameters, no hardcoded data
- Production Ready — Clean codebase, minimal dependencies, easy to fork
✨ Zero External Dependencies for Retrieval — Local keyword-based retriever works without embeddings APIs
🧠 Dual Optimization — Optimize both prompts (GEPA) and workflows (MEGA) in one framework
📊 Built-in Evaluation — Fixed eval set with ground truth answers for consistent measurement
🔄 Local Development — Run everything locally; no cloud services required
📈 MLflow Integration — Automatic tracing and experiment logging
🚀 Production Ready — Clean architecture suitable for fork and customization
┌─────────────────────────────────────────────────┐
│ Your LangChain RAG App (src/app.py) │
│ - Retriever: vector store │
│ - Chain: retriever + LLM + prompt │
└─────────────┬──────────────────┬────────────────┘
│ Calls │ Calls
▼ ▼
┌──────────────────┐ ┌────────────────────┐
│ MLflow Tracing │ │ MLflow Tracing │
│ (for GEPA) │ │ (for MEGA) │
└────────┬─────────┘ └────────┬───────────┘
│ Reads │ Reads
▼ ▼
┌─────────────────────────────────────────────────┐
│ Evaluation Harness (src/eval.py) │
│ - Fixed test set with expected answers │
│ - Shared by both GEPA and MEGA │
└─────────────────────────────────────────────────┘
│ Evaluates
├─────────────────┬──────────────────┐
▼ ▼ ▼
┌───────────────────┐ ┌──────────────────────────┐
│ GEPA Optimizer │ │ MEGA Optimizer │
│ (src/optimize.py) │ │ (src/optimize_mega.py) │
├───────────────────┤ ├──────────────────────────┤
│ Optimizes: │ │ Optimizes: │
│ - Prompts │ │ - Workflow routing │
│ - System config │ │ - Tool selection │
│ - Answer template │ │ - Retrieval settings │
└───────────────────┘ └──────────────────────────┘
Instead of hand-tuning prompts once, GEPA creates a feedback loop:
- Data: real queries + reference answers
- Metrics: clear evaluation criteria (correctness, groundedness, tone)
- Optimization: GEPA uses LLM reflection + evolutionary search to improve
- Deployment: best prompt is registered back and your app picks it up
GEPA doesn't need to differentiate through your model. Instead:
- Works with prompts, configs, even code
- Uses explicit evaluation metrics (LLM-based, rule-based, human-graded)
- More sample-efficient than RL (~35× fewer evals in benchmarks)
GEPA (Prompt Optimization):
- What the agent says
- Improves answer quality, tone, formatting
- Works on textual parameters
- ~35× more sample-efficient than RL
MEGA (Workflow Optimization):
- How the agent works
- Optimizes routing, tool selection, decision logic
- Works on structural parameters
- Block-level performance scoring
- Complements GEPA for comprehensive improvement
Use Together: Run GEPA first to improve answers, then MEGA to improve routing.
Groq makes the boilerplate better because:
- Speed: faster inference means quicker optimization loops
- Cost: free tier is generous
- Simplicity: LangChain integration is seamless
Create a data module with your documents and evaluation set:
# my_data.py
from langchain_core.documents import Document
MY_DOCUMENTS = [
Document(page_content="Your content about topic 1"),
Document(page_content="Your content about topic 2"),
# ... add all your documents
]
MY_EVAL_SET = [
{
"question": "What is your policy on X?",
"expected": "The expected answer that the assistant should give"
},
{
"question": "How do I do Y?",
"expected": "Step-by-step instructions for Y"
},
# ... add comprehensive test cases
]Good eval sets have 8-20 questions covering all major topics.
Pass your data to the optimization functions:
from src.ingest import build_retriever
from src.eval import run_eval
from my_data import MY_DOCUMENTS, MY_EVAL_SET
# Option A: Build retriever and evaluate
retriever = build_retriever(MY_DOCUMENTS)
results = run_eval(MY_EVAL_SET)
# Option B: Run optimization programmatically
from src.optimize import GEPAOptimizer
optimizer = GEPAOptimizer()
best_prompt = optimizer.optimize(MY_EVAL_SET)Or use command-line (modifies demo/eval_set.py to use your data temporarily):
python -m src.optimize # Tests GEPA variants
python -m src.optimize_mega # Tests MEGA variants
python -m src.app # See results interactivelyReplace the simple keyword-based retriever with a vector store:
# src/ingest.py - modify build_retriever()
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
def build_retriever(documents=None):
if documents is None:
from demo.sample_data import SAMPLE_DOCUMENTS
documents = SAMPLE_DOCUMENTS
# Use vector embeddings instead of keyword matching
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)
return vectorstore.as_retriever(search_kwargs={"k": 3})Supported options: FAISS, Pinecone, Weaviate, Chroma, Milvus, etc.
Edit BASE_SYSTEM_PROMPT in src/prompts.py for your domain:
BASE_SYSTEM_PROMPT = """You are a specialized customer support assistant.
Your role is to help users with account management, billing, and technical issues.
Always cite the relevant documentation section when answering.
Be concise but thorough. Use a friendly, professional tone."""GEPA will automatically create variants of this prompt during optimization.
Replace Groq in src/app.py if desired:
# Option 1: OpenAI
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# Option 2: Anthropic Claude
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-opus-4-1", temperature=0)
# Option 3: Keep Groq (fast and free tier)
from langchain_groq import ChatGroq
llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)macOS/Linux with cron:
# Run GEPA every 6 hours
0 */6 * * * cd /path/to/repo && /path/to/.venv/bin/python -m src.optimize >> /var/log/gepa.log 2>&1
# Run MEGA every 12 hours
0 */12 * * * cd /path/to/repo && /path/to/.venv/bin/python -m src.optimize_mega >> /var/log/mega.log 2>&1Windows Task Scheduler:
- Press
Win + R, typetaskschd.msc - Right-click "Task Scheduler" → New Task
- Set program:
C:\path\to\.venv\Scripts\python.exe - Set arguments:
-m src.optimize - Set working directory:
C:\path\to\gepa-langchain-lab - Set schedule (e.g., every 6 hours)
Production checklist:
- Version control your eval sets (for reproducibility)
- Monitor MLflow UI at
http://localhost:5000 - Log optimization metrics over time
- Set alerts if performance degrades
- Review optimized prompts before deployment
Solution: Always use module syntax to run scripts:
python -m src.app # ✓ Correct
python src/app.py # ✗ WrongSolution: Add your Groq API key to .env:
GROQ_API_KEY=your-actual-api-key-here
MLFLOW_TRACKING_URI=http://localhost:5000Get your key at console.groq.com
Solution: Ensure MLflow is running in a separate terminal:
mlflow ui --host 0.0.0.0 --port 5000Then visit http://localhost:5000
Solution: This is normal. The GEPA/MEGA optimizers evaluate multiple variants, which takes time. For faster demos, reduce EVAL_SET size in src/eval.py.
Solution: Make sure you're using the correct activation script:
- PowerShell:
.venv\Scripts\Activate.ps1 - Command Prompt:
.venv\Scripts\activate.bat
macOS/Linux:
python -m src.eval && python -m src.optimize && python -m src.optimize_megaWindows:
python -m src.eval; python -m src.optimize; python -m src.optimize_megamlflow ui --host 0.0.0.0 --port 5000Visit http://localhost:5000 and explore:
- Experiments: Track different optimization runs
- Runs: View traces, parameters, and metrics
- Models: Compare registered prompts over time
rm -rf mlruns/ mlartifacts/ .mlflow/Remove-Item -Recurse -Force mlruns, mlartifacts, .mlflowThis is a boilerplate meant for forking. To customize:
- Clone the repo
- Update
src/ingest.pywith your data - Update
EVAL_SETinsrc/eval.pywith your test cases - Modify
BASE_SYSTEM_PROMPTinsrc/prompts.py - Run optimization pipeline
- Deploy optimized prompts
✅ Fully Functional
- Local keyword-based retriever (no external deps)
- GEPA prompt optimization with variants
- MEGA workflow optimization
- MLflow integration and tracing
- GitHub Pages website with social preview cards
- GEPA GitHub
- LangChain Documentation
- MLflow Documentation
- Groq API Console
- Groq + LangChain Integration
- GitHub Pages Setup
MIT - Feel free to fork and customize for your use case