Real estate · PropTech
An AI agent that qualifies real estate leads
Client intake, database search, and competitor monitoring handled before a human agent picks up the conversation.
The problem
Agents spent their hours on the least valuable part of the job: interviewing clients about what they wanted, searching the internal database by hand, and checking what competitors had listed. Off-the-shelf chatbots didn't help — they hallucinated listings and had no connection to the actual property database, which made them worse than nothing in front of a paying client.
What we built
A stateful AI assistant on Google Gemini that behaves like an employee rather than a chat window. It interviews the client across 20+ parameters, searches the agency's private database itself, scrapes the local classifieds for market context, and hands the lead to a human agent — with a booked call — once the lead is warm.
What it changed
Intake and matching run unattended
Agents stop doing first-contact interviews and start working leads that are already qualified and already matched to inventory.
AI costs stay bounded
A circuit breaker caps the assistant's self-triggered follow-up queries, so a bad conversation cannot turn into a runaway Gemini bill.
Live competitor data
Automated scraping means the agency can quote the current market, not last month's.
How it worksthe engineering detail
Written for the person your CTO forwards this to.
Event-driven core
The Telegram client layer is decoupled from AI processing via Redis Pub/Sub (assistant_channel, broker_channel), so polling threads are never blocked by LLM inference.
The LLM drives the state machine
The model returns structured JSON flags (switched, recurrent) that move the user between stages: intake → search → listing context. State lives in the system, not in the prompt history.
Recursion with a circuit breaker
The assistant can self-trigger follow-up queries recursively; a retry guard caps this at 3 iterations to prevent infinite loops and uncontrolled API spend.
Parallel scraping
A distributed Selenium WebDriver pool scrapes listings in batches, bounded by an ExecutorService and protected by AtomicBoolean mutexes.
Durable scheduling
A persistent task queue backed by Redis hashes restores its state on restart — no Kafka, no broker to operate.
Patterns — Strategy (AI personas) · Registry / Factory · Template Method · Pub/Sub · Circuit Breaker
Stack