Что происходит после остановки записи: общая схема конвейера
Ассистент для созвонов в проекте Charoite_audio включается после остановки записи. Порядок этапов фиксирован: пересборка стенограммы, построение графа встречи, облачная ревизия, доставка минуток, ночная обработка. Локальная модель выдает черновик, облачная ревизия выполняет второй проход и правит то, что первый проход пропустил или исказил.
Схема целиком:
- пересборка стенограммы: сырой транскрипт превращается в связный текст с разметкой реплик;
- построение графа встречи: из стенограммы извлекаются поручения, решения и участники, а также связи между ними;
- облачная ревизия: второй проход по результату локальной модели, который возвращает правки в структурированном виде;
- доставка минуток: пользователь получает итог встречи в привычном формате;
- ночная обработка: фоновая синхронизация, повторные сверки, подготовка записей к следующему дню.
Это четвертая часть серии о разработке Charoite_audio. Все наблюдения ниже взяты из логов проекта, замеров автора и отчета внешнего ревью. Синтетических тестов и придуманных сценариев в материале нет.
Почему одного прохода локальной модели недостаточно
Локальная модель обрабатывает весь созвон и выдает готовый результат: стенограмму и граф. На длинных встречах в этом результате стабильно встречаются три класса ошибок, которые автор видит в логах: ложные поручения, шутка про бюджет, попавшая в граф как решение, неверные имена дорожек.
Ложное поручение появляется, когда модель принимает за задачу фразу, сказанную в другом значении: вопрос, пример, цитату чужого процесса. Шутка про бюджет попадает в решения, если произнесена уверенным тоном и не сопровождается маркером «шучу». Имена дорожек путаются на похожих голосах: диаризация относит реплику не тому участнику, и дальше вся ветка графа закреплена за ошибочным спикером.
Цена таких мелочей растет каскадом. Одна неверно приписанная реплика тянет за собой ложное поручение, а оно тянет неверного исполнителя. Второй проход дешевле, чем разбор вопроса «почему в миньютках висит пункт, которого никто не давал».
Роль облачной ревизии как второго прохода
Ревизия вынесена в облако ради качества проверки. Слабая локальная модель хорошо справляется с черновой работой, но ей тяжело оценивать собственный результат: она смотрит на текст теми же весами, которыми его породила. Более сильная модель на стороне облака замечает расхождения между стенограммой и графом. Какие именно модели заняты в конвейере, автор не раскрывает, поэтому названий здесь нет.
Ревизия получает стенограмму и граф, сверяет одно с другим и возвращает правки. Полтора месяца она работала в режиме «только дописывать»: находила ошибки, но не могла снять уже перенесенные записи. Это ограничение архитектуры, и оно определило следующую итерацию.
Пересборка стенограммы и построение графа встречи
Пересборка идет первой. Транскрибация отдает поток слов с таймкодами: без абзацев, без указания, кто говорит, с повторами и обрывками. Пересборка склеивает реплики, восстанавливает пунктуацию и размечает спикеров. На этом шаге ошибок меньше всего, потому что модель работает почти дословно, но именно здесь закладывается разметка дорожек.
Дальше строится граф. Узлы: поручения, решения, участники, темы обсуждения. Связи: кто поручил, кому, по какому вопросу, что решено. Логика напоминает то, как агенты собирают персональную книгу знаний из видеозаписей: выделение сущностей, дедупликация смысловых повторов и проверка provenance. Разница в масштабе: там часы видео, здесь один созвон, но типы ошибок те же.
Какие ошибки локальной модели попадают в граф
Ложное поручение. Модель слышит задачу там, где ее не ставили: «надо бы посмотреть, как у них с логистикой» превращается в поручение конкретному человеку. В графе появляется узел, которого не было в реальности.
Шутка про бюджет как решение. Фраза вида «давайте просто урежем бюджет вдвое, и все сойдется» звучит как решение, и граф фиксирует ее в соответствующем узле. Через день пункт уходит в миньютки, и кто-то тратит время на попытку понять, откуда он взялся.
Неверные имена дорожек. Спикер определяется по голосу, и на встрече с похожими голосами диаризация ошибается. Поручение закрепляется за человеком, который его не получал.
Все три случая встречались в логах проекта многократно. Это не гипотезы из теории, а наблюдения с конкретных записей.
Почему граф встречи становится центральной структурой
Стенограмма отвечает на вопрос «что говорили», граф отвечает на вопрос «что решили и кто что делает». Миньютки собираются из графа: блок поручений, блок решений, участники, следующий шаг. Дальше сущности из графа расходятся по напоминаниям и памяти, и копий одной записи становится несколько.
Поэтому ошибка в графе живет дольше, чем ошибка в тексте. Исправить стенограмму можно в одном месте. Исправить поручение, которое уже разошлось по миньюткам, напоминаниям и памяти, придется везде. Отсюда термин «перенесенные записи»: снять их сложнее, чем добавить новые.
Проблема: ревизия умела только дописывать
Полтора месяца облачная ревизия работала односторонне. Она находила ошибки локальной модели и дописывала правки, но снять уже перенесенное поручение или вернуть правильное имя дорожки не могла. Ошибка оставалась в графе, а рядом появлялась пометка о том, что с ней что-то не так.
Почему дописывание не решает проблему ложных сущностей
Дописывание добавляет информацию, удаление требует отдельного действия. Если ревизия сообщает, что поручение выглядит сомнительным, в графе оказываются две записи: сомнительное поручение и комментарий о нем. Пользователь видит обе. Ложная сущность остается в структуре, а значит продолжает расходиться по производным документам.
Схожая ситуация с именами дорожек: ревизия может дописать «вероятно, здесь говорил другой участник», но заменить атрибуцию реплики такая формулировка не дает. Снятие и замена требуют отдельной операции, и это уже вопрос архитектуры, а не качества промпта.
Какие типы ошибок накапливались за полтора месяца
- ложные поручения, которые уже разошлись по миньюткам и напоминаниям;
- шутка про бюджет, закрепленная в графе как решение;
- неверные имена дорожек, из-за которых исполнителем значился не тот человек.
Список короткий, но каждый пункт порождает поток жалоб на качество. Разбирать их вручную дороже, чем один раз научить ревизию снимать лишнее.
Как ревизия получила машинночитаемые разделы для снятия поручений и исправления имён
Решение лежало в формате ответа. Ревизия теперь возвращает строгие разделы, которые парсер разбирает однозначно, вместо свободного текста с рекомендациями. Каждый раздел описывает одно действие и содержит минимум полей: идентификатор записи, само действие, причину.
Структура раздела на снятие выглядит так:
- идентификатор поручения в графе;
- действие: снять;
- причина: почему запись считается ложной.
Раздел на исправление имени устроен похоже: идентификатор дорожки, текущее значение, новое значение, основание для замены. Логика близка к тому, как строят human-in-the-loop для AI-агента: риск-ориентированная маршрутизация, blast radius и калибровка порогов. Разница в том, что здесь решение принимает не человек, а строгий формат ответа ревизии.
Снятие поручений: почему нужен отдельный раздел
Общий текст ревизии не дает машиночитаемой команды на удаление. Из формулировки «поручение выглядит неубедительно» невозможно надежно вывести, что запись надо снять: модель может иметь в виду и «понизить уверенность», и «переспросить у пользователя». Отдельный раздел убирает эту неоднозначность: действие названо прямо, причина приложена, операция проверяема.
Проверяемость важна и для отката. Когда каждая операция снятия оформлена одной записью с идентификатором, видно, что именно удалено и по какой причине. Случайное удаление реального поручения становится видимым событием в логе, а не молчаливой потерей.
Исправление имён дорожек: отдельный раздел и его ограничения
Имена дорожек - отдельный класс ошибок. Здесь нужно не удалить запись, а заменить атрибуцию: у реплик меняется владелец, а вместе с ним пересчитываются связи в графе. Раздел на исправление содержит идентификатор дорожки и новое имя, иначе парсер не поймет, какую именно из дорожек править на встрече с пятью участниками.
Полностью проблема не решена. Если диаризация уверенно разложила реплики по неверным дорожкам, ревизия видит уже искаженную картину и может ошибиться повторно. Исправление имен работает как страховка на типовых случаях, а не как гарантия правильной атрибуции.
Нечёткое сопоставление строк и асимметричная цена ошибки
Чтобы снять поручение, его нужно найти в графе. Формулировка ревизии и формулировка в графе почти никогда не совпадают дословно: ревизия пересказывает суть, граф хранит исходную фразу. Точное сравнение строк здесь не работает, поэтому в ход идет нечёткое сопоставление: расстояния по символам и токенам, эмбеддинги, пороги похожести. Границы таких методов разобраны в материале про нечёткое сопоставление в шумном тексте: Levenshtein, BK-tree, Soundex и роль embeddings. Транскрибация созвона дает ровно такой шумный вход.
Дальше начинается самое неприятное. Похожих поручений в графе может быть несколько, и одно неверное срабатывание сопоставления снимает не ту запись.
Почему ложное снятие опаснее пропуска
Цена ошибки несимметрична. Если ревизия не сняла ложное поручение, пользователь увидит лишний пункт в миньютках и отфильтрует его сам: потеря - несколько секунд внимания. Если ревизия сняла реальное поручение, человек его не выполнит: он просто не увидит задачи. Потеря здесь уже рабочая, и обнаружится она позже, когда срок пройдет.
Пример: на встрече звучат две похожие задачи от разных людей, «подготовить смету по проекту А» и «подготовить смету по проекту Б». Нечёткое сопоставление с высоким порогом рискует снять не ту. Поэтому порог подбирают так, чтобы ошибочных снятий было как можно меньше, даже ценой пропущенных срабатываний.
Как строгие разделы снижают риск нечёткого сопоставления
Строгий формат дает идентификаторы и явные действия. Когда ревизия называет конкретную запись, а не описывает проблему словами, пространство для догадок сжимается: сопоставлять приходится не произвольный текст, а пару «идентификатор - действие». Полностью нечёткость не исчезает, потому что идентификатор тоже нужно связать с записью в графе, но риск становится управляемым: понятно, где именно может произойти ошибка и как ее отловить в логе.
Синхронизация с векторной памятью и отключение второй памяти
После правок ревизии меняется не только граф. Сущности встречи уходят в векторную память, чтобы по ним можно было искать: «какие поручения давали по интеграции», «что решали по бюджету в марте». Если снятое поручение останется в индексе, поиск продолжит возвращать отмененную запись.
Что именно синхронизируется с векторной памятью
В память попадают сущности встречи: поручения, решения, участники, темы. Операция снятия должна дойти и туда: запись либо удаляется, либо помечается как отмененная, иначе следующий поиск вернет пользователю записи, которых в графе уже нет. Это отдельный поток, который идет после ревизии и занимает время, отсюда и ночная обработка как отдельный этап.
Ночная обработка добирает то, что не успело пройти днем: переиндексацию, повторные сверки, подготовку сводок. Работа идет с накопленным контекстом, а накопление состояния ведет себя неочевидно: сжатие контекста способно ухудшить результат многошаговой работы, и это стоит учитывать, когда фоновые прогоны обрабатывают историю за недели.
Почему вторая память оказалась дублем графа
В конвейере было две памяти: граф встречи и вторая структура, хранившая те же сущности в другом виде. Автор отключил вторую. Аргумент простой: она дублировала граф, а при правках ревизии возникал рассинхрон. Снятое в графе поручение оставалось во второй памяти и возвращалось оттуда в выдачу.
Решение контекстное. Оно работает, пока граф покрывает все сущности, которые нужны поиску. Если у второй памяти есть собственные задачи, которых в графе нет, отключать ее нечем заменить.
Аудит кода по зонам двумя облачными моделями за 79 центов
Внешнее ревью кода шло по зонам двумя облачными моделями и стоило 79 центов. Результат: 17 подтвержденных дефектов. Дефекты подтверждены, то есть воспроизведены или проверены вручную, а не просто предложены моделями.
Как устроен аудит по зонам
Код разбивается на зоны, и каждая зона проверяется отдельно. Локальные дефекты теряются при чтении всего файла целиком: модель уходит в общую логику и не замечает крайний случай в конкретной ветке. Разбиение заставляет смотреть каждую часть под своим углом.
Две модели дают перекрёстную проверку. Одна может найти то, что пропустит другая, а совпадение находок повышает уверенность, что дефект реальный. Стоимость в 79 центов делает такой прогон дешевле часа ручного чтения кода, поэтому его можно повторять после крупных изменений.
Что дали 17 подтверждённых дефектов
Практическая ценность в том, что находки оказались реальными. Не все из них критичны: часть касается крайних случаев и обработки ошибок, которые редко срабатывают в бою. Но именно такие случаи потом дают ночные падения конвейера и потерянные минутки.
Внешнее ревью ценно тем, что не зависит от автора. Самооценка кода смещена: разработчик помнит, какую задачу решал, и достраивает корректность там, где ее нет. Чужая модель этого контекста не имеет и судит по написанному.
Ограничения подхода и что осталось за кадром
Компромиссы у конвейера видны без прикрас. Локальный ассистент для созвонов все равно отправляет данные в облако на этапе ревизии. Транскрипт созвона - чувствительный материал, и полностью локальной схема не остается.
Приватность и стоимость облачной ревизии
Облачная ревизия требует передачи стенограммы и графа наружу. Для внутренних разговоров компании это осознанный выбор между качеством проверки и закрытостью данных. Полностью локальный вариант оставляет ошибки первого прохода без правки, а это ровно те ложные поручения и перепутанные дорожки, из-за которых конвейер и начали дорабатывать.
Стоимость облачных вызовов на встречу растет с длиной разговора и частотой проверок. Аудит кода за 79 центов показывает, что разовые проверки дешевы, а ежедневная ревизия каждой встречи - уже регулярная статья расходов. Экономить можно на коротких созвонах, пропуская ревизию там, где в графе нет поручений.
Кому подходит такой конвейер
Подход рассчитан на тех, кто уже использует локальные LLM и готов строить пост-процессинг своими руками: транскрибацию, граф встречи, векторную память, облачную ревизию. Порог входа здесь не в модели, а в инженерной обвязке вокруг нее.
Не подходит тем, кто хочет полностью закрытую схему без облачных вызовов, и тем, кто не готов поддерживать сопоставление записей и синхронизацию памяти. Нечёткое сопоставление остается рискованным местом, отключение второй памяти - решением под конкретную архитектуру, а не общим правилом. Материал опирается на реальные логи и замеры проекта Charoite_audio и не претендует на роль универсального руководства: в другом конвейере те же приемы дадут другой результат.