Virtual Me
View on GitHubRetrieval-augmented chat backend that answers real questions about my work from a curated knowledge base, not a hardcoded FAQ. Hybrid retrieval, three-provider LLM failover, and semantic caching, live in production behind the chat widget on this site.
A static portfolio resume page can only state claims about my work, not let a visitor test them. This project replaces a hardcoded chat lookup with a real retrieval-augmented backend that answers questions grounded in a reviewed knowledge base, and refuses honestly rather than inventing an answer when a question falls outside it, all under a hard zero-dollar-per-month, no-credit-card budget.
A Cloudflare Pages Function orchestrates every request through an ordered chain of guardrails, cheapest and most deterministic first. Request validation, concurrent Turnstile verification and rate limiting, a typo-tolerant greeting and closing short-circuit, a deterministic must-refuse topic guard, concurrent history and embedding fetches, a first-turn-only semantic cache check, hybrid dense and sparse retrieval against Qdrant fused with Reciprocal Rank Fusion, a retrieval-score refusal floor, cross-encoder reranking down to the best three chunks, and streamed generation across a three-provider failover chain, all behind one unified streaming response. Ingestion runs as a separate offline path, markdown chunked by heading, embedded, and upserted into Qdrant with deterministic point IDs, so editing content never requires redeploying. The refusal gate was moved from the reranker's compressed score, which had no real separation, to the retrieval fusion score with a much lower threshold that only catches zero-signal retrieval rather than punishing genuine borderline questions. Provider fallback order is privacy-ordered, not just capacity-ordered. One fallback provider has roughly thirty times the free capacity of the primary choice but is held at the lowest priority because its free tier may use prompt data for training.
