OstimGPT
A locally hosted Retrieval-Augmented Generation chatbot answering questions from university sources.
A personal Retrieval-Augmented Generation project that answers shopper questions from a store’s own data: recommendations, product and policy Q&A, comparisons and cached review summaries. The catalogue lives in SQLite and is indexed in Qdrant with BGE-M3; retrieval runs dense and sparse together, fuses the two with reciprocal rank fusion and reranks with a bge-reranker-v2-m3 cross-encoder. Generation runs on Qwen2.5 through Ollama, so the whole system works offline with no API cost, and answers come back in the language they were asked in — Arabic or English.
SmartShop is a personal project about a narrow question: what actually improves retrieval quality when the corpus is a product catalogue rather than prose?
It ended up as a complete shopping assistant. It recommends products, answers questions about a specific item, compares two of them, answers return, shipping and warranty questions out of policy PDFs, and summarises what reviewers said — each answer grounded in the store’s own records and citing them.
Everything runs locally. The catalogue sits in SQLite, the index in an embedded Qdrant, the embeddings and reranker on CPU, and the language model in Ollama, so there is no API key anywhere in the system and no per-query cost.
Recommendation systems are usually judged by anecdote: a few queries are tried, the results look reasonable, and the system is declared to work.
This project took the opposite approach — the golden set and the evaluation harness were built alongside the retrieval, so a change could be shown to help rather than assumed to. The same discipline shows up in the planning: thirteen documents — retrieval architecture, model selection, chunking, filter schema, grounding strategy — were written before the first sprint.
Dense retrieval alone misses exact matches; sparse retrieval alone misses intent. Neither is sufficient for product search, and choosing between them is the wrong question.
My Role
This is my own project, built end to end: the planning documents, the ingestion of the catalogue and the policy PDFs, the hybrid retrieval and reranking pipeline, filter extraction, the answering paths for recommendation, product Q&A, comparison, policy Q&A and review summaries, session personalization, the FastAPI service, the Streamlit and single-page front ends, the golden set and evaluation harness, and the test suite.
Keep the catalogue in a relational store as the source of truth, index it for vector search, retrieve with both strategies at once, then spend the remaining effort on reranking and measurement.
The catalogue and the policy PDFs are ingested into SQLite and embedded with BGE-M3 into an embedded Qdrant index holding both dense and sparse vectors. A question is first resolved into an intent and a set of structured filters; hybrid retrieval then runs both strategies and fuses them with reciprocal rank fusion, a cross-encoder reranks what comes back, and Qwen2.5 answers from those records alone, in the language of the question. Session history feeds preferences back into retrieval, and the golden set measures the pipeline offline.
Dense and sparse candidates fused with reciprocal rank fusion, so exact tokens and intent both work.
bge-reranker-v2-m3 recovers precision after a recall-oriented first pass.
“A phone case under fifteen dollars” becomes a category, a price ceiling and a stock constraint.
Recommendations, comparisons, policy answers and review summaries all cite the records they came from.
The answer comes back in the language the question was asked in.
Ollama, an embedded Qdrant and CPU embeddings — no API key, no per-query cost.
Retrieval and filter extraction are scored against a fixed question set before a change is kept.
Semantic search returns plausible-looking products that are the wrong model or the wrong size, because embeddings blur exactly the tokens that matter most.
Pairing sparse retrieval with dense retrieval keeps exact tokens addressable while intent-style queries still work, and the cross-encoder settles the order afterwards.
The filter extractor was the weakest link: it would settle on the wrong category, or silently drop a constraint the shopper had actually stated, and a good retriever cannot rescue a query that has already been narrowed wrongly.
Constraining the category to the ones that exist and recovering dropped filters explicitly fixed more retrieval failures than any change to the search itself.
A 7B model, an embedding model and a reranker all resident at once is more than a laptop comfortably holds.
Embeddings and reranking were kept on CPU, a smaller model was wired in as a fast fallback, and review summaries were cached rather than regenerated per question.
| Decision | Alternative considered | Why |
|---|---|---|
| Keep SQLite as the primary data source with Qdrant as the vector index. | Treating the vector store as the system of record. | A relational store keeps structured attributes queryable and authoritative; the vector index stays a derived artefact that can be rebuilt. The cost is keeping the two in step. |
| Run the language model locally through Ollama. | Calling a hosted frontier model per query. | Local inference costs nothing per query and keeps the catalogue on the machine, which is what made it reasonable to run the pipeline hundreds of times while tuning it. The price is answer quality: a 7B model writes noticeably plainer prose than a hosted one, and the design leans on retrieval being right rather than on the model covering for it. |
| Add a cross-encoder reranking stage. | Returning the fused first-stage results directly. | Reranking costs time on every query and keeps another model in memory, but first-stage retrieval is tuned for recall — without a second stage, precision stays capped. |
| Narrow the languages to Arabic and English. | Keeping the third language the pipeline originally carried. | A third language doubled the surface to check on every answering path while adding nothing to the retrieval question the project was actually about. It was dropped deliberately, not for lack of support in the models. |
A finished local assistant: it recommends, compares, answers questions about products and about return, shipping and warranty policy, and summarises reviews — grounded in a sample catalogue of ninety products, their reviews and four policy documents, with every answer citing the records behind it.
It runs on one machine with no API key and no network, and it is measured rather than demonstrated: a golden set scores retrieval and filter extraction, and the deterministic test suite runs without the model or the index. It is a personal project, not a deployed store system.

The entry point: suggested analyses stand in for the empty state, and any of them can be typed as a free-form question instead.

An exported answer. The filters the query resolved to are shown alongside the results, and every recommendation cites the product record it came from.
Have a software, AI, RAG, or web application project in mind? Let’s discuss what you need and determine the right technical approach.