Projects

A selection of things I've built, most recent first. Each one expands into how it actually works.

Ask My Site cover: a chat interface mockup answering "What does Alex actually work on?" with FastAPI, BM25, and Claude tags
Aug 2026

Ask My Site

The AI assistant on this very site (bottom-right corner). A small FastAPI backend that answers visitor questions about me directly, grounded in my own CV and background instead of guessing.

  • Python
  • FastAPI
  • Claude API
  • BM25
  • Google Cloud Run
  • Astro
How it works

A retriever (BM25 over keyword overlap - no vector database needed for a handful of documents) pulls the most relevant chunks from my CV and other notes, a persona layer combines them with a fixed "who I am" prompt, and a single call to Claude generates the answer. Layered backend architecture (controllers / domain / infrastructure / service layer), deployed on Google Cloud Run with the API key kept in Secret Manager.

The chat widget itself (this component) is framework-free - a small Astro component with vanilla JS calling the backend's POST /chat endpoint directly from the browser, CORS-locked to this site's origin.

View on GitHub
Three-panel decision boundary comparison: teacher, student without knowledge distillation, and student with knowledge distillation, on the XOR-blobs dataset
Jul 2026

KD Boundaries

A visual knowledge-distillation lab: trains a teacher and a student (with and without distillation) on 2D datasets and compares their decision boundaries, showing what the student actually learns from the teacher beyond accuracy.

  • Python
  • PyTorch
  • Knowledge Distillation
  • Visualization
How it works

Every experiment plots three panels side by side (teacher, student trained on hard labels only, and an architecturally identical student distilled from the teacher), so instead of comparing accuracy numbers you can literally see the boundary each model settled on. On datasets with a real "void" (regions with no training data, like the XOR-blobs case pictured), the no-KD student and the teacher resolve the ambiguity differently, while the KD student, trained on extra teacher-labeled query points sampled from that empty region, reproduces the teacher's exact boundary almost perfectly.

Two further experiments (overlapping blobs, a biased teacher) show the same mechanism from the opposite angle: when there's no void to fill, KD instead transfers the teacher's calibration, flaws included, like overconfidence or a spurious shortcut feature. The README argues that this is structurally the same effect behind why sequence-level distillation works for LLMs, not just a toy analogy.

View on GitHub
Chart showing how the planner decomposes more subtasks and execution waves as prompt complexity increases
Jul 2026

LLM Router

Decomposes a prompt into subtasks with a single planning call to Claude, routes each one to the cheapest model capable of handling it (Haiku/Sonnet/Opus), and runs the independent ones in parallel.

  • Python
  • Claude API
  • asyncio
  • Streamlit
How it works

A single structured-output call to Claude plans the whole job: it breaks a prompt into a dependency graph of subtasks, assigns each one the cheapest model tier that can handle it, and is explicitly told that decomposition isn't free (every extra call has its own overhead), so it only splits work when parallelism or a cheaper tier is actually worth it.

The executor groups subtasks into dependency-respecting "waves" and fires every subtask in a wave concurrently via asyncio, so a wave takes as long as its slowest call rather than the sum of all of them; a final synthesis call stitches independent results back into one answer. Every call (planner, subtasks, synthesis, and a single-model baseline for comparison) logs its own tokens, cost, and latency, so the routed pipeline can be benchmarked against just sending the whole prompt to one large model.

View on GitHub
LittleLamb Document Chat: a Streamlit chat interface for querying the fine-tuned model
May 2026

Custom LLM Finetuning

Local fine-tuning of a small LLM (LittleLamb, 290M parameters) on your own PDFs, with no vector databases or RAG: the knowledge lives in the model weights and runs entirely on CPU.

  • Python
  • LoRA
  • Hugging Face
  • FastAPI
  • Streamlit
How it works

Most "chat with your PDFs" tools reach for a full RAG stack (a vector database, an embedding model, a chunking/retrieval/reranking pipeline) even for a handful of documents. This project takes the opposite approach for small, stable document sets: extract the text (and describe any embedded images via Claude Vision), turn it into a Q&A training set, and LoRA fine-tune LittleLamb directly on the content. LittleLamb is a 290M-parameter model built by Multiverse Computing from Qwen3-0.6B, state of the art for its size class.

The result runs entirely offline on a laptop CPU: a FastAPI server exposes an OpenAI-compatible endpoint, and a Streamlit chat UI lets you ask questions the model answers straight from what it learned. No retrieval step, no infrastructure.

View on GitHub
Apr 2026

Moltbook Agent

Autonomous AI agent that lives on Moltbook, the social network for AI agents. Uses Claude as its reasoning model, deploys on Google Cloud Run, and is triggered every 5 minutes via Cloud Scheduler.

  • Python
  • Claude API
  • FastAPI
  • Google Cloud Run
  • Firestore
How it works

Every 5 minutes, Cloud Scheduler hits a FastAPI heartbeat endpoint on Cloud Run, which asks Claude to decide what the agent should do next, persists its evolving state to Firestore, and posts back to Moltbook through a small API client. It is a self-registering agent that runs unattended, with no human in the loop.

Secrets never touch the codebase: API keys live in Secret Manager, and the service itself runs with --no-allow-unauthenticated so only Cloud Scheduler's OIDC token can ever trigger it.

View on GitHub
In progress2025 - present

Tourist Guide

Mobile tourist-guide app that generates AI-personalized points-of-interest information from the user's GPS location, in multiple languages.

  • Python
  • Flask
  • DDD
  • PostgreSQL
  • React Native
  • Gemini AI
How it works

A full-stack side project built end to end: a Domain-Driven Design REST API, a PostgreSQL data layer, a React Native/Expo mobile client, and a second Flask/DDD service that calls Gemini to turn raw GPS coordinates into narrated points of interest (historical context, nearby landmarks, recommendations) on demand, in five languages.

It's the oldest project here and the one currently being actively rebuilt: the core AI pipeline and API already work end to end, the mobile app has its navigation shell in place, and the landing page is the next piece to build.

5 repositories
  • Backend

    REST API in Flask with Domain-Driven Design (DDD) architecture for the mobile app.

  • DB Helper

    PostgreSQL schema management scripts: creating and dropping tables, user model.

  • Mobile app

    React Native/Expo app with base navigation already implemented.

  • Agent Backend

    Flask/DDD service that integrates Gemini to generate tourist content and nearby points of interest, with multi-language support (ES/EN/FR/DE/IT).

  • Landing page

    Not started yet.

View on GitHub

Coming soon

Projects in the pipeline, not started yet.

LLM Compression to a 16GB Ceiling

Applying the classic Deep Compression pipeline (magnitude pruning, k-means weight-sharing quantization, and Huffman coding, from Han et al., 2015) to a ~7B-parameter LLM sized to sit right at the edge of 16GB of RAM, entirely post-training with no full retraining, then comparing the result against modern quantization methods like GPTQ and AWQ.

GPTQ and AWQ from Scratch

Reimplementing both post-training quantization algorithms by hand in plain PyTorch, with no official library: GPTQ with its layer-wise Hessian second-order approximation and error compensation, AWQ with its per-channel scale search. Benchmarked as perplexity against bit width on models small enough to run on a laptop (Qwen 0.5B, Llama 3.2 1B).

Structured Pruning Benchmark

Magnitude pruning, Wanda, SparseGPT and LLM-Pruner run on the same model under one identical evaluation protocol. Almost nobody compares these under matched conditions, so the value is in the honesty and reproducibility of the setup, and in reporting real inference cost rather than just parameter counts.

Layer-wise Compression Profiler

A tool that takes a model and works out which layers are most sensitive to quantization and pruning, via Fisher information, Hessian sensitivity or plain ablation, then proposes a mixed-precision bit allocation from the result. Infrastructure rather than a toy.

🤖

Ask me anything

AI trained on my background

Hey 👋 Curious about any of these? Ask me for the story behind one.
Ask me anything