Image

Выход за рамки OCR+LLM: создание приложений с API извлечения документов Agentic (часть 2)

Going Beyond OCR+LLM: Building Apps with Agentic Document Extraction API (Part 2) 0636cf29d1dfca82a7d36c874282bea1 Анкит Кхаре

Введение

Современные большие языковые модели (LLM) произвели революцию в анализе текста — пока не столкнулись со сложностями PDF-файлов. PDF-файлы часто содержат замысловатые макеты, визуальные элементы, блок-схемы, изображения и таблицы с взаимозависимыми контекстами и отношениями. Именно здесь Agentic Document Extraction действительно выделяется. В части 1 мы продемонстрировали примеры, где традиционные LLM испытывали трудности, в то время как Agentic Document Extraction преуспел, предоставляя точные ответы, предоставляя визуальное обоснование и предлагая правильные цитаты из сложных академических и технических документов. В этой статье мы рассмотрим, как использовать API Agentic Document Extraction в ваших собственных приложениях — от понимания его JSON-схемы до создания таких функций, как интерактивные, выделяемые пользовательские интерфейсы и расширенные подсказки LLM.

1. Понимание схемы JSON, возвращаемой API

API извлечения документов Agentic обеспечивает представление данных , удобное как для человека , так и для машины . Ниже представлена схема верхнего уровня:

JSON

{
«$defs» : {
«Кусок» : {
«характеристики» : {
«текст» : { «тип» : «строка» },
«заземление» : {
«тип» : «массив» ,
«items» : { «$ref» : «#/$defs/ChunkGrounding» }
},
«chunk_type» : { «$ref» : «#/$defs/ChunkType» },
«chunk_id» : { «type» : «string» }
},
«required» : [ «text» , «grounding» , «chunk_type» , «chunk_id» ],
«тип» : «объект»
},
«ChunkGrounding» : {
«характеристики» : {
«box» : { «$ref» : «#/$defs/ChunkGroundingBox» },
«страница» : { «тип» : «целое число» }
},
«требуется» : [ «ящик» , «страница» ],
«тип» : «объект»
},
«ChunkGroundingBox» : {
«характеристики» : {
«л» : { «тип» : «число» },
«t» : { «тип» : «число» },
«r» : { «тип» : «число» },
«b» : { «тип» : «число» }
},
«требуется» : [ «л» , «т» , «р» , «б» ],
«тип» : «объект»
},
«ChunkType» : {
«перечисление» : [
«title» , «page_header» , «page_footer» , «page_number» ,
«ключ_значение» , «форма» , «таблица» , «рисунок» , «текст»
],
«тип» : «строка»
}
},
«характеристики» : {
«markdown» : { «type» : «string» },
«куски» : {
«тип» : «массив» ,
«items» : { «$ref» : «#/$defs/Chunk» }
}
},
«требуется» : [ «скидка» , «куски» ],
«тип» : «объект»
}

Ключевые моменты, на которые следует обратить внимание

  1. Разделение данных и представления
    • markdown : удобное для пользователя представление документа (идеально подходит для быстрого отображения или отправки в качестве контекста LLM).
    • Фрагменты : каждый фрагмент содержит подробные метаданные, включая ограничивающие рамки и типы фрагментов.
  2. Детальный контроль местоположения
    • Каждый фрагмент включает в себя одну или несколько записей заземления . Каждое заземление связывает фрагмент с индексом страницы и ограничивающим прямоугольником в относительных координатах.
    • Почему именно относительные координаты? Потому что они остаются действительными независимо от разрешения (DPI) и масштабирования при преобразовании PDF-файла в изображение. Это особенно полезно для создания стабильных подсвеченных участков.
  3. Размер, удобный для LLM
    • Схема разработана таким образом, чтобы каждый фрагмент был относительно небольшим. Если вам нужно использовать метод расширенной генерации (RAG) , вы можете хранить эти фрагменты в векторной базе данных и извлекать только соответствующий текст.

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

2. Создание опыта «чата с PDF»

Давайте рассмотрим, как можно интегрировать API извлечения документов Agentic в простое приложение Streamlit, которое выполняет постраничное извлечение, задает вопросы LLM и визуально обосновывает каждый ответ.

e767c78640f6b04c626fa1f82ea8afe0

Общий процесс создания приложения «Чат с PDF» с использованием API извлечения документов Agentic

2.1 Обработка PDF-файлов

Разделение PDF-файлов на отдельные страницы

Разделение PDF-файлов на страницы может помочь уменьшить количество запросов. Например:

def split_pdf_into_chunks ( pdf_file ):
«»»Разделить PDF-файл на отдельные страницы (по 1 странице на часть).»»»
пытаться :
читатель = PdfReader ( pdf_file )
за исключением Исключение как e :
st . error ( f «Ошибка чтения PDF: {e}» )
возврат None , 0

total_pages = len ( reader . pages )
куски = []

для i в диапазоне ( total_pages ):
писатель = PdfWriter ()
писатель . add_page ( читатель . страницы [ i ])
pdf_chunk_buffer = io . BytesIO ()
писатель . запись ( pdf_chunk_buffer )
pdf_chunk_buffer . seek ( 0 )
куски . добавить ( pdf_chunk_buffer . getvalue ())

возврат фрагментов , total_pages

Обработка 50-страничных PDF-файлов в одном запросе может быть излишней. Разделение позволяет контролировать параллелизм и лучше масштабировать данные.

Преобразование страниц PDF в изображения

Затем преобразуйте каждую страницу в изображение. Это позволит позже наложить ограничивающие рамки:

def pdf_to_images ( pdf_file ):
«»»
Конвертируйте каждую страницу PDF-файла в изображение для наложения выделенных фрагментов.
Возвращает список изображений и их размеров (ширина, высота) на странице.
«»»

изображения = []
page_dims = []
пытаться :
импорт фитц # PyMuPDF
pdf_document = fitz . open ( stream = pdf_file . read (), filetype = «pdf» )
для страницы в pdf_document :
rect = страница . rect
page_dims . append (( rect . width , rect . height ))

# Для более чёткого изображения мы выберем 200 точек на дюйм.
пикс = страница . get_pixmap ( точек на дюйм = 200 )
img = Изображение.frombytes ( « RGB» , [ пикселы.ширина , пиксы.высота ] , пиксы.сэмплы )
изображения . добавить ( np . массив ( img ))

pdf_document . закрыть ()
за исключением Исключение как e :
st . error ( f «Ошибка преобразования PDF в изображения: {e}» )

возвращать изображения , page_dims

Мини-юмор: «200 точек на дюйм — это идеальное значение. Если вы повысите, ваш компьютер начнет нашептывать: «Пожалуйста, хватит уже этого высокого разрешения!»»

2.2 Интеграция API

Вызов API извлечения документов агента

def call_api ( pdf_bytes , api_key ):
url = «https://api.landing.ai/v1/tools/document-analysis»
файлы = { «pdf» : ( «chunk.pdf» , io . BytesIO ( pdf_bytes ), «application/pdf» )}

данные = {
«parse_text» : True ,
«parse_tables» : Правда ,
«parse_figures» : Правда ,
«summary_verbosity» : «none» ,
«caption_format» : «json» ,
«response_format» : «json» ,
«return_chunk_crops» : Ложь ,
«return_page_crops» : Ложь ,
}

headers = { «Авторизация» : f «Базовый {api_key}» }

ответ = запросы . пост (
url , files = файлы , data = данные , headers = заголовки ,
тайм-аут = 600 , проверка = Ложь
)

пытаться :
возврат ответа . json ()
за исключением Исключение как e :
return { «error» : str ( e ), «response_text» : response . text }

Обратите внимание, что мы устанавливаем parse_tables и parse_figures в значение True. Это гарантирует захват структурированных элементов, таких как таблицы и изображения, с ограничивающими рамками.

Логика повтора

Проблемы с сетью случаются. Добавление механизма повторных попыток помогает:

def call_api_with_retry ( pdf_bytes , api_key , max_retries = 3 , backoff_factor = 2 ):
для попытки в диапазоне ( max_retries ):
пытаться :
# Те же данные и заголовки, что и выше
url = «https://api.landing.ai/v1/tools/document-analysis»
файлы = { «pdf» : ( «chunk.pdf» , io . BytesIO ( pdf_bytes ), «application/pdf» )}

данные = {
«parse_text» : True ,
«parse_tables» : Правда ,
«parse_figures» : Правда ,
«summary_verbosity» : «none» ,
«caption_format» : «json» ,
«response_format» : «json» ,
«return_chunk_crops» : Ложь ,
«return_page_crops» : Ложь ,
}

headers = { «Авторизация» : f «Базовый {api_key}» }

ответ = запросы . пост (
url , files = файлы , data = данные , headers = заголовки ,
тайм-аут = 600 , проверка = Ложь
)
ответ . raise_for_status ()
возврат ответа . json ()

за исключением Исключение как e :
если попытка == max_retries1 :
return { «error» : str ( e ), «response_text» : getattr ( response , 'text' , str ( e ))}
время_ожидания = коэффициент_возврата ** попытка
st . warning ( f «Попытка {attempt + 1} не удалась. Повторная попытка через {wait_time} секунд…» )
время . сон ( время_ожидания )

2.3 Агрегация и кэширование доказательств

После обработки каждого PDF-файла соберите все извлеченные фрагменты и сохраните их в session_state Streamlit для быстрого извлечения во время запросов:

st.session_state.all_evidence = all_evidence
st.session_state.all_images = all_images
st.session_state.all_page_dims = all_page_dims
st.session_state.all_total_pages = all_total_pages
st.session_state.processed_pdfs = current_pdfs
st.session_state.raw_api_responses = raw_api_responses

Используйте кэширование для повторяющихся вычислений, таких как преобразование ограничивающих рамок:

@lru_cache ( maxsize=128 )
def calculate_scale_factors ( img_width, img_height, pdf_width, pdf_height ):
«»»
Рассчитайте масштабные коэффициенты для сопоставления пространства PDF с пространством изображения.
Мы произвольно вычитаем 0,7, чтобы учесть незначительные отклонения в измерениях.
Ведь кто не любит случайные смещения?
«»»
scale_x = img_width / pdf_width0,7
scale_y = img_height / pdf_height0,7
вернуть масштаб_x , масштаб_y

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

2.4 Запрос к LLM

Используйте извлеченные данные для формирования запроса. Вы можете передать LLM как всю разметку целиком, так и отобранные фрагменты, указав ему вернуть структурированный ответ в формате JSON:

def get_answer_and_best_chunks ( user_query, evidence ):
«»»Для ответа на вопрос используйте следующие доказательства JSON, извлеченные из загруженных PDF-файлов.»»»
пытаться :
клиент = OpenAI ()
chat_response = клиент.чат.дополнения.создать (
модель = «gpt-4o» ,
сообщения = [
{
«role» : «system» , «content» : «Вы полезный эксперт, который дает точные и подробные ответы.» },
{
«role» : «user» , «content» : prompt },
],
температура = 0,5 ,
)
raw = chat_response . choices [ 0 ]. message . content . strip ()

# Очистите ограждения для скидок, если они есть.
если raw . начинается с ( ««`» ):
линии = необработанные . линии разделения ()
если lines[0] . startingwith ( ««`» ):
строки = строки[1:]
если строки и строки[-1] . начинается с ( ««`» ):
строки = строки[:-1]
raw = «n».join ( строки ) .strippe ()

parsed = json . loads ( raw )
возврат проанализирован
за исключением Исключение как e :
st . error ( f «Ошибка получения ответа от ChatGPT: {e}» )
возвращаться {
«answer» : «Извините, мне не удалось получить ответ.» ,
«рассуждение» : «Произошла ошибка.»
«best_chunks» : []
}

Совет: если у вас большое количество фрагментов PDF-файлов, рассмотрите возможность их первоначального сохранения в хранилище векторных изображений и извлечения только соответствующих из них (подход RAG).

2.5 Аннотирование и визуализация доказательств

Наконец, выделите соответствующие ограничивающие рамки на каждой странице PDF-файла. Переведите координаты ограничивающей рамки из координат PDF-файла (0–1) в пиксельные координаты изображения:

def process_chunks_parallel ( chunks_list, img, scale_factors, offset_x, offset_y, invert_y ):
«»»Нарисуйте ограничивающие рамки на изображении на основе данных фрагмента.»»»
img_height , img_width = img . shape [ : 2 ]
масштаб_x , масштаб_y = масштабные_факторы
total_boxes = сумма ( len(chunk.get ( «bboxes» , [] ) для куска в chunks_list )
boxes = np.zeros (( total_boxes , 4 ), dtype = np.int32 )
box_idx = 0
для куска в chunks_list :
bboxes = chunk.get ( «bboxes» , [] )
для bbox в bboxes :
если len(bbox) == 4 :
x1 = int ( bbox[ 0 ] * Scale_x )
x2 = int ( bbox[ 2 ] * scale_x )
если invert_y :
y1 = int ( img_height — ( bbox[ 3 ] * scale_y ))
y2 = int ( img_height — ( bbox[ 1 ] * scale_y ))
еще :
y1 = int ( bbox[ 1 ] * масштаб_y )
y2 = int ( bbox[ 3 ] * Scale_y )
x1 = макс ( 0 , мин (x1 + смещение_x, ширина_изображения — 1) )
x2 = макс ( 0 , мин (x2 + смещение_x, ширина_изображения — 1) )
y1 = макс ( 0 , мин (y1 + смещение_y, высота_изображения — 1) )
y2 = макс ( 0 , мин (y2 + смещение_y, высота_изображения — 1) )
boxes[box_idx] = [ x1 , y1 , x2 , y2 ]
box_idx += 1
для ящика в boxes[:box_idx] :
cv2.rectangle ( img , ( box[0] , box[1] ), ( box[2] , box[3] ), ( 0 , 255 , 0 ), 2 )
вернуть img

Название функции process_chunks_parallel может быть преувеличением, если оно не использует реальный параллелизм, но эй, оно мощное!

Конвертируйте и отображайте результат в формате PDF:

def image_to_pdf ( изображение ):
«»»Сохраните аннотированное изображение как временный PDF-файл.
Отлично подходит, если вы хотите продемонстрировать рядом оригинальные и выделенные доказательства.»»»
temp_img = tempfile.NamedTemporaryFile ( суффикс = «.png» , delete = False )
Image.fromarray(image) . save ( temp_img.name )
temp_img.close()
pdf = FPDF ( единица измерения = «мм» , формат = «A4» )
pdf.add_page()
pdf.image ( temp_img.name , x = 0 , y = 0 , w = 210 )
temp_pdf = tempfile.ИменованныйВременныйФайл ( суффикс = «.pdf» , delete = False )
pdf.output ( temp_pdf.name )
temp_pdf.close()
вернуть temp_pdf.name

Затем вставьте PDF-файл в Streamlit:

def display_pdf ( pdf_path ):
с open(pdf_path, «rb») в качестве f:
base64_pdf = base64.b64encode(f.read()).decode('utf-8')
pdf_display = f''
st.markdown ( pdf_display , unsafe_allow_html = True )

3. Развертывание, масштабируемость и безопасность

При переходе к производству помните о следующих моментах:

  • Обработка ошибок и повторные попытки : у вас уже есть базовые возможности повторных попыток. Также рассмотрите возможность специализированного ведения журнала и мониторинга, чтобы отслеживать повторяющиеся проблемы (например, тайм-ауты).
  • Кэширование и векторные хранилища : используйте кэширование Python (как показано) для небольших задач. Для более крупных задач используйте векторные хранилища (например, FAISS, Pinecone или Milvus) для обработки сотен страниц или PDF-файлов.
  • Защитите свои ключи : не передавайте свои ключи API на GitHub и не храните их в открытом виде. Используйте переменные окружения или менеджеры секретов (например, HashiCorp Vault, AWS Secrets Manager) в рабочей среде.
  • SSL и проверка : для максимальной безопасности включите проверку TLS в своих запросах, особенно если вы работаете в регулируемых отраслях.

4. Потенциальные улучшения

  • Генерация дополненной реальности (RAG)
    • Вместо того, чтобы выгружать все данные в контекстное окно для каждого запроса LLM, сохраняйте каждый фрагмент в векторной базе данных . При запросе пользователя выполняйте семантический поиск , чтобы выбрать только релевантные фрагменты. Это:
      • Уменьшает использование токенов.
      • Улучшает релевантность и скорость.
      • Масштабируется до большого корпуса без проблем с памятью.
  • Объединение нескольких PDF-файлов и документов на уровне документа
    • Если у вас много PDF-файлов, объедините все фрагментированные данные в единый индекс. Тогда запросы смогут ссылаться на весь набор данных, возвращая наиболее достоверные данные из нескольких документов.

Совет от профессионала: RAG не только сокращает расходы, но и радикально сокращает количество бессмысленных или «галлюцинаторных» ссылок в LLM.

5. Заключительные мысли

Agentic Document Extraction позволяет создавать передовые приложения на основе документов, которые не только извлекают значимые данные, но и предоставляют проверяемые, визуально обоснованные ответы, что снижает количество галлюцинаций и повышает доверие пользователей.

Удачной сборки! Если у вас есть вопросы, обращайтесь. Мы с нетерпением ждём возможности увидеть, как вы творчески используете этот API в своих приложениях.

Источник: landing.ai

✅ Найденные теги: Выход, новости
Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Фото сгенерированных лиц: исследование показывает, что люди не могут отличить настоящие лица от сгенерированных
Нейросети построили капитализм за трое суток: 100 агентов Claude заперли…
Скетч: цифровой осьминог и виртуальный мир внутри компьютера с человечком.
Сцена с жестами пальцами, где один жест символизирует "VPN", а другой "KHP".
‼️Paramount купила Warner Bros. Discovery — сумма сделки составила безумные…
Скриншот репозитория GitHub "Claude Scientific Skills" AI для научных исследований.
Структура эффективного запроса Claude с элементами задачи, контекста и референса.
Эскиз и готовая веб-страница платформы для AI-дизайна в современном темном режиме.
ideipro logotyp
Image Not Found
Звёздное небо с галактиками и туманностями, космос, Вселенная, астрофотография.

Система оповещения обсерватории Рубина отправила 800 000 сигналов в первую ночь наблюдений.

Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…

Мар 2, 2026
Женщина с длинными тёмными волосами в синем свете, нейтральный фон.

Расследование в отношении 61-фунтовой машины, которая «пожирает» пластик и выплевывает кирпичи.

Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…

Мар 2, 2026
Черный углеродное волокно с текстурой плетения, отражающий свет.

Материал будущего: как работает «бессмертный» композит

Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений.  Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…

Мар 2, 2026
Круглый экран с изображением замка и горы, рядом электронная плата.

Круглый дисплей Waveshare для креативных проектов

Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран.  Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…

Мар 2, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых