Роадмап Главная EN

Mirror · техническая архитектура

Как устроен Mirror

Человек ведёт дневник и выговаривается, получает отчёты о своём психологическом состоянии, а система ранжирует зарегистрированных терапевтов по тому, насколько эффективны они будут именно для него. Ниже — как это работает под капотом.

Репозиторий: github.com/akipushdev/mirror-bot-v2 — приватный. За доступом напишите мне в Telegram: @GoldPirate, открою.

Система целиком

Весь продукт — одно docker-compose-приложение, деплой одной командой. API не привязан к клиенту: iOS/Android/web-клиенты позже подключаются к тому же use-case-слою без дублирования логики.

Telegram-клиент aiogram-боттолько транспорт FastAPI backenduse-case-слой LangChain / LangGraphоркестрация Gemini APILLM-провайдер
PostgreSQL 16Alembic при деплое Qdrantвекторная база / RAG Langfuseтрейсинг · стоимость · eval

docker-compose-стек · reverse proxy с авто-TLS на облачном VPS

Python 3.12 FastAPI aiogram PostgreSQL 16 SQLAlchemy (async) Alembic LangChain LangGraph Qdrant Langfuse Pydantic Gemini (диалоги · голос · изображения · эмбеддинги) Docker Compose

Три независимых контура

Чувствительный к задержкам диалог, тяжёлая асинхронная аналитика и контроль качества разделены — каждый контур масштабируется и падает независимо.

1 · Живой диалог

Реальное время, ход за ходом. State machine на LangGraph выбирает разговорный ход; RAG заземляет ответы персоны.

2 · Фоновая аналитика

Асинхронные задачи: ежедневные/еженедельные отчёты, обновление психологического портрета, мультиагентный подбор терапевта.

3 · Оценка качества и prompt ops

Оффлайн-эксперименты с LLM-судьёй и guard-метриками; живая A/B-аналитика по версиям промптов. Ни один промпт не едет в прод «на глазок».

Контур 1 — диалоговый движок (LangGraph)

Диалог — это граф состояний, а не один промпт. Каждое сообщение клиента проходит через граф; проверка на кризис — жёсткое ребро: промпт можно «уговорить», ребро графа — нет.

сообщение клиента проверка на кризисжёсткое ребро генерация кандидатовbest-of-N скоринг выбор хода
↳ кризис обнаружен: терапия останавливается · телефон помощи
слушать отзеркалить углубить спросить

state machine на LangGraph · гештальт-интервенции (например, практика пустого стула) подключаются отдельными подграфами за роутером

Best-of-N с контролем стоимости

Граф генерирует несколько кандидатов ответа, скорит их и выбирает ход вместо one-shot-генерации. Сейчас выключено конфигом, чтобы держать стоимость хода низкой для клиентов — путь в графе сохранён и включается per-persona.

RAG-заземление (Qdrant)

Для персоны Ялома перед вызовом модели выполняется векторный поиск — его изданные книги нарезаны и проиндексированы, ответы опираются на реальные примеры работы с клиентами. Тот же пайплайн расширяется на зарегистрированных терапевтов по мере накопления истории сессий.

Типизированный вывод LLM

Каждый ответ LLM, попадающий в бизнес-логику, парсится в Pydantic-схему — и никогда не используется как сырой текст. LangChain отвечает за промпт-темплейты и парсинг структурированного вывода внутри узлов графа.

Абстракция провайдера

Весь доступ к моделям идёт через интерфейс LLMPort с тремя реализациями: Gemini (продакшн), Ollama (локальные эксперименты), stub (быстрые тесты). Смена провайдера — изменение конфига, а не рефакторинг.

Контур 2 — фоновая аналитика

Долгий AI-анализ никогда не блокирует живой диалог. Отчёты работают как LangChain-цепочки; подбор терапевта — мультиагентный пайплайн, где у каждого агента свой промпт и типизированный вывод.

история сессий анализ портретатревожность · тон · тренды ранжирование терапевтовотносительно портрета персональное объяснениепочему именно этот специалист PostgreSQL → клиент

мультиагентный пайплайн подбора · ежедневные/еженедельные отчёты — отдельные LangChain-цепочки над той же историей

Внутренняя экономика

Каждый вызов LLM тарифицируется против баланса пользователя («яломы») — контроль затрат и путь к монетизации с первого дня.

Голос и изображения

Голосовые сообщения и рукописные заметки распознаются через мультимодальный Gemini и попадают в тот же дневниковый пайплайн, что и текст.

Контур 3 — оценка качества и prompt ops

Дифференциатор продукта — не картинки персон, а то, как терапевт разговаривает. Это сложнее всего проверить, поэтому у качества диалога свой пайплайн.

15 клиентских персонмногодневный сценарный контекст симулированные сессииLLM играет клиента, реальный HTTP API LLM-судьяпротив эталона более сильной модели guard-гейтыгаллюцинации · безопасность победитель → в прод

один полный прогон = 302 полных диалога по 10 ходов · судье доверяем только после 80%+ совпадения с ручной оценкой · версия, пробившая guard-порог, отклоняется независимо от остальных цифр

Архитектурный принцип

Одно правило держит кодовую базу в порядке по мере роста к нескольким клиентам: бизнес-логика никогда не живёт в транспортном хендлере.

Use-case-слой (app/core/use_cases/) — вызовы LLM, запись в БД, детекция кризиса, генерация отчётов, обновление портрета, подбор. Всё, что понадобится и будущему web-клиенту.

Handler-слой (app/bot/) — только Telegram-транспорт: разобрать событие, вызвать use case, отрисовать ответ. Никаких вызовов LLM, никакой прямой записи в БД.

Тест для любой новой фичи: «нужна ли эта логика web-клиенту тоже?» Если да — она идёт в use case.

Дальше по роадмапу

Приватность критична для терапевтических данных — следующие шаги переводят инференс и чувствительные данные полностью под контроль продукта.

Self-hosted LLM + LoRA-адаптеры в планах

Развернуть локальную модель (Ollama/vLLM) и подключить LoRA-адаптеры per-persona — свой стиль общения у каждой персоны терапевта, данные клиентов перестают покидать периметр. Локальный провайдер и эксперименты уже на месте.

Обфускация PII в планах

Персональные данные вычищаются/маскируются перед любым внешним API-вызовом, пока облачная LLM остаётся продакшн-провайдером.

Шифрование в базе в планах

Чувствительное содержимое диалогов шифруется в базе данных.

Цикл оптимизации DSPy в планах

Заменить ручной цикл «анализ проигравших → новый промпт → повторный прогон» на DSPy с откалиброванным LLM-судьёй в роли метрики. Плюс judge-оценки на сэмпле продакшн-трафика в Langfuse.