| # Irminsul |
|
|
| > Fine-tuned Llama 3.1 8B Β· QLoRA Β· Pinecone RAG Β· FastAPI Β· Azure Container Apps |
|
|
| A full end-to-end LLMOps serving stack β from a QLoRA fine-tuned model running in 4-bit NF4 on consumer hardware, through a retrieval-augmented generation pipeline, to a containerized API deployed on Azure. Built to be production-shaped, not just a demo. |
|
|
| **[β Live Demo](https://mukulray1603.github.io/Irminsul/demo.html)** |
|
|
| --- |
|
|
| ## About Irminsul |
|
|
| Most LLM projects stop at inference. This one goes further: |
|
|
| - **Fine-tuned model** β Llama 3.1 8B fine-tuned with QLoRA (rank 16, lr 2e-4) on a custom dataset, merged and served locally in 4-bit NF4 quantization on an RTX 3060 6GB |
| - **RAG pipeline** β Documents ingested, chunked, embedded with `sentence-transformers/all-MiniLM-L6-v2` (fully local, zero API cost), and stored in Pinecone. Retrieval is semantic, top-k configurable at query time |
| - **Serving layer** β FastAPI with async lifespan model loading, typed Pydantic request/response models, CORS, health check, and a clean browser UI served from the same process |
| - **Containerized** β Dockerfile built for slim Python 3.12, model loaded at runtime via env-configurable path (not baked in) |
| - **Cloud-ready** β One-shot Azure deployment via ACR + Container Apps, with Pinecone key injected as a secret |
| - **Domain knowledge** β RAG corpus built around Genshin Impact lore, character builds, and elemental mechanics, serving as a rich real-world knowledge base for retrieval evaluation |
|
|
| --- |
|
|
| ## Architecture |
|
|
| ``` |
| User query |
| β |
| βΌ |
| FastAPI /generate |
| β |
| βββ Embed query (sentence-transformers, local) |
| β β |
| β βΌ |
| β Pinecone β semantic search β top-k chunks |
| β β |
| βΌ βΌ |
| LangChain RetrievalQA |
| β |
| βΌ |
| Llama 3.1 8B (QLoRA fine-tuned, 4-bit NF4) |
| β |
| βΌ |
| Grounded answer + source attribution |
| ``` |
|
|
| --- |
|
|
| ## Stack |
|
|
| | Layer | Technology | |
| |---|---| |
| | Base model | Llama 3.1 8B Instruct | |
| | Fine-tuning | QLoRA via PEFT (r=16, Ξ±=32, lr=2e-4) | |
| | Quantization | BitsAndBytes 4-bit NF4, bfloat16 compute | |
| | Embeddings | sentence-transformers/all-MiniLM-L6-v2 | |
| | Vector DB | Pinecone (serverless, cosine similarity) | |
| | RAG chain | LangChain RetrievalQA | |
| | Serving | FastAPI + Uvicorn | |
| | Containerization | Docker (python:3.12-slim) | |
| | Cloud | Azure Container Apps + ACR | |
|
|
| --- |
|
|
| ## Quickstart |
|
|
| ```bash |
| # 1. Clone and set up environment |
| git clone https://github.com/MukulRay1603/Irminsul.git |
| cd Irminsul |
| python -m venv venv && source venv/bin/activate # Windows: venv\Scripts\activate |
| pip install -r requirements.txt |
| |
| # 2. Configure environment |
| cp .env.example .env |
| # Fill in PINECONE_API_KEY in .env |
| |
| # 3. Add your fine-tuned model |
| # Place merged model at: ./models/merged/exp2_lr2e-4_r16 |
| # Or update MODEL_PATH in .env to point to your model |
| |
| # 4. Ingest documents |
| python ingest.py --dir ./docs --chunk-size 300 --chunk-overlap 40 |
| |
| # 5. Start the server |
| uvicorn main:app --reload --port 8000 |
| |
| # UI available at http://localhost:8000 |
| # API docs at http://localhost:8000/docs |
| ``` |
|
|
| --- |
|
|
| ## API |
|
|
| | Method | Endpoint | Description | |
| |---|---|---| |
| | `GET` | `/` | Browser UI | |
| | `GET` | `/health` | Model load status | |
| | `POST` | `/generate` | RAG query β grounded answer | |
| | `POST` | `/ingest` | Ingest docs from local directory | |
|
|
| **Example:** |
|
|
| ```bash |
| curl -X POST http://localhost:8000/generate \ |
| -H "Content-Type: application/json" \ |
| -d '{"query": "What weapons should Hu Tao use on a budget?", "top_k": 3}' |
| ``` |
|
|
| ```json |
| { |
| "answer": "For Hu Tao on a budget, Dragon's Bane is the strongest F2P option β it scales with Elemental Mastery and deals significant bonus damage on vaporized hits. White Tassel is the best 3-star alternative for pure Normal Attack scaling.", |
| "sources": ["docs/character_builds.md"], |
| "latency_ms": 4821.3 |
| } |
| ``` |
|
|
| --- |
|
|
| ## Memory profile (RTX 3060 6GB) |
|
|
| | Component | VRAM | |
| |---|---| |
| | Llama 3.1 8B @ 4-bit NF4 | ~4.5 GB | |
| | all-MiniLM-L6-v2 embedder | ~90 MB | |
| | Inference headroom | ~1.2 GB | |
|
|
| Running the embedder on CPU frees ~90MB if needed β set `device_map="cpu"` in `rag.py`. |
|
|
| --- |
|
|
| ## Deploy to Azure |
|
|
| ```bash |
| export PINECONE_API_KEY=your_key |
| chmod +x deploy_azure.sh |
| ./deploy_azure.sh |
| ``` |
|
|
| The script provisions a resource group, builds and pushes the image via ACR Tasks (no local Docker build needed), creates a Container Apps environment, and deploys with the Pinecone key injected as a secret. Prints the live HTTPS endpoint on completion. |
|
|
| **Model in Azure:** The merged model (~16GB) isn't baked into the image. Recommended approach: mount from Azure Blob Storage as a volume for cheapest cold start on student credits. |
|
|
| --- |
|
|
| ## Project structure |
|
|
| ``` |
| Irminsul/ |
| βββ main.py # FastAPI app β endpoints, lifespan, CORS |
| βββ rag.py # Model loading, 4-bit config, LangChain RAG chain |
| βββ embedder.py # sentence-transformers singleton wrapper |
| βββ ingest.py # Doc loader β chunker β Pinecone upsert |
| βββ index.html # Browser UI (dark theme, query history, source display) |
| βββ Dockerfile |
| βββ deploy_azure.sh # One-shot Azure Container Apps deploy |
| βββ requirements.txt |
| βββ .env.example |
| βββ docs/ # Corpus + GitHub Pages demo |
| βββ demo.html |
| ``` |
|
|
| --- |
|
|
| ## What's next |
|
|
| - [ ] Swap naive word chunker for `MarkdownHeaderTextSplitter` for better retrieval precision |
| - [ ] Add metadata filtering to Pinecone queries (filter by character, content type) |
| - [ ] Streaming response via SSE for lower perceived latency |
| - [ ] Expand corpus β per-character deep dives with stat thresholds and rotation guides |
| - [ ] CI/CD pipeline β GitHub Actions β ACR build β Container Apps deploy on push |
|
|
| --- |
|
|
| Built while learning the full MLOps lifecycle β fine-tuning, quantization, retrieval, serving, and cloud deployment β on consumer hardware. Every component chosen deliberately, not for hype. |
|
|