How I Built This Site's Agent and Tuned It With Evals
A walkthrough of the agent on this site: how it stays grounded, the failure I found and fixed, and the evaluations and analytics that keep it honest.
The highlighted links open the work where I made these same calls for real.
The agent on this site answers questions about my work, grounded in the site's own pages and citing the ones it draws from. This is an account of how it is built: the grounding, a failure I found and fixed during testing, how the evaluations are calibrated, and how the site measures whether any of it works. I built it over a weekend. The harder part was making it trustworthy.
Why there is no vector database
The common pattern for an agent like this is a vector database: split the content into chunks, embed them, and retrieve the closest matches for each question. I decided against it. The corpus is the published site, about sixteen thousand tokens, and it fits in the model's context in full. A vector database is worth the added complexity when the content is too large to fit and you have to select which parts to include. Here it would only add a failure mode, a retrieval step that occasionally fetches the wrong chunk and makes the agent miss something that was present all along. Matching the approach to the size of the problem mattered more than reaching for the more elaborate option. I have written elsewhere about deciding what not to build, and this was a small case of it.
Grounding and citations
The agent is grounded on a single source: the content files that render the pages you can read. It has no access to my private notes, to anything marked confidential, or to internal strategy documents. This is a deliberate security decision. An agent cannot disclose information it was never given, so rather than rely on a prompt to keep quiet about sensitive material, I kept that material out of its context entirely. Each section of the grounding text also carries the route of the page it came from, so every claim the agent makes cites a page you can open and check. It cannot cite a source that does not exist, because the only sources it has are real pages. For a stranger deciding whether to trust it, grounding and citation together are what make the output verifiable rather than merely fluent.
A failure in testing
During testing I asked the agent how I handle failure, expecting it to draw on the Smart Tracker case study, a detailed account of a launch that stalled and how I recovered it. Instead it returned the generic fallback message with my contact details. An off-topic question was declined correctly, but a straightforward, answerable one was failing.
My first assumption was a citation-slug mismatch from a page I had recently renamed. It was wrong, and the traces showed it. Every call is instrumented with full observability, the same approach the AI-Native Service Desk case describes, so I could read what happened rather than guess. The cause was that the model provider was shedding large-context requests under load: small prompts usually succeeded, but the full sixteen-thousand-token request failed on eight consecutive attempts, and the occasional success took eleven to twenty-five seconds. I was compounding it myself, because my request timeout was set to around nine seconds and was cutting off valid answers that took longer.
The fixes were straightforward once the cause was clear. I raised the timeout, added retry with backoff on transient failures, and enabled context caching, which the corpus qualifies for on size, so each question now sends only the new tokens instead of resending the whole corpus. I did not need a vector database to reduce the request; I needed to stop resending content that had not changed. I also settled the cost question with data: use the free options first, measure, and pay for a backup provider only if the traces still showed a problem. They did not.
Calibrating the evaluations
Before the agent went live I wrote an evaluation suite, including a category of adversarial tests that probe for information it must never disclose: the name of an unreleased product, internal pricing, an acquisition target, and similar. The agent passes these only by declining, and the suite is a hard gate. It does not ship unless it scores perfectly on that category on every run.
The first run scored six out of fourteen. On the surface it looked as though the agent was disclosing the things it was meant to protect. Reading the transcripts showed the opposite: it had declined cleanly every time, and the grader was miscalibrated. I had defined a leak too loosely, so the judge flagged clean refusals, treated the agent stating its own public role as a disclosure, and read a neutral line about being open to a conversation as a signal it should not have inferred. The agent was behaving correctly. The measurement was not
.
I fixed the grader rather than the agent. I redefined a leak precisely: an answer fails only if it actually discloses one of the protected items, and the judge has to quote the specific text that gives it away. Declining, saying it does not have the information, citing public content, or stating a public role do not count. The score moved to fourteen out of fourteen, and the change touched only the grader; the agent's prompt, corpus, and routing were untouched. The takeaway is that an alarming metric is itself a suspect, and it is worth validating the measurement before acting on it.
Instrumenting the funnel
The agent has full observability through Langfuse. The site has the same treatment pointed at the people using it, because I want to see the whole path a visitor takes: how they arrive, whether they use the agent, whether they reach a call to action, whether they act on it, and whether it leads to a booked conversation.
I chose PostHog for this. Tools like Google Analytics are built for high-traffic sites focused on search, and they answer a question I do not have. This site is private and reaches a small number of specific people, so I am not counting pageviews; I am following an individual's path and looking for where it converts or stalls. PostHog provides funnels, per-person journeys, and session replay, and its free tier is well beyond anything this site will need.
Two implementation choices matter more than the tool. I route the analytics through my own domain rather than the vendor's, so the ad-blockers many people run do not silently drop the events. And session replay masks all inputs, which is appropriate given who the visitors are. Langfuse measures the system, PostHog measures its use, and both exist so that decisions rest on evidence rather than assumption.
What it demonstrates
None of these choices are unusual on their own. They are the same ones I apply to product work: ground a system in real evidence, instrument it before you need to, diagnose in order rather than guessing, let the data correct your first assumption, sequence spending from free to paid, and hold a quality bar with a test you can trust, which sometimes means fixing the test. The agent itself is a small thing. The method behind it is the part that carries over.