Динамический промптинг, или RAG наоборот

1a2924947fc30cc8ee86b040444b14cc.jpg

Привет! На связи снова команда LegalDocs правового департамента ПАО «Сбербанк». В прошлый раз мы рассказали вам о конструкторе извлечения для аналитиков, а сегодня хотим поделиться с вами, как мы сделали «RAG наоборот» — выработали методику автоматизации рутинных задач аналитиков.

Для начала напомним, что RAG (Retrieval‑Augmented Generation) — это такой способ применения больших языковых моделей (LLM), при котором мы не доверяем LLM «сгенерировать» ответ на интересующий нас вопрос, а подставляем в выдачу один или несколько фактов из базы знаний. Её мы предварительно подготовили для тех задач, где генерация, скажем так, не полезна. Как можно догадаться, юридическая сфера и, в частности, извлечение фактов (NER) для правовых экспертиз — как раз из числа таких задач. В целом, когда размер (в токенах) извлекаемой из контекста информации невелик, большие языковые модели неплохо справляются с задачей NER, хотя периодически и пытаются вставить отсебятину там, где требуемый для принятия решения факт в тексте отсутствует.

Но в поиске методов, позволяющих улучшить качество работы LLM в наших конвейерах, мы пошли ещё дальше и применили RAG для поиска и подстановки в промпт примеров (few‑shots). В результате мы получили прирост по F1-мере до нескольких десятых (порядка 0,2 на таком типе документа как протокол корпоративного одобрения сделки), а заодно придумали способ, позволяющий не только снять значительную часть рутинной нагрузки, но и ускорить процесс работы над ошибками конвейера.

В чём сложности работы с юридическими текстами?

Юридические тексты содержат много специфической терминологии и ссылок на положения и нормы. При этом одна норма может ссылаться на другую, иногда отменяя или противореча предыдущим. Как мы выяснили, экспериментируя с LLM, сокращать и даже пересказывать юридические тексты нельзя, потому что во время сокращения и пересказа можно утратить важные для принятия решения юридические факты.

Юридические факты — информация или обстоятельства, которые имеют юридическое значение и могут играть роль в правовых анализах, решениях или процессах.

Дополнительная сложность работы с юридическими фактами заключается в том, что они имеют многослойную иерархическую структуру (см. рисунок 1). И для правильного принятия решения роботу‑юристу (патентованная Сбером система принятия правовых решений) нужно, чтобы каждый «лист» этого «дерева» был корректно определён.

При этом мы знаем, что моделей машинного обучения, работающих со стопроцентной точностью, в природе не существует. Как, впрочем, и людей, но проверять работу моделей всё‑таки нужно, для чего проверку извлечённых сущностей осуществляют специалисты‑верификаторы.

Рис. 1. Фрагмент структуры юридических фактов, необходимых для проверки одобрения сделки

Рис. 1. Фрагмент структуры юридических фактов, необходимых для проверки одобрения сделки

На рисунке 1 показана часть структуры фактов в протоколах об одобрении сделки. Для корректного принятия решения необходимо идентифицировать, что нужные нам данные (вид оплаты за кредит, период, дата начала и так далее) связаны с конкретной кредитной сделкой, которая является частью формулировки значимого вопроса (ФЗВ) об одобрении, зафиксированного в протоколе. Внутри этих данных также есть своя иерархия и дополнительные связи, например, «ПериодПлаты» в нашем примере относится не просто к сделке, а к конкретному виду платы внутри сделки. Ошибка в установлении этих связей может привести к неверной интерпретации данных. Кроме того, критически важным моментом при извлечении юридических фактов является сохранение логических связей. Поэтому для анализа юридических текстов наиболее подходящий формат выходных данных — это формат дерева, так как юридические документы имеют иерархическую структуру со связями между определёнными элементами.

У этой сложности, однако, есть и положительная черта: мы можем количественно измерить качество работы модели (будь то BERT или LLM), «посчитав», сколько раз модель правильно нашла в тексте тот или иной важный для принятия решения факт. А также мы можем экспериментировать с разными моделями «под капотом» нашего конвейера и сравнивать их друг с другом, выбирая те, которые работают быстрее, дешевле или качественнее (помним, что из этих трёх качеств одновременно можно выбрать только два).

Почему LLM?

Про большие языковые модели сказано уже довольно много, но конкретно для работы с юридическими текстами важно, что модели предобучены на огромном массиве данных, в том числе — юридических. А ещё они обладают большим окном внимания: от 8 тысяч токенов против 512 у BERT, которые считались «золотым стандартом качества» до всеобщего увлечения LLM. Когда мы только начинали экспериментировать с LLM, они уже показывали неплохие результаты на NER‑задачах «из коробки», но если их ещё снабдить некоторым количеством few‑shot‑примеров, чего мы от них и ожидаем (для чего нам опять‑таки пригождается большой размер контекста), — они начинают творить почти чудеса!

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

  • Большинство представленных на рынке LLM относятся к генеративным моделям. А это значит, что как бы мы ни старались «убить» в них стремление к галлюцинированию путём выкручивания температуры (или иных аналогичных параметров) в ноль или околонулевые значения (зависит от конкретной модели), они всё равно будут стараться что‑нибудь да сгенерировать. Мы как‑то столкнулись с тем, что модели становилось скучно закрывать скобки в.json‑формате и она начинала фантазировать с другими знаками препинания или забывала про них вообще. Часто это можно починить с помощью библиотек валидации.json‑формата, но не всегда.

  • Зависимость качества выдачи LLM от качества промпта. И вот мы вплотную подошли к тем практиками управления промптом (prompt engineering), которые, смеем полагать, у нас получаются довольно неплохо.

Передаваемый в большую языковую модель промпт состоит из:

  • System prompt — системного промпта, стартовой установки, которая определяет общие правила поведения модели.

  • Format instructions — инструкций, направляющих модель на выполнение конкретной задачи.

  • Schema — схемы данных, в которой даётся определение ожидаемой структуры выходных данных и описание атрибутов, которые необходимо извлечь. Также мы задаём иерархию сущностей и атрибутов, про важность которых мы говорили выше, определяем множественность и тип данных, которые хотим извлечь: текстовый, категориальный или булев (True/False).

  • Examples — примеров, демонстрирующих пример запроса и ожидаемый подходящий ответ.

  • Input — текущего документа или (кон)текста, из которого нужно извлечь информацию.

Рис. 2. Пример логики формирования промпта для извлечения

Рис. 2. Пример логики формирования промпта для извлечения

После того как промпт сформирован и запрос отправлен в модель, LLM генерирует ответ в виде JSON‑строки с вложенными структурами, то есть дерево, где значения атрибутов соответствуют извлечённым данным. Использование примеров существенно улучшает качество извлечения из небольших и не очень сложных структур информации, но, как упоминалось выше, большинство юридических документов содержат сложные взаимосвязи, которые модель не способна извлекать последовательно и связно.

Что такое динамический промптинг и чем он отличается от статического?

Вот мы и подошли к главной идее статьи. Всё описанное выше подразумевает, что промпт подбирается человеком и фиксируется для определённого типа документа в рамках определённой задачи. Но такой подход может приводить к ограниченным результатам. Как упоминалось ранее, одной из сложностей извлечения является то, что документы одного и того же типа могут сильно отличаться по структуре, стилю и содержанию, в связи с чем статичные промпты могут быть недостаточно гибкими для эффективной адаптации модели к этим различиям. В результате качество извлечения может оказаться ниже ожидаемого.

«А что если подбирать примеры динамически?» — подумали мы… и придумали следующий конвейер:

Рис. 3. Схема конвейера по обогащению промпта перед отправкой в LLM

Рис. 3. Схема конвейера по обогащению промпта перед отправкой в LLM

Наша гипотеза состояла в том, что документы со схожим содержанием будут разбираться похожим образом, то есть во few‑shot«ы будет эффективнее включать фрагменты документов, похожих на документ в запросе. И эта гипотеза полностью оправдалась! Но есть ряд хитростей, о которых стоит помнить.

Первая хитрость: выбор оптимальной модели генерации векторных представлений (эмбеддингов). Это важно, поскольку в базе данных мы храним не фрагменты текстов, а их векторные представления — чтобы искать похожие друг на друга кусочки текста по формуле косинуса между векторами:

https://i0.wp.com/neptune.ai/wp-content/uploads/2022/10/Recommender-Systems-ML-Metrics-vs-Business-Metrics_10.png?resize=474%2C110&ssl=1

Рис 4. Формула косинуса угла между n-размерными векторами x и y

Поскольку в LLM мы отдаём не сам эмбеддинг, а соответствующий ему текст, нужно, чтобы модель генерации векторных представлений обладала, с одной стороны, достаточно развёрнутым словарём (от этого зависит качество), а с другой стороны, работала достаточно быстро, не добавляя ожидания к работе с большой языковой моделью. Мы применяем модель Е5, но будем признательны за комментарии читателей, если есть соображения по альтернативам.

Вторая хитрость — это найти оптимальный размер фрагмента текста так, чтобы он содержал достаточно информации, но при этом не слишком много — что плохо как для скорости обработки (и разметки), так и для качества (после определённой величины качество работы конвейера начинает падать с ростом размером фрагментов). На рисунке 5 показан пример разбиения текста на фрагменты с гранулярностью до предложения, но на практике гранулярность, как правило, несколько выше.

Рис. 5. Примерная величина косинусной близости (размеченных) фрагментов в БД примеров и фрагмента из текста в поле input

Рис. 5. Примерная величина косинусной близости (размеченных) фрагментов в БД примеров и фрагмента из текста в поле input

Динамический промптинг позволяет модели адаптироваться к запросу, используя методы информационного поиска, благодаря которому модель получает лучшее представление о задаче, что снижает качество ошибок и повышает качество выводов. Ещё одно преимущество динамического промптинга — это его масштабируемость. Такой подход легко распространить на различные типы документов, а при получении на вход нового по структуре и смыслу документа такой текст также векторизуется и добавляется в базу данных, что ускоряет создание нового конвейера.

Выводы

Во‑первых, разработанный нами подход позволяет автоматизировать такую достаточно трудоёмкую рутинную задачу как подбор примеров для подстановки в промпт, и при этом увеличить качество работы NER‑конвейера. В приведённом в этой статье примере с протоколами о корпоративном одобрении сделки прирост F1-меры, определяемой по сравнению с заранее размеченными эталонами, составил более 0,2.

Во‑вторых, этот же подход позволяет быстрее исправлять те ошибки конвейера извлечения, которые вызваны неудачно подобранными примерами. Всё, что нужно делать по мере накопления примеров — регулярно обновлять векторную базу данных. Пересобирать конвейер при этом не требуется, а это уже существенная экономия времени и ресурсов.

Описанная в статье технология доступна в рамках навыка извлечения юридически значимых фактов ИИ‑помощника юриста GigaLegal. Ознакомиться подробнее и запросить демо можно по ссылке.

© Habrahabr.ru