품질 엔지니어가 RAG 시스템에 다음과 같이 질문합니다: “SOP-8812에 따른 수성상 1(Aqueous Phase 1)의 최대 유속은 얼마인가요?”

시스템은 청크 하나를 검색해 반환합니다. 해당 청크에는 ’1.8 mL/min’이라는 수치가 적혀 있습니다. 하지만 정작 그 바로 앞 문장 — “경고: 지질 나노입자(LNP)를 처리하는 경우 냉각 재킷이 작동 중인지 확인하십시오” — 은 누락되어 있습니다. 엔지니어는 유속을 설정합니다. 나노입자가 과열됩니다. 배치(생산분) 전체를 폐기하게 됩니다.

이것은 모델의 환각(Hallucination) 문제가 아닙니다. 모델은 자신에게 주어진 데이터를 바탕으로 정확하게 답했을 뿐입니다. 이는 전적으로 청킹(Chunking) 의 문제이며, 생명과학 RAG 배포 과정에서 가장 엔지니어링이 미흡하게 이루어지는 계층이기도 합니다.

RAG와 파인튜닝을 결합한다는 고차원적 전략 결정은 이미 널리 정립되어 있습니다. 더 어렵고도 본질적인 질문 — 즉 시스템이 규제 준수 수준(compliance-grade)의 신뢰할 수 있는 답변을 내놓을지, 아니면 규제 위반 수준의 재앙을 초래할지를 결정짓는 질문 — 은 바로 규제 문서를 어떻게 파싱하고, 청킹하며, 인덱싱하고, 모델에 제시하느냐입니다.


핵심 문제: 고정 크기 청킹이 SOP를 파괴한다

문서의 구조를 무시하고 512토큰 단위로 기계적으로 분할하는 표준 고정 크기 청킹(Fixed-size chunking)은 대다수 RAG 튜토리얼에서 기본으로 사용됩니다. 그러나 이는 SOP를 가치 있게 만드는 필수 문맥을 파괴하는 가장 빠른 방법이기도 합니다.

생명과학 문서는 일반 산문이 아닙니다. 제목(헤더), 중첩 섹션, 표, 상호 참조(cross-references), 안전 경고, 그리고 버전 관리 메타데이터로 이루어진 정밀하게 구조화된 산출물입니다. 이를 맹목적으로 자르게 되면 다음과 같은 치명적인 문제가 발생합니다:

  • 안전 경고가 적용 대상 절차와 분리됩니다. 냉각 재킷에 관한 경고가 정작 자신이 수식해야 하는 RPM 제한 수치 청크에서 떨어져 나가 버립니다.
  • 상호 참조가 끊어집니다. SOP-402에 “섹션 5.1의 표 3을 참조하십시오”라고 명시되어 있어도, 표 3이 다른 청크로 넘어가면 링크가 소실됩니다.
  • 버전 메타데이터가 증발합니다. 문서 ID, 버전 번호, 섹션 참조 없이 “450 RPM을 초과하지 마십시오”라고만 적힌 청크는 추적이 불가능하며, 이는 명백한 ALCOA+ 규정 위반입니다.

해결책은 더 나은 임베딩 모델을 찾는 것이 아닙니다. 해결책은 더 견고한 데이터 수집(Ingestion) 파이프라인을 구축하는 것입니다.


부모-자식 청킹: 실제로 작동하는 아키텍처

구조화된 규제 문서를 처리하는 데 가장 효과적인 패턴은 부모-자식(Parent-Child, 또는 Small-to-Big) 청킹입니다. 이는 RAG의 근본적인 역설, 즉 ’검색 정확도에는 작은 청크가 유리하지만, LLM의 종합 및 맥락 이해에는 큰 청크가 유리하다’는 딜레마를 깔끔하게 해결합니다.

작동 방식

                    SOP Document                 
                         │                       
          ┌──────────────┼──────────────┐        
          │              │              │        
     Section 4.1    Section 4.2    Section 5.0   
     (Parent Chunk) (Parent Chunk) (Parent Chunk)
     ~1000 tokens   ~1000 tokens   ~1000 tokens  
          │              │              │        
    ┌─────┼─────┐   ┌────┼────┐   ┌────┼────┐    
    │     │     │   │    │    │   │    │    │    
   4.1a  4.1b  4.1c 4.2a 4.2b  5.0a 5.0b 5.0c    
  (Child)(Child)(Child)            (Child)       
  ~100t  ~100t  ~100t               ~100t        

1단계: 문서 구조에 따라 파싱합니다. 범용 텍스트 분할기를 사용하지 마십시오. 문서를 파싱하여 제목, 소제목, 목록, 표와 같은 구조적 경계를 명확히 식별해야 합니다. 의미론적으로 내용을 그룹화합니다(예: 섹션 5.1과 그 하위의 모든 글머리 기호 항목이 하나의 블록을 이룸).

2단계: 모든 청크에 글로벌 메타데이터를 주입합니다. 특정 단계에 “밸브를 엽니다”라고만 적혀 있다면, 해당 청크에는 반드시 Doc_ID: SOP-402, Title: Bioreactor Sterilization, Version: 3.0, Section: 5.0 Procedure와 같은 정보가 포함되어야 합니다. 이렇게 해야 LLM이 해당 청크를 단독으로 보더라도 어떤 문서의 맥락인지 정확히 인지할 수 있습니다.

3단계: 부모(Parent) 청크와 자식(Child) 청크를 생성합니다. 부모 청크는 전체 섹션 단위(~1,000토큰)입니다. 자식 청크는 개별 문장이나 세부 절차 단계 단위(~100토큰)입니다.

4단계: 자식 청크만 임베딩합니다. 자식 청크를 벡터 데이터베이스에 저장합니다. 그리고 별도의 키-값(Key-Value) 문서 저장소 포인터를 통해 각 자식 청크를 해당 부모 청크에 연결합니다.

검색 흐름

User Query: "What is the RPM limit for centrifuge X-100?"
    │                                                    
    ▼                                                    
Search Child Chunks (high precision, bite-sized)         
    │  → Finds: "Do not exceed 450 RPM."                 
    │                                                    
    ▼                                                    
Follow pointer to Parent Chunk                           
    │  → Retrieves full section including:               
    │    "Warning: If processing lipid nanoparticles,    
    │     ensure cooling jacket is active.               
    │     Do not exceed 450 RPM."                        
    │                                                    
    ▼                                                    
Send Parent Chunk to LLM                                 
    → Surrounding warnings and procedural context intact 

LLM은 RPM 한계값과 함께 필수 안전 경고를 온전히 전달받습니다. 품질 엔지니어의 배치 생산분은 안전하게 보호됩니다.

구현 스택

레이어 권장 도구 비고
문서 파싱 Docling (IBM), OpenParse 레이아웃 인식형; 제목, 표, 목록 구조 식별
청킹 오케스트레이션 LangChain RecursiveTextSplitter 문서 구조 기반 맞춤 구분자(Custom Separators) 적용
벡터 DB (자식 청크) Qdrant, Milvus, Pinecone 메타데이터 필터링 및 역할 기반 접근 제어(RBAC) 지원 필수
키-값 저장소 (부모 청크) Redis, MongoDB, PostgreSQL 포인터가 연결된 전체 부모 섹션 저장

하이브리드 인덱싱: 벡터 검색만으로는 실패하는 이유

생명과학 쿼리는 의미론적(Semantic) 검색과 완전 일치(Exact-match) 검색이 복합적으로 얽혀 있습니다. 순수 벡터 검색은 전자는 잘 처리하지만 후자에서는 취약성을 드러냅니다.

의미론적 쿼리 — “생물반응기 온도 이탈(excursion)을 어떻게 해결합니까?” — 는 조밀 벡터 임베딩(Dense vector embeddings)으로 훌륭하게 처리됩니다. 모델은 “해결(fix)“이라는 단어를 “트러블슈팅 절차(troubleshooting steps)“와 자연스럽게 매칭합니다.

완전 일치 쿼리 — “SOP-881에 따른 원심분리기 X-100의 RPM 제한은 얼마인가요?” — 는 벡터 검색을 무너뜨립니다. “USP <85>”(세균 엔도톡신)와 “USP <87>”(생물학적 반응성 시험)은 임베딩 상으로는 거의 동일하지만, 규제적 의미는 완전히 다릅니다. “SOP-QA-007”과 “SOP-QA-070” 역시 코사인 유사도 상으로 매우 가깝게 매칭되어 버립니다.

관계형 쿼리 — “EQ-042 장비와 연계된 CAPA는 무엇인가요?” — 는 벡터 검색이나 단순 키워드 검색 모두 제공할 수 없는 문서 간 관계 파악을 필요로 합니다.

3중 인덱스 스택

인덱스 유형 처리 대상 구현 방식
조밀 벡터 (Dense Vector) 의미론적 의도 매칭 자식 청크 대상 도메인 적응형 임베딩(BioBERT, LLM-Embedder, FINBGE 등)
BM25 (어휘 검색) 정확한 장비 ID, 배치 번호, GxP 약어 BM25를 통한 청크 인덱싱; 상호 순위 융합(RRF)으로 벡터 결과와 결합
GraphRAG 문서 간 관계 파악 개체(Entity)를 추출하여 SOP 청크를 장비, 역할, CAPA, 일탈(Deviation)과 연결

제약 환경에서 BM25는 결코 양보할 수 없는 필수 요소입니다. 품질 엔지니어가 “SOP-QA-042”를 검색할 때 필요한 것은 그 특정 문서이지, 유사한 의미 내용을 담은 5개의 다른 SOP가 아닙니다. 상호 순위 융합(Reciprocal Rank Fusion, RRF)은 벡터 검색과 BM25 검색의 순위 결과를 단일 통합 순위로 결합하여, 의미론적 재현율(Recall)과 키워드 정밀도(Precision)를 동시에 확보해 줍니다.


표 추출: 생명과학 RAG의 아킬레스건

SOP는 주요 공정 파라미터(CPP), 허용 기준(Acceptance Criteria), 장비 사양, 시험 프로토콜 등 무수한 표로 채워져 있습니다. 이 표들에는 품질 엔지니어가 반드시 확인해야 하는 핵심 수치(pH 범위, 압력 한계, 온도 임계값, 유속 등)가 담겨 있습니다.

표준 PDF 파서는 이러한 표를 완전히 훼손합니다.

pypdf나 pdfplumber 같은 도구로 표를 읽으면 행과 열이 평탄화되어 선형적인 숫자 나열로 변환됩니다. 예를 들어 다음과 같은 표가 있다고 가정해 보겠습니다:

Buffer Type Min Flow Target Flow Max Flow
Aqueous Phase 1 1.2 1.5 1.8

…이 표는 대략 다음과 같은 텍스트로 바뀝니다: Buffer Type Aqueous Phase 1 Min Flow 1.2 Target Flow 1.5 Max Flow 1.8. 헤더와 값 사이의 2차원 구조적 관계가 완전히 사라지는 것입니다.

전략 1: 구조적 레이아웃 엔진

표를 단순 텍스트가 아닌 격자(Grid) 구조로 온전히 취급하는 레이아웃 인식형 파서를 사용해야 합니다:

  1. Docling (IBM): Microsoft Table Transformer를 활용하여 셀 경계, 행 병합(Row span), 열 인덱스, 헤더 플래그를 정밀하게 식별합니다.
  2. OpenParse: UniTable을 사용하여 유사한 격자 인식 기반 추출을 수행합니다.
  3. GitHub Flavored Markdown 또는 순수 HTML로 출력: 특히 다단계 중첩 헤더를 가진 복잡한 표의 경우, 계층 구조를 보존할 수 있는 HTML(<th rowspan="2"> 등)이 구조적으로 우수합니다.
  4. 표를 절대로 반으로 쪼개지 말 것: 표는 분할할 수 없는 단일 청크로 취급하고, 표 앞뒤의 2~3개 단락을 함께 포함해야 합니다. 표 자체에는 파라미터 수치가 들어가고, 주변 텍스트에는 그에 따르는 조건이 기술되어 있기 때문입니다.

전략 2: 멀티모달 비전 엔진

완벽한 형식의 마크다운 표라 할지라도 벡터 유사도 검색에서는 실패할 수 있습니다. 단순한 숫자 행렬은 의미 있는 임베딩 벡터를 형성하지 못하기 때문입니다.

이에 대한 해결책은 바로 시각적 레이트 인터랙션(Visual Late Interaction)을 사용하는 멀티모달 모델인 ColPali 또는 ColQwen입니다.

User Query: "What is the pressure limit for Column 2?"
        │                                             
        ▼                                             
  ColPali Retriever                                   
  (Scans page patches visually)                       
        │                                             
        ▼                                             
  Identifies Page 14 contains the exact visual grid   
        │                                             
        ▼                                             
  Fetches pre-parsed HTML/Markdown of Page 14         
        │                                             
        ▼                                             
  LLM receives clean structured table data            

텍스트를 추출하는 대신, ColPali는 PDF 페이지 전체를 이미지로 변환하고 시각적 패치(Visual patch)로 분할하여 표의 공간적 배치를 있는 그대로 매핑합니다. 사용자가 특정 값을 질의하면, 모델은 ‘레이트 인터랙션(Late Interaction)’ 메커니즘(MaxSim)을 통해 텍스트 질의를 해당 데이터가 위치한 픽셀 패치와 직접 매칭합니다.

텍스트 추출 과정의 왜곡을 원천 차단하고 시각적 관련성을 바탕으로 정확한 페이지를 검색해 내는 방식입니다.

통합 파이프라인

단계 수행 작업 기술 스택
수집 (Ingestion) SOP를 페이지 단위로 분할; 멀티모달 시각적 임베딩 생성 ColPali + Qdrant 또는 Pgvector
파싱 (Parsing) 레이아웃 인식형 파서를 통해 표를 HTML/Markdown으로 추출 Docling (Table Transformer)
매핑 (Mapping) 파싱된 표를 해당 페이지 번호에 역매핑 키-값 저장소 (Redis/MongoDB)
검색 (Retrieval) 시각적 인덱스를 통해 상위 K개 관련 페이지 검색 시각적 벡터 검색 (Visual vector search)
종합 (Synthesis) 매칭된 페이지에서 정제된 HTML 표를 가져와 LLM에 전달 프론티어 VLM (GPT-4o, Gemini 1.5 Pro 등)

시각적으로 인덱싱하고, 구조적으로 읽어냅니다(Index visually, read structurally). 이 설계를 통해 깨진 표로 인한 환각을 방지하고, 규제 파라미터가 완벽한 정확도로 전달되도록 보장합니다.


복잡한 표를 위한 프롬프트 엔지니어링

완벽하게 추출되었다 하더라도, 복잡하게 중첩된 HTML 표는 LLM을 혼란스럽게 만들 수 있습니다. colspan 및 rowspan 속성이 포함된 표는 암묵적인 헤더 계층 구조를 형성하므로, 선형적 토큰 처리를 수행하는 LLM이 이를 정확히 추적하기 어렵습니다.

메타데이터 래퍼

원시 HTML 표를 프롬프트에 그대로 던져 넣지 마십시오. 표의 거시적 맥락(매크로 컨텍스트)을 정의하는 구조화된 메타데이터로 표를 감싸야 합니다:

### [CONTEXT BLOCK: TABLE DATA]
- Document ID: SOP-8812
- Section: 4.3 Phase II Elution Parameters
- Table Title: Critical Process Parameters for Column Chromatography
- Table Type: Complex/Nested Matrix
- Structural Map:
  - Columns 1-2: Equipment State and Buffer Type
  - Columns 3-5: Flow Rate Limits (Nested under Min / Target / Max)
  - Rows 1-3: Resin Lot Variant A
  - Rows 4-6: Resin Lot Variant B

이를 통해 LLM은 원시 HTML을 분석하기 전에 구조적 청사진을 먼저 파악할 수 있습니다.

시스템 프롬프트 지침

헤더 평탄화(Header Flattening) — 답변을 생성하기 전에 모델이 중첩 관계를 먼저 재구성하도록 강제합니다:

CRITICAL INSTRUCTION FOR TABLE READING:
When reading HTML tables with nested attributes (colspan or rowspan),
do not evaluate cells in isolation. Trace parent headers downwards
and row labels leftwards. Before answering, execute a "Table Mapping
Step" stating exact coordinates: [Row Label] -> [Parent Header /
Child Header] -> [Value].

인접 셀 확인(Neighbor Check) — 모델이 수반되는 전제 조건과 제약사항을 반드시 확인하도록 강제합니다:

DATA VERIFICATION RULE:
Life science compliance parameters are highly conditional. When
identifying an acceptable threshold in a table cell, check adjacent
cells for mandatory qualifying conditions, footnotes, or sub-lot
variations. Include all constraints in your output.

내부 추론 과정

이러한 지침이 적용되면, “SOP-8812에 따른 수성상 1의 최대 유속은 얼마인가요?“라는 질문에 대한 모델의 생각 사슬(Chain-of-Thought)은 다음과 같이 정밀하게 전개됩니다:

  1. 표 위치 확인: 컬럼 크로마토그래피 주요 공정 파라미터(Critical Process Parameters for Column Chromatography)
  2. 행 탐색: Aqueous Phase 1 — tbody의 1행
  3. 열 추적: 셀 1 = Buffer Type, 셀 2 = 1.2, 셀 3 = 1.5, 셀 4 = 1.8
  4. 헤더 매핑: Flow Rate Limits가 2~4열에 걸쳐 병합(colspan="3"); 2열 = Min, 3열 = Target, 4열 = Max
  5. 좌표 확정: [Aqueous Phase 1] → [Flow Rate Limits / Max] → 1.8
  6. 인접 셀 확인: 인접 셀에 별도의 조건부 단서 없음

헤더 평탄화 지침이 없다면 모델은 1.2(최솟값)를 잘못 반환하거나 어떤 열이 무엇을 나타내는지 혼동할 수 있습니다. 지침이 적용되면 답변은 결정론적(Deterministic)으로 정확해집니다.

HTML vs. JSON

만약 파싱 파이프라인에서 사전 계산된 셀 좌표와 부모 매핑이 포함된 계층형 JSON 형태로 표를 출력할 수 있다면, HTML보다 JSON을 선호하는 것이 좋습니다. 토큰 오버헤드를 줄여줄 뿐 아니라, LLM이 거의 오차 없이 파싱할 수 있는 명확한 키(row_context, column_hierarchy)를 제공하기 때문입니다.


피해야 할 함정

규제 문서에 고정 크기 청킹을 적용하는 것. 모든 SOP에는 고유한 의미적 경계가 있습니다. 이를 존중하는 것은 선택이 아니라 필수입니다.

표를 평탄한 일반 텍스트로 임베딩하는 것. 행과 열의 관계 자체가 곧 핵심 정보입니다. 이를 평탄화하면 정보는 소실됩니다.

제약 환경에서 벡터 전용 검색을 사용하는 것. 장비 ID, 배치 번호, 규제 참조 번호는 정확한 일치 검색이 필요합니다. BM25를 도입하지 않는다면 품질 엔지니어에게 엉뚱한 문서를 전달하는 위험을 감수해야 합니다.

메타데이터 래퍼 없이 표를 프롬프트에 투입하는 것. colspan/rowspan이 포함된 중첩 헤더는 순차적 토큰 처리를 교란합니다. 구조적 매핑의 유무가 정답과 ’자신만만한 오답’을 가릅니다.

표를 반으로 자르는 것. 표는 쪼갤 수 없는 하나의 단위입니다. 조건과 맥락을 제공하는 주변 텍스트를 반드시 함께 포함해야 합니다.


결론

헤드라인을 장식하는 것은 화려한 하이브리드 RAG와 파인튜닝 아키텍처입니다. 하지만 실제 시스템에 문제가 발생했을 때 비난을 받는 것은 언제나 청킹 파이프라인입니다.

부모-자식 청킹은 고정 크기 분할이 파괴하는 안전 경고를 보존합니다. 하이브리드 인덱싱(조밀 벡터 + BM25)은 순수 의미 검색이 놓치는 정확한 장비 ID와 규제 참조 번호를 완벽히 포착합니다. 듀얼 엔진 표 추출(구조적 파싱 + 멀티모달 비전)은 표준 PDF 파서가 무의미한 노이즈로 뭉개버리는 컴플라이언스 파라미터를 복원해 냅니다. 그리고 메타데이터 래퍼와 헤더 평탄화 지침을 갖춘 프롬프트 엔지니어링은 LLM이 표를 정확하게 읽어내도록 보장합니다.

규제 대상인 생명과학 분야에서 검색 파이프라인은 단순한 배관 작업이 아닙니다. 감사관(Auditor)이 신뢰하고 승인할 시스템인지, 아니면 경고 서한(Warning Letter)을 받게 될 시스템인지를 판가름하는 핵심 경계선입니다. 그에 걸맞은 철저한 엔지니어링이 필요합니다.


벤치마크 데이터, 규제 인용 및 상세 구현 내용이 포함된 전체 연구 보고서는 [[RAG Pipeline Engineering for Life Sciences SOPs - Chunking Tables and Prompt Strategy]]를 참조하십시오.

관련 글