Почему результаты поиска, которые отлично выглядят на бумаге, в реальных рабочих процессах RAG и работы с агентами могут вести себя как шум?
Делиться

Вдохновлено статьей/публикацией в блоге ICLR 2026 под названием «Парадокс 99% успеха: когда почти идеальный поиск равен случайному выбору».
Получив степень доктора философии в области информационного поиска в Эдинбурге в лаборатории мультимедийного информационного поиска Виктора Лавренко, где я проходил обучение в конце 2000-х годов, я долгое время рассматривал поиск информации в рамках традиционного подхода к информационному поиску:
- Удалось ли нам получить хотя бы один релевантный фрагмент?
- Увеличилось ли количество отзывов продукции?
- Улучшились ли результаты ранжировщика?
- Выглядело ли качество ответа на последующих этапах приемлемым по результатам сравнительного анализа?
Это по-прежнему полезные вопросы. Но после ознакомления с недавними работами по теме «Биты поверх случайных чисел» (BoR) я думаю, что они неполны для агентных систем, которые многие из нас сейчас фактически создают.

В статье в блоге ICLR я еще раз убедился в том, что давно чувствовал, работая с системами LLM: качество поиска должно учитывать как количество найденного качественного контента, так и количество нерелевантного материала. Другими словами, чем больше мы используем для запоминания, тем выше риск загрязнения контекста .
Полезность BoR заключается в том, что он предоставляет нам язык для этого. BoR показывает, действительно ли поиск является избирательным, или же мы достигаем успеха в основном за счет заполнения контекстного окна большим количеством материала. Когда BoR падает, это признак того, что найденный набор становится менее дискриминационным по сравнению со случайным совпадением. На практике это часто коррелирует с тем, что модель вынуждена читать больше мусора, больше пересечений или больше слабо релевантного материала.
Важный нюанс заключается в том, что BoR не измеряет напрямую то, что модель «чувствует» при чтении подсказки. Он измеряет избирательность извлечения информации относительно случайности . Но более низкая избирательность часто идет рука об руку с большим количеством нерелевантного контекста, большим количеством «загрязнения» подсказкой, большей рассредоточенностью внимания и худшими результатами в дальнейшем. Проще говоря, BoR помогает нам определить, когда извлечение информации все еще является избирательным, а когда оно начинает вырождаться в перенасыщение контекстом .
Эта идея имеет гораздо большее значение для RAG и агентов, чем для классического поиска.
Почему панели мониторинга поиска информации могут вводить в заблуждение команды агентов.
Одна из самых распространенных ловушек в RAG — это взглянуть на панель мониторинга поиска, увидеть хорошие показатели и сделать вывод, что система работает хорошо. В результате вы можете увидеть:
- высокий успех@K,
- хорошая память,
- хороший показатель ранжирования,
- и, по-видимому, большее значение K улучшает охват.
На бумаге всё может выглядеть лучше, но в реальности агент может вести себя хуже. У вашего агента может быть множество проблем, таких как нечёткие ответы на запросы, ненадёжное использование инструментов или просто увеличение задержки и стоимости токенов без какой-либо реальной пользы для пользователя.
Это несоответствие возникает потому, что большинство панелей мониторинга поиска по-прежнему отражают человеческое мировоззрение. Они предполагают, что потребитель полученного набора данных может бегло просматривать, фильтровать и игнорировать ненужную информацию. Люди на удивление хорошо справляются с этим. А вот специалисты в области управления обучением не всегда хорошо справляются с этим.
Модель LLM не «замечает» десять найденных элементов и не сосредотачивается на двух лучших, как это сделал бы опытный аналитик. Она обрабатывает весь набор данных как контекст для подсказок. Это означает, что слой поиска выявляет доказательства, которые активно формируют рабочую память модели.
Вот почему я считаю, что командам, работающим с агентами, следует перестать рассматривать поиск как задачу ранжирования в бэк-офисе и начать рассматривать его как задачу распределения бюджета на основе рассуждений . При создании высокопроизводительных агентных систем ключевой вопрос заключается в следующем:
- Удалось ли нам найти что-нибудь полезное?
и:
- Какой уровень шума мы заставили обработать модель, чтобы получить этот результат?
Именно на этот взгляд вас направляет BoR, и я считаю его очень полезным.
Контекстная инженерия становится первоклассной дисциплиной.
Одна из причин, по которой эта статья нашла у меня отклик, заключается в том, что она вписывается в более широкую тенденцию, уже происходящую на практике. Инженеры-программисты и специалисты по машинному обучению, работающие над системами LLM, постепенно становятся чем-то большим, чем просто инженерами контекста .
Это означает разработку систем, которые принимают решения:
- Что следует ввести в подсказку?
- когда оно должно войти,
- в какой форме?
- с какой степенью детализации,
- а то, что следует полностью исключить.
В традиционном программном обеспечении нас беспокоят ограничения памяти, вычислительных ресурсов и API. В системах LLM нам также необходимо беспокоиться о чистоте контекста . Контекстное окно — это спорная когнитивная область.
Каждый нерелевантный фрагмент, дублированный фрагмент, слабо связанный пример, многословное определение инструмента и несвоевременный результат поиска конкурируют с тем, на чём модели нужно сосредоточиться больше всего. Вот почему мне нравится метафора загрязнения. Нерелевантный контекст загрязняет рабочее пространство модели.
Плакат BoR придает этой интуиции более строгую форму, указывая на то, что мы должны перестать оценивать поиск только по тому, насколько он успешен. Мы также должны задаться вопросом, насколько лучше поиск по сравнению со случайным результатом на той глубине (K наиболее часто извлекаемых элементов), которую мы фактически используем. Это очень полезный для практиков вопрос.
Почему перегрузка инструментами приводит к сбоям в работе агентов
Именно здесь, на мой взгляд, работа над BoR становится особенно важной для реальных агентных систем.
В классическом алгоритме RAG корпус данных часто бывает большим. Вам может потребоваться извлечение информации из десятков тысяч или миллионов фрагментов. В этом режиме случайность остается слабой в течение более длительного времени. Выбор инструментов существенно отличается.
В случае с агентом модель может выбирать из 20, 50 или 100 инструментов. Это кажется выполнимым, пока вы не поймете, что несколько инструментов часто смутно подходят для одной и той же задачи. Как только это происходит, включение всех инструментов в контекст перестает быть тщательным подходом. Это путаница, замаскированная под полноту.
Я неоднократно сталкивался с этой закономерностью в разработке агентских программ:
- Команда добавляет новые инструменты.
- описания становятся длиннее,
- Перекрытие между инструментами увеличивается.
- Агент начинает принимать нерешительные или противоречивые решения.
- И первое, что приходит в голову, — это усилить настойчивость в подсказке.
Но зачастую реальная проблема носит архитектурный, а не технический характер. От модели требуется выбор в перегруженном контексте, где различия слишком слабы и многочисленны.
В данном случае BoR предлагает полезный способ формализации того, что люди часто ощущают лишь интуитивно: существует точка, когда задача выбора становится настолько сложной, что модель перестает демонстрировать значимую избирательность.
Вот почему я отдаю предпочтение агентным архитектурам со следующими особенностями:
- Поэтапный поиск инструментов: поэтапное сужение поиска, сначала нахождение небольшого набора подходящих инструментов, а затем окончательный выбор из этого короткого списка, а не из всей библиотеки сразу.
- Маршрутизация по предметной области: перед окончательным выбором инструмента необходимо сначала определить, к какой широкой области относится задача, например, поиск, CRM, финансы или программирование, и только затем выбрать конкретный инструмент в этой области.
- Сокращенные описания возможностей: представление каждого инструмента с кратким, содержательным описанием его назначения, случаев применения и отличий от аналогичных инструментов, вместо того чтобы вываливать в командную строку длинные и подробные спецификации.
- Явное исключение нерелевантных инструментов: преднамеренное удаление инструментов, не подходящих для текущей задачи, чтобы модель не отвлекалась на правдоподобные, но ненужные варианты.
По моему опыту, выбор инструмента следует рассматривать скорее как поиск информации, чем как статическое оформление подсказок.
Понимание баланса ответственности посредством выбора инструментов
Одно из самых полезных свойств BoR заключается в том, что он помогает агентам, использующим инструменты, точнее понять, что на самом деле означает top-K .
В поиске документов увеличение количества лучших K фрагментов часто означает переход от 5 лучших фрагментов к 20 или 50 лучшим из очень большого корпуса. В выборе инструментов тот же шаг имеет совершенно иной характер. Когда у агента есть лишь скромная библиотека инструментов, увеличение количества лучших K может означать переход от короткого списка из 3 инструментов-кандидатов к 5, затем к 8 и, в конечном итоге, к знакомому, но опасному запасному варианту: просто использовать все 15 инструментов для безопасности.
Это часто улучшает показатель полноты или успешности при K, поскольку правильный инструмент с большей вероятностью находится где-то в видимом наборе. Но это улучшение может ввести в заблуждение. По мере роста K вы помогаете не только маршрутизатору, но и облегчаете случайному селектору включение соответствующего инструмента.
Таким образом, настоящий вопрос заключается не просто в том, содержал ли топ-8 полезный инструмент чаще, чем топ-3? Более важный вопрос: улучшил ли топ-8 осмысленную избирательность или же он в основном упростил задачу за счет включения элементов методом перебора? Именно здесь BoR становится полезным.
Простой пример проясняет ситуацию. Предположим, у вас есть 10 инструментов, и для заданного класса задач 2 из них действительно актуальны. Если вы покажете модели только 1 инструмент, случайная вероятность появления актуального инструмента составит 20 процентов. При наличии 3 инструментов случайный базовый уровень резко возрастает. При наличии 5 инструментов случайная вероятность уже достаточно высока. При наличии 10 инструментов она достигает 100 процентов, потому что вы показали все инструменты. Таким образом, да, показатель Success@K растет по мере роста K. Но смысл этого успеха меняется. При низком K успех указывает на реальную избирательность. При высоком K успех может просто означать, что вы включили достаточное количество инструментов из меню, чтобы неудача стала затруднительной.
Вот что я имею в виду под помощью случайности, а не осмысленным отбором .
Это важно, потому что в случае с инструментами проблема хуже, чем просто вводящая в заблуждение метрика. Когда вы показываете слишком много инструментов, запрос становится длиннее, описания начинают перекрываться, модель видит больше близких совпадений, различия становятся более размытыми, возрастает путаница с параметрами, и увеличивается вероятность выбора правдоподобного, но неправильного инструмента. Таким образом, даже несмотря на улучшение показателя полноты top-K, качество окончательного решения может ухудшиться. Это парадокс малого количества инструментов: добавление большего количества инструментов-кандидатов может увеличить кажущийся охват, одновременно снижая способность агента сделать правильный выбор .
Практический подход к этому вопросу заключается в том, что выбор инструментов часто делится на три режима. В здоровом режиме K невелик по сравнению с количеством инструментов, и появление релевантного инструмента в списке кандидатов говорит о том, что маршрутизатор действительно сделал что-то полезное. Например, 30 инструментов, 2 или 3 релевантных, и список из 3 или 4 все еще воспринимается как настоящий выбор. В серой зоне K достаточно велик, чтобы улучшить показатель полноты (recall), но при этом быстро растет и показатель случайного включения. Например, 20 инструментов, 3 релевантных, список из 8. Здесь вы все еще можете получить что-то, но уже сейчас следует задаться вопросом, действительно ли вы осуществляете маршрутизацию или просто расширяете воронку. Наконец, существует режим коллапса , где K настолько велик, что успех в основном достигается за счет раскрытия достаточного количества инструментов, чтобы случайный выбор также часто оказывался успешным. Если у вас 15 инструментов, 3 релевантных и список из 12 или все 15, то «высокий показатель полноты» уже ничего не значит. Вы приближаетесь к методу грубой силы.
В практическом плане это подталкивает меня к более уместному вопросу. В небольшой системе инструментов я рекомендую избегать подхода, основанного на чрезмерном раскрытии информации, который задает следующие вопросы:
- Каким должно быть значение K, чтобы показатель полноты (recall) выглядел хорошо?
Более уместный вопрос:
- Насколько узким может быть мой список кандидатов, чтобы при этом сохранить высокую эффективность выполнения задач?
Такой подход способствует дисциплинированному планированию маршрутов.
На практике это обычно означает сначала маршрутизацию, а затем выбор, сохранение очень небольшого списка инструментов, сжатие описаний инструментов, чтобы различия были очевидны, разделение инструментов на области перед окончательным выбором и проверку того, улучшает ли увеличение K точность выполнения задачи от начала до конца , а не только полноту поиска инструментов. Полезной проверкой является следующее: если предоставление модели всех инструментов приводит к примерно таким же результатам, как и при использовании вашего списка инструментов, то ваш слой маршрутизации, возможно, не приносит большой пользы. А если предоставление модели большего количества инструментов улучшает полноту поиска, но ухудшает общую производительность задачи, то вы, вероятно, находитесь именно в той ситуации, когда K больше способствует случайности, чем реальной избирательности.
Когда меняется характер отказа: большие библиотеки инструментов.
В случае с большим количеством инструментов ситуация иная, и здесь важен важный нюанс. Большее количество инструментов не означает, что мы должны просто объединить сотни инструментов в одном контексте и ожидать, что система будет работать лучше. Это просто означает изменение характера отказов.
Если у агента есть 1000 доступных инструментов, и лишь немногие из них релевантны, то увеличение списка лучших K инструментов с 10 до 50 или даже 100 всё ещё может представлять собой значимую избирательность. Случайность остаётся слабее дольше, чем в случае небольшого количества инструментов. В этом смысле BoR всё ещё полезен: он помогает нам не путать более широкое распространение с лучшей маршрутизацией. Он задаёт вопрос, отражает ли более широкий список истинную избирательность или же он просто помогает, предоставляя доступ к большей части пространства поиска.
Однако BoR не отражает всей проблемы. При очень больших библиотеках инструментов проблема может заключаться уже не в том, что случайность стала слишком сильной. Проблема может заключаться в том, что модель просто тонет в вариантах . Краткий список из 200 инструментов может быть лучше случайного выбора с точки зрения BoR, и при этом оставаться ужасным вариантом. Описания инструментов перекрываются, количество близких совпадений увеличивается, различия становится сложнее поддерживать, и модель вынуждена рассуждать, используя перегруженное семантическое меню.
Таким образом, BoR (Board of Reference — показатель избирательности) ценен, но сам по себе недостаточен. Он лучше показывает, действительно ли короткий список является дискриминационным по сравнению со случайностью, чем то, остается ли этот список когнитивно управляемым для модели. Поэтому в больших библиотеках инструментов нам необходимы обе перспективы: BoR для измерения избирательности и последующие показатели, такие как качество выбора инструмента, время отклика, правильность параметров и успешность выполнения задачи от начала до конца, для измерения удобства использования.
BoR показывает, действительно ли поиск является избирательным, или же мы достигаем успеха в основном за счет заполнения контекстного окна большим количеством материала. Падение BoR свидетельствует о том, что извлекаемый набор информации становится менее дискриминационным по сравнению со случайностью. На практике это часто коррелирует с тем, что модель вынуждена читать больше мусора, больше дублирующегося или более слабо релевантного материала. Важно понимать, что BoR не измеряет напрямую то, что модель «чувствует» при чтении подсказки. Он измеряет избирательность по сравнению со случайностью. Но низкий BoR часто является предупреждающим сигналом того, что модель вынуждена обрабатывать все более зашумленное контекстное окно.
Смысл проектирования одинаков, хотя причины разные. При небольшом наборе инструментов широкое распространение быстро становится вредным, поскольку слишком сильно влияет на случайность. При очень большом наборе инструментов широкое распространение становится вредным, поскольку перегружает модель. В обоих случаях решение заключается не в том, чтобы добавить больше элементов в контекст, а в том, чтобы разработать более эффективную маршрутизацию.
Моё эмпирическое правило: модель должна видеть меньше, но при этом лучше.
Если бы мне нужно было в одном предложении резюмировать практические изменения, я бы сказал так: для систем LLM меньший размер и более простое решение часто лучше, чем больший размер и более комплексное решение .
Это звучит очевидно, но многие системы по-прежнему проектируются так, как будто «больше контекста» автоматически делает систему безопаснее. В действительности, как только появляется базовый уровень полезных данных, дальнейшее их извлечение может стать вредным. Это увеличивает стоимость токена и задержку, но, что более важно, расширяет поле конкурирующих подсказок внутри запроса.
Я пришел к выводу, что построение подсказок может быть трехслойным:
Уровень 1: обязательный контекст задачи
- Основные инструкции, ограничения и непосредственная цель пользователя.
Слой 2: высокоизбирательное заземление
- Только минимальное количество подтверждающих доказательств или определений инструментов, необходимых для следующего этапа рассуждений.
Слой 3: необязательный перелив
- Материал, который кажется лишь правдоподобным, косвенно связан с темой или включен «на всякий случай».
Большинство сбоев происходит из-за проникновения трафика третьего уровня во второй. Именно поэтому качество восстановления следует оценивать не только по охвату, но и по способности сохранить чистый второй уровень.
В каких случаях, на мой взгляд, BoR особенно полезен?
Я не рассматриваю BoR как замену всем метрикам поиска. Я вижу в нем очень полезный дополнительный инструмент, особенно в следующих случаях:
1. Выбор K в производстве
- Многие команды продолжают увеличивать показатель Top K до тех пор, пока полнота не покажется достаточно хорошей. BoR побуждает задавать более дисциплинированный вопрос: в какой момент увеличение K начинает в основном способствовать случайности, а не значимой избирательности?
2. Оценка маршрутизации инструментов агентов.
- Это, пожалуй, наиболее убедительный вариант использования. Агенты часто терпят неудачу не потому, что нет подходящего инструмента, а потому, что одновременно предлагается слишком много почти подходящих инструментов.
3. Диагностика причин снижения качества продукции на последующих этапах обработки, несмотря на «улучшенную обработку».
- Это классический парадокс. Объем охвата увеличивается, а качество конечного ответа снижается. Метод BoR помогает объяснить, почему.
4. Сравнение систем с различной глубиной извлечения.
- Показатели успешности могут быть обманчивыми, когда одна система извлекает гораздо больше материала, чем другая. BoR помогает нормализовать эти показатели.
5. Предотвращение чрезмерной уверенности в результатах сравнительных тестов.
- Некоторые тестовые задачи могут оказаться слишком простыми при выбранной глубине поиска. Положительный результат может быть скорее следствием удачи, чем мы думаем.
В тех случаях, когда, на мой взгляд, одного лишь механизма BoR может быть недостаточно.
Мне понравилась статья, но я бы не стал рассматривать BoR как окончательный ответ на вопрос оценки эффективности поиска. Есть как минимум несколько важных оговорок.
Во-первых, для выполнения любой задачи достаточно одного качественного элемента. Некоторые задачи действительно требуют обобщения множества доказательств. В таких случаях подход, ориентированный на успех, может недооценивать необходимость более широкого поиска информации.
Во-вторых, полезность извлечения информации не является бинарной. Два фрагмента могут считаться «релевантными», в то время как один из них может быть гораздо более полезным, лаконичным или способствующим принятию решений для модели.
Во-третьих, своевременная организация по-прежнему имеет значение. Шумный, но тщательно структурированный пакет может работать лучше, чем немного более аккуратный, но плохо упорядоченный или неправильно отформатированный пакет.
В-четвертых, важна сама модель. Разные LLM-модели имеют разную устойчивость к загромождению информацией, различное поведение в длительном контексте и разную надежность использования инструментов. Политика поиска, которая загрязняет одну модель, может быть приемлема для другой.
В-пятых, и это особенно актуально для больших библиотек инструментов, BoR говорит нам больше о избирательности, чем об удобстве использования . Краткий список может выглядеть значительно лучше случайного, но при этом быть слишком перегруженным, слишком дублирующимся или слишком семантически запутанным, чтобы модель могла эффективно его использовать.
Поэтому я бы не стал использовать BoR изолированно. Я бы использовал его в сочетании с:
- точность выполнения последующих задач,
- Анализ задержки и стоимости токенов.
- качество вызова инструмента,
- корректность параметров,
- а также определенные меры обеспечения оперативной чистоты или избыточности.
Тем не менее, даже с учетом этих оговорок, BoR вносит важный вклад: он заставляет нас перестать путать охват с избирательностью .
Как это меняет мою практику оценки
Самое существенное практическое изменение заключается в том, что теперь я буду оценивать системы поиска примерно так:
- Во-первых, обратите внимание на стандартные метрики поиска. Они по-прежнему важны. В идеале следует рассмотреть подход «мешок метрик» , использующий несколько взаимодополняющих метрик.
Затем спросите:
- Каков случайный базовый уровень на этой глубине?
- Действительно ли более высокий показатель Success@K свидетельствует о высоком уровне мастерства, или же это просто более лёгкие условия?
- Какой дополнительный контекст мы добавили, чтобы получить этот результат?
- Улучшилось ли качество ответов на последующих этапах, осталось ли неизменным или ухудшилось?
- Мы заставляем модель функционировать логически или просто делаем её более понятной?
В отношении агентов я бы пошел еще дальше:
- Сколько инструментов было видно в момент принятия решения?
- Насколько сильно пересекались возможности различных инструментов-кандидатов?
- Могла ли система сначала проложить маршрут, а затем выбрать второй вариант?
- Предложили ли модели выбирать из четкого списка кандидатов или из обширного меню?
Это более реалистичная схема оценки для тех типов систем, которые многие команды действительно развертывают.
Более широкий урок
Главный вывод, который я сделал из плаката ICLR, гораздо шире, чем просто новый показатель: качество системы LLM во многом зависит от чистоты контекста, который мы создаём вокруг модели. Это имеет последствия для всей системы Agentic:
- извлечение,
- память,
- маршрутизация инструмента,
- планирование работы агентов,
- многоэтапные рабочие процессы,
- и даже дизайн пользовательского интерфейса для систем с участием человека.
Лучшие системы LLM — это те, которые предоставляют нужную информацию в нужный момент в минимальном, чистом виде, при этом поддерживая поставленную задачу . Именно так выглядит качественная разработка контекста.
Заключительная мысль
Долгое время поиск информации сводился в основном к поиску иголок в стоге сена. Для систем LLM этого уже недостаточно. Теперь задача состоит еще и в том, чтобы избежать попадания половины стога сена в подсказку вместе с иголкой.
Вот почему я считаю, что идея BoR важна и оказывает такое значительное влияние. Она дает специалистам более понятный язык для решения реальной производственной проблемы: как измерить, когда полезный контекст незаметно превращается в загрязненный. И как только вы начнете рассматривать свои системы таким образом, многие знакомые сбои агентов начнут обретать гораздо больше смысла.
BoR напрямую не измеряет, что модель «чувствует» при чтении подсказки, но она показывает, когда поиск перестаёт быть осмысленно избирательным и начинает напоминать грубое заполнение контекста. На практике это часто именно тот режим, когда LLM начинают читать больше мусора, рассуждать менее четко и работать хуже в дальнейшем.
В более широком смысле, я думаю, это указывает на важную зарождающуюся подотрасль: разработку более совершенных метрик для измерения производительности систем LLM в реалистичных условиях , а не только возможностей модели в отрыве от контекста. Мы достаточно хорошо научились измерять точность, полноту и производительность в эталонных задачах, но гораздо хуже — измерять, что происходит, когда модель вынуждена рассуждать в загроможденном, перекрывающемся или слабо отфильтрованном контексте.
На мой взгляд, это выявляет реальный пробел. BoR помогает измерить избирательность относительно случайности, что очень ценно. Но всё ещё отсутствует концепция того, что я бы назвал когнитивной перегрузкой : точка, в которой модель, возможно, всё ещё имеет нужную информацию где-то в поле зрения, но работает хуже, потому что одновременно представлено слишком много конкурирующих вариантов, фрагментов, инструментов или подсказок. Другими словами, неудача — это уже не просто неудача в извлечении информации. Это неудача в рассуждениях, вызванная загрязнением информации мгновенными подсказками.
Я подозреваю, что более совершенные способы измерения такого рода когнитивной перегрузки будут становиться все более важными по мере усложнения агентных систем. Следующий шаг вперед может быть сделан не только за счет более крупных моделей или больших контекстных окон, но и за счет более эффективных способов количественной оценки того момента, когда рабочий контекст модели переходит грань от полезной широты к вредной перегрузке.
Вдохновлено статьей/публикацией в блоге ICLR 2026 под названием «Парадокс 99% успеха: когда почти идеальный поиск равен случайному выбору» .
Оговорка: Взгляды и мнения, выраженные в этой статье, являются исключительно моими собственными и не отражают взгляды моего работодателя или каких-либо аффилированных организаций. Содержание основано на личных размышлениях и предположениях о будущем науки и техники. Его не следует интерпретировать как профессиональные, академические или инвестиционные рекомендации. Эти перспективные взгляды призваны стимулировать дискуссию и воображение, а не давать окончательные прогнозы.
Источник: towardsdatascience.com
























