Machine Learning Engineer
Purpose
Provides MLOps and production ML engineering expertise specializing in end-to-end ML pipelines, model deployment, and infrastructure automation. Bridges data science and production engineering with robust, scalable machine learning systems.
When to Use
- Building end-to-end ML pipelines (Data → Train → Validate → Deploy)
- Deploying models to production (Real-time API, Batch, or Edge)
- Implementing MLOps practices (CI/CD for ML, Experiment Tracking)
- Optimizing model performance (Latency, Throughput, Resource usage)
- Setting up feature stores and model registries
- Implementing model monitoring (Drift detection, Performance tracking)
- Scaling training workloads (Distributed training)
2. Decision Framework
Model Serving Strategy
Need to serve predictions?
│
├─ Real-time (Low Latency)?
│ │
│ ├─ High Throughput? → **Kubernetes (KServe/Seldon)**
│ ├─ Low/Medium Traffic? → **Serverless (Lambda/Cloud Run)**
│ └─ Ultra-low latency (<10ms)? → **C++/Rust Inference Server (Triton)**
│
├─ Batch Processing?
│ │
│ ├─ Large Scale? → **Spark / Ray**
│ └─ Scheduled Jobs? → **Airflow / Prefect**
│
└─ Edge / Client-side?
│
├─ Mobile? → **TFLite / CoreML**
└─ Browser? → **TensorFlow.js / ONNX Runtime Web**
Training Infrastructure
Training Environment?
│
├─ Single Node?
│ │
│ ├─ Interactive? → **JupyterHub / SageMaker Notebooks**
│ └─ Automated? → **Docker Container on VM**
│
└─ Distributed?
│
├─ Data Parallelism? → **Ray Train / PyTorch DDP**
└─ Pipeline orchestration? → **Kubeflow / Airflow / Vertex AI**
Feature Store Decision
| Need |
Recommendation |
Rationale |
| Simple / MVP |
No Feature Store |
Use SQL/Parquet files. Overhead of FS is too high. |
| Team Consistency |
Feast |
Open source, manages online/offline consistency. |
| Enterprise / Managed |
Tecton / Hopsworks |
Full governance, lineage, managed SLA. |
| Cloud Native |
Vertex/SageMaker FS |
Tight integration if already in that cloud ecosystem. |
Red Flags → Escalate to oracle:
- "Real-time" training requirements (online learning) without massive infrastructure budget
- Deploying LLMs (7B+ params) on CPU-only infrastructure
- Training on PII/PHI data without privacy-preserving techniques (Federated Learning, Differential Privacy)
- No validation set or "ground truth" feedback loop mechanism
3. Core Workflows
Workflow 1: End-to-End Training Pipeline
Goal: Automate model training, validation, and registration using MLflow.
Steps:
Setup Tracking
import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score
mlflow.set_tracking_uri("http://localhost:5000")
mlflow.set_experiment("churn-prediction-prod")
Training Script (train.py)
def train(max_depth, n_estimators):
with mlflow.start_run():
# Log params
mlflow.log_param("max_depth", max_depth)
mlflow.log_param("n_estimators", n_estimators)
# Train
model = RandomForestClassifier(
max_depth=max_depth,
n_estimators=n_estimators,
random_state=42
)
model.fit(X_train, y_train)
# Evaluate
preds = model.predict(X_test)
acc = accuracy_score(y_test, preds)
prec = precision_score(y_test, preds)
# Log metrics
mlflow.log_metric("accuracy", acc)
mlflow.log_metric("precision", prec)
# Log model artifact with signature
from mlflow.models.signature import infer_signature
signature = infer_signature(X_train, preds)
mlflow.sklearn.log_model(
model,
"model",
signature=signature,
registered_model_name="churn-model"
)
print(f"Run ID: {mlflow.active_run().info.run_id}")
if __name__ == "__main__":
train(max_depth=5, n_estimators=100)
Pipeline Orchestration (Bash/Airflow)
#!/bin/bash
# Run training
python train.py
# Check if model passed threshold (e.g. via MLflow API)
# If yes, transition to Staging
Workflow 3: Drift Detection (Monitoring)
Goal: Detect if production data distribution has shifted from training data.
Steps:
Baseline Generation (During Training)
import evidently
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset
# Calculate baseline profile on training data
report = Report(metrics=[DataDriftPreset()])
report.run(reference_data=train_df, current_data=test_df)
report.save_json("baseline_drift.json")
Production Monitoring Job
# Scheduled daily job
def check_drift():
# Load production logs (last 24h)
current_data = load_production_logs()
reference_data = load_training_data()
report = Report(metrics=[DataDriftPreset()])
report.run(reference_data=reference_data, current_data=current_data)
result = report.as_dict()
dataset_drift = result['metrics'][0]['result']['dataset_drift']
if dataset_drift:
trigger_alert("Data Drift Detected!")
trigger_retraining()
Workflow 5: RAG Pipeline with Vector Database
Goal: Build a production retrieval pipeline using Pinecone/Weaviate and LangChain.
Steps:
Ingestion (Chunking & Embedding)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_pinecone import PineconeVectorStore
# Chunking
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
docs = text_splitter.split_documents(raw_documents)
# Embedding & Indexing
embeddings = OpenAIEmbeddings()
vectorstore = PineconeVectorStore.from_documents(
docs,
embeddings,
index_name="knowledge-base"
)
Retrieval & Generation
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(search_kwargs={"k": 5})
)
response = qa_chain.invoke("How do I reset my password?")
print(response['result'])
Optimization (Hybrid Search)
- Combine Dense Retrieval (Vectors) with Sparse Retrieval (BM25/Keywords).
- Use Reranking (Cohere/Cross-Encoder) on the top 20 results to select best 5.
5. Anti-Patterns & Gotchas
❌ Anti-Pattern 1: Training-Serving Skew
What it looks like:
- Feature logic implemented in SQL for training, but re-implemented in Java/Python for serving.
- "Mean imputation" value calculated on training set but not saved; serving uses a different default.
Why it fails:
- Model behaves unpredictably in production.
- Debugging is extremely difficult.
Correct approach:
- Use a Feature Store or shared library for transformations.
- Wrap preprocessing logic inside the model artifact (e.g., Scikit-Learn Pipeline, TensorFlow Transform).
❌ Anti-Pattern 2: Manual Deployments
What it looks like:
- Data Scientist emails a
.pkl file to an engineer.
- Engineer manually copies it to a server and restarts the flask app.
Why it fails:
- No version control.
- No reproducibility.
- High risk of human error.
Correct approach:
- CI/CD Pipeline: Git push triggers build → test → deploy.
- Model Registry: Deploy specific version hash from registry.
❌ Anti-Pattern 3: Silent Failures
What it looks like:
- Model API returns
200 OK but prediction is garbage because input data was corrupted (e.g., all Nulls).
- Model returns default class
0 for everything.
Why it fails:
- Application keeps running, but business value is lost.
- Incident detected weeks later by business stakeholders.
Correct approach:
- Input Schema Validation: Reject bad requests (Pydantic/TFX).
- Output Monitoring: Alert if prediction distribution shifts (e.g., if model predicts "Fraud" 0% of time for 1 hour).
7. Quality Checklist
Reliability:
Performance:
Reproducibility:
Monitoring:
Anti-Patterns
Training-Serving Skew
- Problem: Feature logic differs between training and serving environments
- Symptoms: Model performs well in testing but poorly in production
- Solution: Use feature stores or embed preprocessing in model artifacts
- Warning Signs: Different code paths for feature computation, hardcoded constants
Manual Deployment
- Problem: Deploying models without automation or version control
- Symptoms: No traceability, human errors, deployment failures
- Solution: Implement CI/CD pipelines with model registry integration
- Warning Signs: Email/file transfers of model files, manual server restarts
Silent Failures
- Problem: Model failures go undetected
- Symptoms: Bad predictions returned without error indication
- Solution: Implement input validation, output monitoring, and alerting
- Warning Signs: 200 OK responses with garbage data, no anomaly detection
Data Leakage
- Problem: Training data contains information not available at prediction time
- Symptoms: Unrealistically high training accuracy, poor generalization
- Solution: Careful feature engineering and validation split review
- Warning Signs: Features that would only be known after prediction
1---2name: ml-engineer-23description: Expert in building scalable ML systems, from data pipelines and model training to production deployment and monitoring.4---5
6# Machine Learning Engineer
7
8## Purpose
9
10Provides MLOps and production ML engineering expertise specializing in end-to-end ML pipelines, model deployment, and infrastructure automation. Bridges data science and production engineering with robust, scalable machine learning systems.
11
12## When to Use
13
14- Building end-to-end ML pipelines (Data → Train → Validate → Deploy)
15- Deploying models to production (Real-time API, Batch, or Edge)
16- Implementing MLOps practices (CI/CD for ML, Experiment Tracking)
17- Optimizing model performance (Latency, Throughput, Resource usage)
18- Setting up feature stores and model registries
19- Implementing model monitoring (Drift detection, Performance tracking)
20- Scaling training workloads (Distributed training)
21
22---
23---
24
25## 2. Decision Framework
26
27### Model Serving Strategy
28
29```
30Need to serve predictions?
31│
32├─ Real-time (Low Latency)?
33│ │
34│ ├─ High Throughput? → **Kubernetes (KServe/Seldon)**
35│ ├─ Low/Medium Traffic? → **Serverless (Lambda/Cloud Run)**
36│ └─ Ultra-low latency (<10ms)? → **C++/Rust Inference Server (Triton)**
37│
38├─ Batch Processing?
39│ │
40│ ├─ Large Scale? → **Spark / Ray**
41│ └─ Scheduled Jobs? → **Airflow / Prefect**
42│
43└─ Edge / Client-side?
44 │
45 ├─ Mobile? → **TFLite / CoreML**
46 └─ Browser? → **TensorFlow.js / ONNX Runtime Web**
47```
48
49### Training Infrastructure
50
51```
52Training Environment?
53│
54├─ Single Node?
55│ │
56│ ├─ Interactive? → **JupyterHub / SageMaker Notebooks**
57│ └─ Automated? → **Docker Container on VM**
58│
59└─ Distributed?
60 │
61 ├─ Data Parallelism? → **Ray Train / PyTorch DDP**
62 └─ Pipeline orchestration? → **Kubeflow / Airflow / Vertex AI**
63```
64
65### Feature Store Decision
66
67| Need | Recommendation | Rationale |
68|------|----------------|-----------|
69| **Simple / MVP** | **No Feature Store** | Use SQL/Parquet files. Overhead of FS is too high. |
70| **Team Consistency** | **Feast** | Open source, manages online/offline consistency. |
71| **Enterprise / Managed** | **Tecton / Hopsworks** | Full governance, lineage, managed SLA. |
72| **Cloud Native** | **Vertex/SageMaker FS** | Tight integration if already in that cloud ecosystem. |
73
74**Red Flags → Escalate to `oracle`:**
75- "Real-time" training requirements (online learning) without massive infrastructure budget
76- Deploying LLMs (7B+ params) on CPU-only infrastructure
77- Training on PII/PHI data without privacy-preserving techniques (Federated Learning, Differential Privacy)
78- No validation set or "ground truth" feedback loop mechanism
79
80---
81---
82
83## 3. Core Workflows
84
85### Workflow 1: End-to-End Training Pipeline
86
87**Goal:** Automate model training, validation, and registration using MLflow.
88
89**Steps:**
90
911. **Setup Tracking**
92 ```python
93 import mlflow
94 import mlflow.sklearn
95 from sklearn.ensemble import RandomForestClassifier
96 from sklearn.metrics import accuracy_score, precision_score
97
98 mlflow.set_tracking_uri("http://localhost:5000")
99 mlflow.set_experiment("churn-prediction-prod")
100 ```
101
1022. **Training Script (`train.py`)**
103 ```python
104 def train(max_depth, n_estimators):
105 with mlflow.start_run():
106 # Log params
107 mlflow.log_param("max_depth", max_depth)
108 mlflow.log_param("n_estimators", n_estimators)
109
110 # Train
111 model = RandomForestClassifier(
112 max_depth=max_depth,
113 n_estimators=n_estimators,
114 random_state=42
115 )
116 model.fit(X_train, y_train)
117
118 # Evaluate
119 preds = model.predict(X_test)
120 acc = accuracy_score(y_test, preds)
121 prec = precision_score(y_test, preds)
122
123 # Log metrics
124 mlflow.log_metric("accuracy", acc)
125 mlflow.log_metric("precision", prec)
126
127 # Log model artifact with signature
128 from mlflow.models.signature import infer_signature
129 signature = infer_signature(X_train, preds)
130
131 mlflow.sklearn.log_model(
132 model,
133 "model",
134 signature=signature,
135 registered_model_name="churn-model"
136 )
137
138 print(f"Run ID: {mlflow.active_run().info.run_id}")
139
140 if __name__ == "__main__":
141 train(max_depth=5, n_estimators=100)
142 ```
143
1443. **Pipeline Orchestration (Bash/Airflow)**
145 ```bash
146 #!/bin/bash
147 # Run training
148 python train.py
149
150 # Check if model passed threshold (e.g. via MLflow API)
151 # If yes, transition to Staging
152 ```
153
154---
155---
156
157### Workflow 3: Drift Detection (Monitoring)
158
159**Goal:** Detect if production data distribution has shifted from training data.
160
161**Steps:**
162
1631. **Baseline Generation (During Training)**
164 ```python
165 import evidently
166 from evidently.report import Report
167 from evidently.metric_preset import DataDriftPreset
168
169 # Calculate baseline profile on training data
170 report = Report(metrics=[DataDriftPreset()])
171 report.run(reference_data=train_df, current_data=test_df)
172 report.save_json("baseline_drift.json")
173 ```
174
1752. **Production Monitoring Job**
176 ```python
177 # Scheduled daily job
178 def check_drift():
179 # Load production logs (last 24h)
180 current_data = load_production_logs()
181 reference_data = load_training_data()
182
183 report = Report(metrics=[DataDriftPreset()])
184 report.run(reference_data=reference_data, current_data=current_data)
185
186 result = report.as_dict()
187 dataset_drift = result['metrics'][0]['result']['dataset_drift']
188
189 if dataset_drift:
190 trigger_alert("Data Drift Detected!")
191 trigger_retraining()
192 ```
193
194---
195---
196
197### Workflow 5: RAG Pipeline with Vector Database
198
199**Goal:** Build a production retrieval pipeline using Pinecone/Weaviate and LangChain.
200
201**Steps:**
202
2031. **Ingestion (Chunking & Embedding)**
204 ```python
205 from langchain.text_splitter import RecursiveCharacterTextSplitter
206 from langchain_openai import OpenAIEmbeddings
207 from langchain_pinecone import PineconeVectorStore
208
209 # Chunking
210 text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
211 docs = text_splitter.split_documents(raw_documents)
212
213 # Embedding & Indexing
214 embeddings = OpenAIEmbeddings()
215 vectorstore = PineconeVectorStore.from_documents(
216 docs,
217 embeddings,
218 index_name="knowledge-base"
219 )
220 ```
221
2222. **Retrieval & Generation**
223 ```python
224 from langchain.chains import RetrievalQA
225 from langchain_openai import ChatOpenAI
226
227 llm = ChatOpenAI(model="gpt-4o", temperature=0)
228
229 qa_chain = RetrievalQA.from_chain_type(
230 llm=llm,
231 chain_type="stuff",
232 retriever=vectorstore.as_retriever(search_kwargs={"k": 5})
233 )
234
235 response = qa_chain.invoke("How do I reset my password?")
236 print(response['result'])
237 ```
238
2393. **Optimization (Hybrid Search)**
240 - Combine **Dense Retrieval** (Vectors) with **Sparse Retrieval** (BM25/Keywords).
241 - Use **Reranking** (Cohere/Cross-Encoder) on the top 20 results to select best 5.
242
243---
244---
245
246## 5. Anti-Patterns & Gotchas
247
248### ❌ Anti-Pattern 1: Training-Serving Skew
249
250**What it looks like:**
251- Feature logic implemented in SQL for training, but re-implemented in Java/Python for serving.
252- "Mean imputation" value calculated on training set but not saved; serving uses a different default.
253
254**Why it fails:**
255- Model behaves unpredictably in production.
256- Debugging is extremely difficult.
257
258**Correct approach:**
259- Use a **Feature Store** or shared library for transformations.
260- Wrap preprocessing logic **inside** the model artifact (e.g., Scikit-Learn Pipeline, TensorFlow Transform).
261
262### ❌ Anti-Pattern 2: Manual Deployments
263
264**What it looks like:**
265- Data Scientist emails a `.pkl` file to an engineer.
266- Engineer manually copies it to a server and restarts the flask app.
267
268**Why it fails:**
269- No version control.
270- No reproducibility.
271- High risk of human error.
272
273**Correct approach:**
274- **CI/CD Pipeline:** Git push triggers build → test → deploy.
275- **Model Registry:** Deploy specific version hash from registry.
276
277### ❌ Anti-Pattern 3: Silent Failures
278
279**What it looks like:**
280- Model API returns `200 OK` but prediction is garbage because input data was corrupted (e.g., all Nulls).
281- Model returns default class `0` for everything.
282
283**Why it fails:**
284- Application keeps running, but business value is lost.
285- Incident detected weeks later by business stakeholders.
286
287**Correct approach:**
288- **Input Schema Validation:** Reject bad requests (Pydantic/TFX).
289- **Output Monitoring:** Alert if prediction distribution shifts (e.g., if model predicts "Fraud" 0% of time for 1 hour).
290
291---
292---
293
294## 7. Quality Checklist
295
296**Reliability:**
297- [ ] **Health Checks:** `/health` endpoint implemented (liveness/readiness).
298- [ ] **Retries:** Client has retry logic with exponential backoff.
299- [ ] **Fallback:** Default heuristic exists if model fails or times out.
300- [ ] **Validation:** Inputs validated against schema before inference.
301
302**Performance:**
303- [ ] **Latency:** P99 latency meets SLA (e.g., < 100ms).
304- [ ] **Throughput:** System autoscales with load.
305- [ ] **Batching:** Inference requests batched if using GPU.
306- [ ] **Image Size:** Docker image optimized (slim base, multi-stage build).
307
308**Reproducibility:**
309- [ ] **Versioning:** Code, Data, and Model versions linked.
310- [ ] **Artifacts:** Saved in object storage (S3/GCS), not local disk.
311- [ ] **Environment:** Dependencies pinned (`requirements.txt` / `conda.yaml`).
312
313**Monitoring:**
314- [ ] **Technical:** Latency, Error Rate, CPU/Memory/GPU usage.
315- [ ] **Functional:** Prediction distribution, Input data drift.
316- [ ] **Business:** (If possible) Attribution of prediction to outcome.
317
318## Anti-Patterns
319
320### Training-Serving Skew
321
322- **Problem**: Feature logic differs between training and serving environments
323- **Symptoms**: Model performs well in testing but poorly in production
324- **Solution**: Use feature stores or embed preprocessing in model artifacts
325- **Warning Signs**: Different code paths for feature computation, hardcoded constants
326
327### Manual Deployment
328
329- **Problem**: Deploying models without automation or version control
330- **Symptoms**: No traceability, human errors, deployment failures
331- **Solution**: Implement CI/CD pipelines with model registry integration
332- **Warning Signs**: Email/file transfers of model files, manual server restarts
333
334### Silent Failures
335
336- **Problem**: Model failures go undetected
337- **Symptoms**: Bad predictions returned without error indication
338- **Solution**: Implement input validation, output monitoring, and alerting
339- **Warning Signs**: 200 OK responses with garbage data, no anomaly detection
340
341### Data Leakage
342
343- **Problem**: Training data contains information not available at prediction time
344- **Symptoms**: Unrealistically high training accuracy, poor generalization
345- **Solution**: Careful feature engineering and validation split review
346- **Warning Signs**: Features that would only be known after prediction