Связаться со мной
Статьи
ChatGPT Image Sep 17, 2026, 06_32_57 PM

Как я чуть не превратил теннисную тренировку в обслуживание базы данных

Я хотел всего лишь записывать теннисные тренировки дочери. Через некоторое время рядом с кортом выросла небольшая информационная система. А дальше всё пошло не по плану.

Цифровизация тренировок

Итак, у меня есть ученица. В свободное от творчества и просвещения время я — тренер. Создаю из собственной дочери теннисистку вот уже несколько лет.

Вообще-то по жизни я — латентный аналитик. Любую сложную проблему стараюсь вогнать в Excel. Я даже книгу написал для бизнес-аналитиков «Охота на данные».

Поэтому идея оцифровки тренировок пришла в мою восполенную бошечку одновременно с идеей самих тренировок.

Давным-давно, ещё когда сам занимался с тренером, я предпринял первую попытку всю вариативность теннисных ударов переложить в таблицу.

Не смог.

Потом познакомился с родственной душой — другим тренером, который в прошлом был аналитиком коммерческого банка. Сейчас он с помощью Excel тренирует кучу народу в разных точках Москвы. Мы с ним попытались вместе описать такую модель данных.

Чуть не разругались, разбежались.

Сами посудите. Вот открываете вы Excel. Вот форхенд, вот бэкхенд. Задняя линия, half-court, сетка, middle — это между задней линией и half-court. Ваш удар идёт по линии, кроссом или обратным кроссом. Удар плоский, с топспином или слайсом. Скорость, траектория, движение соперника, удар на ходу или из подготовленной позиции... Бр-р-р...

ИзмерениеПримеры
УдарFH, BH, slice, drive volley, smash, serve
Позиция игрокаbaseline, middle, half-court, net
Направлениеline, cross, reverse cross
Вращениеflat, topspin, backspin
Источник мячаball machine, coach, sparring partner
Положение подающегоbaseline → net
Траекторияобычная, высокая, низкая, короткая
Предсказуемостьигрок знает направление → не знает
Движениестатично, в сторону, вперёд, назад
Вариативностьодинаковый мяч → постоянно меняющийся
Контекстdrill, rally, point, match

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

Дело не в том, что мы забыли добавить ещё три поля. По идее, компьютер всё должен стерпеть. Проблема в самой попытке заранее описать пространство всех возможных теннисных ситуаций.

Трекер, который построил я

Когда появился доступный AI, я возрадовался. Ну теперь-то мы этого монстра распланируем и размоделируем. AI поможет придумать правильную модель данных, а ИИ-агенты — быстренько собрать приложение «какое хош».

На каждой тренировке я буду записывать, что именно мы делали, сколько времени длилось упражнение и какой получился результат. Потом из всего этого вырастут графики. Мы будем с интересом смотреть на них вместе с ученицей и принимать какие-то решения.

При любой непонятной ситуации делай PWA. Прекрасный девиз!

Тип удара — отдельная кнопка. Позиция соперника. Позиция играющего. Позиция ученика. Скорость и траектория мяча. Пушка или живой ввод мяча. Всё это было с успехом запрограммировано.

И вот мы выходим на тренировку.

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

Начинаю что-то подозревать: блин, а как это всё записать в нашем прекрасном, только что навайбкоженном трекере?

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

А упражнения?! Два удара форхенд, два — бэкхенд, выход к сетке. Два воллея и, мать его, смеш!

Сегодня я могу добавить поле feeder_position. Завтра выяснится, что важно, знает ли ученица заранее направление следующего мяча. Послезавтра понадобится степень вариативности. Потом — качество предыдущего удара, потому что один и тот же forehand после удобного и после выбивающего мяча — это не один и тот же forehand.

Я тогда назвал это «бегом в мутную неизвестность». Автоматизировать всякие «газпромы» с «лукойлами» было гораздо легче, знаете ли.

Страшно то, что тренировка практически остановилась. Приходилось думать не об ученице, а о классификации упражнений.

Здесь есть ещё одна проблема: «с пушки получается» и «в живой игре получается» — не одно и то же. В спортивной науке существует понятие Representative Learning Design: тренировочная задача должна в достаточной степени воспроизводить информационные и двигательные требования настоящей игры. В небольшом исследовании теннисистов различались даже время начала движения и длительность замаха при приёме мяча от пушки и от реального подающего. А отдельная работа о переносе навыка в теннисе показала, что упражнения разной репрезентативности приводят к разным изменениям поведения игрока.

То есть контекст упражнения — не украшение карточки. Без него мы можем записать «форхенд получился» и потерять главное: где именно он получился и переносится ли этот навык в живую игру.

Хорошо. Тогда долой все кнопки

Дома я принял кардинальное решение: в приложении по конкретной тренировке останутся только текстовые записи.

При совершенно вольной диктовке можно что-то упустить. Есть, например, нюансы вроде разножки, о которой все забывают, хотя она должна отрабатываться фоном.

Но десятки кнопок на корте мне точно не нужны.

Записи могут выглядеть так:

Ученица на задней линии. Я сам ввожу мячи. Сначала стою у задней линии, потом постепенно двигаюсь к сетке. С пушки forehand шёл стабильно, от живого ввода качество резко упало.

Или так:

Ученица на задней линии. Сначала два мяча под forehand, потом два под backhand. Затем она выходит на half-court: два drive volley и один smash.

В этих описаниях будет время, результат и мои оценочные суждения. А структуру из них извлечёт AI.

Раньше цепочка выглядела так:

human → structured form → database → AI

Теперь гипотеза другая:

human → raw observation → AI → structured interpretation → database / analytics

Первичными данными становится человеческое наблюдение. ИИ превращает его в одну из возможных JSON-интерпретаций, которую при желании можно строить задним числом снова и снова.

Понимаете, о чём я? Когда мы шли через форму и забыли предусмотреть обязательное поле — например, величину backspin, — его просто нет.

А если мы просто пишем, что было сделано, свободным текстом, то через полгода можем сказать: слушай, я вспомнил, весь октябрь у нас вообще не было backspin. Возможно, поэтому сейчас нет навыка принимать резаные мячи. И новую информацию можно извлечь из старых наблюдений.

Если же в базе за эти полгода копилось только FH / BH / baseline / скорость 85% / рейтинг 4, недостающий контекст уже умер.

Логика похожа на schema-on-read из инженерии данных: сначала сохранить богатый исходный материал, а структуру накладывать при последующей обработке. Это, конечно, аналогия: Tennis Tracker — не data lake. Microsoft Azure Architecture Center использует schema-on-read именно для описания данных, которые сохраняются ближе к исходному виду и преобразуются позднее.

Задача языковой модели здесь не в том, чтобы поговорить со мной о теннисе. Она должна извлечь структурированные признаки из человеческого рассказа. Такой класс задач действительно существует: например, в работе Learning to Extract Structured Entities Using Language Models языковые модели используются для превращения свободного текста в структурированные сущности и свойства.

И что получается — формы ввода умерли? Да здравствует свободный и беспредельный ИИ?!

Нет. Структура всё равно нужна. Только создаёт её машина после «словоблудий» человека.

От «вертолётного кокпита» к «просто рассказу»

Несколько тренировок подряд я тщетно пытался надиктовывать в приложение всякие истории, в которых фигурировали уровни мощности бол-машины, количество мячей в корзине, соотношение попыток и результатов плюс всяческие импровизации...

Чтобы не отвлекаться сильно на телефон, я болтал в него «как придётся» — без редактирования и шлифовки.

То есть ничего не тегировал. Не выбирал из dropdown. Не заполнял карточку упражнения. Просто «что видел, то и пел».

Моей голубой мечтой было начать получать примерно вот такой джейсончик:

{
  "feed_source": "ball_machine",
  "ball_machine_power_percent": 60,
  "estimated_ball_count": 70,
  "strokes": ["forehand", "backhand"],
  "target": "soft topspin to half-court",
  "backhand_success_rate": 0.3,
  "follow_up": ["short angles", "live coach feed", "slice serve preparation"]
}

Точность не нужна. Приблизительные значения могут оставаться приблизительными. Неизвестные — неизвестными. Качество зависит от схемы извлечения и возможности вернуться к первоисточнику.

Но тут пришла Apple и всё испортила

Следующая версия Tennis Tracker должна была стать почти идеальной. Минимум полей. Свободный текст. Диктовка непосредственно во время тренировки.

Но встроенное распознавание iPhone так обработало теннисную терминологию, английские слова и мою разговорную речь, что местами транскрипт перестал быть исходными данными.

Вот реальные примеры:

«поиграли косы и мячи»

«резана высоким реза NOM»

И особенно:

«ну конечно же не лучше получается чем в начале тренировки прогноз непонятных людей на нервничал не получив ударов даже дома нет особо пакет рве и Надя»

Последнюю тарабарщину даже я сам не разобрал. И... кто такая Надя?))

В общем, если использовать нативную диктовку iPhone, вместо тренировки происходит постоянное производство ошибок и их лихорадочное истребление.

До чего мы в итоге докатились

Мы с моими ИИшками дошли до версии Tennis Tracker, в которой на корте вообще не надо транскрибировать речь. Приложение стало «тупым» диктофоном: нажал кнопку → сказал наблюдение → сохранился оригинальный аудиофайл.

Это решило важную проблему предыдущей версии: ошибка распознавания больше не уничтожает первичные данные. Не нравится сегодняшняя расшифровка — через год можно прогнать тот же .m4a другой моделью.

Ну океюшки, аудио мы накапливаем. Кто потом превратит его в нормальный текст?

Пока ехал за дочкой в школу, надиктовал мерзкий тестовый файл секунд на пятьдесят. Не «Здравствуйте, я ваш тренер», а сбивчивая речь с запинками, самоповторами, ээээ, немотивированным переключением с русского на английский и обратно, backhand, forehand, drive volley, с жаргоном и матюгами.

Сначала прогнали через установленный на Mac WhisperNotes. Общий смысл он ловил, переключение языков тоже, но на сложных местах начинал фантазировать. drive volley превратился в drive all the shoulders, а ахуительно хорошо — в толерантное опустительно хорошо.

Выслушав мой ор, Codex установил whisper.cpp и полную неквантованную OpenAI Whisper large-v3 — модель примерно на 3 ГБ — и прогнал тот же самый исходный файл. Эксперимент получился сравнительно честным.

И вот теперь всё стало намного лучше. Локальная модель корректно разобралась с моей белибердой.

Да, модель не справилась с drive volley: получилось drive более. Но смысл записи уже практически не разрушен.

Конечно, занятие теннисом — не заседание суда. Нам не нужна идеальная транскрипция. Всё равно следующим шагом пойдёт большая LLM, которой предстоит понять, что же в действительности происходило на корте.

Поэтому архитектура на данный момент получается простая, как рельса:

корт → оригинальное аудио → распознавание речи → LLM → структура → накопленная история → аналитика

Как только мы поймали оригинальное аудио, всё остальное можно адаптировать до посинения: заменить Whisper, поменять промпт, сменить LLM, придумать новую схему JSON, через год извлечь признаки, о которых сегодня вообще не задумывались.

Но как из разговоров всё-таки вызревает система

Система не будет «брать на веру» произнесённые мною слова. У неё есть уйма контекста.

Она знает даты, время и длительность тренировок. Может вычислять примерную продолжительность каждого упражнения. Знает габариты корта и позиции, которые я называю в диктовке. Не секрет для неё и возраст, и уровень игрока. Знает, сколько мячей помещается в корзину и сколько раз мы её собирали. Если я сказал, что пушка работала пять минут, система может оценить возможное количество подач — но не должна делать вид, что знает их точное число.

Она сможет затем оценивать даже количество шагов ученицы и пройденное ею расстояние.

Получается уже не просто расшифровка, а восстановление события из нескольких типов свидетельств:

ИсточникЧто из него можно получить
Голос тренераЦель упражнения, качество выполнения, неожиданные наблюдения
Время записиНачало, конец и приблизительную длительность эпизода
История сессииПоследовательность упражнений и переходы между ними
Размеры кортаНормализацию позиций и расстояний
Корзина с мячамиВерхнюю границу количества ударов между сборами
Параметры пушкиВозможный темп, направление, вращение и повторяемость
Данные об игрокеВозраст, уровень, предыдущие тренировки и индивидуальные ориентиры

AI может сопоставить эти сведения и дать справочку: «Упражнение длилось около пяти минут. При заданном темпе пушки и одной корзине могло быть выполнено примерно 55–70 ударов. Тренер отдельно отметил около 30% удачных backhand. Оценка приблизительная: точного счётчика ударов не было».

Вот здесь и появляется свет в конце тоннеля. Я наконец-то не утыкаюсь в телефон, когда должен смотреть на ученицу.

Что получилось из четырёх подходов

ПодходЧто сохраняетЧто теряетРабота человека при вводе
ExcelСравнимые числаНеизвестный заранее контекстВысокая
Structured Tennis TrackerВыбранные признаки и часть контекстаВсё, для чего не оказалось поляОчень высокая на корте
Свободный AI-чатБогатый и понятный контекстНакопленную структуру без отдельной обработкиНизкая
Оригинальное аудио → AIБогатый исходник и возможность поздней обработкиТребует отдельного распознавания и анализаМинимальная на корте

Контрольные работы

Нужно будет ещё протоколировать матчи. Я не говорю про буквальную запись самой игры через какой-нибудь SwingVision. Я снова про голос, который помогает делать заметки, не отрывая взгляда от игры.

Голос сохраняет богатство контекста. AI извлекает признаки. Код считает и интерпретирует результат.

Через условные двадцать четыре тренировки отдельный анализатор должен отвечать не на вопрос «какой средний балл у forehand?», а на гораздо более полезные:

  • что мы практически не тренируем;
  • какие навыки существуют только с пушкой и исчезают в живой игре;
  • где слишком мало вариативности;
  • где нужен спарринг, иначе ничего не прокатит;
  • когда пора чаще играть на счёт;
  • какие упражнения я, как тренер, почему-то постоянно повторяю;
  • где остановился прогресс;
  • что включить в следующие четыре недели.

Да и за мной присмотр нужен. Я могу увлечься одним навыком, упустив какой-то базовый.

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

Что искатьГлавный вопрос
ДырыЧто мы систематически недотренировываем?
ПереносРаботает ли навык вне стерильного упражнения?
Чит-кодыЧто даёт этому игроку необычно высокий результат?

Чит-коды в теннисе

Часть моей «авторской методики» — чит-коды.

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

Меня самого даже немного смущало, насколько легко мне это давалось и какие разрушительные результаты приносило.

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

Я считаю, что при обучении любого игрока нужно найти его чит-коды. У кого-то убийственный backhand именно кроссом. Окей, его надо закрепить, периодически развивать, а если он уже развит — просто вспоминать.

Это нужно ещё и для нормальной психологической базы. Особенно после проигрышей. Все мы человеки и все мы психуем, переживаем, когда проигрываем. Иногда нужно поделать что-то достаточно лёгкое и дать команду собственному организму: ты молодец, ты не всё растерял, у тебя есть чит-коды, которые получаются вообще со свистом.

У разных игроков я видел разные чит-коды. У кого-то получается офигенный drop shot, у кого-то — убийственный drive volley. Кто-то играет slice так, что ты задолбаешься его ударчики выковыривать.

Поэтому будущий AI-анализатор должен искать две противоположности: дыры — чего не хватает для гармоничного развития, и чит-коды — где возникает необычно высокая эффективность.

И ещё одна задача — перенос навыка. То, что получается в упражнении, действительно должно работать против живого игрока.

То есть мы не только задалбываем ученика: вот это у тебя не получается, вот это у тебя не получается, вот это не получается. Нет. Просто строим нормальный процесс:

Закрываем дыры. Проверяем перенос. Выращиваем оружие.

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

Теперь на корте моя задача — снова с восхищением смотреть на ученицу, а не обслуживать базу данных.


Источники

  1. Microsoft Azure Architecture Center. What is a data lake?.
  2. Wu H. et al. Learning to Extract Structured Entities Using Language Models. EMNLP, 2024.
  3. Pinder R. A. et al. Representative Learning Design and Functionality of Research and Practice in Sport. Journal of Sport and Exercise Psychology, 2011.
  4. Krause L. et al. Enhancing skill transfer in tennis using representative learning design. Journal of Sports Sciences, 2019.
  5. Carboch J., Süss V., Kocib T. Ball machine usage in tennis. Journal of Sports Science & Medicine, 2014.