Схема работы LLM-агента для извлечения фрагментов из транскрипта: от расшифровки к готовым видеофрагментам

Извлечение фрагментов из расшифровки: как заставить LLM работать

ИИ-инструменты 30 июня 2026 г.

У вас есть часовая расшифровка выступления — полотно из нескольких тысяч слов с таймкодами. Вам нужно достать из него 5–6 самодостаточных фрагментов для вертикальных роликов: законченная мысль, не оборванная на полуслове, которую можно показать вне контекста. Первая мысль — закинуть в LLM промпт «найди интересные моменты» и забыть. Эта мысль разваливается сразу.

Источник: Habr

Практический результат: если вы даёте модели свободу резать где угодно, она возвращает старт с середины фразы, таймкоды «из головы» и нестабильный JSON. Решение — сузить пространство выбора до предложений. Модель не называет секунды и не режет по словам — она выбирает диапазон номеров предложений.

Проверьте свой текущий пайплайн: если вы используете LLM для извлечения фрагментов из расшифровок и получаете мусор на выходе, причина не в модели, а в том, как вы формулируете задачу.

Четыре способа, которыми ломается наивный подход

Первое, что приходит в голову: «Вот транскрипт с таймкодами. Найди 6 самых интересных моментов и верни их время начала и конца.» Это не работает. А именно происходит:

Старт с середины фразы. Модель возвращает start, попадающий внутрь предложения: «…а вот это уже меняет всё». Зритель не понимает, о чём речь.

Старт со связки. Грамматически это «начало предложения», но смыслово — мусор: «Но если посмотреть глубже…», «Поэтому я и говорю…». Формально корректно, на деле — оборванный контекст.

Таймкоды «из головы». Если просить модель назвать секунды, она их галлюцинирует. Возвращает start: 734.0, а реального слова на 734-й секунде нет — там середина паузы или чужая фраза. Модель не считает время, она его придумывает.

Нестабильный формат. На длинном входе модель то возвращает 6 фрагментов, то 1; то валидный JSON, то JSON с комментарием сверху, то с оборванной скобкой. Один и тот же промпт на одном и том же входе ведёт себя по-разному от запроса к запросу.

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

Идея, которая всё развернула: единица — предложение, а не слово и не секунда

Главная ошибка наивного подхода — давать модели свободу резать где угодно. Решение: сузить пространство выбора до предложений. Модель не называет секунды и не режет по словам — она выбирает диапазон номеров предложений.

Сначала склеиваем слова/сегменты Whisper обратно в предложения и нумеруем их. Функция build_sentences проходит по массиву слов, собирает их в предложения по знакам пунктуации (точка, восклицательный, вопросительный, многоточие) и сохраняет тайминги границ — start первого слова и end последнего.

Теперь модель видит пронумерованный список:

[0] Сегодня я хочу поговорить про найм.
[1] Когда мы выросли с пяти до пятидесяти человек, всё сломалось.
[2] Оказалось, что нанимать людей — это не про поиск резюме.
...

Вместо «найди 6 интересных моментов и верни секунды» промпт звучит так: «Выбери диапазоны номеров предложений, которые содержат законченную мысль и укладываются в 15–75 секунд». Модель не может ошибиться с таймкодом — она просто возвращает номера, а тайминги подставляются из заранее собранного массива.

Как это выглядит в коде: функция склейки слов в предложения

def build_sentences(words: list[dict]) -> list[dict]:
    """Склеивает слова в предложения, сохраняя тайминги границ."""
    sentences, cur = [], []
    for w in words:
        cur.append(w)
        if w["word"].endswith((".", "!", "?", "…")):
            sentences.append({
                "id": len(sentences),
                "text": " ".join(x["word"] for x in cur),
                "start": cur[0]["start"],
                "end": cur[-1]["end"],
            })
            cur = []
    if cur:  # хвост без финальной пунктуации
        sentences.append({"id": len(sentences),
                          "text": " ".join(x["word"] for x in cur),
                          "start": cur[0]["start"], "end": cur[-1]["end"]})
    return sentences

Функция простая, но именно она решает проблему галлюцинированных таймкодов. Модель больше не отвечает за время — она отвечает только за смысл. Тайминги берутся из данных, которые вы уже получили от Whisper.

Что меняется в стоимости и времени

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

Экономия: вместо 20–30 минут ручного отбора на одно видео — 2–3 минуты на проверку результатов модели. Если вы обрабатываете 10–20 видео в неделю, разница в часах.

Где остаются риски и ограничения

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

Связки в начале предложения. Даже при работе с предложениями модель может выбрать фрагмент, который начинается с «Но», «Поэтому», «И». Формально это начало предложения, но смыслово — мусор. Решение: добавить в промпт запрет на старт со связок и дать 1–2 примера правильных и неправильных начал.

Нестабильность JSON. На длинном входе модель может вернуть JSON с комментарием сверху или с оборванной скобкой. Нужна обёртка, которая парсит ответ и повторяет запрос при ошибке формата.

Зависимость от качества расшифровки. Если Whisper ошибся в таймкодах или разбил слова не по границам предложений, ошибка перейдёт в финальные фрагменты. Проверяйте качество расшифровки до передачи в модель.

Что проверить на этой неделе

  1. Возьмите одну часовую расшифровку и запустите наивный промпт «найди 6 интересных моментов». Посмотрите, сколько фрагментов начинаются с середины фразы или содержат галлюцинированные таймкоды.
  2. Напишите функцию build_sentences для вашего языка программирования. Склейте слова в предложения, сохраните тайминги границ.
  3. Переформулируйте промпт: вместо «верни секунды» — «выбери диапазоны номеров предложений». Добавьте ограничение по длине (15–75 секунд) и количество фрагментов.
  4. Добавьте проверку на связки в начале предложения. Если модель возвращает фрагмент, начинающийся с «Но», «Поэтому», «И», «А», отбрасывайте его или запрашивайте перевыбор.
  5. Оберните вызов модели в повтор при ошибке JSON. Если ответ не парсится, отправляйте запрос снова с указанием «верни только валидный JSON без комментариев».
  6. Сравните результаты: сколько времени ушло на ручную проверку до и после изменения подхода. Если разница меньше 30%, возможно, ваш текущий промпт уже достаточно хорош — но в большинстве случаев она будет в 3–5 раз.

Источники

Генерация изображения

  • Модель: flux-schnell
  • Провайдер: replicate

Что почитать дальше

Теги