Обновить
7
Проваторов Александр@AlexProvatorov

Python Backend Developer

1
Рейтинг
5
Подписчики
Отправить сообщение

Всем привет! Решил сразу подсветить пару моментов в комментариях, чтобы направить обсуждение в продуктивное русло:

  1. Почему именно Bitcoin? Данные по BTC взяты исключительно как живой, агрессивный и максимально волатильный датасет. На нём очень удобно гонять детекторы аномалий (Ruptures) — тут вам и крах FTX, и Terra/Luna, и банковские кризисы. Задача была проверить фреймворк на "грязных" реальных данных за 4.5 года, а не спекулировать на цене.

  2. Проблема с котами и уверенностью 1.0 (Fallback): Да, подстановка первого документа по BM25 при ReadTimeout от Ollama с выдачей confidence=1.00 — это явный архитектурный костыль текущей версии, который будет поправлен в будущем релизе. Я специально не стал вырезать этот failure mode из отчётов, чтобы честно показать, как это работает на текущий момент с локальной моделью.

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

Спасибо за вопрос.

Да, сейчас единственный способ отличить их снаружи это confidence=1.00 + один cause + шаблонная фраза "may be related to X", но это эвристика читателя, а не явный флаг от системы. Как раз в roadmap стоит post-ranker фильтр с разметкой "correlation_only / likely_cause" — по сути это и есть явный флаг вместо угадывания по паттерну. Пока не сделал, потому что хотелось сначала понять частоту и природу самого fallback на реальных данных — эта статья и была таким замером.

Спасибо за вопрос.

По коду Pipeline на том прогоне восемь explain шли через asyncio.gather, то есть стартовали вместе. Wall-clock — а время до завершения самого позднего запроса.

Ollama на одной GPU при этом обычно почти сериализует генерацию. Запрос в очереди для httpx — всё ещё ожидание ответа, поэтому хвост очереди на 32B чаще упирается в 180 с и уходит в fallback. Поднять timeout до 400–500 с имело бы смысл, если цель — дождаться именно 32B-ответов: больше шансов, что хвост очереди успеет посчитаться. Цена — дольше ждать весь gather (ближе к сумме инференсов в очереди). Для статьи важнее было уложиться в разумное время и получить воспроизводимый прогон, а не выжать максимум из 32B.

14B тут не костыль вокруг лимита, а практичный выбор: на той же GPU она быстрее → короче очередь → реже timeout при 180 с → меньше fallback. Для этого шага пайплайна топовая модель и не обязательна: на вход уже есть детекция, окно и отранжированные evidence, на выход нужен структурированный JSON-черновик гипотез. Сильнее модель имеет смысл позже, точечно, когда правишь формулировки или разбираешь спорные даты.

Надеюсь ответил на вопрос.

Спасибо за отличный вопрос. Отвечу структурно.

Keyword задаёт аналитик при сборке пайплайна (CSVSource(..., keyword="...")GoogleTrends("...") и т.п.). Ряд даёт только момент аномалии и окно ±window_days. Collectors ищут внешние материалы по этому keyword и датам. Ranker (BM25 или embeddings) упорядочивает уже найденные тексты — эмбеддинг не "угадывает причину из графика", а ранжирует документы относительно запроса/события.

Магазин A и пожар в B
Если keyword — только "магазин A", фреймворк сам слово "пожар" не выведет. Причину найдет лишь если в окне дат попалась подходящая новость/пост и она поднялась в ранге — или если аналитик задал более широкий/умный keyword. Иначе честный исход: мало evidence или ложная/слабая корреляция.

WhyTrend не заменяет аналитика и не выводит причинность из кривой. Он ускоряет рутину: быстрее карта аномалий + черновик гипотез со ссылками в том же временном окне(автоматизация рутины). Гипотезу, keyword и финальный вывод по-прежнему делает человек.

Завтра выйдет статья про "разбор аномалий BTC 2022–2026 с WhyTrend". Рассмотрим как это работает на практике: keyword + окно + внешний контекст. Как раз релевантный кейс — длинный ряд, много переломов, keyword очевиден (Bitcoin), причины обычно в том же информационном поле (новости/HN в окне дат), а руками это долго гонять по каждой точке. Фреймворк как раз ускоряет эту рутину: карта аномалий -> контекст -> черновик гипотез. Там будет видно где и в чем происходит ускорение работы аналитика. Не "доказали причинность", а "быстро собрали расследование по публичному рынку".

Кейс с пожаром у конкурента — другая задача: нужна гипотеза аналитики или более широкий keyword.

Спасибо за глубокий разбор с кодом! Результаты бенчмарков в worst-case сценарии действительно впечатляют.

Но возникает философский вопрос: да, инкрементальный сборщик проигрывает по объему памяти в разы, но в абсолютных цифрах (даже на ваших утяжеленных тестах) речь идет о разнице в пару гигабайт. При этом по latency (особенно p99) инкрементальный алгоритм показывает отличные результаты, минимизируя stop-the-world паузы. Для многих realtime-сервисов (например, в финтехе или геймдеве) плавность работы и предсказуемые задержки критичнее, чем лишние гигабайты оперативной памяти на сервере, которой обычно с запасом.

Не кажется ли вам, что лишение разработчиков выбора (полный откат вместо внедрения флага запуска, как в Go или Java) — это слишком радикальный шаг со стороны core-разработчиков Python? Почему, по вашему мнению, они так упорно отказываются поддерживать два алгоритма параллельно, пусть даже инкрементальный шел бы с пометкой "experimental"?

Никакие :) Весь код проекта от первой до последней строчки написан вручную. Кода там на самом деле не так много, архитектура достаточно компактная, и мне было важно и интересно самому спроектировать взаимодействие через протоколы (typing.Protocol) и логику конвейера. Так что в плане логики тут исключительно чистый ручной крафт!

Единственное — я привлекал LLM, чтобы немного "причесать" структуру и английский язык в README. Но на саму кодовую базу это никак не повлияло.

Спасибо за вопрос)

Спасибо, за вопрос)
В статье «BM25 против эмбеддингов» — скорее про почему BM25 появился раньше, а не про то, что эмбеддинги хуже. BM25 и эмбеддинги не противники, а комплементарные сигналы. Сейчас в WhyTrend они просто живут как два независимых Ranker (BM25Ranker / EmbeddingRanker) — в pipeline пока выбирается один, без merge.

Гибрид через RRF как раз хорошо ложится на архитектуру: отдельный HybridRanker, который гоняет оба скорера и склеивает списки. Это логичный следующий шаг по качеству retrieval, рядом с тем, что уже обсуждаем для слоя после ranker (пороги relevance, более умный rerank, меньше ложных корреляций).

По контекстуальному чанкингу — идея сильная для длинных документов, но у WhyTrend evidence чаще уже короткое (title + snippet из API). Там выигрыш меньше, чем в классическом RAG по PDF/базе знаний. Имеет смысл там, где collector тащит длинные тексты (релизы, тикеты, внутренние wiki) — тогда summarize-before-embed как опция к embedding-ветке.

Заголовок, похоже, получился чуть конфликтнее, чем задумывалось 🙂

Спасибо за вопрос — это главная ловушка explainable anomaly detection / RAG.

WhyTrend не претендует на доказательство причинности. Задача сейчас — быстро собрать кандидатов и черновик гипотезы, а не заменить каузальный анализ.

Как снижаем риск ложной корреляции (мягко):

  1. Ограничение контекста. LLM видит только collectors + ranker; промпт запрещает выдумывать факты и просит при слабом evidence снизить confidence. Галлюцинаций меньше, но «дотянуть» историю из совпадения по дате модель всё ещё может.

  2. Прозрачность. В отчёте остаются cited causes (источник, URL, score) и confidence — аналитик видит, на чём стоит вывод, и может отбраковать мусор.

  3. Модульность. Для узких метрик лучше свои collectors (деплои, акции, логи), а не надежда, что Google News + BM25 отделят причину от шума.

Жёсткого фильтра «только совпадение → drop», каузальных тестов и обязательного no_causal_link пока нет: BM25/embeddings ранжируют похожесть текста, не причинность.

В планах — слой после ranker (до explainer): пороги relevance, умнее rerank и явный вердикт (evidence_insufficient / correlation_only / likely_cause). Плюс на стороне ряда в dev уже есть ZScoreDetectorProphetDetector и RupturesDetector — разные типы аномалий ловим, а вот anti false-correlation для объяснений как раз следующий шаг что добавиться в roadmap. Спасибо, что подсветили это.

Хороший вопрос. Да, это учтено на двух уровнях.

1. Изоляция источников. Коллекторы крутятся через asyncio.gather(..., return_exceptions=True). Если Reddit отдаёт 429 или падает с ошибкой, исключение не валит весь pipeline: этот источник просто не добавляет evidence, остальные продолжают работу.

2. Таймауты HTTP. У встроенных collectors из коробки есть timeout (по умолчанию 10 секунд) на httpx-клиент — «зависший» сокет не держит конвейер бесконечно. Значение можно подкрутить в конструкторе, например RedditCollector(timeout=5.0).

Важно: это таймаут сетевых запросов, а не отдельный deadline на весь кастомный collect(). Retry при 429 и circuit breaker пока не встроены — при желании их легко добавить в свой collector или обертку. Идея та же: один капризный источник не должен ронять объяснение аномалии целиком.

Да — на одних только стандартных публичных коллекторах (Wikipedia / HN / общий Google News) узкий B2B-кейс вроде локального магазина автозапчастей обычно не взлетит: в открытом интернете часто просто нет сигнала, а BM25 ранжирует уже собранное и «из воздуха» индустриальный контекст не достанет.

WhyTrend задуман как фреймворк (подключаемые Source / Collector / Ranker / Explainer), а не готовое SaaS «под любую нишу из коробки». Сила в том, что под задачу пишете свой CompetitorPromoCollector или OrdersSQLCollector, цепляете в Pipeline — а ранжирование и суммаризацию WhyTrend берёт на себя. Для тихих бизнес-метрик кастомные (часто внутренние) collectors — нормальный и ожидаемый путь, а не костыль.

Фреймворк модульный и сам по себе «внутренности» компании не видит. Если в Pipeline подключены только внешние источники (Google News, Hacker News и т.п.), а про ваш деплой / падение БД / наплыв ботов в открытом интернете тишина, WhyTrend не сможет надёжно назвать настоящую причину: у него просто нет этих данных.

В лучшем случае, когда внешний контекст пустой или явно слабый, LLM по системному промпту должна сказать, что внешних подтверждений нет, и снизить confidence. Но если внешние новости за ту же дату просто «рядом» по словам, модель всё ещё может ошибочно к ним притянуться — это не железный отказ по низкому BM25 (ranker сейчас ранжирует, а не отбрасывает шум).

Прелесть WhyTrend в другом: пользователь может написать свой InternalSlackCollector или GitLabReleasesCollector на базе BaseCollector, подключить через .add_collector(...) в Pipeline — и тогда фреймворк сможет связать внутренний деплой / инцидент с графиком метрик. Без внутренних источников остаётся честный ответ: «аномалия есть, внешней причины не видно».

Спасибо за отличный вопрос! Вы затыкаете пальцем самую уязвимую зону всех RAG-систем.

В текущей реализации WhyTrend эта проблема решается двумя барьерами:

  1. Жёсткий системный промпт (Prompt Engineering): Мы не просто отдаем модели текст со словами "объясни аномалию". В Explainer зашит системный промпт с правилами:

    • опираться только на переданный event и evidence;

    • не выдумывать источники, URL и факты;

    • если evidence слабый или отсутствует — сказать об этом прямо и снизить confidence. 


    Современные LLM (вроде тех же Qwen 2.5 или DeepSeek) при таком ограничении работают на удивление честно и вместо фантазий выдают что-то вроде: "Контекст найден, но явной причинно-следственной связи не прослеживается".

  2. Прозрачность для пользователя: Даже если модель немного притянет версию, в Markdown-отчёте WhyTrend видны cited causes: источники, URL и score. Пользователь может открыть ссылки и понять, на чём строился вывод. Если материалы мусорные — человек это быстро заметит. Инструмент не заменяет аналитика, а готовит первый черновик.

В планах — усилить отсев текстового шума ещё до LLM (например, cross-encoder / более умное переранжирование и явный вывод ranked evidence в отчёт), чтобы такие документы реже доходили до модели.

Информация

В рейтинге
1 973-й
Зарегистрирован
Активность

Специализация

Бэкенд разработчик
Средний
Python
FastAPI
SQL
NoSQL
Docker
Apache Kafka
RabbitMQ
Grafana
Apache Airflow
CI/CD