사용자가 자신에게 맞는 정책을 빠르게 찾을 수 있도록, 비정형 공고 문서를 구조화하고 하이브리드 검색기법을 적용한 RAG 파이프라인을 직접 설계·구현했습니다.
RAG 파이프라인은 두 단계로 구성됩니다.
graph TB
%% 노드 정의 (한글 명칭)
API([<b>외부 연동:</b> 기업마당 API]):::external
PDF[<b>데이터 추출:</b> PDF 텍스트 파싱<br/>PyMuPDF 활용]:::process
LLM_STR{<b>AI 분석:</b> GPT-4o<br/>정책 필드 구조화}:::ai
DB_RAW[(<b>원문 저장소</b><br/>PostgreSQL)]:::database
CHUNK[<b>데이터 분할:</b> 청킹 처리]:::process
CTX_EMB[<b>문맥 보강:</b> 임베딩용 텍스트 생성]:::process
OPENAI_EMB([<b>AI 변환:</b> 임베딩 API 호출]):::external
DB_VEC[(<b>벡터 저장소</b><br/>pgvector)]:::database
%% 흐름 연결
API ==>|응답 수신| PDF
PDF ==>|텍스트 추출| LLM_STR
LLM_STR -.->|데이터 저장| DB_RAW
DB_RAW ==>|원문 불러오기| CHUNK
CHUNK ==> CTX_EMB
CTX_EMB ==> OPENAI_EMB
OPENAI_EMB ==>|벡터 데이터| DB_VEC
%% 스타일 설정 (고급스러운 색감)
classDef external fill:#f5f5f5,stroke:#9e9e9e,stroke-width:2px,color:#333
classDef process fill:#e3f2fd,stroke:#2196f3,stroke-width:2px,color:#0d47a1
classDef ai fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px,color:#4a148c
classDef database fill:#fff8e1,stroke:#ffb300,stroke-width:2px,color:#ff6f00
%% 영역 구분
subgraph STAGE1 [1단계: 데이터 수집 및 구조화]
API
PDF
LLM_STR
end
subgraph STAGE2 [2단계: 검색 최적화 및 벡터화]
DB_RAW
CHUNK
CTX_EMB
OPENAI_EMB
DB_VEC
end
chunk_text)왜 이렇게 만들었나
정책 공고를 직접 보니 "지원대상", "지원내용", "신청방법" 같은 섹션이 반복되는 구조가 있었습니다. 문서 전체를 통째로 임베딩하면 "지원대상이 뭔가요?" 같은 질문에 엉뚱한 섹션이 딸려오는 문제가 생겼고, 이 구조를 활용해 의미 단위로 쪼개면 검색 정밀도가 올라갈 것이라 판단했습니다.
처리 순서
□ ■ ● ○ ▶ ◆ ※ 숫자. ① ② 가. 나. 등오버랩 100자를 둔 이유: 섹션 경계에서 문맥이 잘리는 경우를 대비해 앞 청크의 끝 부분을 다음 청크 앞에 붙였습니다. 실제로 "신청기간은 ~까지이며" 같은 문장이 두 청크에 걸쳐 있어도 검색이 되는 걸 확인했습니다.