golang

Никто не просил — а я сделал банку робота‑секретаря

  • среда, 9 сентября 2026 г. в 00:00:09
https://habr.com/ru/companies/uralsib/articles/1077456/

Я Тимур Баян, занимаюсь разработкой почти всю свою жизнь, ещё со студенческих лет. Программирование и разработка у меня в крови! Я люблю решать нерешаемые проблемы, делать людям жизнь легче, тестить гипотезы, создавать крутые продукты. Так меня позвали работать в Уралсиб помогать управлять уже не одной, а сразу тремя командами. Сложностей я не боюсь, так что ныряем в задачи с головой!

Дано: три очень разные команды разработки, каждая со своим стеком технологий. С самого второго дня на меня понеслась тонна информации: куча встреч, много новых лиц, особенности технологий, legacy (куда ж без него). Я понял, что не успеваю заниматься всем и вся, что упускаю важные детали и нюансы из головы, прежде чем успею их оформить в минутки встречи или поручения.

Первым делом начал просто записывать проведённые встречи к себе на комп. Ха! А кто будет переслушивать и, самое главное, когда? Времени не хватит, чтобы снова всё переслушивать. Читать было бы гораздо быстрее. А если это чтиво ещё и прогнать через LLM'ку, то было бы вообще огонь! Она за меня всё прочитает и выдернет лишь самые интересные моменты, и мне не придётся ничего читать! Так зародилась идея создать что‑то такое, что сильно упростило бы мою жизнь, а заодно и жизнь коллег.

Для начала нужно было проверить гипотезу — создать первый рабочий MVP и убедиться, что это в целом рабочая схема. Достал самый обычный OBS Studio, записал парочку своих конференций и полез искать в интернете, чем же можно вытащить слова из записи (транскрибировать). Самый более‑менее вариант на тот момент был Yandex SpeechKit. Использовал его, стоимость примерно 30р/час. Не вопрос — регистрируемся, закидываем денег на аккаунт — прогоняем аудиозапись, получаем довольно точную транскрибацию встречи!

Развернул локально ollama, выбрал YandexGPT-5-Lite (она как раз тогда вышла, начало 2025-го) — хорошая моделька, которую потянет моя старенькая GTX 1080. Попросил её проанализировать текст и составить итоги встречи, подождал 30 секунд, получил сводные результаты и вуаля! Готово! Огонь! Домашняя видеокарта с довольно простой моделькой прогнала через себя все слова конференции и выдала результат. Сразу всё перечитал — основные моменты были подчёркнуты и записаны. Даже имена местами откуда‑то узнала (поняв по контексту поручения вида: «Юра, сделаешь такую задачу до выходных?», «Да, не вопрос.»)! Проверял я этот комплекс ещё несколько раз, чтобы убедиться, что всё это стабильно воспроизводимые результаты, а не галлюцинации ИИ, и делился в письмах с коллегами. Со временем коллеги начали спрашивать, как я это делаю, и тоже захотели такое же себе. Восторг, надо масштабировать! Получив добро у Насти, я принялся за работу.

Надо автоматизировать

Имеем: серверы банка, где можно проводить созвоны, проверенную и отлаженную гипотезу, что если записать конференцию, а затем извлечь текст, то можно с этим текстом поработать. Значит, нужно:

  1. Научиться подключаться к конференц‑комнатам, проходить авторизацию и записывать конференцию. Желательно ещё и записывать, кто говорил.

  2. Транскрибировать получившиеся записи (желательно с максимально возможным качеством), вытащив слова. Желательно ещё сопоставить говорящих.

  3. Прогнать через LLM, получить результаты.

  4. Найти на это время. Не забываем, что основная работа — не строить роботов‑секретарей:)

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

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

Подключение и запись

Это оказалась самая сложная часть. Я подумал: большинство софта под ИИ реализовано на python, значит, логично будет взять python для всего. Проводим исследование — что и как сейчас подключается, снимаем дампы, делаем описание протокола (в целом довольно популярная технология конференц‑комнат по WebRTC). Берём python, просим chatgpt накидать скрипт по подключению к конференц‑комнате. Получаем, запускаем... ошибки... Часть исправляем сами, часть просим gpt дальше доработать скрипт. Смогли проходить авторизацию, видеть пользователей и даже отправлять сообщения в чат. Но подключиться к аудиопотоку по WebRTC не удалось. Снова ошибки. И снова, и снова, и снова. Ах, эта любовь и ненависть к chatgpt. Браузер же как‑то подключается? Да и клиентов webrtc огромное количество, как может не получаться‑то? Главное — не сдаваться, продолжай!

Ни много ни мало разными попытками и подходами прошёл целый месяц проб и ошибок. Я перепробовал всё: и пробрасывал порты, и изучал WebRTC, и даже пробовал перед отправкой чистить SDP от неиспользуемых адресов — ничего не помогало! Я перепробовал все опенсорсные пакеты на python, самым более‑менее рабочим из них был aiortc — все ссылки и весь интернет указывали на него как на самый лучший пакет. Но что‑то не клеилось — соединение RTC так и не могло установиться, ICE‑протокол не мог установить связь с сервером.

Поняв, что я хожу по кругу и зря трачу время, несмотря на достигнутые успехи, я решил переписать всё на нормальный язык программирования — на Go. Чтобы не тратить лишнее время — скидываем уже почти рабочие наработки на python в chatgpt, просим его переписать на Go, получаем 5–6 файликов, собираем, компилируем, подпиливаем под себя (пару часиков), запускаем... работает! Сказать, что я был в шоке — не сказать ничего. Я месяц (!) возился с python, чтоб заставить aiortc записывать конференцию, а здесь версия на Go заработала спустя всего 4 часа, буквально с первого раза! С одной стороны, жаль потраченного времени, с другой стороны — опыт. Главное: у нас теперь есть прога, которая может подключаться к выбранной конференции и производить запись. Так получилась первая часть: recorder.

Транскрибация

Теперь мне надо вытащить слова из звукозаписи — транскрибировать её. Уже набив руку в работе с LLM, я понял, как ей надо ставить задачи. Поискав по интернету и изучив лучшие практики, я остановился на Whisper от openai (в том числе на Хабре всё чаще натыкался на статьи про него). Опять же, зачем писать всё самому, если можно с gpt собрать всё это быстрее? Описываем ситуацию, генерируем с ним dockerfile, разворачиваем, исправляем ошибки, снова разворачиваем. Спустя 4–5 итераций имеем рабочий билд. После нескольких тестов понимаем, что эта штука в целом работает, но с нюансом: работает только на моём процессоре, скорость обработки при 100% загрузки CPU составляет примерно 1:1 к длительности конференции. Если конференция шла час, то и ждёшь час, наблюдая, как компьютер умирает... Так дело не пойдёт! Снова описываем ситуацию чату гпт, так и так, мне нужна версия whisper с поддержкой GPU. В интернете есть всё, и про всё это знает chatgpt: разворачиваем переделанный whisper: https://github.com/ggml‑org/whisper.cpp. Самой стабильной моделью оказалась ggml‑large‑v3-turbo: если будете тоже что‑то транскрибировать, не скупитесь: она кушает чуть больше памяти (1.5гб), но распознаёт гораздо лучше остальных. Прокидываем gpu в докер‑контейнер, собираем, вуаля! Контейнер подтвердил, что работа с gpu теперь возможна. Закидываем часовой файл конференции, ждём... на GeForce GTX 1080 (флагман 2016) соотношение 4:1. То есть часовая конференция обрабатывается за 15 минут! Это уже вкусно. Сохраняем как сервис транскрибации. Идём дальше.

Сопоставление говорящих

Теперь нужен скрипт, который возьмёт произнесённые слова, сопоставит их с говорившими в тот момент участников и отправит всё в локальную LLM, развёрнутую на домашней видеокарте. От recorder'а у меня есть лог говорящих с точностью до секунды. Пишем скрипт сопоставления, прогоняем... получаем какой‑то бред. Почему говорил я, а засчитывают моей коллеге? Оказалось, что секундной точности недостаточно: в одну и ту же секунду может говорить или издавать звук сразу 2–3 человека. А целую реплику или вопрос можно успеть произнести за полсекунды. Значит, нужно просто записывать лог говорящих с точностью до миллисекунды.

Добавил миллисекундную точность — всё равно проблемы. Разбираю лог, сверяю с аудиозаписью и вижу проблему: сервер конференц‑связи сообщает о говорящих с рандомной задержкой, в то время как звук и слова уже идут. То есть у нас имеются произнесённые слова, но в этот момент, судя по логу, «никто не говорил». Что ж, кто сказал, что будет просто? Делаем эвристики, пытаемся угадать, кто говорил, в том числе по продолжающейся складной речи до следующего абзаца. Решение не идеально, туда попадают рандомные перебивания, фоновый шум и разговоры, но это максимальное качество в текущих условиях.

Агент LLM

Окей, наконец‑то мы получили долгожданный, заветный текст всей конференции, да ещё и с сопоставленными по логу именами говорящих! В чём обрабатывать? Для пилота берём заветный народный уже полюбившийся мне YandexGPT-5-Lite (спасибо, Яндекс!). Пишем промптер — берёт транскрибированный текст, прогоняет через LLM, получает результаты.

В целом это оказалась самая простая часть — все api давно известны: поднимаешь llama/ollama, обращаешься по REST'у, получаешь простой понятный ответ. Ошибиться шансов практически нет.

Приём заказов

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

Раннер — оркестратор

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

Его тоже решил написать на Go, всё же это очень ответственная часть. Проблем здесь не возникло, для простоты использовал обычную БД Postgres с таблицей и очередями заданий. Я разместил всё оборудование полностью на домашнем компьютере, мы собрали пилотную группу из 20 человек и начали пилот.

Кто ещё за DimaTorzok?

Пилотный проект проходил неплохо: в день записывал по 3–5 встреч, смотрел результаты и анализировал их, следил за стабильностью работы. Всё чаще стал замечать упоминания какого‑то DimaTorzok. Сначала подумал, что кто‑то прикалывается. Оказалось — это баг, ему даже сайт отдельный сделали: https://dimatorzok.com/ru/. Суть такова: Whisper учили русской речи по роликам на ютубе, и, чтобы сопоставить, кто что сказал — они брали субтитры от роликов. И так получилось, что определённая часть из этих материалов была подготовлена человеком с ником DimaTorzok. И в сценах, где ролик уже заканчивался и было определённое молчание (не полный мут, а звук тишины, когда кто‑то молчит во включённый микрофон) — там показывалось сообщение: «Субтитры подготовил DimaTorzok». И вот такой шум, когда все молчат, но какой‑то фон идёт и распознаётся whisper'ом как «DimaTorzok». Это явный баг, и, к счастью, его легко обойти. После сбора нескольких десятков конференций выяснилось, что самые частые багованные словосочетания это: «Субтитры сделал DimaTorzok», “Таскай и файди стендерка аутбуксделал” (я не знаю, откуда это, не спрашивайте), «Продолжение следует» (да, кто бы мог подумать, что такое пишут в конце роликов).

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

Нестабильность LLM

Получавшиеся результаты в целом соответствовали моим ожиданиям: моя LLM генерировала основные тезисы, часть из них пропускала. Бывает, путала имена (из‑за исходно грязного материала). Но самое ужасное было то, что она периодически выдавала контент в.md формате! Как бы я её ни просил — через раз получался не тот формат. Со временем я нашёл закономерность — чем дольше шла конференция (1.5 часа), тем выше шанс, что робот пришлёт что‑то не то. Начал копать, вся причина оказалась в маленьком контексте: 32к токенов — это примерно 15 тысяч слов, которые произносятся в среднем за 45–60 минут обычной конференции (конечно, если там не было человека, который очень быстро говорит). Из‑за слишком большого контекста LLM забывала то, о чём мы её просили в начале (выдать конференцию в html с простой разметкой), и начинала выдавать то, что посчитает нужным.

Для решения этой проблемы был написан обход: если конференция получалась слишком длинной (свыше 12 000 слов) — она делилась на 2 части (или на большее количество частей с перекрытием). Затем просим ИИ разделить выбранный участок на темы с разметкой: с какой строки какую тему обсуждали, с перекрытиями. И дальше LLM'ке скармливались эти нарезанные части, одна за другой. У каждой порядка 5000 слов. С таким уже можно работать и получать довольно точные результаты.

Пора внедрять

Пилот был признан успешным, мы с Анастасией Половьян показали и рассказали о нём руководству, всем понравилось, поехали внедрять. Больше всего в банке Уралсиб мне понравилась лёгкость внедрения: мы с Настей показали наше решение архитекторам, безопасникам и коллегам, отвечающим за железки: всем всё понравилось, довольно быстро одобрили внедрение в контуре банка. Банк как раз в это же время уже закупал промышленные видеокарты Nvidia H200, на которых спокойно разворачивается и Whisper и мощные LLM'ки. Мы оформили все необходимые документы, заявки. В течение недели нам выделили новые сервера, за пару дней получили все доступы, дождались поставки видеокарт и разворачивания LLM. Помогли коллегам собрать и поднять локальный Whisper.cpp, и понеслась!

Лучший интерфейс — отсутствие интерфейса

Напомню — на время пилота коллеги заказывали транскрибацию через телеграм‑бота. Это, конечно, всё прикольно (и тогда телеграм ещё не был заблокирован), но надо было делать что‑то другое в контуре. Вариантов несколько:

  1. Создавать внутренний сайт, где любой сотрудник мог бы заказать запись конференции

  2. Создавать бота во внутреннем мессенджере

  3. А может, сделать ещё проще? Может, да ну их, эти интерфейсы?

Я сторонник упрощения, а не усложнения. Чтобы придумать, как сделать пользовательский путь проще, надо самому пройти по нему. Начать нужно с вопроса: с чего начинается конференция? С её планирования. Встреча ставится через календари в Outlook, где проверяются свободные слоты и выбирается время и место встречи. А значит, самый простой путь попасть в конференцию — это чтобы робота сразу к ней добавили! Значит, нужно заделаться обычным юзером Outlook, чтобы робота можно было пригласить в конференцию. Не вопрос! Пишем заявку в SD, описываем ситуацию, нам регистрируют техучётку, выделяют ей даже почтовый ящик. Переписываем telegram‑бота: вместо работы с telegram он теперь будет работать с почтой Outlook по протоколу EWS. Проблем снова не возникло, рука в php набита — бот ищет непрочитанные письма‑приглашения на конференцию каждые 15 секунд (повторяя логику Outlook, так что лишней нагрузки не создаём, мы же не хотим уронить корпоративную почту?). По итогам встречи организатору/всем участникам (в зависимости от настроек) приходят результаты встречи.

Разворачивание и внедрение

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

Опубликовали внутреннюю новость, провели небольшое демо, и народ начал пользоваться: достаточно во встречу добавить робота‑секретаря, и он подключится к конференции. Поначалу с неохотой, а затем всё больше и больше людей начало узнавать о таком сервисе. Изначально мы пиарили этого бота как робота‑секретаря, который очень помогает командам разработки фиксировать договорённости и двигаться по плану, а по итогу половина пользователей — коллеги из бизнеса: они тоже ведут различные проекты, и такой бот им оказался очень кстати! С ним ведут дейлики, планёрки, обсуждают результаты продаж, планы, проекты, новости и погоду. После массового распространения, я получил от коллег кучу лайков, похвалы и уважения.

Дальнейшее развитие

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

С момента внедрения мы добавили аналитику встреч: была ли озвучена повестка встречи, были ли договорённости, сколько приглашённых реально участвовало во встрече (чтоб не звать в будущем тех, кого не обязательно было звать, отвлекая от работы). Это больше информационная аналитика для замера развития персонала.

Со временем мы заметили, что некоторые встречи, бывает, задерживаются и вместо запланированного часа могут проходить 1:05, 1:15 или даже 1:30 часа. Робот максимум досиживал 5 лишних минут и отключался. А некоторые встречи заканчивались намного раньше запланированного. Мы поняли, что бессмысленно хардкодить точное количество минут, которое должен сидеть бот. Вместо этого он остаётся в конференции до тех пор, пока основной состав участников всё ещё разговаривает: если 50–70% пользователей не меняется, значит, конференция продолжается, а значит, и боту нужно продолжать записывать (но через чат можно преждевременно остановить такое продолжение записи).

Также улучшили отправку писем: стали добавлять туда опрос о качестве анализа результатов встречи и добавили ссылку на внутренний ресурс, где можно прочитать всю транскрибацию встречи. Из недавнего: сгенерировали видеовставки с kling.ai, и, когда время встречи уже заканчивается, бот включает камеру и начинает намекать на то, что встреча скоро заканчивается/встреча вышла за рамки запланированного и пора идти работать. Это помогает не выходить за лимит времени и не опаздывать.

Заключение

Этой статьёй я хотел поделиться собственным опытом: продолжать верить в свои идеи, даже если кто‑то (даже ИИ) говорит, что это невозможно: никогда не останавливайтесь и продолжайте верить в свои силы! Если вы это придумали и можете повторить — значит, это возможно закодить! Напоминаю, что это было сделано ещё до эпохи массового внедрения кодинговых агентов, которые вполне могут реализовать такой стек за несколько вечеров. А сейчас мы в Уралсибе запускаем совсем другие проекты, подписывайтесь!