Case study · Personal build · Live on this site

Ask about my work

A grounded AI assistant, live on this site, that answers questions about my work from my real case studies and resume. It cites every answer, and when it does not know, it says so.

The problem
A portfolio assistant that makes things up is worse than none. A generic AI will happily invent a metric, a client, or a claim, and sound confident doing it.
What I built
A retrieval pipeline on Google Cloud that answers only from my real documents, links the sources it used, and refuses when it finds nothing relevant.
My role
Solo, end to end. The grounding contract, the cloud architecture, the retrieval calibration, the ship.
The difference
Cite or refuse. Every answer points back to a real page, and an off topic question gets an honest no instead of a confident guess.
Live on this siteEvery answer citedRefuses off topic questionsCosts nothing at rest
01 · The problem

A portfolio assistant that makes things up is worse than none

A generic AI will happily invent a metric, a client, or a claim, and sound confident doing it. On a page about my own work, that is a disaster.

So I did not want a chatbot. I wanted something that could only tell the truth about what I have actually done, and that would rather stay quiet than guess.

Before building anything, I looked at the ways to get there.

The options, before I wrote a line of code

I mapped the ways to put an assistant on a portfolio

Everything on this list can produce an answer. The differences that matter are what the answer is grounded in, whether it shows its sources, and what it does when it does not know.

ToolGrounded in my documentsCites its sourcesRefuses instead of guessingCost at restWhat I control
A generic chatbotan LLM with a system promptNo, answers from model memoryNoNo, it sounds confident anywayPer tokenThe prompt, nothing else
Prompt stuffingpaste all my docs into the promptYes, until the corpus outgrows itNoNo, it fills the gapsPays for the whole corpus per questionThe prompt, nothing else
Chatbot widgetsChatbase, CustomGPTYes, on their serversSometimesTuned to keep answeringA monthly subscriptionTheir stack, their rules
Managed RAGVertex AI SearchYesYesConfigurableMore than a portfolio needsThe service owns the internals
This buildRAG, hand built on Google CloudOnly my case studies and resumeEvery answer links its sourcesSays so when it does not knowScales to zeroEvery piece, tuned by hand

Representative options per approach, from scoping the build. The behaviour I could not buy anywhere was principled refusal.

The call

Why I built it by hand

The widgets get you a chatbot in an afternoon, and every one of them is tuned for the same thing: always answer, keep the visitor engaged. On a page about my own work, a confident wrong answer costs more than no answer. The one behaviour I could not buy was refusal.

So I built the pipeline myself on Google Cloud. Not because RAG is exotic, it is not, but because I wanted the grounding contract in my own hands, the running cost near zero, and the cloud skills earned for real instead of claimed.

02 · The core decision

Grounded, or quiet

The answer is retrieval augmented generation, RAG. Instead of letting the model answer from its own memory, it first pulls the most relevant passages from my real documents, my case studies and my resume, and answers using only those.

Every answer links the sources it used, so you can check it against the real page it came from. If nothing relevant is found, it says so rather than guessing.

Cite or refuse is not a nice touch here. For a bot speaking about my work, refusing to invent is the whole product.

03 · The architecture

How it works, on Google Cloud

My documents live in Cloud Storage. A step chunks them and turns each piece into an embedding, a numeric fingerprint of its meaning, using Vertex AI, and stores them in Cloud SQL with the pgvector extension. When a question comes in, the app on Cloud Run embeds it, pulls the closest chunks, and passes them to Gemini with one instruction: answer only from these, cite them, or say you do not have it.

The service choices were deliberate and cost aware. Cloud Run scales to zero, so it costs nothing at rest. I used Cloud SQL rather than the pricier managed option, because at this scale the difference was all cost and no benefit. Access and secrets are handled by IAM and Secret Manager, not by keys sitting in code.

The discipline

Reliable is the hard part

The hard part of RAG is not wiring it up. It is making it reliable. I calibrated the retrieval threshold from real query scores rather than guessing, so genuine questions get answered and off topic ones get refused. I set the model to answer deterministically, so the same question does not flip between answering and refusing. And I kept the answers short, first person, and free of invented detail.

This is the same grounded, cite or refuse pattern from my ServiceNow and dental copilots, rebuilt as a genuinely Google Cloud native system.

Where it stands

The honest result

It is live on this site. You can open the Ask feature and try it, and every answer points back to the real page it came from.

The same engine also powers a private second brain over my own notes and reading, kept behind a login. What this build demonstrates is the part I care about: shipping a real, grounded AI system on the cloud, one that is honest about the limits of what it knows.

Tech & tools

Retrieval augmented generationVertex AI (Gemini + embeddings)Google Cloud RunGoogle Cloud StorageCloud SQL + pgvectorIAM + Secret ManagerNext.js

My role

  • Mapped the options first, widgets, prompt stuffing, managed RAG or hand built, and chose the only one whose grounding contract I fully control.
  • Designed and built the whole system Google Cloud native: a cite or refuse RAG pipeline on Vertex AI, Cloud Run, Cloud Storage and Cloud SQL with pgvector, with retrieval calibrated from real query scores and deterministic answers.
  • Shipped it live on this site, reused the engine for a private notes brain, and kept the infrastructure frugal: scale to zero, least privilege, secrets out of code.