AI Specialist — Operational Digital Twin
Target role: AI Specialist @ Parsons (or equivalent infrastructure / GovTech AI roles)
Core differentiator: Production LLM deployment in air-gapped, on-prem environments with RAG over geospatial/asset data.
⚠️ Four roles, four tracks. This README and Labs 1–6 target jd.md — the applied air-gapped Digital Twin role (RAG, fine-tuning, guardrails). Three very different roles each have their own dedicated, principal-depth curriculum:
➡ jd2-inference-optimization-track/ — AI Model Porting, Optimization & Accelerator Solutions Architect (jd2.md)
Quantization, model conversion, vLLM/TGI/Triton serving, distributed inference, GPU/accelerator architecture, CV/video pipelines, capacity sizing. 9 knowledge modules + 5 labs + interview prep — from "how does a GPU run a matmul" to "size a cluster and defend the $/token to a CFO."
➡ jd4-azure-agentic-banking-track/ — Senior / Agentic AI Engineer, Banking on Microsoft Azure (jd4.md)
Azure-native, agentic, regulated-banking application engineering: Azure OpenAI, Azure AI Search (hybrid/semantic RAG), LangGraph / Microsoft Agent Framework / Foundry Agent Service, Document Intelligence, multimodal + Arabic, FastAPI/Docker/Cosmos/CI-CD, evaluation & Responsible AI. 10 knowledge modules + 7 labs + a 5-part interview-day battle plan. Start here if you're targeting jd4 — and if the interview is tomorrow, jump to its Interview-Day Battle Plan.
(jd3.md — the AppliedAI/Opus inference-plumbing role — is a separate JD with no dedicated track yet.)
What the Role Actually Requires
| Requirement | What to Demonstrate |
|---|---|
| LLM deployment on-prem / air-gapped | Serve a model with vLLM or Ollama, zero internet |
| RAG over internal documents | Ingest PDFs/schemas → vector DB → retrieval chain |
| Fine-tuning / domain adaptation | LoRA/QLoRA on a 7B model with domain corpus |
| Prompt pipelines + function-calling | LLM calls tools to query structured data |
| Evaluation & guardrails | Hallucination detection, safety filters, quality scoring |
| Data curation | Clean, chunk, and embed domain documents |
Labs
Lab 1 — Air-Gapped LLM Serving
Goal: Deploy a 7B model locally with no internet dependency. Expose it as an OpenAI-compatible API.
Stack: Ollama (easiest) or vLLM (production-grade)
Steps:
- Pull
llama3:8bormistral:7bvia Ollama before going offline. Verify~/.ollama/models/contains the weights. - Disable network (
sudo ifconfig en0 downon macOS or pull the Ethernet). - Start the server:
ollama serve→ confirm it answers onlocalhost:11434. - Hit it with the OpenAI SDK pointing at
base_url="http://localhost:11434/v1". - Wrap in a FastAPI service with a
/chatendpoint that logs every request/response.
Test: curl the /chat endpoint with Wi-Fi off. Must return a response.
Resume bullet: "Deployed Llama-3 8B as an OpenAI-compatible REST service on air-gapped infrastructure using Ollama; validated zero-network-dependency operation and built a FastAPI wrapper with request logging."
Lab 2 — RAG Pipeline Over Domain Documents
Goal: Build a RAG pipeline that answers questions from a corpus of PDFs (asset manuals, schemas, specs).
Stack: LangChain or LlamaIndex · ChromaDB (local) · sentence-transformers for embeddings
Steps:
- Collect 5–10 PDF documents (use public infrastructure manuals or IEEE specs as stand-ins).
- Load → chunk (512 tokens, 50-token overlap) → embed with
all-MiniLM-L6-v2→ store in ChromaDB on disk. - Build a retrieval chain: user query → top-k chunk retrieval → stuff into prompt → LLM (Lab 1 server).
- Add a source citation step: return which document + page number each answer draws from.
- Test with 20 questions you know the answers to; log retrieval hit rate.
Key design decision to understand: chunk size vs retrieval precision trade-off. Try 256 vs 512 vs 1024 and report F1 on your 20 questions.
Resume bullet: "Built a fully local RAG pipeline (LangChain + ChromaDB) over 10 infrastructure PDFs; implemented source-citation, measured retrieval precision at three chunk sizes, achieved 84% answer accuracy on a 20-question eval set."
Lab 3 — Domain Fine-Tuning with QLoRA
Goal: Fine-tune a 7B model on domain Q&A pairs so it speaks the vocabulary of asset management / infrastructure operations.
Stack: transformers · peft · bitsandbytes · trl (SFTTrainer) · single GPU (16–24 GB)
Steps:
- Create or download ~500–1000 instruction pairs in the target domain (e.g., OpenAssistant filtered by topic, or synthesize with GPT-4o).
- Load
mistralai/Mistral-7B-v0.1in 4-bit withBitsAndBytesConfig. - Attach LoRA adapters (
r=16,lora_alpha=32, targetq_projandv_proj). - Train with
SFTTrainerfor 1–2 epochs; log loss. - Merge adapters and quantize the merged model to GGUF with
llama.cppfor Ollama deployment. - Compare base vs fine-tuned on 10 domain-specific questions (qualitative diff is fine).
Critical concept: Fine-tuning vs RAG — when to use which. Answer: fine-tune for style/vocabulary/format; RAG for factual retrieval from documents. Combine both for production.
Resume bullet: "QLoRA fine-tuned Mistral-7B on 800 domain instruction pairs (r=16, 4-bit NF4); merged and converted to GGUF for on-prem Ollama deployment; measured perplexity drop of 18% on held-out domain eval set."
Lab 4 — Function-Calling Over Structured Asset Data
Goal: Let the LLM query a mock asset/operations database via tool calls — no SQL knowledge required from the user.
Stack: OpenAI function-calling API (or Ollama with tools support) · SQLite mock DB · FastAPI
Steps:
- Create a SQLite DB with tables:
assets(id, name, type, location_lat, location_lon, status)andmaintenance_logs(asset_id, date, description). Populate with 100 fake rows. - Define two tools:
get_asset_status(asset_id)andsearch_assets_by_type(type, radius_km, lat, lon). - Register these as OpenAI-style function schemas in your chat loop.
- Parse the LLM's tool-call response → execute SQL → return result → re-inject into conversation.
- Test: "Which pumping stations within 5 km of [lat, lon] had maintenance in the last 30 days?" — LLM should call both tools in sequence.
Talking point: This pattern (LLM as orchestrator, tools as data accessors) is exactly how the Digital Twin AI Assistant integrates with enterprise systems.
Resume bullet: "Implemented a tool-calling LLM agent over a geospatial asset database; defined 5 function schemas, built a tool-execution loop, and demonstrated multi-hop queries combining spatial search and maintenance history retrieval."
Lab 5 — Evaluation & Guardrails
Goal: Measure response quality and catch hallucinations / unsafe outputs before they reach users.
Stack: deepeval or ragas (for RAG eval) · presidio (PII detection) · custom judge LLM prompt
Steps:
- RAG eval (builds on Lab 2): use
ragasto score your pipeline on Faithfulness, Answer Relevancy, and Context Recall against your 20-question set. - Hallucination check: write a judge prompt —
"Given CONTEXT: {ctx}\nANSWER: {ans}\nIs the answer fully supported by the context? Reply YES or NO and cite the unsupported claim."Run it over 50 answers. - PII / safety filter: add
presidioas a pre-processing step to redact any names, coordinates, or IDs from user input before it hits the LLM. - Output length / format guardrail: if the model response is >1000 tokens or missing a required JSON key, retry with a stricter prompt (max 2 retries).
- Log all guardrail triggers to a file. Report: what % of responses needed intervention.
Resume bullet: "Built a multi-layer guardrail stack: RAGAS eval (faithfulness 0.87), LLM-as-judge hallucination detector (flagged 11% of responses), PII redaction via Microsoft Presidio, and format-enforcement retry logic."
Lab 6 — End-to-End: Air-Gapped Digital Twin Assistant
Goal: Wire all prior labs into a single deployable service — a chat assistant that retrieves from docs, queries structured data, and refuses out-of-scope questions.
Steps:
- Single
docker-compose.yml: Ollama container + ChromaDB container + FastAPI app container. No external network required (--network noneon the app container). - Request router: classify incoming query as "document question" (→ Lab 2 RAG) or "data query" (→ Lab 4 tool-calling) or "out of scope" (→ polite refusal).
- Add a simple Streamlit UI: chat box + source citations panel.
- Record a 3-minute demo video showing all three query types working offline.
Resume bullet: "Delivered a containerised, fully air-gapped LLM assistant (Ollama + ChromaDB + FastAPI + Streamlit) combining RAG and tool-calling with a query router and guardrail layer; demonstrated live with Wi-Fi disabled."
Concepts You Must Be Able to Explain Out Loud
| Topic | One-line answer to have ready |
|---|---|
| RAG vs fine-tuning | RAG = retrieve facts at runtime; fine-tune = bake style/format into weights |
| Chunking strategy | Fixed-size with overlap; semantic chunking for higher precision |
| Embedding model choice | all-MiniLM-L6-v2 for speed; bge-large for accuracy; domain-specific if available |
| Hallucination causes | LLM fills gaps when context is absent; fix with retrieval + faithfulness checks |
| Air-gap constraints | No API calls, no pip install at runtime → freeze deps, ship weights, use GGUF |
| Function-calling vs RAG | Function-calling for live structured data; RAG for static document knowledge |
| LoRA rank choice | r=8 fast & cheap; r=64 better quality; r=16 standard starting point |
| Guardrail layers | Input filter → retrieval → LLM → output filter → format check |
Interview Preparation
See interview-prep/ for system design walkthroughs and behavioural Q&A specific to this role.
Recommended Order
- Lab 1 (serving) → Lab 2 (RAG) → Lab 4 (function-calling) → Lab 5 (eval) → Lab 3 (fine-tuning) → Lab 6 (capstone)
Fine-tuning (Lab 3) is placed after function-calling because most real deployments solve domain queries with RAG+tools before reaching for fine-tuning.