10 KiB
created, updated, tags
| created | updated | tags | |||||
|---|---|---|---|---|---|---|---|
| 2026-05-19 | 2026-05-19 |
|
Session Design — AI Psychologist App
Детальный дизайн сессии: UX-флоу, механика вопросов, открытие/закрытие. Связан с: overview (раздел 5-6 — базовая структура и архитектура ботов)
1. Механика вопросов (Question Delivery)
Pipeline вопросов
Бот 2 (Analyst / "Психолог")
→ генерирует 1-2 вопроса в 3-м лице ("пользователь избегает...")
↓
Бот 1 (Narrator / "Посредник")
→ переформулирует в 1-е лицо ("ты избегаешь?")
→ на выходе: структурированный массив вопросов для UI
↓
UI алгоритм (не агент!)
→ показывает вопросы по одному в карточках
→ ждёт ответа → следующий
Ключевой принцип: раздача вопросов — детерминированный алгоритм, не LLM-вызов. Агент генерирует батч вопросов один раз → посредник переформулирует → UI сам управляет порядком.
Структура данных от агента (JSON для UI)
{
"questions": [
{
"id": 1,
"text": "Ты замечаешь, что откладываешь этот разговор?",
"type": "open"
},
{
"id": 2,
"text": "Что происходит внутри когда думаешь об этом?",
"type": "open"
}
],
"answered": [],
"session_id": "2026-05-19"
}
Завершение батча вопросов → подбивка
Когда все вопросы в батче отвечены, UI передаёт агенту нумерованную подбивку:
1. [вопрос] → [ответ пользователя]
2. [вопрос] → [ответ пользователя]
Это входные данные для следующей итерации диалога (следующий батч вопросов или инсайт).
2. Открытие сессии
Структура intro
- Персонаж-активация (анимация, 1-2 сек) — без текста, пауза перед словами
- Короткое введение (1-2 предложения максимум):
- Что происходит сегодня в целом (настроение агента, не диагноз)
- Без "Давай начнём с..." — сразу к делу
- "Крючки-активаторы" из прошлых бесед:
- 1-2 элемента из profile.md / последних сессий
- Формат: карточка-напоминание ("В прошлый раз ты говорил о...")
- Не перегружать: максимум 2 крючка, не перечислять всю историю
- Если нет прошлых сессий — пропустить этот блок
- Переход к теме — либо предложение агента, либо выбор пользователя
Prompt агента для intro
Агент (Analyst) при старте сессии получает:
profile.md— текущий профильsessions/[last 1-2].md— последние сессии- Задача: сформировать intro + max 2 крючка, без перечисления всего
3. Закрытие сессии
Последовательность закрытия (3 этапа)
Этап 1 — Психолог обновляет документы (backend, не видно пользователю)
После завершения диалогового флоу Analyst:
- Пишет
sessions/YYYY-MM-DD.md— запись сессии - Обновляет
profile.md— новые паттерны/наблюдения - Формирует structured summary для Посредника
Этап 2 — Посредник: человечный итог (видно пользователю)
Посредник в режиме "простого AI-агента" — без аналитики, без психолого-языка:
- Тёплая, живая фраза от себя (не "подводя итог...")
- Примерный тон: "И от себя — это больше чем ничего. Ты на верном пути."
- Не повторять то что уже сказал психолог
- Не хвалить избыточно — anti-sycophancy принцип сохраняется
- Сказать когда следующая сессия: "До встречи в четверг" (из расписания пользователя)
Этап 3 — "One last thing" + завершение
- Агент задаёт открытый вопрос с вольным промптом: "Хочешь что-то добавить?"
- Визуально: маленький текстовый input, не акцентная кнопка "Завершить"
- Этот экран не предполагает продолжения полноценной сессии
- Если пользователь что-то написал → агент может добавить это в заметки сессии, ответить коротко
- Если нажал "Завершить" без ввода → сессия закрывается
Сценарий сдвига расписания
Если в "one last thing" (или на любом этапе закрытия) пользователь упоминает сдвиг даты/времени:
- Детектируется ключевыми словами (перенести, следующий раз, не смогу в четверг, и т.д.)
- Запускается сценарий планировщика (отдельный флоу)
- Беседа переходит в режим планировщика и завершается в нём (не возвращается в сессионный флоу)
- Результат: обновлённое расписание, подтверждение новой даты
4. Флоу сессии целиком
ОТКРЫТИЕ
├── Анимация персонажа (1-2 сек)
├── Intro: 1-2 предложения + max 2 крючка из истории
└── Выбор темы (пользователь или AI предлагает)
ДИАЛОГ
├── Analyst генерирует 1-2 вопроса (3-е лицо)
├── Narrator переформулирует → JSON карточек (1-е лицо)
├── UI раздаёт по одному
├── Пользователь отвечает → нумерованная подбивка
└── Следующий батч / инсайт
ИНСАЙТ
├── Analyst кристаллизует наблюдение (3-е лицо)
└── Narrator переформулирует для пользователя (1-е лицо)
ЗАКРЫТИЕ
├── [backend] Analyst пишет session summary, обновляет profile.md
├── Посредник: тёплая фраза + дата следующей сессии
├── "One last thing" (вольный промпт, неакцентное завершение)
│ ├── Написал что-то → агент добавляет в заметки, отвечает коротко
│ ├── Упомянул перенос → сценарий планировщика
│ └── Завершить (кнопка) → сессия закрыта
5. State Persistence & Session Recovery
Сохранение стейта на каждом шаге
Каждый шаг сессии сохраняется немедленно — не в конце:
step_state {
session_id: "2026-05-19",
user_id: "...",
phase: "dialogue", // intro | questionnaire | dialogue | insight | closing
current_question_idx: 2,
answered: [ {q: "...", a: "..."}, ... ],
last_activity_ts: 1747612800
}
При следующем открытии приложения — автоматически восстанавливается точка, где пользователь остановился. Не начинает с начала.
Заброшенная сессия (пользователь пропал посередине)
Триггер: last_activity_ts > 20 часов, сессия не завершена.
Действие (backend cron):
- Принудительно завершить сессию — агент пишет partial summary на основе того, что успело ответить
- Обновить
profile.md— даже неполные данные полезны - Пометить сессию как
completed_partial
Уведомление: на следующий день примерно в то же время (± 30 мин от last_activity_ts предыдущих сессий) — push:
"Мы не успели закончить в прошлый раз. Вернёмся?"
Retention protocol (Stage 2): при N пропущенных сессиях подряд — запускается отдельный флоу "возвращение пользователя" с мягким реактивационным сообщением. Детали — в будущем документе.
6. Открытые вопросы
- Как именно Narrator детектирует что вопросы в 3-м лице и нужно переформулировать? Prompt rule или регекс-паттерн?
- Сценарий планировщика — отдельный агент или встроен в посредника?
- Как хранить расписание сессий: отдельный
schedule.mdв профиле? - Что если "one last thing" раскрывает новую тему — прерывать или кратко зафиксировать?