Руководство по построению модульных рабочих процессов для структурированной аналитики
Делиться

Введение
Разрабатывая простые рабочие процессы LLM для задач структурированного извлечения данных, я со временем обнаружил в них несколько подводных камней. В одном из своих проектов я разработал два независимых рабочих процесса, используя Grok и OpenAI, чтобы посмотреть, какой из них лучше подходит для структурированного извлечения данных. Тогда я заметил, что оба пропускали факты в случайных местах. Более того, извлекаемые поля не соответствовали схеме.
Чтобы решить эти проблемы, я настроил специальные проверки обработки и валидации, которые заставляли LLM повторно обращаться к документу (как второй проход), чтобы отследить недостающие факты и добавить их обратно в выходной документ. Однако многократные проверки приводили к превышению ограничений API. Более того, тонкая настройка подсказок была настоящим узким местом. Каждый раз, когда я изменял подсказку, чтобы LLM не пропускал факты, возникала новая проблема. Важным ограничением, которое я заметил, было то, что, хотя одна LLM хорошо работала с набором подсказок, другая не так хорошо работала с тем же набором инструкций. Эти проблемы побудили меня искать механизм оркестровки, который мог бы автоматически точно настраивать мои подсказки в соответствии со стилем подсказок LLM, обрабатывать пропуски фактов и гарантировать, что мои выходные данные соответствуют моей схеме.
Недавно я наткнулся на LangExtract и попробовал её. Эта библиотека решила несколько моих проблем, в частности, связанных с выравниванием схемы и полнотой фактов. В этой статье я объясняю основы LangExtract и то, как она может дополнить простые рабочие процессы LLM для решения задач структурного извлечения. Я также хочу поделиться своим опытом работы с LangExtract на примере.
Почему LangExtract?
Известно, что при настройке чистого рабочего процесса LLM (например, с использованием OpenAI для сбора структурированных атрибутов из корпуса) необходимо разработать стратегию фрагментации для оптимизации использования токенов. Также потребуется добавить специальную обработку пропущенных значений и несоответствий форматирования. Что касается проектирования подсказок, вам придётся добавлять или удалять инструкции в подсказке на каждой итерации, чтобы оптимизировать результаты и устранить расхождения.
LangExtract помогает справиться с вышеперечисленным, эффективно координируя запросы и выходные данные между пользователем и LLM. Он точно настраивает запросы перед передачей их LLM. В случаях, когда входной текст или документы большие, он разбивает данные на фрагменты и передает их LLM, гарантируя соблюдение ограничений на количество токенов, установленных каждой моделью (например, ~8000 токенов для GPT-4 против ~10000 токенов в Claude). В случаях, когда скорость критически важна, можно настроить распараллеливание. Если ограничение на количество токенов является ограничением, можно настроить последовательное выполнение. Я постараюсь подробно рассмотреть работу LangExtract и его структуры данных в следующем разделе.
Структуры данных и рабочий процесс в LangExtract
Ниже представлена диаграмма, показывающая структуры данных в LangExtract и поток данных из входного потока в выходной поток.

LangExtract хранит примеры в виде списка объектов пользовательских классов. У каждого объекта-примера есть свойство «text», представляющее собой образец текста из новостной статьи. Другое свойство — «extraction_class» — категория, присваиваемая новостной статье LLM во время выполнения. Например, новостная статья о поставщике облачных услуг будет помечена тегом «Облачная инфраструктура». Свойство «extraction_text» — это справочный вывод, который вы предоставляете LLM. Этот справочный вывод помогает LLM вывести наиболее близкий вывод, ожидаемый для похожего фрагмента новости. Свойство «text_or_documents» хранит фактический набор данных, требующий структурированного извлечения (в моём примере входными документами являются новостные статьи).
Инструкции по созданию подсказок в виде нескольких снимков отправляются выбранному LLM (model_id) через LangExtract. Основная функция LangExtract 'extract()' собирает подсказки и передает их LLM после тонкой внутренней настройки подсказки в соответствии со стилем подсказок выбранного LLM и для предотвращения несоответствий модели. Затем LLM возвращает результат по одному за раз (т. е. по одному документу за раз) в LangExtract, который, в свою очередь, возвращает результат в объекте-генераторе. Объект-генератор похож на временный поток, который возвращает значение, извлеченное LLM. Аналогом генератора, являющегося временным потоком, может служить цифровой термометр, который выдает текущие показания, но не сохраняет их для дальнейшего использования. Если значение в объекте-генераторе не получено немедленно, оно теряется.
Обратите внимание, что свойства «max_workers» и «extraction_pass» подробно обсуждались в разделе «Рекомендации по использованию LangExtract».
Теперь, когда мы увидели, как работает LangExtract и какие структуры данных он использует, давайте перейдем к применению LangExtract в реальном сценарии.
Практическая реализация LangExtract
В данном примере используется сбор новостных статей из RSS-лент techxplore.com, относящихся к сфере бизнеса в сфере технологий (https://techxplore.com/feeds/). Для анализа URL и извлечения текста статей используются Feedparser и Trifaltura. Пользователь создает запросы и примеры и передает их в LangExtract, который выполняет оркестровку, обеспечивая соответствие запроса используемому LLM. LLM обрабатывает данные на основе инструкций из запроса и предоставленных примеров и возвращает их в LangExtract. LangExtract снова выполняет постобработку перед отображением результатов конечному пользователю. Ниже представлена диаграмма, показывающая, как данные поступают из источника входных данных (RSS-ленты) в LangExtract и, наконец, через LLM для получения структурированных результатов.

Ниже приведены библиотеки, которые были использованы для этой демонстрации.
Сначала мы присваиваем URL-адрес RSS-ленты Tech Xplore переменной «feed_url». Затем мы определяем список «keywords», содержащий ключевые слова, связанные с технологическим бизнесом. Мы определяем три функции для анализа и извлечения новостных статей из новостной ленты. Функция «get_article_urls()» анализирует RSS-ленту и извлекает заголовок статьи и URL-адрес отдельной статьи (ссылку). Для этого используется Feedparser. Функция «extract_text()» использует Trifaltura для извлечения текста статьи из URL-адреса отдельной статьи, возвращаемого Feedparser. Функция «filter_articles_by_keywords» фильтрует полученные статьи на основе списка ключевых слов, заданного нами.
После выполнения вышеизложенного мы получаем вывод:
«Найдено 30 статей в RSS-ленте.
Отфильтрованные статьи: 15″
Теперь, когда список «filtered_articles» доступен, мы переходим к настройке подсказки. Здесь мы даём инструкции, позволяющие LLM определить, какой тип новостной информации нас интересует. Как объяснялось в разделе «Структуры данных и рабочий процесс в LangExtract», мы настраиваем список пользовательских классов с помощью «data.ExampleData()» — встроенной структуры данных в LangExtract. В данном случае мы используем подсказку с несколькими примерами.
Мы инициализируем список «results», а затем циклически проходим по корпусу «filtered_articles», извлекая по одной статье за раз. Выходные данные LLM доступны в объекте-генераторе. Как было показано ранее, поскольку выходное значение в «result_generator» является временным потоком, оно немедленно добавляется к списку «results». Переменная «results» представляет собой список аннотированных документов.
Мы перебираем результаты в цикле for, чтобы записать каждый аннотированный документ в JSONL-файл. Хотя это необязательный шаг, при необходимости его можно использовать для аудита отдельных документов. Стоит отметить, что в официальной документации LangExtract есть утилита для визуализации этих документов.
Мы циклически просматриваем список «results», чтобы собрать все извлечения из аннотированного документа по одному за раз. Извлечение — это не что иное, как один или несколько атрибутов, запрошенных нами в схеме. Все такие извлечения хранятся в списке «all_extractions». Этот список представляет собой упрощённый список всех извлечённых данных в формате [extraction_1, extraction_2, extraction_n].
Мы получаем 55 извлечений из 15 статей, собранных ранее.
Заключительный шаг включает итерацию по списку «all_extractions» для сбора каждого извлечения. Объект Extraction — это настраиваемая структура данных в LangExtract. Атрибуты собираются из каждого объекта извлечения. В данном случае Attributes — это объекты словаря, содержащие имя и значение метрики. Имена атрибутов/метрик соответствуют схеме, изначально запрошенной нами в рамках запроса (см. список «examples» словаря «attributes» в объекте «data.Extraction»). Окончательные результаты предоставляются в виде фрейма данных, который можно использовать для дальнейшего анализа.
Ниже представлен вывод, показывающий первые пять строк фрейма данных:

Рекомендации по эффективному использованию LangExtract
Подсказка с несколькими кадрами
LangExtract разработан для работы с однократной или многократной структурой подсказок. При использовании многократной структуры подсказок требуется указать подсказку и несколько примеров, поясняющих ожидаемый результат от магистра права. Этот стиль подсказок особенно полезен в сложных междисциплинарных областях, таких как торговля и экспорт, где данные и терминология в одном секторе могут значительно отличаться от данных в другом. Вот пример: в новостном фрагменте говорится: «Стоимость золота выросла на X», а в другом — «Стоимость определенного типа полупроводника выросла на Y». Хотя в обоих фрагментах говорится «стоимость», они означают совершенно разные вещи. Когда речь идет о драгоценных металлах, таких как золото, стоимость основана на рыночной цене за единицу, тогда как в случае с полупроводниками это может означать объем рынка или стратегическую ценность. Предоставление примеров, специфичных для предметной области, может помочь магистрам права получить метрики с учетом нюансов, требуемых предметной областью. Чем больше примеров, тем лучше. Широкий набор примеров может помочь как модели LLM, так и LangExtract адаптироваться к различным стилям письма (в статьях) и избежать ошибок при извлечении.
Многоэкстракционный проход
Проход многократного извлечения (Multi-Extraction) — это процесс, в ходе которого LLM повторно обращается к входному набору данных более одного раза, чтобы заполнить информацию, отсутствующую в выходных данных в конце первого прохода. LangExtract направляет LLM повторное обращение к набору данных (входным данным) несколько раз, подстраивая подсказку во время каждого прохода. Он также эффективно управляет выходными данными, объединяя промежуточные выходные данные из первого и последующих проходов. Количество необходимых проходов указывается с помощью параметра 'extraction_passes' в модуле extract(). Хотя в данном случае подойдет проход извлечения '1', любое значение больше '2' поможет получить более точно настроенный и согласованный с подсказкой и предоставленной схемой вывод. Более того, проход многократного извлечения 2 или более гарантирует, что выходная схема соответствует схеме и атрибутам, указанным в описании подсказки.
Распараллеливание
При наличии больших документов, которые потенциально могут потреблять допустимое количество токенов за запрос, идеальным решением будет последовательный процесс извлечения. Последовательный процесс извлечения можно включить, установив max_workers = 1. Это заставит LangExtract принудительно обрабатывать запрос LLM последовательно, по одному документу за раз. Если скорость имеет решающее значение, можно включить распараллеливание, установив max_workers = 2 или более. Это гарантирует, что для процесса извлечения будут доступны несколько потоков. Более того, модуль time.sleep() можно использовать при последовательном выполнении, чтобы гарантировать, что квоты запросов LLM не будут превышены.
Как распараллеливание, так и многопроходный процесс извлечения могут быть установлены следующим образом:
Заключительные замечания
В этой статье мы узнали, как использовать LangExtract для структурированного извлечения данных. К настоящему моменту должно быть понятно, что наличие такого инструмента, как LangExtract, для вашего LLM может помочь с тонкой настройкой подсказок, фрагментацией данных, разбором выходных данных и выравниванием схемы. Мы также увидели, как LangExtract работает внутри, обрабатывая запросы в соответствии с выбранной LLM и преобразуя необработанные выходные данные LLM в структуру, согласующуюся со схемой.
Источник: towardsdatascience.com





















