Ask Your 10-K
A local, citation-grounded RAG assistant for querying SEC filings in plain English
Project information
- Category: Data Science / GenAI / Finance
- Data source: SEC EDGAR (live 10-K filings, any ticker)
- Stack: LangChain, ChromaDB, Ollama (llama3.2), Hugging Face embeddings, Streamlit
- Link to github: GitHub repo →
- Link to App: View App →
Answers you can actually verify
Generic chatbots will confidently answer financial questions with numbers they made up. This project takes the opposite approach: every factual claim in an answer is tied to a citation that maps to a real, retrieved excerpt from an actual SEC filing — and if the answer isn't in the filings that were ingested, the assistant says so instead of guessing. Built to demonstrate the full RAG stack (embeddings, vector search, retrieval, prompt engineering, grounded generation) applied where verifiability matters more than fluency.
Project deep dive
Problem statement
10-K filings are hundreds of pages of dense, structured disclosure — reading one end-to-end to answer a single question ("what were the main supply chain risks in FY2022?") is impractical, and asking a general-purpose chatbot risks a confident, fabricated answer. This project builds a retrieval pipeline that keeps every answer traceable to its source: the exact filing, fiscal year, and Item section it came from, with the underlying excerpt shown alongside the answer for the user to verify directly.
Data
Live SEC EDGAR filings, downloaded on demand for any ticker — not a static dataset.
- Coverage: Apple (AAPL) 10-K filings, fiscal years 2015–2025 ingested (11 filings, ~7,200 chunks)
- Sections parsed: Item 1. Business, Item 1A. Risk Factors, Item 7. MD&A, Item 8. Financial Statements, and every other standard 10-K Item, detected and normalized automatically from raw filing HTML
Pipeline
- Ingestion — downloads filings directly from SEC EDGAR (
sec-edgar-downloader) for a given ticker and year range, no manual file handling. - Parsing — a custom BeautifulSoup-based parser strips SEC's iXBRL/HTML boilerplate and detects Item/Part headings, so each chunk keeps its section context instead of becoming an anonymous blob of text.
- Chunking + embedding —
RecursiveCharacterTextSplitter(1000 chars, 150 overlap) feeds a local Hugging Face embedding model (all-MiniLM-L6-v2), so no API key or internet round-trip is required per query. - Vector store — ChromaDB, persisted locally, with metadata per chunk (ticker, form type, fiscal year, Item, source path) enabling precise filtering, not just semantic search.
- Generation — retrieved chunks are numbered and injected into a prompt template that instructs the LLM (Ollama,
llama3.2, temperature 0) to answer only from context, cite every claim as[n], and explicitly refuse when the answer isn't present rather than fabricate one. - Evaluation — a hand-written suite of Q&A test cases runs automatically, checking citation presence, correct fiscal-year attribution, and appropriate refusal on out-of-scope questions (see Key findings below).
Key findings
| Eval check | What it catches |
|---|---|
| Citation presence | Answer includes at least one [n] reference |
| Fiscal-year match | All cited chunks come from the requested filing year |
| Refusal behavior | Out-of-scope questions are declined, not fabricated |
- The pipeline correctly refused questions about other companies, live stock prices, and general knowledge, rather than blending in unrelated context.
- Fiscal-year filtering was validated end-to-end: an early bug caused chunks from a mislabeled filing year to pollute the store — caught and fixed by testing retrieval against known filings rather than trusting the ingestion log alone.
- Running on a small local model (
llama3.2, not a frontier API model) trades some citation-formatting reliability for zero API cost and full data privacy — documented as an explicit limitation rather than hidden.
Tech stack
Full source, ingestion CLI, eval harness, and setup instructions are in the GitHub repo →