[0. 핵심 설계 규칙 (TL;DR)]
이미지를 “객관적 구조화 설명문으로 전사할 대상”으로 정의.
이미지 1장을 VLM으로 객관적 설명문으로 만들고, 이를 임베딩해 RAG 인덱스에 적재. → 다양한 다운스트림 질의는 개별 이미지에 매번 질문하지 않고 검색(retrieval)으로 흡수됨. (multi-modal embedding 모델은 추후 도입 예정)
이미지 → [VLM] 객관적 구조화 설명문 → 임베딩 → RAG 인덱스 → (다운스트림) 검색/질의응답
- VLM은 추측/판정하지 않고 이미지에서 객관적으로 확인 가능한 요소만 빠짐없이 기술해야 한다
- 하나의 범용 설명문이 서로 다른 유형의 질의를 한 벌의 임베딩으로 커버할 수 있도록.
[1. 문제 정의 & 접근 전환]
1.1 하나의 설명문이 커버해야 하는 다운스트림
- 단일 범용 프롬프트로 뽑은 하나의 설명문이 임베딩 후 아래 질의 유형을 검색으로 커버해야 함.
| 다운스트림 유형 | 예시 | 설명문에서 이를 가능하게 하는 부분 |
|---|---|---|
| 내용 검색 | “균열 보이는 현장”, “조직도 이미지”, “안전모 미착용자” | Type / Summary / Details |
| 이미지 내 텍스트 조회 | “이 영수증 금액/날짜”, “명함 정보” | Text(원문 그대로) / Table |
| 단건 해석 | “이 다이어그램 구조”, “그래프 최고 항목” | Diagram / Chart / Details |
| 객관적 검증 | “서명 누락 여부”(이미지로 확인 가능) | Details / Text |
| 위치/시각 | “토스카나에서 찍은 사진”, “2008년 촬영” | Capture metadata |
1.2 의도적으로 범위 밖에 둔 것
“객관 사실 전사”라는 규칙 하에 의도적으로 제외. 주관/규범/집계를 파서에서 빼야 환각과 책임 범위가 통제됨.
- 규범적 판정 - “안전기준 충족?”처럼 국가/상황마다 다른 외부 기준이 필요한 판단은 배제. 단 “서명이 있다/없다”처럼 이미지로 객관 확인 가능한 사실은 포함.
- PII/보안 검출 - 자체 비식별화 필요 x. (영스증/계약서 이미지 업로드 고려)
[2. 설명문 구조 - 8섹션 + 객관성 규칙]
하나의 프롬프트로 항상 동일한 섹션 틀을 채우고 내용이 없는 섹션은 생략
다양한 시나리오(영수증/차트/조직도/현장사진)를 한 틀로 흡수하고 객관 사실만 채워 환각을 줄임.
2.1 8섹션 정의
| 섹션 | 내용 | 역할 |
|---|---|---|
| Type | • 이미지 종류 • 영수증 • 명함 • 차트 • 조직도 • 현장사진 • etc … |
헤더 / 검색 필터 |
| Summary | 객관적 1문장 요약 | 헤더 / 자기설명 |
| Details | 보이는 장면/객체/구성/배치 | 본문 / 외형 |
| Text | 이미지 내 텍스트 원문 그대로(verbatim) | 본문 / OCR (번역 금지, 언어 보존) |
| Table | 격자형 전부(표/시간표/가격표)를 GFM 마크다운 표로 재현 |
본문 / 행/열 보존 |
| Chart | 그래프(막대/선/원/산점)만. 축/범례/ 계열 + 보이는 라벨/값만 |
본문 / 값 추정 금지 |
| Diagram | 다이어그램/플로차트/조직도의 노드/ 연결 구조 |
본문 / 구조 |
| Capture metadata | 위치(좌표/지명)/촬영시각/방향/고도 | 헤더 / EXIF/geocoding 사실 |
- 헤더 섹션(Type/Summary/Capture metadata): 모든 chunk에 복제되어 이미지 자체 설명을 보조
- 본문 섹션(Details/Text/Table/Chart/Diagram): 청킹 대상.
- 서술 언어는 출력 언어 파라미터 단 Text 섹션의 원문은 원어 그대로 보존.
2.2 객관성 8규칙
프롬프트에 명시하는 제약(실험 및 튜닝 결과).
- 보이는 것만 기술 - 추론/추측/인상 평가 금지 (들판 사진을 좌표만 보고 “아레초 농가”로 단정 X)
- 규범적 판정 금지 - 외부 기준이 필요한 적법성/안전기준 판단 X
- 텍스트 번역 금지, 원문 보존 - 판독 불가 시
[판독불가] - 표/차트 값 임의 계산/추정 금지 - 인쇄된 값/라벨만
- 촬영 메타데이터는 “메타데이터 기반 사실”로 분리 표기 - 시각적 관찰과 섞지 않음
- 빈 섹션은 생략 - 없는 정보를 채우지 않음
- 섹션 내용을 코드펜스로 감싸지 않음 - 마크업 추가 금지 (영수증 OCR을 코드펜스로 감싸 렌더 깨진 이슈 보정)
- 섹션 간 중복 회피 - Details=외형 / Text=원문 전사 / Table=격자 / Diagram=구조로 역할 분리
- 시나리오 튜닝 과정에서의 주요 보정: ① Text 코드펜스 금지, ② 시간표/일정표를 Chart가 아닌 Table로 라우팅, ③ 섹션 중복 축소.
- 위 8가지 규칙은 관념/추측으로 고정된 것이 아닌 반복 실험을 통해 고정된 것들임
2.3 길이 정책 - 생성부 제한, 추출부 무제한
- 생성 섹션(VLM 서술: Summary/Details/Chart/Diagram): 완만한 상한(Summary 1문장, Details ≤~200단어 등).
- 추출 섹션(verbatim: Text/Table): 인위적 상한 없음 - 자르면 검색 recall이 깨진다. 길이는 이미지 내용에 종속.
- VLM 호출은
max_completion_tokens를 넉넉히(8192) 두어 긴 문서 truncation을 방지.
생성은 절제, 추출은 보존 → 객관적 사실을 빠짐없이 전사하기 위함
[3. 위치 파이프라인 설계]
위치 정보는 이미지에서 추측한 정보가 아닌 메타데이터에서만 추출
3.1 위치 정보 성격별 조사
| 작업 | 필요한 것 | 도구 의존성 |
|---|---|---|
| ① 좌표(위/경도) 읽기 | EXIF GPS IFD | 어느 라이브러리나 동일 결과 |
| ② XMP/IPTC 지명 태그 읽기 | XMP/IPTC 블록 | 특정 라이브러리만 가능 |
| ③ reverse geocoding(좌표→지명) | 외부 API 또는 오프라인 DB | 메타데이터 라이브러리와 무관 |
결론: ①+③. 좌표를 읽어 지명으로 변환하는 채택. 이미지 위치 메타데이터에 대해 일관적으로 정상 동작하는 것으로 확인 (동작 안정성 확보)
3.2 좌표 추출 - Pillow
6개 메타데이터 라이브러리에 동일 샘플을 적용한 결과 모두 같은 좌표를 산출함을 확인. 좌표 정확도는 변별력이 없으므로 선택 기준은 견고성/포맷/생태계가 됨
- Pillow 채택:
- VLM 파이프라인은 어차피 이미지를 디코딩/리사이즈로 Pillow에 넣는다
- → 이미 존재하는 의존성이라 좌표 읽기에 재활용.
-
- 포맷 커버리지 넓고 견고.
3.3 좌표 → 지명 - offline geocoder
- 오프라인
reverse_geocoder채택:- api key X / 네트워크X / 무제한
- 좌표→국가/행정구역/도시(도시 레벨). (도로명/POI까지는 필요하지 X)
- 좌표를 외부로 전송하지 않아 프라이버시에도 유리.
- 대량 배치/rate limit 회피에 강점.
3.4 VLM 주입 - 관찰과 사실의 분리
- 좌표/지명/방향/촬영시각을 촬영 메타데이터 문자열로 만들어 Capture metadata 섹션 입력으로 주입
- VLM에는 이를 “메타데이터 기반 사실”로 표기하고 시각적 관찰과 정보를 혼합하지 않도록 지시
[4. 청킹 전략]
설명문 한 건을 1개 벡터로 임베딩하면 정보가 희석돼 recall이 떨어짐. 의미 단위로 나누되 각 chunk가 단독으로도 검색/이해 가능하게 만드는 것이 목표.
4.1 핵심 결정
| 항목 | 결정 | 이유 |
|---|---|---|
| 분할 단위 | 하이브리드(섹션 경계 우선, 작은 섹션 병합, 큰 섹션만 내부 분할) | 의미 보존 + chunk 수 최소화 |
| 공통 헤더 | Type/Summary/Capture metadata를 모든 chunk에 복제(≤250자) | chunk 단독 자기설명성 ↑ (contextual header) |
| 크기 상한 | chunk 전체(헤더+본문) ≤ 1000자 하드 상한 | 길이 폭주 방지, 임베딩 입력 안정화 |
| 측정 단위 | 문자 수(모델 비종속) | 임베딩 모델 미정 + 기존 텍스트 청커도 문자 기반. 추후 토크나이저 교체 가능하게 함수 분리 |
| 산문 분할 | langchain RCTS 위임 | 기존 텍스트 청커와 동일 엔진/세퍼레이터/overlap |
| 표 분할 | 행 경계 분할 + 헤더행 반복 | 표 무결성 보존(셀 중간 분할 금지) |
| 메타 필드 | type/location/timestamp를 본문 외 structured 필드로도 저장 | 하이브리드 검색(필터+벡터) |
4.2 알고리즘 요지
##헤더로 섹션 분리 → 공통 헤더 1블록 구성(≤250자)- 본문 예산 = 상한 − 헤더 길이
- 섹션이 예산 이하면 atomic 유지, 초과 시 표는 행 경계, 산문은 RCTS로 분할(2번째 조각부터
(cont.)라벨) - 그리디 패킹: 본문 블록을 예산 초과 직전까지 병합(작은 섹션 흡수)
- 하드 상한 보장: RCTS는 soft target이므로 초과분을 한 번 더 재분할, 최후엔 hard-cut으로 강제
[5. 다국어 출력 설계]
설명문의 서술 언어(output_language)를 요청마다 결정
- 결정 흐름: 파일 소유 회사 식별자를 파싱 메시지로 넘겨받아 → 내부 회사정보 API로 국가/언어 코드를 조회 → 언어명으로 매핑해 프롬프트에 per-request 주입.
- fail-soft 원칙: 조회 실패/응답에 코드 없음/식별자 없음/API 미설정 - 모든 비정상 경로는 영어(English)로 귀결하며 이미지 파싱을 중단시키지 않도록 함. 위치 정보 조회 실패가 전체 파싱을 중단시키지 않는 것과 같은 원칙(부가 정보의 결핍은 본 기능을 차단하지 않는다.).
- 언어 코드→언어명 변환은 기존에 쓰던 표준 라이브러리를 재사용해 매핑 유지 비용을 낮춤.
“보조 정보(언어/위치) 추출 실패로 인한 본 파이프라인(설명 생성) 중단은 없다” 는 일관된 방어를 유지
[6. 검증 결과]
6.1 시나리오 (E2E)
9종 시나리오로 파이프라인 전 구간을 실행, 다국어 verbatim OCR/표/차트/도식/메타데이터가 정상 산출됨을 확인.
| 시나리오 | 확인 포인트 |
|---|---|
| 영수증 / 제품 | verbatim OCR(다국어), 촬영시각 메타데이터 |
| 차트(영/한) | 축/범례/계열/인쇄값만(추정 없음), Chart 섹션 |
| 표(일) | GFM 표 재현, 시간표→Table 라우팅 |
| 조직도 / 플로차트 | 노드/연결 구조(Diagram) |
| 균열 현장 | 객관적 외형 기술(규범 판정 없음) |
| 장소 | EXIF GPS → 지명 → Capture metadata 분리 표기 |
6.2 청킹 (하드캡 보장)
| 대상 | 원문 | chunks | 최대 chunk | 결과 |
|---|---|---|---|---|
| 영문 차트 | 1,525자 | 2 | 862자 | O (≤1000) |
| 일본어 표 | 1,450자 | 2 | 949자 | O |
| 조직도 | 2,258자 | 3 | 940자 | O (섹션 분리) |
| 합성 긴 산문 | 1,733자 | 2 | 940자 | O (RCTS 분할 + overlap + (cont.)) |
전 케이스 하드 상한 ≤1000 보장, 작은 섹션 병합/큰 섹션 분할/헤더 복제/overlap 정상.