Зміст
Демонстраційний RAG «завантажує PDF» як одну операцію: файл → текст → фрагменти → вектори. У продакшені це чотири різні контури, і ламається зазвичай перший. Сканований договір перетворюється на кашу колонок, таблиця втрачає заголовок, колонтитул стає найчастішим «фактом» корпусу, а нова редакція регламенту живе поряд зі старою без періоду дії. Завантаження документів — це виробництво канонічної версії, а не виклик бібліотеки розбору.
Нижче — практична архітектура прийому для команд, які тягнуть у пошук корпоративні PDF, вивантаження з ECM, вкладення листів і скани. Стаття розвиває контур «прийом і нормалізація» в промисловій інженерії RAG і не підміняє експерименти з розбиттям: спочатку чесний документ, потім нарізка.
Стійка одиниця тут — канонічна версія джерела, а не файл на диску.
Ключові висновки
Оригінал незмінний, індекс — похідна. Сирий байтовий об’єкт, результат кожного перетворення і пошукові представлення зберігають окремо. Новий парсер має вміти переграти корпус без повторного вивантаження з SharePoint.
Розбір — вимірюваний продукт, не разова утиліта. Версія парсера, упевненість розпізнавання, ознаки «це таблиця / це колонтитул / це скан» входять у маніфест документа. Тихий провал розбору забруднює і лексичний пошук, і вектори.
Таблиця без шапки — не доказ. Комірка, відірвана від заголовків рядків і стовпців, дає впевнену, але хибну відповідь. Макет важливіший за «витягнутий текст».
Версія і видалення — частина контракту свіжості. Один source_id з історією редакцій, періодом дії і каскадом видалення на фрагменти, кеш і цитати. «Просто перезалити теку» створює двійників.
Карантин дорожчий за мовчання, але дешевший за інцидент. Документ із низькою впевненістю розпізнавання або зламаною структурою не повинен потрапляти в бойовий індекс «про всяк випадок».
Що таке конвеєр завантаження документів
Завантаження починається до ембедінгу. Якщо на цьому кроці переплутані колонки кошторису, жоден гібридний пошук цього не виправить: обидва канали чесно ранжуватимуть хибний текст. Організаційний шар — що вважати джерелом, хто володіє актуальністю — описаний у підготовці даних для RAG і в архітектурі корпоративного RAG. Тут — інженерія контуру: ідемпотентність, парсери, OCR, таблиці, версії.
Практична межа: будь-який компонент, який бачить текст документа після розбору — нарізка, індекс, оцінка, налагоджувальне вивантаження — споживає канон, а не «те, що вийшло з PDF сьогодні вночі». Якщо канон не можна відтворити з оригіналу і версії парсера, у вас немає завантаження, є разова міграція.
Чим це не є
Це не «обрати Unstructured чи Docling». Бібліотека — деталь етапу. Контракт — входи, артефакти, відмова, версія.
Це не нарізка. Межі фрагментів залежать від структури, яку завантаження зобов’язане зберегти: заголовки, списки, комірки, підписи до рисунків. Якщо парсер сплющив документ в одну простирадло, эксперименти з розбиттям вимірюють уже зіпсований вхід.
Це не контроль доступу. Права копіюються на документ у момент прийому і оновлюються подіями, але рішення «чи можна шукати» лишається за фільтром до вилучення. Завантажувач не повинен писати в спільний індекс текст, який нікому буде відфільтрувати.
Чому парсер важливіший за ембедінг
Команди змінюють модель векторів, коли користувач скаржиться на «дурні відповіді». Часто винен розбір.
Типовий ланцюжок: PDF із двома колонками читається зліва направо крізь обидві колонки одразу; заперечення («не застосовується до підрядників») відривається від умови; повторюваний колонтитул «конфіденційно, стор. 14» стає частим токеном; у таблиці «ставка / 12%» комірка 12% індексується без шапки. Ембедінг чесно вважає це сенсом. BM25 чесно піднімає колонтитул за словом «конфіденційно».
Другий клас помилок — відсутність тексту. Скан без OCR дає порожній канон. Система індексує ім’я файлу і шлях. Пошук за змістом мовчить, пошук за назвою бреше. Третій клас — суміш: половина сторінок текстовий шар, половина картинка. Наївний парсер витягує лише текстовий шар і мовчки втрачає додатки зі сканами.
Незмінний оригінал і канон
Робоча схема — три шари.
Шар 0 — оригінал. Байти файлу, MIME, розмір, контрольна сума, ідентифікатор у системі-джерелі, час source_updated_at. Цей об’єкт не переписують. Якщо джерело віддало новий файл із тим самим ім’ям, це нова версія, а не перезапис.
Шар 1 — канон. Структуроване представлення: дерево розділів, блоки (абзац, список, таблиця, рисунок, колонтитул), мова, геометрія сторінки якщо є, впевненість OCR, версія парсера, попередження. Формат — ваш JSON або Markdown з явною розміткою таблиць, головне щоб був стабільний і придатний до порівняння. Канон можна перерахувати, оригінал — ні.
Шар 2 — пошукові представлення. Фрагменти, лексичні поля, вектори. Їх можна спалити і зібрати знову з канону. Якщо ви вмієте лише «переіндексувати з канону», ви вже попереду більшості демо.
Мінімальний маніфест документа:
| Поле | Навіщо |
|---|---|
source_id |
стійка особистість у системі істини |
version_id |
конкретна редакція |
content_hash |
ідемпотентність і звірка |
parser_version |
відтворюваність канону |
media_class |
цифровий PDF, скан, html, офіс, лист |
ocr_confidence |
поріг карантину |
acl / орендар |
копія політики на момент прийому |
valid_from / valid_to |
діловий строк редакції |
Повторна обробка з тим самим content_hash і тією самою parser_version не створює другий запис. Зміна парсера створює новий канон тієї самої версії оригіналу і позначає старий канон архівним. Так порівнюють парсери на одному корпусі.
Текст, макет і скани
«PDF» — не один формат, а три різні входи.
Цифровий PDF із текстовим шаром
Є символи, шрифти, координати. Задача — відновити порядок читання і блоки, а не склеїти extractText(). Багатоколонкова верстка, врізки, виноски потребують аналізу макета. Бібліотеки рівня PyMuPDF, pdfminer, Docling, комерційні конвеєри різняться саме тут, а не «вмінням відкрити файл».
Перевіряйте на своїх макетах: двоколонковий регламент, бланк із бічною навігацією, паспорт виробу з рамкою. Універсального переможця немає. Є набір еталонних сторінок і метрика: порядок блоків збігся з людським читанням, виноски не вплелися в абзац, колонтитули відокремлені.
Скан і «PDF-картинка»
Текстового шару немає або він порожній сміття. Потрібен OCR. Зберігайте впевненість за сторінкою і за блоком. Низька впевненість — карантин або повтор з іншою моделлю розпізнавання і мовою, не мовчазна індексація. Мову документа задавайте явно: автодетект на бланку з латиницею в шапці і кирилицею в тілі часто обирає не той рушій.
Не змішуйте в одному каноні «впевнений текстовий шар» і «сумнівний OCR» без ознаки. Інакше оцінка якості пошуку не відрізнить поганий ембедінг від поганої літери «з» замість «3».
Гібрид
Багато корпоративних PDF — текст плюс вставлені скани додатків. Конвеєр має йти сторінками: є текстовий шар достатньої щільності — макетний розбір; інакше OCR. Додатки (вкладені PDF, TIFF) — окремі документи зі зв’язком parent_source_id, а не «ще сторінка того самого файлу», якщо в них своя нумерація і гриф.
Офісні файли і листи
DOCX і таблиці Excel часто здаються «простішими за PDF», і на цьому команда заощаджує контур. Ревізії Word, упроваджені об’єкти, приховані аркуші й об’єднані комірки ламають канон так само, як двоколонковий регламент. Для таблиць джерело .xlsx зазвичай чесніше, ніж «надрукований у PDF» звіт: сітка вже є, її не треба вгадувати за координатами. Друкований PDF лишається потрібен, коли юридично підписаний саме він — тоді оригінал PDF, а таблиця з Excel, якщо її надіслали окремо, живе як пов’язане джерело, а не як здогад парсера.
Лист — не один документ. Тема, тіло, ланцюжок відповідей і кожне вкладення мають різний гриф і різну цінність як доказ. Канон листа зберігає заголовки, учасників і посилання на дочірні вкладення; вкладення йдуть тим самим конвеєром, що й файли з ECM. Інакше пошук за «тим листом із договором» піднімає цитату з підпису менеджера.
Таблиці, колонтитули і хибний факт
Таблиці — головне джерело впевнено невірних відповідей у промисловому RAG.
Комірка без контексту шапки марна. «12» може бути ставкою, кількістю, роком або кодом помилки. Канон таблиці зобов’язаний нести: заголовки стовпців, заголовок рядка якщо є, об’єднання комірок, номер таблиці і підпис. Для пошуку часто роблять два представлення: структуровані рядки «стовпець=значення» для точних питань і серіалізований Markdown/CSV для моделі. Обидва будуються з однієї розібраної сітки, а не з «тексту навколо».
Зламаний порядок комірок (читаємо за стовпцями замість рядків, або навпаки) дає правдоподібний абзац. Це гірше за порожній результат: модель цитує «доказ». На еталонних таблицях рахуйте не близькість тексту, а збіг ключ→значення.
Колонтитули і повторювані шапки сторінок потрібно класифікувати і відрізати від тіла. Інакше BM25 закохується в «ТОВ Ромашка, конфіденційно». Підписи до рисунків, навпаки, не можна втрачати: питання «що на схемі 3» шукає підпис, а не пікселі. Зв’язка «рисунок — підпис — номер» живе в каноні до нарізки.
Виноски: або прив’язка до абзацу з маркером, або окремий блок із номером. Склейка виноски з наступним абзацом змінює правові формулювання.
Версії, видалення, ідемпотентність
Джерело рідко віддає «ось актуальний файл». Воно віддає події, теки і конфлікти імен.
Ідемпотентний прийом
Ключ (source_id, content_hash) або (source_id, source_version). Повтор події не плодить точок в індексі. Перейменування файлу без зміни хешу — той самий зміст, оновити шлях у маніфесті. Зміна хешу — нова версія: стара позначається superseded_by, період valid_to закривається, фрагменти старої редакції або знімаються з поточного пошуку, або лишаються доступні для запиту «на дату».
Юридичний і бухгалтерський контури майже завжди потребують історичний пошук. Не видаляйте канон попередньої редакції, поки політика зберігання це дозволяє. Видаляйте його з чинного індексу.
Видалення
Подія видалення повинна каскадом пройти: канон (статус «видалено»), фрагменти, вектори, лексичний індекс, кеш відповідей, збережені цитати в сесіях. «Файл прибрали з теки, у чаті все ще цитується» — дефект завантаження, не генерації. Для відкликання прав дивіться сусідній матеріал про права доступу до пошуку: це інший тригер, але той самий каскад на похідні.
Конфлікт версій
Два конектори принесли один source_id з різними хешами за одну хвилину. Потрібне правило: джерело істини перемагає (ECM, а не поштова скринька), або ручний карантин. Мовчки взяти «останній за часом прийому» — лотерея.
Карантин і якість розбору
Карантин — черга документів, які не повинні потрапити в бойовий пошук без рішення. Причини: OCR нижче порога, нуль витягнутих блоків за ненульового розміру файлу, таблиця з неможливою геометрією, непідтримуваний шифр PDF, мова поза політикою, вірусне сканування, розбір упав винятком.
Кожен запис карантину: оригінал, помилка, версія парсера, власник джерела, строк. Мовчки пропустити «розберемо потім» означає, що користувач думає, ніби документ у системі. Краще явний статус у картці джерела: «прийнято, не проіндексовано».
Оцінка парсера — окремий контур, не плутати з еталонним набором питань. Набір сторінок: двоколонковий текст, скан середньої якості, таблиця з об’єднаними комірками, колонтитул, змішаний PDF. Метрики: порядок блоків, якість ключів таблиці, частка сторінок у карантині, регресія при підвищенні parser_version. Новий парсер спочатку ганяють цим набором, потім переграють канон, потім збирають індекс.
Не порівнюйте парсери «на око за одним договором». Порівнюйте на фіксованому знімку корпусу і дивіться, які пошукові зрізи змінилися: ідентифікатори, таблиці, скани.
Події, пакети і контракт свіжості
Конектори різні: SharePoint і диск віддають дельту, пошта — листи з вкладеннями, Git — коміти, ERP — вивантаження вкладень до картки, ручна тека — нічого. Єдиний «нічний скрипт по всіх шарах» ховає втрачені події.
Практичний контур: потік змін (webhook, журнал змін, черга) плюс періодична звірка за хешами. Звірка ловить те, що потік втратив. Потік дає свіжість. Без звірки ви одного дня виявите, що три місяці індексуєте привида видаленого файлу.
Контракт свіжості вже названий в опорному гайді: source_updated_at, ingested_at, indexed_at, видалення, valid_from / valid_to. Завантаження відповідає за перші два і за те, що канон готовий до індексації. Якщо ingested_at − source_updated_at стабільно більше SLO джерела, проблема не в LLM.
Спостережуваність: скільки документів прийнято, скільки в карантині, розподіл ocr_confidence, частка таблиць із розпізнаною шапкою, відставання звірки, помилки конектора за джерелом. Без цих рядів «індекс оновлюється» — гасло.
Типові помилки і план на чотири тижні
Типові помилки
Один виклик extractText на весь PDF. Втрачаєте макет, таблиці і половину сканів.
Перезапис оригіналу. Не можна довести, що канон відповідає файлу, який бачив юрист.
Індексація з карантину «щоб покриття було». Покриття сміттям гірше за діру: модель цитує кашу.
Версія = ім’я файлу. регламент_фінал_v3_new(2).pdf не є version_id.
Зміна парсера разом зі зміною ембедінгу. Регресію неможливо віднести до контуру.
Права лише в джерелі, не на маніфесті. Після вивантаження зв’язок з ACL рветься; див. мультиоренду.
Оцінка лише відповідей чату. Парсер зелений, поки не розібрали табличний зріз запитів.
Чотири тижні до контрольованого прийому
Тиждень 1 — інвентаризація і шари. Реєстр джерел, форматів, обсягів. Введіть шар оригіналу і заборону перезапису. Порахуйте, скільки файлів зараз потрапляють в індекс без хешу і версії парсера — це борг.
Тиждень 2 — канон і карантин. Один формат канону, черга карантину, ознаки media_class і OCR. Еталон із 20–40 сторінок ваших реальних макетів, не демо-PDF з інтернету.
Тиждень 3 — таблиці і гібридні PDF. Окреме представлення таблиць, відрізання колонтитулів, посторінковий вибір «текст чи OCR». Проженіть еталон, зафіксуйте базову лінію.
Тиждень 4 — версії і звірка. Ідемпотентний ключ, каскад видалення, нічна звірка одного джерела. Переграйте канон новим парсером без повторного вивантаження. Якщо це неможливо — контур ще не готовий.
Якщо потрібно зібрати прийом не як скрипт аналітика, а як спостережуваний сервіс із контрактами, послуга впровадження ШІ закриває саме зв’язку джерел, розбору й оцінки.
Часті питання
Чи потрібен OCR для всіх PDF?
Ні. Спочатку дивіться щільність текстового шару за сторінками. OCR дорогий і сам вносить помилки. Його вмикають там, де шару немає або він порожній, і завжди з упевненістю в маніфесті.
Чи можна годувати модель сирим PDF без канону?
Для разового розбору — іноді. Для корпусу з версіями, правами й оцінкою — ні. Без канону не можна переграти парсер, порівняти регресію і відрізати колонтитул один раз для всіх каналів пошуку.
Чим завантаження відрізняється від підготовки даних?
Підготовка даних — ще й політика: що взагалі індексувати, хто володіє джерелом, як часто оновлювати. Завантаження — технічний контур, який цю політику виконує: оригінал, канон, карантин, версії.
Як версіонувати, якщо ECM не дає номера редакції?
Власний version_id від хешу змісту плюс source_updated_at. Ім’я файлу не використовувати як істину. Конфлікт хешів за того самого id — карантин.
Що робити із зашифрованими PDF і захищеними від копіювання?
Не індексувати в обхід захисту. Або конектор ходить з обліковим записом, що має право експорту, або документ у карантині з причиною. Обхід пароля «щоб RAG запрацював» — інцидент, не можливість.
Чи потрібно зберігати канон, якщо є оригінал?
Так. Перерахунок канону дорогий (OCR). Канон — кеш перетворення з версією парсера. Оригінал потрібен, щоб цей кеш можна було інвалідувати.
Як зрозуміти, що винен парсер, а не пошук?
Дивіться канон знайденого фрагмента: чи є в ньому шапка таблиці, чи не склеєні колонки, чи не стирчить колонтитул. Якщо канон уже бреше, гібридний пошук лише розмножить брехню.
Чи пов’язане завантаження з промпт-ін’єкцією?
Так. Кожне проіндексоване джерело — канал вводу. Карантин і класифікація «це текст документа, не інструкція» не замінюють захист від ін’єкцій, але відсікають очевидне сміття і чужі вкладення без розбору.
Чи можна пропустити карантин для «простих» DOCX?
Можна знизити поріг, не можна прибрати облік помилок. DOCX теж буває з упровадженими OLE-об’єктами, зламаними таблицями і ревізіями. Ідемпотентність і хеш потрібні всім форматам.
Коли підключати мультимодальний індекс картинок?
Коли канон уже стабільний для тексту і таблиць, а питання реально потребують схеми чи креслення. Інакше ви подвоїте вартість, не закривши базовий розбір. Це сусідня тема кластера, не заміна завантаженню.
Подальше читання
- Промислова інженерія RAG — увесь конвеєр; ця стаття закриває прийом.
- Підготовка даних для RAG — політика джерел і якості корпусу.
- Архітектура корпоративного RAG — платформа навколо багатьох джерел.
- Експерименти з розбиттям — нарізка після чесного канону.
- Права доступу і мультиоренда — права копіюються під час прийому, фільтр — до пошуку.
- Еталонний набір для оцінки RAG — куди додати зрізи «таблиця» і «скан».
- Промпт-ін’єкції в продакшені — кожен прийнятий файл як канал вводу.
Висновок
Промисловий RAG перестає брехати таблицями в той момент, коли завантаження стає окремим продуктом: незмінний оригінал, відтворюваний канон, карантин замість тиші, версії замість файлу з п’ятьма «фінал» в імені. Ембедінг і переранжувальник працюють поверх цього контуру, а не замість нього.
Цього тижня зробіть одну перевірювану дію: забороніть перезапис оригіналу і запишіть content_hash плюс parser_version на кожен прийнятий файл. Потім покладіть у карантин усе, що зараз індексується без текстового шару і без OCR. Решта — нарощування тієї самої межі: макет, таблиці, звірка, перегравання парсера без повторного вивантаження.
Розбір документів нудний. Саме він відділяє корпоративний пошук від теки PDF із ввічливою моделлю зверху.

