Source is private. This is the architecture and the thinking behind it — no product code. The retrieval technique is shown, runnable, in a separate repo: rag-demo.
PitchPilot is a white-label app for door-to-door / field sales reps: capture a lead, run the pitch, handle objections, and track commission — all on a phone, at the door. Its core is Wingman, a retrieval-augmented copilot that answers a rep's question ("what do I say when they mention price?") from the product's own knowledge base, in real time, grounded and cited.
A field rep can't read a 40-page playbook on a doorstep. When a prospect pushes back, the rep has seconds to answer, accurately, in the product's own words. Wingman turns the whole playbook — pricing, objections, scripts — into something you ask in natural language and get a one-paragraph, on-message answer from.
flowchart LR
subgraph Ingest [once, offline]
D[product docs<br/>pricing · objections · scripts] -->|chunk + embed| KB[(pgvector KB)]
end
subgraph Ask [at pitch time]
R[rep question] --> EF[copilot-ask<br/>edge function]
EF -->|embed + match| KB
KB -->|top-k chunks| EF
EF -->|context-limited prompt| G[Gemini]
G -->|grounded answer + actions| R
end
- Knowledge base — the playbook is chunked, embedded, and stored in Supabase pgvector, partitioned by product so a white-label tenant only ever retrieves its own content.
- Retrieval RPC — a Postgres
matchfunction returns the nearest chunks; this is the exact shape shown in rag-demo. - Grounded generation — a Supabase Edge Function builds a context-limited prompt and calls Gemini. The system prompt hard-limits the model to the retrieved chunks and forbids inventing pricing or promises — accuracy over hype, because a wrong answer at a doorstep costs a sale.
- White-label — one codebase rebrands for any industry in under a day; a public demo runs as "VoltLine" for the energy sector.
- Retrieval was silently returning nothing. An IVFFlat index over a tiny corpus collapsed recall to zero — the copilot kept deflecting to "check the FAQ." Dropping to exact search fixed it instantly. Lesson: approximate indexes need enough rows to be approximate over.
- Truncated mid-sentence answers. The model is a "thinking" variant; reasoning tokens were eating the output budget. Setting the thinking budget to zero restored full answers.
- Cost under load. The free tier dried up during a 50-question QA run, so generation falls back through a cost-ordered chain of models to stay within quota.
The public demo and the real product shared one API key, so demo traffic burned the production quota. I added product-aware key selection in the edge function — the demo tenant uses its own key — so a curious visitor can never exhaust or bill the real one.
Screenshots are from the public white-label demo (fictional "VoltLine" energy tenant), not a client deployment.
| Wingman — answering a live price objection | Pitch kit — tools, demos & key numbers |
|---|---|
![]() |
![]() |
Supabase (pgvector · Edge Functions) · Gemini · RAG · TypeScript / React · Cloudflare Pages
- Live demo: https://lucky-cat.pages.dev/pitcher-template/
- The retrieval pipeline, runnable end-to-end: github.com/augbastos/rag-demo
More work: augustobastos.pages.dev

