Spaces:
Sleeping
Sleeping
Aissugur Kurganbekov
Claude Opus 4.8 (1M context)
Add recruiter-facing docs: case study, architecture, interview notes, demo, CV, outreach
b2f4ef1 |
Download INTERVIEW_NOTES.md from financeflow/ai: direct link, hf CLI and curl.
- Browser
- Download file 5.03 kB
-
https://huggingface.co/spaces/financeflow/ai/resolve/main/INTERVIEW_NOTES.md
- Command line
-
hf download hf://spaces/financeflow/ai/INTERVIEW_NOTES.md
-
curl -L -o INTERVIEW_NOTES.md https://huggingface.co/spaces/financeflow/ai/resolve/main/INTERVIEW_NOTES.md
5.03 kB
| # Interview Notes β FinanceFlow AI | |
| Direct, honest answers I can give in an interview. No hype. | |
| ### Why did you build this? | |
| I wanted a portfolio project that proves I can ship **trustworthy AI for a real | |
| business workflow**, not another chatbot wrapper. Finance is a good forcing | |
| function: numbers and dates have to be exactly right, so the system has to ground | |
| every answer and refuse to guess. It also runs with no paid API key, which forced | |
| me to build the actual RAG machinery instead of leaning on a model. | |
| ### What problem does it solve? | |
| Finance/ops teams repeatedly look up the same facts in invoices, contracts, and | |
| payment notes (totals, due dates, payment terms, late fees). It's slow by hand and | |
| unsafe with a generic chatbot that hallucinates figures. FinanceFlow answers from | |
| the document, shows the source, and abstains when the evidence isn't there. | |
| ### Why FastAPI? | |
| Typed request/response models via Pydantic, automatic OpenAPI/Swagger docs, | |
| first-class async, and dependency injection for the DB session. It let me build a | |
| small, well-validated API quickly and get interactive docs at `/docs` for free β | |
| which is also how I test endpoints manually. | |
| ### Why React? | |
| The UI needed real interactive state (upload status, async retrieval, a | |
| collapsible evidence panel, an evaluation table). React + Vite gives fast HMR, a | |
| clean component model, and a tiny build. I kept it dependency-light (no UI kit) and | |
| wrote a small reusable component system instead. | |
| ### How does document chunking work? | |
| Text is extracted per page for PDFs (so I can cite a page number) and as one block | |
| for TXT. Each page is normalized and split into **overlapping ~120-word windows | |
| with a 25-word overlap**. The overlap means a fact sitting on a chunk boundary | |
| still appears intact in at least one chunk. Each chunk stores `document_id`, | |
| `chunk_index`, `page`, and `text`. | |
| ### How does retrieval work? | |
| A **TF-IDF keyword ranker** β no external model. At query time I compute an IDF | |
| weight per term across the document's chunks (rare words count more). Each chunk is | |
| scored as `Ξ£ tf(term)Β·idf(term)` over the question's terms, divided by | |
| `β(chunk length)` so long chunks don't automatically win. I take the top-K chunks | |
| above a threshold as the context. | |
| ### How do citations work? | |
| The chunks that survive the threshold become citations, each carrying the document | |
| name, page/chunk index, a **query-focused excerpt** (the relevant span, not the | |
| chunk's opening), and the relevance score. They're shown under every answer and | |
| stored with the Q&A history, so past answers stay auditable. | |
| ### How do you reduce hallucinations? | |
| Five things working together: | |
| 1. **Two abstention gates** β a score floor, plus a term-coverage check (the | |
| evidence must share β₯2 distinct content words with the question, so a single | |
| incidental overlap can't trigger a confident answer). | |
| 2. **Extractive by default** β answers are copied verbatim from the document, so | |
| the engine literally cannot invent a number. | |
| 3. **Grounded LLM prompt** (when LLM mode is on) β forbids inventing facts, | |
| requires the exact abstain string, temperature 0, with fallback to extractive. | |
| 4. **Evidence always shown** β the user can verify instantly. | |
| 5. **Evaluation** β `unsupported_answer_count` is tracked and gated in CI. | |
| ### What happens when the answer is not in the document? | |
| It returns exactly: **"Not enough information in the uploaded document."** with no | |
| citations, and the UI shows an "abstained" state. In evaluation, a correct | |
| abstention counts as a *pass*; answering anyway counts as an unsupported answer | |
| (a failure). | |
| ### How would you improve it with more time? | |
| Swap the keyword ranker for sentence embeddings + a vector index to handle | |
| paraphrases (and A/B it against the current ranker on the same golden dataset), | |
| add exact answer-span highlighting, cross-document Q&A, auth/multi-tenancy, and OCR | |
| for scanned PDFs. | |
| ### What technical tradeoffs did you make? | |
| Keyword TF-IDF over embeddings (zero deps + transparency, at the cost of paraphrase | |
| recall); extractive over generative by default (no hallucinations, less fluent | |
| phrasing); discarding raw files after parsing (privacy + no cleanup, can't | |
| re-process); SQLite (zero-setup for a reviewer, not for production concurrency); | |
| and abstaining aggressively (trust over coverage). | |
| ### How is this relevant to AI Product / Product Ops / FinTech / Backend roles? | |
| - **AI Product / Product Ops:** the evaluation harness *is* the product-ops work β | |
| defining expected behaviour, measuring grounded-vs-refused vs unsupported, and | |
| treating a correct refusal as success. That's how you operate an AI feature | |
| responsibly. | |
| - **FinTech / document automation:** invoices, contracts, and dunning notes are | |
| core finance artifacts; reliable extraction with an audit trail is real back- | |
| office automation. | |
| - **Backend / ML:** a validated, typed, tested FastAPI service with a retrieval | |
| pipeline, logging, CI, and Docker β the end-to-end engineering, not just a model | |
| call. | |