Building a Property Inquiry Agent: Answering Buyer Questions About Listings 24/7
Learn how to build an AI agent that answers buyer questions about property listings around the clock, including database lookups, FAQ handling, photo sharing, and automated showing scheduling.
Why Real Estate Needs 24/7 Inquiry Agents
The average buyer browses listings at 9 PM on a Tuesday. By the time an agent responds the next morning, that buyer has already messaged three competitors. A property inquiry agent eliminates this gap by answering questions about listings, sharing photos, and scheduling showings instantly — no matter the hour.
In this guide, we will build a property inquiry agent that connects to a listing database, handles common buyer questions, serves property photos, and books showings automatically.
Designing the Listing Database Layer
Every property inquiry agent starts with structured access to listing data. We will use a simple schema and a retrieval layer that the agent can call as a tool.
flowchart LR
CALLER(["Buyer or Seller Lead"])
subgraph TEL["Telephony"]
SIP["Twilio SIP and PSTN"]
end
subgraph BRAIN["Real Estate AI Agent"]
STT["Streaming STT<br/>Deepgram or Whisper"]
NLU{"Intent and<br/>Entity Extraction"}
TOOLS["Tool Calls"]
TTS["Streaming TTS<br/>ElevenLabs or Rime"]
end
subgraph DATA["Live Data Plane"]
CRM[("CRM and Notes")]
CAL[("Calendar and<br/>Schedule")]
KB[("Knowledge Base<br/>and Policies")]
end
subgraph OUT["Outcomes"]
O1(["Showing scheduled"])
O2(["Lead routed to agent"])
O3(["Pre-qual handed to broker"])
end
CALLER --> SIP --> STT --> NLU
NLU -->|Lookup| TOOLS
TOOLS <--> CRM
TOOLS <--> CAL
TOOLS <--> KB
NLU --> TTS --> SIP --> CALLER
NLU -->|Resolved| O1
NLU -->|Schedule| O2
NLU -->|Escalate| O3
style CALLER fill:#f1f5f9,stroke:#64748b,color:#0f172a
style NLU fill:#4f46e5,stroke:#4338ca,color:#fff
style O1 fill:#059669,stroke:#047857,color:#fff
style O2 fill:#0ea5e9,stroke:#0369a1,color:#fff
style O3 fill:#f59e0b,stroke:#d97706,color:#1f2937
import asyncpg
from dataclasses import dataclass
from typing import Optional
@dataclass
class PropertyListing:
listing_id: str
address: str
price: float
bedrooms: int
bathrooms: float
sqft: int
description: str
photo_urls: list[str]
status: str # active, pending, sold
listing_agent: str
class ListingDatabase:
def __init__(self, pool: asyncpg.Pool):
self.pool = pool
async def search_listings(
self,
min_price: Optional[float] = None,
max_price: Optional[float] = None,
min_beds: Optional[int] = None,
city: Optional[str] = None,
limit: int = 10,
) -> list[PropertyListing]:
conditions = ["status = 'active'"]
params = []
idx = 1
if min_price is not None:
conditions.append(f"price >= ${idx}")
params.append(min_price)
idx += 1
if max_price is not None:
conditions.append(f"price <= ${idx}")
params.append(max_price)
idx += 1
if min_beds is not None:
conditions.append(f"bedrooms >= ${idx}")
params.append(min_beds)
idx += 1
if city is not None:
conditions.append(f"LOWER(city) = LOWER(${idx})")
params.append(city)
idx += 1
where_clause = " AND ".join(conditions)
query = f"""
SELECT * FROM listings
WHERE {where_clause}
ORDER BY created_at DESC
LIMIT {limit}
"""
rows = await self.pool.fetch(query, *params)
return [PropertyListing(**dict(r)) for r in rows]
async def get_listing(self, listing_id: str) -> Optional[PropertyListing]:
row = await self.pool.fetchrow(
"SELECT * FROM listings WHERE listing_id = $1",
listing_id,
)
return PropertyListing(**dict(row)) if row else None
This layer gives the agent parameterized search capabilities. The key design choice is returning structured data rather than raw SQL rows so the agent can format responses naturally.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
Building the Agent with Tools
Now we wire the database into an agent using tool functions. Each tool handles a specific buyer intent.
from agents import Agent, Runner, function_tool
listing_db: ListingDatabase # initialized at startup
@function_tool
async def search_properties(
city: str,
max_price: float = None,
min_bedrooms: int = None,
) -> str:
"""Search available properties by city, price range, and bedroom count."""
results = await listing_db.search_listings(
city=city,
max_price=max_price,
min_beds=min_bedrooms,
limit=5,
)
if not results:
return "No matching properties found. Try broadening your search."
lines = []
for p in results:
lines.append(
f"- {p.address}: {p.bedrooms}bd/{p.bathrooms}ba, "
f"{p.sqft} sqft, ${p.price:,.0f} (ID: {p.listing_id})"
)
return "\n".join(lines)
@function_tool
async def get_property_details(listing_id: str) -> str:
"""Get full details and photos for a specific listing."""
p = await listing_db.get_listing(listing_id)
if not p:
return "Listing not found."
photos = "\n".join(p.photo_urls[:5])
return (
f"Address: {p.address}\n"
f"Price: ${p.price:,.0f}\n"
f"Beds/Baths: {p.bedrooms}/{p.bathrooms}\n"
f"Sqft: {p.sqft}\n"
f"Description: {p.description}\n"
f"Photos:\n{photos}"
)
@function_tool
async def schedule_showing(
listing_id: str,
buyer_name: str,
buyer_phone: str,
preferred_date: str,
) -> str:
"""Schedule a property showing for a buyer."""
# In production, this writes to a calendar/CRM system
return (
f"Showing scheduled for {buyer_name} at listing "
f"{listing_id} on {preferred_date}. "
f"A confirmation will be sent to {buyer_phone}."
)
property_agent = Agent(
name="PropertyInquiryAgent",
instructions="""You are a helpful real estate assistant. Answer
questions about available properties using the search and detail
tools. When a buyer is interested, offer to schedule a showing.
Always be accurate — never invent property details.""",
tools=[search_properties, get_property_details, schedule_showing],
)
Handling FAQs with a Knowledge Base
Many buyer questions are not about specific listings but about process — closing costs, inspection timelines, mortgage pre-approval. We handle these with a lightweight FAQ retrieval tool.
FAQ_DATA = {
"closing_costs": "Typical closing costs range from 2-5% of the purchase price...",
"inspection": "Home inspections usually occur within 7-10 days of accepted offer...",
"preapproval": "Mortgage pre-approval typically requires pay stubs, tax returns...",
}
@function_tool
async def lookup_faq(topic: str) -> str:
"""Look up common real estate FAQs by topic keyword."""
topic_lower = topic.lower()
for key, answer in FAQ_DATA.items():
if key in topic_lower or topic_lower in key:
return answer
return "I do not have a specific FAQ on that topic. Let me connect you with an agent."
This approach keeps the agent grounded in verified information rather than hallucinating answers about legal or financial topics.
Running the Agent
import asyncio
async def main():
result = await Runner.run(
property_agent,
input="I am looking for a 3-bedroom house in Austin under $500k",
)
print(result.final_output)
asyncio.run(main())
The agent will call search_properties with the extracted parameters and present matching listings in a conversational format.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
FAQ
How does the agent handle questions about properties not in the database?
The agent is instructed to never fabricate details. If a listing is not found, it responds honestly and suggests broadening the search or contacting a human agent for off-market properties.
Can this agent handle multiple languages for international buyers?
Yes. Since the underlying LLM supports multilingual input and output, you can add an instruction to detect the buyer's language and respond accordingly. The database queries remain the same — only the presentation layer changes.
What happens when the agent cannot answer a question?
The FAQ tool returns a fallback message suggesting human escalation. You can extend this by adding a handoff to a live agent tool that creates a callback request in your CRM.
#RealEstateAI #PropertyInquiry #AgenticAI #Python #Chatbot #LearnAI #AIEngineering
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.