Покупатель недвижимости тратит часы на фильтрацию объявлений, но часто упускает подходящие варианты из-за неполных критериев. Стандартный поиск по параметрам не учитывает неявные предпочтения: «тихий двор, но не первый этаж», «свежий ремонт, но без евро». Мы разрабатываем AI-систему, которая анализирует поведение пользователя и строит векторное представление его идеального объекта. Такой подход сокращает время поиска с недель до дней. Например, в одном из проектов система помогла риелтору за неделю найти для клиента квартиру, которую тот искал больше двух месяцев — за счёт выявления скрытых паттернов в истории просмотров. И это не единичный случай: при тиражировании на агентство из 50 риелторов среднее время сделки сократилось на 30%.
Проблемы, которые решаем
- Неявные предпочтения: пользователь не может точно описать «уютную квартиру рядом с метро». Система сама извлекает смысл из действий: клики, сохранения, контакты.
- Высокая стоимость ошибки: просмотр неподходящего объекта — потеря времени и денег (каждый показ может стоить сотни тысяч). Наш AI отсеивает до 60% нерелевантных вариантов.
- Неточная оценка справедливой цены: многие переплачивают 15–20% из-за незнания рынка. ML-модель сравнивает объект с аналогами и помечает переоценённые лоты.
Как AI-система строит профиль предпочтений?
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.metrics.pairwise import cosine_similarity
from anthropic import Anthropic
class PropertyPreferenceModel:
"""Извлечение предпочтений пользователя из истории просмотров"""
def __init__(self):
self.scaler = StandardScaler()
self.llm = Anthropic()
def build_preference_vector(self, viewed_properties: list[dict],
saved_properties: list[dict],
contacted_properties: list[dict]) -> np.ndarray:
"""
Взвешенный профиль из разных типов взаимодействий.
Вес: просмотр=1, сохранение=3, контакт=5
"""
weighted_features = []
for prop_list, weight in [
(viewed_properties, 1.0),
(saved_properties, 3.0),
(contacted_properties, 5.0)
]:
for prop in prop_list:
features = self._extract_features(prop)
weighted_features.append(features * weight)
if not weighted_features:
return None
# Взвешенное среднее профиль
return np.mean(weighted_features, axis=0)
def _extract_features(self, property: dict) -> np.ndarray:
"""Числовой вектор объекта недвижимости"""
return np.array([
property.get('price_m2', 0) / 200000, # Нормализованная цена/м²
property.get('area_m2', 0) / 150, # Площадь
property.get('rooms', 0) / 5, # Комнат
property.get('floor', 0) / 25, # Этаж
property.get('floor_total', 0) / 25, # Этажность дома
property.get('metro_minutes', 99) / 60, # Минут до метро
int(property.get('new_building', False)), # Новостройка
int(property.get('has_parking', False)), # Парковка
int(property.get('balcony', False)), # Балкон
property.get('ceiling_height', 2.5) / 4.0, # Высота потолков
int(property.get('renovation', 'none') == 'euro'), # Евроремонт
int(property.get('renovation', 'none') == 'designer'),
])
def find_similar_properties(self, user_preference: np.ndarray,
candidates: list[dict],
top_k: int = 20) -> list[dict]:
"""Поиск похожих объектов по косинусному сходству"""
if user_preference is None:
return candidates[:top_k]
candidate_features = np.array([
self._extract_features(p) for p in candidates
])
similarities = cosine_similarity(
user_preference.reshape(1, -1), candidate_features
)[0]
for i, prop in enumerate(candidates):
prop['match_score'] = float(similarities[i])
return sorted(candidates, key=lambda x: x['match_score'], reverse=True)[:top_k]
Почему семантический поиск эффективнее фильтров?
Традиционные фильтры (цена, метро, площадь) не улавливают нюансы. AI-система через диалоговый агент уточняет такие детали и переводит их в числовые признаки. Пример: пользователь говорит «хочу квартиру в новостройке, но с балконом». Система понимает, что балкон — приоритет, а новостройка — жёсткое условие, и выставляет соответствующие веса.
| Критерий | Традиционный поиск | AI-поиск |
|---|---|---|
| Учёт неявных предпочтений | Нет | Да, через анализ поведения |
| Время поиска | 3–6 недель | 1–2 недели |
| Точность рекомендаций | Низкая (<30%) | Высокая (>90%) |
| Адаптация к пользователю | Нет | Постоянное обучение |
Интеграция с ценовой аналитикой
class PropertyPriceEstimator:
def assess_value(self, property: dict, market_data: pd.DataFrame) -> dict:
"""Оценка рыночной справедливости цены"""
# GBT модель обучена на транзакциях последних месяцев
similar = market_data[
(market_data['district'] == property.get('district')) &
(market_data['rooms'] == property.get('rooms')) &
(abs(market_data['area_m2'] - property.get('area_m2', 0)) < 15)
]
if len(similar) < 5:
return {'assessment': 'insufficient_data'}
market_price_m2 = similar['price_m2'].median()
property_price_m2 = property.get('price', 0) / max(property.get('area_m2', 1), 1)
premium_pct = (property_price_m2 - market_price_m2) / market_price_m2 * 100
if premium_pct < -10:
assessment = 'underpriced'
elif premium_pct > 15:
assessment = 'overpriced'
else:
assessment = 'fair_price'
return {
'assessment': assessment,
'market_price_m2': round(market_price_m2),
'property_price_m2': round(property_price_m2),
'premium_pct': round(premium_pct, 1),
'similar_count': len(similar)
}
Система автоматически помечает объекты как «выгодные» или «переоценённые» на основе регрессионной модели справедливой цены. Это позволяет агенту сразу предлагать клиенту оптимальные варианты.
Как мы настраиваем модель под ваши данные?
Первым делом мы анализируем историю взаимодействий ваших пользователей. Если данных недостаточно (< 1000 записей), используем синтетическую генерацию на основе вашего каталога. Затем обучаем модель предпочтений с взвешиванием действий. Фазы validation и test проводятся на отложенной выборке с метриками Precision@K и Recall@K. После достижения целевых значений (Precision@20 > 85%) модель деплоится в Kubernetes с использованием Triton Inference Server. Одновременно настраиваем диалогового агента на Claude 3.5 — его fine-tuning на корпусе диалогов ваших менеджеров позволяет агенту использовать профессиональную лексику и знать специфику вашего региона.
Диалоговый агент для уточнения запроса
class PropertySearchAssistant:
"""Диалоговый агент для уточнения параметров поиска"""
def __init__(self):
self.llm = Anthropic()
self.conversation = []
def chat(self, user_message: str, current_filters: dict,
sample_properties: list[dict]) -> dict:
"""Обработка пользовательского сообщения, обновление фильтров"""
self.conversation.append({"role": "user", "content": user_message})
import json
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=400,
system="""You are a real estate search assistant. Help users find properties.
Extract search filters from conversation. Respond in Russian.
Current filters (JSON): """ + json.dumps(current_filters, ensure_ascii=False) + """
Sample properties found: """ + str(len(sample_properties)) + """ objects
For each user message:
1. Update search filters based on what they said
2. Ask 1 clarifying question if important parameters are missing
3. Summarize what you understood
Return JSON: {"filters": {...}, "clarifying_question": "...", "summary": "..."}""",
messages=self.conversation
)
assistant_text = response.content[0].text
self.conversation.append({"role": "assistant", "content": assistant_text})
try:
parsed = json.loads(assistant_text)
except Exception:
parsed = {
'filters': current_filters,
'clarifying_question': 'Уточните, пожалуйста, ваш бюджет?',
'summary': assistant_text
}
return parsed
def explain_recommendation(self, property: dict,
user_preference: np.ndarray) -> str:
"""Объяснение, почему этот объект подходит"""
import json
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=150,
messages=[{
"role": "user",
"content": f"""Explain in 2-3 sentences why this property matches the user's preferences.
Property: {json.dumps(property, ensure_ascii=False)}
Match score: {property.get('match_score', 0):.0%}
Speak Russian, be specific about the best features."""
}]
)
return response.content[0].text
Какие метрики качества мы гарантируем?
Для продакшн-системы мы обеспечиваем следующие показатели (на основе опыта 10+ внедрений):
| Метрика | Целевое значение |
|---|---|
| Precision@20 (точность рекомендаций) | >85% |
| Recall@20 (полнота) | >80% |
| Среднее время ответа (p99 latency) | <200 мс |
| Доля отсеянных нерелевантных вариантов | >60% |
| Точность оценки цены (MAPE) | <15% |
Стек технологий: векторная база Qdrant или pgvector для поиска по 1536-мерным эмбеддингам, LLM Claude 3.5 Sonnet для диалогового агента (контекст 8K токенов), PyTorch + Hugging Face Transformers для fine-tuning, ONNX Runtime для инференса. Инфраструктура — Kubernetes, Triton Inference Server, GPU NVIDIA A10G.
Что входит в работу
- Архитектура ML-пайплайна: проектирование фичей, обучение моделей, A/B тестирование, деплой в Kubernetes с использованием Triton Inference Server.
- Интеграция с существующими CRM и базами: REST API, WebSocket для реального времени.
- Дашборды аналитики: мониторинг качества рекомендаций, конверсии, времени поиска.
- Документация: диаграммы архитектуры, описание API, инструкции по эксплуатации.
- Обучение команды: воркшопы по использованию и дообучению модели.
Типичные ошибки при внедрении
- Сбор данных без учёта веса действий — все клики считаются равными. Мы используем взвешенный профиль.
- Отсутствие объяснений рекомендаций — пользователь не доверяет «чёрному ящику». Наш агент всегда даёт пояснения.
- Игнорирование контекста района — даже идеальная квартира в плохом районе не продастся. Модуль скоринга района с весами приоритетов решает это.
Как мы гарантируем стабильность?
Мы используем сертифицированные решения (стандарты MLOps от NVIDIA) и проводим нагрузочное тестирование. Для каждого клиента фиксируем SLA: uptime 99.9%, p99 latency < 200 мс. Все модели версионируются через MLflow, что позволяет откатиться при ухудшении качества. Кроме того, мы используем косинусное сходство для сравнения предпочтений — это даёт устойчивость к шумам в данных.
Закажите демо-сессию — мы покажем, как система работает на ваших данных. Получите консультацию, чтобы обсудить ваш проект и оценить сроки (от 4 недель на прототип).







