Blackhawk AI
A knowledge-base app built for a client. Semantic search over their teaching material, from a single-user script to a deployed web app with an admin panel.
- Python
- Flask
- Supabase
- pgvector
Overview
Blackhawk Coaching had years of teaching material and no way for anyone to find anything in it. I scoped the work with them and built a knowledge-base app that answers questions against the whole corpus. Keyword search was not good enough, because people ask questions using different words than the source material happens to use. So the documents get split into chunks and embedded once, up front. At query time the app embeds the question the same way, finds the closest chunks by vector similarity, and builds the answer from those.
Architecture
- Document ingestion
- A multi-format pipeline splits source documents into a 700-chunk searchable corpus.
- Vector store
- PostgreSQL with the pgvector extension holds the embeddings and serves similarity search.
- Semantic search
- Queries are embedded with the same model as the corpus and matched by vector similarity, returning results in under four seconds.
- Access control
- The client authorizes users, who then sign in to query the corpus.
- Admin panel
- An authenticated dashboard for managing the corpus and monitoring usage.
Build process
- Prototype
- Started as a single-user command-line script for querying documents locally.
- Scale-up
- Rebuilt as a multi-user Flask web application backed by Supabase, adding sign-in and an authenticated admin panel.
- Security hardening
- Cleared pre-launch findings for stored XSS, debug-mode exposure, and missing HTTP security headers by adding input sanitization and hardening the Flask configuration.
Outcome
Delivered to the client and in use, with sign-in, an admin panel for managing the corpus, and queries that come back in under four seconds over 700 chunks.
What I'd do differently
I tuned chunk size and top-k by reading the answers and deciding whether they looked better. That works up to a point, but it means I can't say how much any single change actually helped. Next time I'd write a small set of test questions with known good answers first, so the tuning is measurable. The other thing is ordering. I ran the security review after the admin panel was finished, and sanitizing input and setting headers would have been much less work if I'd built for them from the start instead of going back through code that already worked.