A zero-hallucination RAG broker on a 100% free stack
Mar 20, 2026 · 10 min read
Buying property is a search problem wrapped in a scheduling problem. You describe what you want in plain language (“2BHK under 60 lakh near a metro, decent amenities”), someone translates that into filters, sends you listings, and then the real bottleneck begins: coordinating site visits. I wanted to collapse that entire journey — from vague query to a confirmed, calendared visit — into one conversation, with zero manual steps and, just as importantly, zero hallucinated listings.
The hard constraint I set myself: it had to run on a 100% free stack. No paid vector DB, no premium API tier. That constraint made the design better, not worse.
Why “zero hallucination” is the whole game
For a chatbot that tells jokes, a made-up detail is harmless. For one that tells you a flat exists at a price that doesn't exist, it's a lawsuit. So the design principle was simple: the model may only speak about listings that are actually in the index. The LLM is a language layer over retrieved facts — never a source of facts itself. That's the entire promise of RAG, and honoring it strictly is what makes the assistant trustworthy.
The pipeline
- Scrape real listings with BeautifulSoup — price, location, BHK, amenities, images, PDF brochures.
- Chunk each listing with a recursive splitter and tuned overlap so a flat's details never get cut in half.
- Embed the chunks with Sentence Transformers and store the vectors in FAISS.
- Retrieve the top-k semantically matched listings for a query.
- Generate a grounded answer with the LLM, given only those retrieved chunks.
Retrieval is where the accuracy lives
People underestimate how much of RAG quality is decided before the LLM is ever called. Two things mattered most:
- Chunk overlap. Property listings are dense with numbers. Too small a chunk and “₹58L” ends up in a different chunk than the locality it belongs to; retrieval then returns half-truths. A little overlap keeps each fact with its context.
- FAISS for the search itself. It's free, it's fast, and for this catalog size an exact index returns top-k in milliseconds. No managed service required.
# The grounding contract, in spirit
context = faiss_index.search(embed(query), k=5)
if not context:
return "I don't have a listing that matches that yet."
answer = llm.generate(
system="Answer ONLY from the listings provided. "
"If it isn't in the context, say you don't have it.",
context=context,
question=query,
)The prompt contract is doing real work here. If retrieval comes back empty, the assistant says so instead of inventing a flat. That single guardrail is the difference between a demo and something you'd let talk to a real buyer.
Context found → answer strictly from the retrieved listings.
Context empty → “I don't have a listing that matches that yet.” — never invent one.
Talking like a buyer: Hinglish and comparisons
Real buyers in India don't query in clean English — they mix Hindi and English mid sentence. The Streamlit conversational UI handles Hinglish, and it supports dynamic comparison across BHK, budget, location, and amenities, so “inme se metro ke paas kaunsa best hai?” is a first-class query, not an edge case.
The part I'm proudest of: it books its own visits
Retrieval answers the search problem. The scheduling problem is solved by letting the agent act. An NLP intent-detection layer watches the conversation, and the moment a buyer confirms interest in a specific property, it:
- calls the Google Calendar API to schedule the site visit, and
- calls the Gmail API to dispatch dual confirmations — one to the buyer, one to the broker.
No form, no “our team will get back to you.” Query to booked visit, entirely inside the chat. That closed loop — retrieval you can trust, plus actions that actually happen — is the whole point.
Takeaways
- Guardrail first, model second. Deciding what the model is forbidden to say shaped the architecture more than model choice did.
- Free stacks are underrated. BeautifulSoup + Sentence Transformers + FAISS + a small hosted LLM (I used Groq for fast inference) covered the whole thing.
- An agent that can act beats an agent that can only answer. The Calendar and Gmail calls turned a nice search demo into an end-to-end product.