← Блог

Почему AI неправильно понимает длинные тексты

Сережа Рис · 6 February 2026

youtubeclaude code

Генерирую описание для 2.5-часового стрима. В заголовки глав пролез GitHub. Codex — нет. При том что Codex я активно демонстрировал треть видео.

Что случилось

У меня есть многопроходной пайплайн для генерации YouTube-метаданных. Четыре стадии: разбить транскрипт на куски по 5-10 минут, извлечь сущности из каждого куска параллельно, объединить и ранжировать, сгенерировать финальные заголовки и описание.

На стадии агрегации пайплайн ранжировал сущности по concentration_score. Формула примитивная — сколько раз упомянут, в скольких кусках появился.

Обработал стрим “Opus 4.6 и GPT 5.3”. Смотрю на результат:

GitHub — в заголовках. Codex — нет.

Но подождите. GitHub я упоминал мимоходом — в списках инструментов, в контексте “закоммить на GitHub”. А Codex — запускал, демонстрировал, клонировал игры, тестировал подписки. Тридцать процентов видео.

Spread vs depth

Проблема оказалась фундаментальной. Метрика не различала “назвал в списке” и “демонстрировал 20 минут”.

GitHub:  ■□■□■□■□■□■□■□■□■□■□■  (мелькает везде, но мимоходом)
Codex:   □□□□□□□□□□■■■■■■□□□□□  (концентрированно и глубоко)

GitHub разбросан по 8 из 21 чанка — 38% видео. Но в каждом чанке это просто упоминание: “залить на GitHub”, “открыть репозиторий”. Одно слово в потоке.

Codex сконцентрирован в 6 чанках — 30% видео. Но в каждом я его активно использую: генерирую проекты, клонирую Vampire Survivors, тестирую лимиты.

Метрика видела spread. Не видела depth.

Похоже на проблему TF-IDF в информационном поиске. Наивная TF (term frequency) считает слова — и common words типа “the” доминируют. IDF (inverse document frequency) фильтрует шум, взвешивая по редкости. Мой concentration_score был наивной TF — считал mentions без учёта того, насколько глубоко entity вовлечён.

Пять фиксов

1. Новая формула

relevance_score = avg_role × time_share × total_mentions

Три множителя вместо двух. avg_role — средняя глубина вовлечённости (от 1 до 3). time_share — доля видео, где entity присутствует. total_mentions — суммарные упоминания.

По-моему, это ≈ TF-IDF для видео. avg_role × time_share фильтрует шум как IDF. total_mentions — это TF.

2. Роли на стадии извлечения

Раньше Stage 2 считал только количество упоминаний. Добавил роль — как именно entity используется в каждом куске:

Role Что значит Пример
3 main_focus Спикер демонстрирует Codex, строит проект
2 actively_used Деплоит на Railway как инструмент
1 mentioned “Можно залить на GitHub” в списке

GitHub в большинстве чанков получал role=1. Codex — role=2 и role=3.

3. Activity-first заголовки

Раньше: берём самую популярную entity → ставим в заголовок.

Теперь: сначала описываем что спикер ДЕЛАЕТ → entity появляется только если она в фокусе.

BEFORE                              AFTER
─────                               ─────
"GitHub и инструменты"      →       "Регистрация на хакатон в боте"
"Сравнение моделей: Opus    →       "Тестирование Codex и подписки"
 vs Codex"

4. Жёсткие пороги

Entity попадает в заголовок только если выполнены ВСЕ три условия:

title_eligible = (
    time_share >= 0.10      # присутствует в ≥10% видео
    and avg_role >= 2.0      # активно используется, не просто упоминается
    and total_mentions >= 10  # достаточно упоминаний
)

GitHub: time_share=38.6% ✓, mentions=22 ✓, но avg_role=1.75 ✗. Не прошёл.

Codex: time_share=29.8% ✓, mentions=31 ✓, avg_role=2.33 ✓. Прошёл.

5. Детектор фабрикаций

Заголовки LLM любит приукрашивать. Поэтому добавил два валидатора.

Narrative fabrication detector — ловит паттерны выдуманных нарративов:

Keyword grounding — больше 50% значимых слов в заголовке должны встречаться в анализах чанков. Если слово не из транскрипта — заголовок галлюцинирует.

Когда агент сгенерировал “Сравнение моделей: Opus vs Codex” — валидатор поймал паттерн “vs” и зарубил. Заменили на “Тестирование Codex и подписки” — activity-first, grounded.

Что получилось

Данные из реального прогона:

Entity          mentions  chunks  time_share  avg_role  score   title?
───────────────────────────────────────────────────────────────────────
Claude Code     28        8       36.6%       2.50      25.62   ✓
Codex           31        6       29.8%       2.33      21.54   ✓
GitHub          22        8       38.6%       1.75      14.86   ✗
Agent Teams     16        3       14.4%       2.67       6.16   ✓
Railway         14        3       14.6%       2.67       5.44   ✓
Warp            —         —        <10%       1.00       —      ✗

Claude Code — основной инструмент стрима, score=25.62. Codex — второй по значимости, score=21.54. GitHub — третий по score, но avg_role=1.75 < 2.0, в заголовки не попал. Warp — периферийный, даже порог time_share не прошёл.

21 глава стрима. Заголовки соответствуют тому, что я делал, а не тому, что мимоходом называл.

Вывод

Метрика без глубины взаимодействия — мусор. Как наивная TF без IDF: common words доминируют, важное теряется.

avg_role × time_share × mentions решает ту же задачу для видео, что TF-IDF для текста. Глубина вовлечённости (role) и временное покрытие (time_share) фильтруют шум. Только entities с role ≥ 2.0 и time_share ≥ 10% попадают в заголовки.

GitHub корректно отфильтрован. Codex корректно в заголовках. Пайплайн перестал врать про содержание видео.

Подписаться на обновления — @sereja_tech