← Все проекты
ПРОЕКТ 2026 Solo-разработка Live в проде

Travel AI Platform

Как устроен AI-продукт изнутри - архитектура, компромиссы и то, что реально ломалось по пути, включая продакшн.

Зачем я это построил

Я хотел принимать решения про AI-продукты, опираясь на собственное техническое понимание - не на слайд из презентации. Стоимость токена, бюджет задержки, grounding против галлюцинаций, риск вендор-лока - эти темы всплывают в любом обсуждении AI-роадмапа, и мне не хотелось кивать, не прочувствовав компромиссы на себе.

Поэтому я построил полноценный продукт: AI-ассистент для планирования путешествий, в одиночку, от начала до конца - аутентификация, streaming-чат, retrieval-augmented generation (RAG), деплой на собственный сервер с доменом и HTTPS, CI/CD. Не обёртка над чат-API, а система с реальными архитектурными решениями за ней - и реальной эксплуатацией после запуска.

Роль и стек Solo - продуктовые решения, архитектура и реализация. FastAPI, PostgreSQL + pgvector, React, Docker, GitHub Actions, Caddy, self-hosted Ollama, Metabase. AI-провайдер менялся трижды по ходу проекта - подробности ниже.

Что умеет платформа

Решения, которые реально имели значение

Рабочая демка доказывает, что ты умеешь доставлять результат. Решения за ней доказывают, что ты умеешь думать как продакт. Вот четыре, за которые я готов ответить на любом интервью.

1. pgvector вместо отдельной векторной БД

«Правильный» выбор для RAG - Qdrant/Weaviate/Pinecone. Я использовал pgvector - расширение поверх Postgres, который и так был нужен для реляционных данных. На масштабе MVP вторая база данных - это операционная стоимость (ещё один сервис, который нужно поднимать, мониторить, бэкапить) без соразмерной выгоды. Это паттерн, который я бы отслеживал в любом ревью AI-роадмапа: команда тянется к специализированному инструменту раньше, чем простой инструмент реально исчерпал себя.

2. Streaming-ответы вместо request/response

Первая версия ждала полного ответа AI и только потом показывала его. Технически работало нормально - но ощущалось медленным, хотя задержка была той же, просто не было обратной связи во время генерации. Перешёл на Server-Sent Events, чтобы токены появлялись по мере генерации. Тот же бэкенд, ощутимо лучший UX - то, что невидимо в спеке и очевидно в первую же секунду использования продукта.

3. AI-провайдер, который можно поменять одной строкой

Начал на OpenAI, перешёл на бесплатный тариф Gemini, чтобы не жечь платные кредиты на ранней итерации. Вся интеграция с провайдером живёт в одном модуле - смена провайдера - это правка конфига, а не рефакторинг.

Это решение окупилось не один раз, а три. Дважды ещё во время разработки - новый формат API-ключей Google, тихо ломающий стандартную интеграцию, и модель, которую отключили для новых аккаунтов прямо во время работы над проектом. А затем - уже в проде: Gemini API оказался недоступен из региона, где физически находится мой сервер (геоблокировка на уровне провайдера, не связанная с кодом или аккаунтом). Решением стал полный переход на self-hosted LLM (Ollama) - локальная модель, без единого внешнего запроса, а значит без риска повторной блокировки. Миграция заняла часы, а не дни, именно потому что весь AI-слой был изолирован в одном модуле с самого начала.

4. Урезал архитектуру из исходного эскиза

В стартовой схеме Intent Router, Prompt Builder и AI Gateway были отдельными сервисами. Я объединил всё это в ответственности внутри одного FastAPI-приложения. Разбивать на микросервисы раньше, чем появилась реальная причина (размер команды, разная скорость деплоя, независимое масштабирование) - это добавление координационных издержек без компенсирующей выгоды. Знать, когда не строить более сложную версию - тот же навык, что и знать, когда не добавлять лишнюю фичу в бэклог.

Как я проверил, что RAG реально работает

Когда RAG был готов, я не просто посмотрел на правдоподобный ответ и закрыл задачу. Я добавил в тестовый документ выдуманный факт (несуществующее кафе с придуманным фирменным блюдом) и напрямую спросил AI про него. Если модель не могла знать эту деталь ниоткуда, кроме моего документа, и ответила правильно - это доказательство, что retrieval-пайплайн реально работает от начала до конца, а не что модель просто хорошо угадывает про путешествия в целом.

Почему это важно AI-фича, которая выглядит так, будто опирается на контекст, но на деле просто генерирует правдоподобный текст - частый и незаметный failure mode. Любую RAG-фичу, которую я бы принимал как продакт, я бы проверял так же - состязательным тестом, а не доверием к красивой демке.

Что ломалось при разработке

Деплой и продакшн

Проект не остался на localhost - поднят на собственном VDS, со своим доменом и автоматическим HTTPS (Caddy сам получает и обновляет сертификат Let's Encrypt, без ручной возни с certbot). За этим стоит ещё один слой решений, отдельный от собственно продуктовой логики:

Что бы сделал дальше

Ссылки GitHub: github.com/WorkiNik/travel-ai-platform
Живая демка: inproject.my