Pull to refresh
8K+
6
Проваторов Александр@AlexProvatorov

Python Backend Developer

19,1
Rating
2
Subscribers
Send message

Спасибо за глубокий разбор с кодом! Результаты бенчмарков в 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 в отчёт), чтобы такие документы реже доходили до модели.

Information

Rating
426-th
Registered
Activity

Specialization

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