TL;DR
TL;QR (Too Long; Query with logical temporal Reasoning) делит работу пополам. LLM отвечает только на локальные вопросы про каждый отдельный текст, например «этот отзыв положительный?». Всё остальное делает обычный движок на правилах: считает, упорядочивает, сравнивает группы и ищет окна во времени. Паттерн описывается одним запросом на специальном языке. Перед LLM стоит дешёвый фильтр по ключевым словам (regexp), и в модель попадает лишь малая часть корпуса.
Главная находка: LLM плохо справляются со счётом и порядком событий на длинной дистанции, даже если сами тексты понимают прекрасно. Типичная картина: «группа перешла от поддержки к критике» превращается в «то нашла, то нет, а даты съехали». Авторы проверили это отдельно. Одна LLM извлекла те же метки, что и TL;QR, а вторая LLM рассуждала по ним о времени. Эта связка оказалась заметно хуже движка, а на некоторых задачах хуже даже простого запроса «найди сам». Значит, проблема не в разметке, а в том, что модель считает «в голове».
Метод работает в 4 шага: фильтр → разметка LLM → подсчёт по скользящему окну → правило срабатывания. Каждый найденный случай привязан к конкретным фрагментам и решениям модели, поэтому результат можно перепроверить.
Схема метода
ШАГ 1: Regexp-фильтр отсекает неподходящие тексты → остаются «кандидаты» (LLM не вызывается)
ШАГ 2: LLM отвечает «да/нет» на локальный вопрос по каждому кандидату → метки Pos / Neg
ШАГ 3: Движок считает метки в скользящем окне (ONCE [0,N], CNT) → «в основном за / против»
ШАГ 4: Движок проверяет условие сдвига (было «за», стало «не за») → найденная группа + время + список фрагментов-доказательств
Шаги 1–4 выполняет движок, а не один промпт. LLM вызывается только на шаге 2.
Пример применения
Задача: Аналитик «Самоката» хочет понять, в каких городах отзывы о доставке за последний год перешли от «в основном хвалят» к «в основном ругают». Отзывов десятки тысяч. Просить чат «найди города, где тон испортился» бесполезно: он собьётся на счёте и датах.
Запрос (по структуре из статьи, окно 90 дней, g — город):
LET Snip(g, s) = EXISTS r. Review(r, g, s)
AND /(доставк|курьер|опозд|свеж|просроч)/s IN
LET Pos(g) = EXISTS s. Snip(g, s)
AND "{s} — положительный отзыв о доставке" IN
LET Neg(g) = EXISTS s. Snip(g, s)
AND "{s} — отрицательный отзыв о доставке" IN
LET PosN(g,x) = x <
CNT (t; g; ONCE [0,90] (Pos(g) AND tp (t))) IN
LET NegN(g,y) = y <
CNT (t; g; ONCE [0,90] (Neg(g) AND tp (t))) IN
LET MostlyPos(g) = EXISTS x,y.
PosN(g,x) AND NegN(g,y) AND x >= y IN
Neg(g) AND PREV MostlyPos(g) AND NOT MostlyPos(g)
Результат: Движок вернёт список городов, где тон сменился, и дату сдвига. К каждому городу приложены отзывы-доказательства и счётчики «за/против» в окне. Отзывы без слов про доставку в LLM не попадут, это экономит вызовы. Метки можно проверить вручную на выборке.
Почему это работает
Слабость LLM. Задача «посчитай, упорядочь и сравни по тысячам текстов» требует держать счётчик в голове на длинной дистанции. Модель генерирует правдоподобный текст, а не считает. Ошибки накапливаются, и результат расплывается.
Сильная сторона LLM. На коротком локальном вопросе («тон этого фрагмента положительный?») она точна. Это её родная территория.
Как метод использует это. Модели отдают только локальные суждения. Подсчёт, окна и условие сдвига переходят к программе, которая не ошибается в арифметике. Так точность растёт, а проверка становится возможной: любой вердикт раскладывается на конкретные фрагменты.
Рычаги управления:
- Regexp-фильтр → расширь слова, чтобы не терять релевантное (полнота), или сузь, чтобы меньше платить.
- Формулировка утверждения в кавычках → точнее вопрос, точнее метки. Это главная точка настройки качества.
- Окно ONCE [0,N] → короче окно ловит быстрые сдвиги, длиннее сглаживает шум.
- Условие в последней строке → заменяй на своё: «набрал ≥15 негативных за окно», «отложил решение и не вернулся».
- Размер модели → в экспериментах дешёвая модель в TL;QR работала почти так же, как дорогая.
Шаблон промпта
Это шаблон запроса на языке TL;QR, с сохранением каскада из статьи. Подставь свои данные:
LET Snip(g, s) = EXISTS e. {Событие}(e, g, s)
AND /({слова_фильтра})/s IN
LET Pos(g) = EXISTS s. Snip(g, s)
AND "{s} {утверждение_позитив}" IN
LET Neg(g) = EXISTS s. Snip(g, s)
AND "{s} {утверждение_негатив}" IN
LET PosN(g,x) = x <
CNT (t; g; ONCE [0,{окно_дней}] (Pos(g) AND tp (t))) IN
LET NegN(g,y) = y <
CNT (t; g; ONCE [0,{окно_дней}] (Neg(g) AND tp (t))) IN
LET MostlyPos(g) = EXISTS x,y.
PosN(g,x) AND NegN(g,y) AND x >= y IN
Neg(g) AND PREV MostlyPos(g) AND NOT MostlyPos(g)
{Событие}— тип записи в корпусе (Review, Speech, Ticket).g— группа, по которой ищешь сдвиг (город, партия, клиент).{слова_фильтра}— корни слов через|.{утверждение_…}— короткая проверяемая фраза про фрагмент.{окно_дней}— размер скользящего окна.
🚀 Быстрый старт — вставь в чат:
Вот шаблон запроса TL;QR. Адаптируй под мою задачу: [твоя задача].
Задавай вопросы, чтобы заполнить поля.
[вставить шаблон выше]
LLM спросит, что за тексты, по какой группе искать сдвиг, какие слова отсекают лишнее и какое окно нужно. Эти четыре вещи определяют фильтр, группировку, утверждения для разметки и окно подсчёта. Структуру каскада она возьмёт из шаблона.
Запросы выполняет открытый движок TL;QR, а не сам чат. Чат поможет написать и отладить запрос.
Ограничения
⚠️ Нужен движок, а не промпт: метод — это инструмент: установка, Python, ключи API, запросы на специальном языке. Без этого он не работает. В обычном чате применим только сам принцип разделения труда.
⚠️ Синтетические данные: количественная проверка шла на сгенерированных парламентских корпусах. Реальный язык грязнее, формулировки хитрее.
⚠️ Сложные паттерны всё равно тяжёлые: на задаче «отложил позицию и не вернулся» метод набрал лишь 62–75% точности (F1), хотя соперники были ещё хуже.
⚠️ Простые паттерны не требуют метода: в сдвиге тона на малых корпусах обычный запрос с сильной моделью тоже дал почти 100%. Метод окупается на длинных корпусах и сложных условиях.
⚠️ Фильтр может отрезать нужное: regexp, составленный неудачно, теряет релевантные тексты, и LLM их уже не увидит.
⚠️ Реальный кейс без эталона: на парламенте ЕС метод нашёл только «кандидаты на сдвиги». Истинность не проверяли. Результат — повод изучить, не вердикт.
⚠️ Только прошлое: язык поддерживает лишь операторы «что было раньше», будущее не описать.
Как исследовали
Идея была простой: если LLM плохи в счёте по времени, отдайте им только разметку. Авторы построили три синтетических парламентских корпуса (1,5 тыс., 3 тыс. и 4,5 тыс. событий) с заранее спрятанными паттернами. Паттерны: смена позиции группы, «отложил и не вернулся», координированная травля цели. Тексты написала LLM, и все методы видели одни и те же данные. Сравнивали TL;QR с четырьмя соперниками: словарь с эвристикой, zero-shot, few-shot и связка из двух LLM (первая размечает, вторая рассуждает о времени). Все LLM прогнали в трёх размерах одной линейки моделей, результаты усреднили по трём запускам.
Что удивило: двухступенчатая связка LLM часто проигрывала даже простому запросу. Она получала те же метки, что и TL;QR, но терялась на временной части. Это доказывает, что слабое место — именно рассуждение о времени, а не разметка. На «отложил и не вернулся» TL;QR дал 62–75% против 30–45% у лучших LLM-соперников. На травле — около 100% против 0–33%.
Затем метод применили к 442 593 речам Европарламента за десять лет на теме GDPR. Стоимость LLM составила менее $2 благодаря фильтру и кэшу одинаковых запросов. Для практика вывод такой: самое дорогое и ненадёжное место в анализе текстов во времени — это не разметка, а счёт и порядок.
Адаптации и экстраполяции
🔧 Техника: перенеси принцип в обычный чат → то же разделение труда без движка
Идея: LLM размечает, а счёт делает таблица или скрипт.
Шаг 1. Вот {N} отзывов с датами и городами. Для каждого верни строку
таблицы: дата | город | про_доставку (да/нет) | тон (положительный/
отрицательный/нейтральный). Больше ничего не считай и не выводи выводов.
Шаг 2 (новый чат или код). Вот таблица. Напиши формулу Excel или
скрипт Python: по каждому городу посчитай за скользящие 90 дней число
положительных и отрицательных и найди даты, когда «положительных ≥
отрицательных» сменилось на обратное.
Это перенос принципа, а не метод из статьи. Но он следует из её главной находки: LLM не должна считать сама. Для больших объёмов разбивай отзывы на пачки.
Экстраполяция: проверка метки перед счётом.
Вот 30 случайных строк из таблицы с твоими метками. Для каждой скажи,
согласен ли ты с меткой, и если нет — какая метка верна. В конце
посчитай долю несогласий.
Так ты оцениваешь шум в разметке до того, как верить сдвигам. Это вытекает из идеи аудита, но в статье в таком виде не проверялось.
Ресурсы
- Работа: TL;QR: Querying Temporal Discursive Patterns in Textual Corpora
- Авторы: François Hublet, Vladimir Krsmanović, Jesús Solano, Ahmed Bouhoula, Ana Oliveira da Costa
- Организации: ETH Zürich, CISPA Helmholtz Center for Information Security, IST Austria
- Основа: метрическая временная логика первого порядка (MFOTL); символьный движок EnfGuard (Hublet et al., 2025)
- Сопутствующие работы: LOTUS, Palimpzest, DocETL, VectraFlow
