Головна / Статті

Від простого підходу до готового рішення RAG для звітів SEC 10-K: формування частин даних, гібридний пошук.

Чому підхід RAG у підручниках зазнав невдачі при обробці 300-сторінкових звітів 10-K та як це виправити: частини даних з урахуванням структури розділів, гібридний пошук, переранжування за допомогою крос-кодерів, перевірка та посилання на метадані.

Видавець: REACTAPP.TOP8 хв читання1758 слів

Джерела: **How I Built a RAG Pipeline on Legal & Financial Documents and What Actually Broke?**

Пайплайн, який виглядав правильно, але повертав неправильні дані

Уявіть собі пайплайн типу RAG для подання звітів SEC 10-K, створення якого зайняло три тижні; він використовує LangChain для обробки даних, ChromaDB як базу векторних даних, чистий скрипт для імпорту даних у Python та оптимізований інтерфейс Streamlit. Простий перший тест полягає у з’ясуванні, які критичні аспекти аудиту стосуються визнання доходів. Система відповідає, повністю впевнена в собі, про компенсацію керівництва з зовсім іншого розділу документа. Слово „галюцинація“ тут не зовсім підходить – текст є справжнім, але походить з неправильної частини 300-сторінкового документа, причому система нічого цього не помітила.

Виглядати як система RAG та функціонувати як така — це різні речі. Нижче наведені рішення щодо розділення тексту на частини, проблеми зі знаходженням інформації, експерименти з використанням ембеддингів, набір даних для оцінки, створений з необхідності, а також версія, яка нарешті скоротила час ручної перевірки на 65%. Кожен, хто розробляє функції на основі справжніх документів, а не примітивних PDF-файлів, може уникнути тижнів марної роботи над навчанням.

Чому документи 10-K важко знаходити

Розглядати документ 10-K як звичайний PDF — це недооцінка його складності. Звіт середньої чи великої публічної компанії має від 150 до 400 сторінок, у яких є фінансові таблиці, примітки, що посилаються на інші примітки, довгі юридичні формулювання, описи ризиків та коментарі керівництва. Метою пошуку були критичні аудиторські питання (Critical Audit Matters, CAM), де аудитори пояснюють найскладніші чи найбільш суб’єктивні аспекти своєї роботи.

Те, що читач хоче знайти, таке як терміни, пов’язані з ризиками, та висновки аудиту, розподілено нерівномірно. Це зосереджено у певних розділах, написаних спеціалізованою лексикою, та пов’язано з цифрами, які не мають значення поза контекстом. Слід розглядати документ як набір окремих фрагментів, і система пошуку більшість часу обирає неправильні з них, що саме і сталося з першою версією.

Два підходи поруч

Різниця між версіями містить усі уроки.

Версія 1 була заснована на класичному підході: завантажувався PDF, розділявся на фрагменти по 500 токенів із перекриттям у 50 токенів, вставлявся за допомогою моделі OpenAI text-embedding-ada-002, зберігався у ChromaDB, для запиту вибиралися найкращі 5 фрагментів, які потім передавалися GPT-4 для створення резюме. Цей підхід працював ефективно з простими запитами до чистих документів, але при роботі з щільним 300-сторінковим документом зазнавав проблем трьома конкретними способами.

Версія 2 має значно більше етапів: обробку PDF, шар виявлення розділів, розділово-орієнтоване розділення на частини з розмірами, що змінюються залежно від типу розділу, позначення метаданих для кожної частини, модель вбудовування даних з урахуванням контексту домену, зберігання в ChromaDB із детальними метаданими, переписування запитів, гібридний пошук (семантичний та за ключовими словами), переранжування, перевірка та, нарешті, генерація. Кожен етап існує з певної причини, яка буде розглянута далі.

Перша проблема: фіксовані частини розривають контекст

Найбазовіша помилка версії V1 полягала у використанні частин по 500 токенів, що розрізали текст у будь-якому місці. Документи типу 10-K мають природну структуру: вони складаються з заголовка, опису, відповіді аудитора та часто посилання на фінансову записку, причому їх довжина може сягати 600–800 токенів. Розділення на частини по 500 токенів часто розрізало такий документ навпіл — опис потрапляв у одну частину, а відповідь у іншу, тож жодна з них сама по собі не була корисною.

Виправленням стало додавання шару виявлення розділів перед процесом розділення на частини. pdfplumber аналізував структуру документа для пошуку меж розділів, заголовків, підзаголовків та країв таблиць, після чого розділення відбувалося всередині розділів, а не між ними, з використанням розмірів, які враховували природні перерви. У випадку щільних фінансових таблиць утворювалися невеликі частини об’ємом приблизно 200–300 токенів, щоб зберегти можливість пошуку деталей на рівні рядків. У розповідних розділах, таких як CAM та інформація про ризики, утворювалися великі частини об’ємом до 800–900 токенів, щоб зберегти цілісність кожної логічної одиниці. Рівень перекриття залишався на рівні 10% від розміру частини. Ця єдина зміна значно покращила релевантність результатів пошуку ще до того, як було змінено щось інше.

Друга проблема: ембеддинги, які не враховували фінансову лексику

text-embedding-ada-002 є потужною універсальною моделлю, хоча її не тренували спеціально на фінансовому чи юридичному тексті, і це проявляється при роботі з щільними аудиторськими документами. Запит щодо сфер оцінки визнання доходів призвів до отримання фрагментів про доходи та про процес прийняття рішень у загальному сенсі. Деякі з них походили з обговорень керівництва, деякі — з приміток, а кілька — з не пов’язаних з цим ризикових заяв; сам модуль CAM для визнання доходів не було вдалося знайти надійно.

Було протестовано два варіанти. Новіша модель OpenAI text-embedding-3-large значно покращила якість пошуку. Гібридний підхід, який поєднував щільний векторний пошук із розрідженим пошуком за ключовими словами BM25 та об’єднував результати, виявився кращим за кожен з методів окремо. Логіка проста: щільний пошук знаходить контент, концептуально пов’язаний із запитом, тоді як розріджений пошук знаходить точну термінологію. У фінансових текстах точність формулювань має величезне значення. Фраза „критичне питання аудиту“ не є тотожною фразі „суттєва проблема аудиту“ у юридичній термінології, і наявність обох показників суттєво підвищує точність. Для розрідженого пошуку використовувалась бібліотека Python rank_bm25, а проста функція об’єднання рангів з використанням взаємних коефіцієнтів об’єднувала два списки результатів перед їхнім повторним ранжуванням.

Третя проблема: відсутність перевірки, впевнені неправильні відповіді

Це була найтихіша та найнебезпечніша проблема. У версії V1 некоректні фрагменти даних, отримані під час пошуку, все одно змушували ШІ давати відповіді, а GPT-4 дуже добре вміє виглядати впевненим у собі навіть за обмежених умов. Його відповіді не були очевидно неправильними — це були правдоподібні узагальнення того, що надійшло, навіть коли ці фрагменти походили з неправильної частини документа.

Проблему виявила лише невелика набір даних для оцінки: 30 пар питань та відповідей, перевірених вручну за певними документами, кожна з яких мала позначки з точними фрагментами джерела, які мали б бути використані. За цими критеріями V1 знаходив правильні фрагменти джерела приблизно у 55% випадків, а у решті 45% випадків створював логічний текст на основі нерелевантних даних.

Два зміни виправили проблему. Першою була стадія переранжування: крос-енкодер від HuggingFace під назвою ms-marco-MiniLM-L-6-v2 переоцінив десять отриманих фрагментів, і лише три найкращі потрапили до генератора. Крос-енкодери працюють повільніше, ніж бі-енкодери, але забезпечують значно точніше ранжування, оскільки запит та потенційний фрагмент обробляються як один вхід замість двох окремих.

Другою зміною був механізм перевірки перед генерацією. Він перевіряв, чи містять отримані фрагменти ідентифікатори розділів, які очікуються з метаданих часу отримання даних. Наприклад, коли запит щодо CAMs повертав фрагменти з таблиць компенсацій, перевірка провалювалась, і система переписувала запит та намагалася ще двічі, перш ніж позначити відповідь як ненадійну. Це відрізняє демо-версію від продакшн-системи: демо охоплює успішні сценарії, тоді як продакшн працює з 45% випадків, коли цей сценарій не діє.

Метадані кожного фрагмента

Одне з рішень щодо дизайну рідко згадується у навчальних матеріалах RAG: наявність детальних метаданих, приєднаних до кожного фрагмента. Кожен фрагмент у колекції ChromaDB містив такі поля:

  • section_type – частина документа 10-K, з якої він походить, наприклад CAM, розкриття ризиків, фінансові звіти, примітки чи обговорення керівництва
  • section_title – точний заголовок над контентом
  • page_range – сторінки джерельного документа, які охоплює фрагмент
  • document_id – ідентифікатор документа у вигляді тикера компанії та фінансового року
  • has_table – булеве значення, яке позначає наявність табличних даних
  • fiscal_year – період звітності

Метадані виконували дві функції. Вони дозволяли фільтроване пошукове знаходження: для запитань, пов’язаних з аудитом, пошук міг попередньо фільтрувати результати за типом розділу critical_audit_matter перед векторним пошуком, що суттєво звужувало обсяг даних. Вони також забезпечували роботу рівня цитування в інтерфейсі користувача, адже кожне резюме містило посилання на сторінки та розділи, з яких воно було складене, що дозволяло аудиторам негайно перевіряти джерела.

У інструментах фінансового аудиту цитування є обов’язковим. Аудитор, який не може підтвердити походження резюме, не може покладатися на нього, а автоматичне створення цитувань на основі метаданих перетворило систему з засобу для досліджень на інструмент, яким користувачі можуть ефективно працювати.

Кінцева система

Повний процес, який скоротив час аудиторського перегляду на 65%, складається з трьох рівнів.

  • Прийом даних: pdfplumber, виявлення розділів, динамічне розділення на частини, вилучення метаданих, вбудовування з використанням text-embedding-3-large, потім зберігання у ChromaDB із повними метаданими.
  • Запит: переписування запиту (переформулювання за допомогою LLM для більшої конкретності), фільтроване пошукове отримання даних із попереднім фільтруванням метаданих за типом розділу за потреби, гібридний метод пошуку dense плюс BM25 для вибору топ-10 результатів, переранжування за допомогою cross-encoder до топ-3, перевірка на коректність, генерація тексту за допомогою GPT-4, додавання посилань та відображення у інтерфейсі.
  • Оцінка: набір даних із 30 елементів, відстеження точності пошуку та оцінка якості відповідей, використання LLM як оцінювача для визначення релевантності, точності та повноти інформації.

Фронтенд Streamlit надавав аудиторам поле для введення запиту, створений огляд, посилання на джерела, які розкривалися за запитом, та індикатор впевненості, отриманий на етапі перевірки.

Що потрібно зробити інакше

  • Спочатку створіть набір даних для оцінки. Його було складено у відчаї після невдачі V1, і він має бути присутнім з самого початку. Без вимірювань нічого не покращується, а фраза «здається кращим» не є показником.
  • Рано розробіть схему метаданих. Щоб її правильно сформувати, знадобився час, проте кожна година принесла кількакратну вигоду у якості пошуку та завдяки функціям інтерфейсу, які вона дозволила реалізувати. Метадані заслуговують на першорядне становище в архітектурі.
  • Вважайте, що парсер PDF пропускає щось. pdfplumber є чудовим інструментом, проте об’єднані клітинки, повернуті верхні частини або позначки приміток усередині клітинок у фінансових таблицях все ще можуть його спантеличити. Фіксуйте кожну аномалію під час обробки та регулярно переглядайте ці записи, адже безслідні помилки під час обробки — це найскладніші баги для виявлення згодом.
  • Ставте під сумнів кожну стандартну налаштування. Стандартний розмір частин, стандартна модель ембеддингу та стандартний показник top-k існують тому, що вони в середньому працюють прийнятно, але тип документа може не бути типовим. Протестуйте кожне з них на реальних даних.

Результат

Після впровадження система витягувала та узагальнювала інформацію про критичні аудиторські аспекти, витрачаючи на це на 65% менше зусиль, ніж попередній процес. Виконуючи функцію першого етапу перевірки, вона знаходила відповідні розділи та складала структуровані узагальнення, тож аудитори могли перейти від витягування та синтезування інформації до її перевірки та оцінки.

Останній момент є найважливішим. Метою ніколи не було замінити судження аудитора, а лише усунути механічні, трудомісткі кроки, щоб експертна оцінка залишалася там, де це важливо. Добре спроєктовані системи на основі LLM не замінюють експертизу — вони спрямовують її у правильне русло.

Пов’язана література

  • Практичні нотатки: ZQ Intelligence: Orchestrator-Specialist Agents для фінансів — Детальний огляд Практичних нотаток: ZQ Intelligence: Orchestrator-Specialist Agents для фінансів: контракти, перевірки та шаблони коду для команд, які використовують цю модель.
  • Виправлення проблем RAG за допомогою онтології та графа знань у документації до напівпровідників — Як набір документації EDA на основі DITA отримав онтологію RDF/OWL, граф Neo4j та механізм пошуку з обмеженнями онтології, що дозволило скоротити кількість додаткових запитів на 30%.
  • Коли індексування RAG зупиняється: стандартна кількість шардів у OpenSearch, яку ніхто не ставить під сумнів — Кластер RAG із нормальною роботою процесора, пам’яті та диска припинив індексування. Причиною стала стандартна кількість шардів у OpenSearch, а також правила розмірювання, шаблони та безпечний шлях для переіндексації.