AWS 기술 블로그

Amazon Bedrock의 파운데이션 모델을 활용한 효과적인 PDF 파싱을 위한 프롬프트 엔지니어링 기법

데이터는 현대 비즈니스의 핵심 자산이며, 기업은 이를 문서, 보고서, 계약서 등 다양한 형태의 정보로 변환하여 보유하고 있습니다. 그리고, 이러한 정보의 상당수는 PDF 와 같은 문서 형식으로 저장되어 있습니다. PDF는 문서 공유와 보전에는 편리하지만, 내부 데이터를 추출하고 가치 있는 인사이트를 도출하기에는 다양한 기술적 접근이 고려되어야 합니다.

PDF 파일에서 데이터를 추출할 때, 추출 대상이 스캔 된 이미지인 경우 일반적으로 광학 문자 인식(Optical Character Recognition, OCR) 기술이 사용됩니다. OCR은 이미지나 스캔 문서에서 텍스트를 인식하여 디지털 데이터로 변환하는 기술 입니다. 그러나 PDF 파일은 텍스트 뿐만 아니라 이미지, 테이블, 차트 등 다양한 요소로 구성되어 있어 OCR 기술만으로는 데이터 추출에 한계가 있습니다.

따라서, 최근에는 자연어 처리(Natural Language Processing, NLP) 기술을 활용하여 PDF 파일의 컨텍스트를 이해하고 중요 정보를 추출하는 방식이 주목받고 있습니다. 특히 Amazon Bedrock에서 제공되는 파운데이션 모델 중 Anthropic의 Claude 3Claude 3.5 모델은 다양한 자연어 처리 작업에서 우수한 성능을 발휘하며, PDF 파일에서 정보를 추출하는 데에도 효과적으로 활용될 수 있습니다.

문제 정의

기업에서는 다양한 종류의 PDF 파일에서 데이터를 사람이 직접 수동으로 추출하여 DB에 저장하는 작업을 반복적으로 수행하고 있습니다. 이는 곧 업무의 비 효율성을 초래합니다. 특히 PDF 파일은 텍스트, 테이블 등 다양한 요소로 구성되어 있어 문서의 구조를 이해하고 데이터를 추출하는 데 어려움이 따릅니다. 기존 OCR 기술은 텍스트를 인식할 수는 있지만, 레이아웃이 복잡한 PDF 파일의 전체 컨텍스트를 파악하기는 어렵습니다.

따라서 효과적인 PDF 파싱을 위해서는 텍스트 영역에서 자연어 이해 모델을 활용하여 의미 있는 데이터를 추출해야 합니다. 이 과정에서 레이아웃 분석, 테이블 인식 등 다양한 기술이 필요합니다. 또한 PDF 파일마다 레이아웃, 문서 구조, 사용 언어 등이 다르기 때문에 일반화된 솔루션을 적용하기 어렵습니다. 이에 따라 기업들은 자사의 특정 문서 유형에 맞춰 커스텀 PDF 파싱 솔루션을 구축하는 경우가 많습니다.

요약하면, PDF 파일의 복잡성과 다양성으로 인해 기존의 기술만으로는 정확하고 효율적인 데이터추출이 어려우므로 새로운 접근 방법이 필요합니다.

Amazon Bedrock에서 제공하는 Anthropic Claude 3 및 Claude 3.5 모델

Amazon Bedrock은 선도적인 AI 스타트업과 Amazon에서 제공하는 고성능 파운데이션 모델을 통합 API를 통해 사용할 수 있게 하는 완전 관리형 서비스 입니다. Amazon Bedrock의 서버리스 환경을 통해 인프라를 관리할 필요 없이 빠르게 파운데이션 모델을 사용할 수 있습니다.

Amazon Bedrock에서 제공하는 대표적인 파운데이션 모델 중 하나가 Anthropic의 Claude 3 및 Claude 3.5이며, 높은 수준의 자연어 처리 능력을 갖춘 멀티모달 모델로서 다음과 같은 핵심 특징을 지니고 있습니다:

  • 즉각적인 결과: 실시간으로 채팅, 자동 완성, 데이터 추출 작업을 지원합니다. 특히 Haiku 모델은 데이터를 빠르게 처리하여 빠른 응답을 제공합니다.
  • 강력한 비전 능력: 다양한 시각 형식을 인식하고 처리할 수 있는 높은 수준의 비전 능력을 갖추고 있습니다.
  • 책임감 있는 AI: 정보 오류와 다양한 위험을 추적하고 완화하는 전담 팀이 있으며, 모델의 안전성과 투명성을 향상시키기 위한 다양한 방법을 개발하고 있습니다.
  • 복잡한 작업에 대한 멀티태스크 학습 역량
  • 견고성과 안전성을 높이기 위한 설계
  • 언어적, 논리적, 윤리적 일관성 유지

그림 1: 여러 벤치마크에서 Claude 3.5 Sonnet 모델을 동급 제품과 비교한 결과 (원문 참조)

따라서 Amazon Bedrock에서 제공하는 Anthropic Claude 3 및 Claude 3.5 모델을 활용하여, 강력한 언어 이해 및 생성 능력을 바탕으로 PDF 파일 내 중요한 데이터를 정확하게 추출하는 효과적인 PDF 파싱 솔루션을 구축할 수 있습니다.

아키텍처

다음 아키텍처는 PDF 파싱을 위한 테스트 환경 예시 입니다. 다음과 같은 흐름으로 진행 됩니다.

  1. S3에 파싱할 PDF문서를 업로드 합니다.
  2. PDF 문서의 텍스트를 읽어서 프롬프트 템플릿을 채우는데 사용합니다.
  3. 읽은 텍스트에서 정보를 추출하기 위한 프롬프트 템플릿을 작성하고 프롬프트를 만들 때 사용합니다.
  4. 완성된 프롬프트를 이용해서 Bedrock의 Claude 3.5 Sonnet 모델을 호출하고 정보를 추출합니다.
  5. Claude 3.5 Sonnet 의 답변을 저장하고 생성된 응답(추출된 정보)을 평가 합니다.
  6. 평가 결과를 기반으로 프롬프트를 수정하고 테스트를 반복 합니다.

그림 2: PDF 파싱을 위한 아키텍처 예시

프롬프트 엔지니어링

Claude 3 및 Claude 3.5와 같은 멀티모달 모델의 성능을 극대화하기 위해서는 효과적인 프롬프트가 필수입니다. 프롬프트 엔지니어링은 모델에 제공하는 입력(프롬프트)을 설계하고 최적화하는 기법을 의미합니다. 잘 구성된 프롬프트는 모델이 원하는 작업을 정확히 이해하고 좋은 결과를 출력할 수 있도록 돕습니다.

Anthropic에서는 Claude 3 및 Claude 3.5 모델을 위한 다양한 프롬프트 엔지니어링 기법을 제안하고 있으며, 이러한 기법들은 PDF 파싱 작업에서도 적용 가능 합니다. 주요 프롬프트 엔지니어링 기법은 다음과 같습니다:
(Anthropic에서 제공하는 다양한 프롬프트 엔지니어링 기법도 함께 참조하세요)

  • 작업 설명 (Task Description)
  • 예시 제공 (Few-shot Prompting)
  • XML 태그 활용 (XML Tag Prompting)
  • 반복적인 질의 (Iterative Querying)
  • 결과 재순환 (Result Recycling)

프롬프트 엔지니어링 기법을 활용하여 실제 프롬프트를 개발하는 경우, 아래와 같은 라이프 사이클을 가지게 됩니다. 각 단계에 대한 설명은 다음과 같습니다.

  • 테스트 사례 확인: 프롬프트 개발의 첫 단계로, 테스트할 사례를 정의하고 확인 합니다.
  • 예비 프롬프트: 초기 프롬프트를 작성하는 단계 입니다.
  • 사례별 프롬프트 테스트: 작성된 프롬프트를 다양한 사례에 적용하여 테스트 합니다.
  • 프롬프트 구체화: 테스트 결과를 바탕으로 프롬프트를 더욱 구체화하고 개선합니다.
  • 프롬프트 완성: 최종적으로 프롬프트를 완성하는 단계 입니다.

그림 3: 프롬프트 개발 라이프 사이클

효과적인 프롬프트의 시작은 요구사항을 명확히 정의하는 것입니다. PDF 파싱의 경우, “이 PDF 파일에서 주요 키워드와 중요 데이터를 추출하세요.”와 같은 지시를 줄 수 있습니다. 그리고 XML 태그 활용은 프롬프트에 구조적 힌트를 제공하는 방법입니다. 예를 들어 <keyword>와 같은 태그를 사용하여 모델이 키워드 추출에 집중할 수 있도록 유도할 수 있습니다.
이 외에도 반복적인 질의, 결과 재순환 등의 기법을 활용할 수 있습니다. 본 블로그에서는 XML 태그와 Few-shot 프롬프트를 활용한 예시를 통해 설명 합니다.

구현 내용

이번 예시에서는 물질안전자료대장(Material Safety Data Sheet, MSDS)와 관련된 기업이 보유하고 있는 문서 상에 [2. 유해성 및 위험성] 항목과 [4. 구성성분의 명칭 및 함유량] 테이블이 있다고 가정하고, 이것을 추출하는 시나리오입니다. 아래 구현 코드는 Amazon SageMaker Notebook 에서 테스트되었습니다.

1. 라이브러리 설치

사용할 라이브러리를 설치합니다. PDF 를 읽기 위해서 pdfplumber 라이브러리를 사용합니다.

그림 4: Amazon SageMaker JupyterLab notebook 스크린샷

2. Bedrock Client 생성

Amazon Bedrock 을 사용하기 위해서 AWS SDK for Python (Boto3) 를 이용해서 Client 를 생성합니다.

import json
 import boto3
 from pprint import pprint


 # Bedrock runtime 생성
 bedrock_runtime = boto3.client(
     service_name="bedrock-runtime"
 )

3. Bedrock 호출 함수 정의

Bedrock 을 이용해서 Claude 모델을 호출하고 추출된 결과를 얻기 위한 함수를 정의합니다.

def invoke_bedrock(
     query: str,
     model_id: str = "anthropic.claude-3-5-sonnet-20240620-v1:0",
     max_tokens: int = 4096,
     temperature: float = 1.0,
     top_p: float = 1.0,
     top_k: int = 250,
 ) -> str:


     # Request body 작성
     request_data = {
         "anthropic_version": "bedrock-2023-05-31",
         "max_tokens": max_tokens,
         "temperature": temperature,
         "top_p": top_p,
         "top_k": top_k,
         "messages": [
             {
                 "role": "user",
                 "content": [
                     {"type": "text", "text": query},
                 ],
             }
         ],
     }
     request_body = json.dumps(request_data)


     # 모델 호출
     response = bedrock_runtime.invoke_model(
         body=request_body,
         modelId=model_id,
         contentType="application/json",
         accept="application/json"
     )


     response_body = json.loads(response['body'].read())
     answer = response_body['content'][0]['text']
     return answer

4. PDF 문서 읽는 함수 정의

추출 대상이 되는 PDF 문서의 텍스트를 모두 읽는 함수를 정의합니다.

import pdfplumber


 def get_all_texts_from_pdf(filepath: str):


     with pdfplumber.open(filepath) as pdf:
         number_of_pages = len(pdf.pages)
         contents = ""
         for i in range(number_of_pages):
             page = pdf.pages[i]
             contents += page.extract_text()
         return contents

5. 프롬프트 생성 함수 정의

[2. 유해성 및 위험성] 항목과 [4. 구성성분의 명칭 및 함유량] 추출을 위한 프롬프트 생성 함수를 각각 정의합니다. PDF에서 읽은 전체 텍스트를 함수의 전달인자로 받아서 {pdf_texts} 에 입력합니다. PDF 에서 추출한 내용은 JSON 형태로 <json> 태그 안에 넣어서 출력되도록 정의합니다.

5-1. [2. 유해성 및 위험성] 항목 추출을 위한 프롬프트

def get_harmful_extract_prompt(pdf_texts: str):
     return f"""

주어진 <content> 안의 문서에서 특정 내용을 추출하고 JSON object 를 생성합니다.
추출하고자 하는 내용은 '유해성, 위험성' 에 있습니다. 

추출한 내용에서 '유해성·위험성 분류', '신호어', '유해·위험문구', '예방조치문구 - 예방',
 '예방조치문구 - 대응', '예방조치문구 - 저장', '예방조치문구 - 폐기' 의 내용을 별도로 나눕니다.

테이블로 구성되어 있는 경우 테이블 내용을 모두 사용합니다.
워터마크로 인해서 알파벳이 하나씩 있는 부분은 무시합니다.

<content>
 {pdf_texts}
 </content>

다음 단계로 진행합니다.
 1. 먼저 '유해성, 위험성' 세션을 찾고 데이터를 파싱합니다. 파싱되는 값이 없으면 '해당없음' 으로 표기합니다.
     1-1. 찾은 세션에서 '유해성·위험성 분류' 내용을 'category' key 에 대한 value 로 보관합니다.  
     1-2. 찾은 세션에서 '신호어' 내용을 'signal' key 에 대한 value 로 보관합니다.
     1-3. 찾은 세션의 예방조치 문구에서 '유해·위험문구' 내용을 'phrase' key 에 대한 value 로 보관합니다.
     1-4. 찾은 세션의 예방조치 문구에서 '예방' 내용을 'prediction' key 에 대한 value 로 보관합니다.
     1-5. 찾은 세션의 예방조치 문구에서 '대응' 내용을 'action' key 에 대한 value 로 보관합니다.
     1-6. 찾은 세션의 예방조치 문구에서 '저장' 내용을 'keep' key 에 대한 value 로 보관합니다.
     1-7. 찾은 세션의 예방조치 문구에서 '폐기' 내용을 'dispose' key 에 대한 value 로 보관합니다.
     1-8. 보관한 데이터를 아래와 같은 JSON 포맷으로 변경합니다. JSON 은 파싱할 수 있도록 유효한 문법을 가져야 합니다.
         [{{"category":"string","signal":"string","phrase":"string","prediction":"string","action":"string","keep":"string","dispose":"string"}}].
 2. 서두는 출력하지 않습니다.
 3. <content> 데이터는 출력하지 않습니다. 
 4. 최종 JSON 데이터만 <json></json> 태그 안에 출력합니다.

 """

5-2. [4. 구성성분의 명칭 및 함유량] 항목 테이블 추출을 위한 프롬프트

 def get_cas_table_extract_prompt(pdf_texts: str):
     return f"""
     
주어진 <content> 안의 문서에서 테이블을 추출하고 추출된 테이블의 내용으로 JSON object 를 생성합니다.
테이블은 '구성성분의 명칭 및 함유량' 에 있습니다. 추출하는 코드나 방법을 요청하는 것이 아닙니다.

<content>
{pdf_texts}
</content>

다음 단계로 진행합니다.
1. 먼저 '구성성분의 명칭 및 함유량' 세션의 테이블을 csv 형태로 파싱합니다.
2. 파싱된 테이블 중 '관용명' 이나 '이명' 과 관련된 컬럼은 제외합니다.
3. 테이블의 각 컬럼은 탭으로 구분됩니다.
4. csv 내용을 아래와 같은 JSON 포멧으로 변경합니다.
    [{{"name":"string","cas_no":"string","content_wt_1":"string"}}].
    4-1. 'name' 에는 물질명이 들어갑니다.
    4-2. 'cas_no' 에는 CAS 번호가 들어갑니다. CAS 번호는 {{number}}-{{number}}-{{number}} 형태입니다.
    4-3. 'content_wt_1' 에는 함유량이 순서대로 들어갑니다   
5. 서두는 출력하지 않습니다.
6. <content> 데이터는 출력하지 않습니다. 
7. 최종 JSON 데이터만 <json></json> 태그 안에 출력합니다.
"""

6. <json> 태그 안에서 JSON 객체 추출하는 함수 정의

추출된 내용을 JSON 형태로 <json> 태그 안에 넣어서 출력하도록 프롬프트를 작성했기 때문에, Bedrock 응답 내용 중 <json> 태그에서 JSON 객체를 추출하는 함수를 정의합니다.

import json
 import re

def parse_json_from_text(text):
     print("Call - parse_json_from_text()")

     json_pattern = r'<json>(.*?)</json>'
     json_matches = re.findall(json_pattern, text, re.DOTALL)
     parsed_data = []

     for json_str in json_matches:
         try:
             data = json.loads(json_str)
             parsed_data.append(data)
         except json.JSONDecodeError as e:
             print(f"JSON 파싱 오류: {e}")

     return parsed_data

7. 정의된 함수를 호출해서 최종 결과 생성

위에서 정의한 함수를 호출해서 최종 결과물을 얻습니다.

  1. PDF 에서 전체 텍스트를 읽습니다.
  2. 전체 텍스트를 사용해서 프롬프트를 생성합니다.
  3. 프롬프트를 사용해서 Bedrock을 호출합니다.
  4. Bedrock 의 응답에서 JSON 텍스트를 JSON 객체로 변환합니다.
filepath = "./MSDS-sample.pdf"
 texts = get_all_texts_from_pdf(filepath=filepath)
 prompt = get_harmful_extract_prompt(pdf_texts=texts)
 result = invoke_bedrock(query=prompt, temperature=0, top_p=0)
 data = parse_json_from_text(text=result)

그림 5: [2. 유해성 및 위험성] 항목 추출 예시

그림 6: [4. 구성성분의 명칭 및 함유량] 항목 추출 예시

정확도 평가 결과

PDF 파싱 솔루션의 성능을 평가하는 것은 매우 중요합니다. 휴먼 평가 방법이나 자동 평가와 같은 다양한 방법이 있습니다.
실제 비즈니스 데이터를 활용한 평가를 할때 각 기업이 보유한 PDF 문서는 고유한 특성을 지니고 있기 때문에 일반적인 벤치마크 데이터셋으로는 실제 성능을 정확히 측정하기 어려울 수 있습니다. 따라서 기업 내부의 PDF 문서를 샘플링하여 정답지(ground truth)를 수동으로 작성한 후, 파운데이션 모델의 출력 결과와 비교하는 방식으로 정확도를 평가할 수 있습니다. 정답지 작성 후 포맷이 다른 다양한 MSDS 50개 문서를 이용해서 테스트를 진행 했을 때 평균 93점 이상의 결과를 얻을 수 있었습니다. 정확도는 텍스트 Fuzzy String Matching 를 통한 텍스트 유사도로 계산했습니다.

그림 7: 추출한 내용에 대한 정확도 평가 결과

구현 내용의 응용 및 고려사항

응용 가능성

Claude 3 및 Claude 3.5 모델을 활용하여 다양한 분야에서 PDF 파일을 분석하고 중요한 데이터를 추출하는데 응용할 수 있습니다.

  1. 계약서 분석: 법률 문서에서 중요 조항 추출 및 요약
  2. 재무보고서 처리: 재무제표에서 주요 지표 자동 추출
  3. 의료 기록 관리: 환자 기록에서 중요 의료 데이터 추출
  4. 학술 연구: 논문에서 핵심 내용 및 참고문헌 자동 추출
  5. 제품 메뉴얼 분석: 기술 문서에서 주요 사양 및 지침 추출

개선 방향

효과적인 PDF 파싱 솔루션을 구축하기 위해 서드파티 OCR 활용, 보안 및 규정 준수, 대용량 처리, 프롬프트 관리 기능 활용, 사용자 피드백 통합 등의 개선 방향을 고려할 수 있습니다.

  1. OCR 통합: 본 블로그에서는 프롬프트 엔지니어링에 초점을 맞추었지만, Amazon Textract 또는 서드파티 OCR을 활용하여 이미지 기반PDF도 효과적으로 파싱할 수도 있습니다. 이를 통해 더 다양한 유형의 PDF를 처리할 수 있을 것입니다.
  2. 보안 및 규정 준수: 민감한 데이터가 포함된 PDF 처리 시 데이터 보안과 규정 준수에 대한 추가적인 고려가 필요합니다. Amazon Macie를 이용하면 이러한 PII 및 민감정보를 탐지하고 제거하는데 도움을 받을 수 있습니다. (참조 Blog) 또한 보안과 관련하여, Amazon Bedrock에서는 Guardrails를 통해서 생성형 AI 애플리케이션에서 책임감 있는 AI 정책을 구현하기 위해 사용자 지정 보호 장치를 제공하고 있습니다.
  3. 대용량 처리: 대량의 PDF를 효율적으로 처리하기 위한 병렬 처리 및 최적화 전략이 필요할 수 있습니다.
  4. Prompt Management 기능 활용: Amazon Bedrock에서 제공하는 Prompt Management 기능을 활용하여 프롬프트 관리와 최적화를 효율적으로 수행할 수 있습니다.
  5. 사용자 피드백 통합: PDF 파싱 결과에 대한 사용자 피드백을 수집하고 이를 모델 개선에 반영하는 시스템을 구축할 수 있습니다.

결론

Amazon Bedrock의 파운데이션 모델, 특히 Anthropic의 Claude 3 및 Claude 3.5 모델을 활용한 PDF 파싱 기법은 기존 OCR 기반 접근 방식의 한계를 극복하고 효과적으로 대규모 데이터 추출을 가능하게 합니다. 이 기법은 문서의 컨텍스트를 이해하고 복잡한 레이아웃에서도 중요 데이터를 식별할 수 있는 능력을 제공합니다.

이번 블로그에서는 효과적인 PDF 파싱을 위한 프롬프트 엔지니어링 기법, 특히 XML 태그 활용 방법을 살펴보았습니다. 또한 실제 비즈니스 데이터를 활용한 커스텀 평가 방법의 중요성을 강조했습니다. 이러한 접근 방식은 기업들이 PDF 문서에서 가치 있는 데이터를 신속하고 정확하게 추출하여 데이터 기반 의사결정을 내리는 데 큰 도움이 될 것입니다. 자동화된 PDF 파싱은 업무 효율성을 크게 향상시키고 인적 오류를 줄이는데도 기여할 것입니다.

향후에는 생성형 AI 모델의 지속적인 발전과 함께 PDF 파싱 기술도 더욱 정교해질 것으로 예상됩니다. 특히 멀티모달 AI 모델의 발전으로 텍스트 뿐만 아니라, 이미지, 차트, 그래프 등 다양한 요소를 포함한 PDF 문서의 종합적인 이해와 데이터 추출이 가능해질 것 입니다.

결론적으로, Amazon Bedrock의 파운데이션 모델을 활용한 PDF 파싱 기법은 기업의 데이터 활용 능력을 한 단계 높이는 솔루션이 될 것입니다. 이를 통해 기업들은 더욱 스마트하고 효율적인 데이터 중심 비즈니스 환경을 구축할 수 있을 것입니다.

Jesam Kim

Jesam Kim

김제삼 솔루션즈 아키텍트는 엔터프라이즈 고객의 클라우드 기술 도입과 문제 해결을 돕고 있으며, 특히 추천 서비스 및 생성형 AI와 같은 AIML 영역에서 비즈니스 요구사항과 과제를 해결할 수 있는 아키텍처를 설계할 수 있도록 기술적인 도움을 드리는 역할을 수행하고 있습니다.

Kichul Kim

Kichul Kim

김기철 솔루션즈 아키텍트는 고객의 요구사항을 도출하고 다양한 개발 경험과 모범사례를 바탕으로 효율적인 아키텍처를 제안하는 역할을 수행하고 있습니다. 현재는 생성형 AI를 이용한 자동화 시스템 구축을 위한 기술적인 도움을 드리고자 노력하고 있습니다.