카테고리 없음

[후기] 재정 정보 AI 검색 알고리즘 경진대회 공모전-2

루피95 2025. 3. 16. 16:44

안녕하세요! 오늘은 작년 데이콘에서 진행했던 '재정 정보 AI 검색 알고리즘 경진대회 공모전' 후기 2편을 가지고 왔습니다!

저번 후기에선 대회소개부터 시작해 데이터셋 소개, 전체적인 대회 전략 그리고 model selection까지 다뤄봤습니다.

이번엔 이어서 RAG를 한 번 다뤄보도록 하겠습니다. RAG 모든 부분을 다루진 못하고 그 중에서도 문서 전처리, chunk를 어떻게 나눴는지에 대해서 어떤 고민이 있었고 어떻게 문제를 해결하려고 노력했는지 등 작성해 보도록 하겠습니다!

 

제 글이 비슷한 고민을 하시는 분들께 조금이나마 도움이 되길 바라며, 시작하도록 하겠습니다!

 

 


 

4. RAG(Retrieval-Augmented Generation)

대회의 데이터셋이나 규칙을 보면 확실히 대회의 의도가 Fine-tuning 보단 RAG 쪽에 가깝다는 걸 알 수 있습니다. 

따라서 대회의 질의응답 모델을 만들때 가장 신경써야하는 부분이며, 저희의 공수도 가장 많이 들어갔던 부분이었습니다. 그럼 저희가 RAG에서 어떤 고민과 문제를 갖고 있었는지, 그리고 그를 위한 어떤 다양한 시도를 했는지 알아보도록 하겠습니다!

그전에 RAG가 무엇인지 정확히 알아야 저희의 프로젝트를 이해하기 더 쉽겠죠?


RAG란 무엇인가요?

LLM은 학습시점을 기준으로 학습된 데이터에 한해서는 올바른 답을 제공하지만, 학습되지 않은 질문에 대해선 사실이 아니지만, 그럴듯한 답을 만들어내는 환각현상(Hallucination)이 발생하게 됩니다.

이런 환각현상을 보완하기 위해 나온 기법이 바로 RAG입니다.

 

RAG란 Retrieval-Augmented Generation의 약자로 '검색 증강 생성' 이라고 번역되며, 외부 지식을 활용하는 검색 단계를 추가해 LLM이 학습되지 않은 내용에 대해서도 정확한 답을 하도록 만듭니다.

 

좀 더 쉽게 얘기하자면, 대학교 오픈북 시험과 같다고 보면 됩니다.

수업 때 배운 모든 내용을 완벽히 학습해 기억하진 못하지만, 시험 문제에 대해 필요 지식이 전공책 몇페이지, 어느 위치에 있는지 알며 해당 내용을 참고해 문제를 푸는 것입니다. 이 때 가장 중요한 건 질문과 관련된 내용이 어딨는지 알아야하며, 핵심 내용만 뽑을 수 있어야겠죠?

 

LLM도 마찬가지입니다.

LLM은 질문에 대한 내용이 학습되진 않았지만, 참고 문서에서 질문과 비슷한 내용들을 찾고 그를 바탕으로 답변을 만들어 내게 됩니다. 따라서 여기서 중요한 부분은 문서에서 질문과 관련된 내용을 찾는 것이 됩니다.

그런데 관련된 내용을 찾고, 끄집어 내기 위해선 하나의 문서를 작은 단위로 나누고 관리할 수 있어야하며, 문서를 나누는 것도 잘!! 나눠야 합니다!

 

여기서 RAG의 중요 포인트가 나오는데요,

 

문서를 작은 단위로 나누는 것 -> Chunking

질문과 관련된 내용을 찾는 것 -> Retrieval

 

이 되며, 두 가지가 RAG 그리고 저희 프로젝트에서 성능을 좌지우지하는데 KeyPoint가 됩니다.


RAG에 대략적인 개요 알아보기!

이렇게 RAG가 무엇인지 그 개념그렇다면 RAG 파이프라인을 어떻게 구성했는지 러프하게 알아보도록 하겠습니다!

 

rag 파이프라인은 Load, Split(Chunking), Embedding, Retrieval 총 4단계로 이뤄져 있습니다.

 

우선 Loading 과정을 통해 문서를 불러옵니다. 문서는 다양한 형식이 존재할 수 있지만, 대회는 pdf 파일이므로 저희는 다양한 pdf loader를 사용했습니다.

 

그 다음은 문서를 불러왔다면 text의 길이를 작게 분할한 chunk를 만드는 split 과정을 거칩니다. chunk를 어떤 방식으로, 몇 글자 길이로 자르느냐에 따라 검색 결과가 매우 달라지게 되며 답변 정확도를 좌지우지했습니다.

 

이제 문서를 적절한 chunk로 나눴다면, 이 chunk들을 관리해줘야 합니다. 이때 텍스트 형태인 chunk를 관리 하기 쉬운 형태인 벡터로 변환해준 뒤, 벡터 데이터베이스에 저장해줍니다. 이때 벡터로 변환해주는게 embedding 모델이 됩니다.

어떤 embedding모델을 쓰냐에 따라 질문과 유사한 chunk가 뽑히는 확률(?)이 매우 다르므로 적절한 embedding을 사용해줘야합니다.

 

마지막으로 chunk를 벡터로 변환해 저장까지 해줬다면 입력된 질문(query)를 이용해 검색(retrieval)을 진행해서 적절한 chunk를 뽑아주면 끝입니다~!


문서 전처리를 어떻게 접근했을까요?

그렇다면 이제 본격적으로 RAG에 대해 어떤 고민이 있었고, 어떻게 문제를 해결하려고 했는지 차근차근 풀어나가보도록 하겠습니다!

 


문서별 형식

공모전에서 제공한 데이터는 두 가지 형식의 문서였습니다. 하나는 리포트 형식의 문서이며, 다른 하나는 보도자료 형식의 문서였습니다.

문서의 형식을 캡쳐해서 올리고 싶지만 저작권 문제가 있을 수 있어 링크로 대신합니다.

 

리포트 형식

예시 : https://www.fis.kr/ko/notification/data/issue_focus?articleSeq=3300

 

한국재정정보원

재정활동 디지털 플랫폼‘디브레인(dBrain)’운영 공공기관

www.fis.kr

 

 

보도자료 형식

예시 : https://www.bizinfo.go.kr/web/lay1/bbs/S1T122C128/AS/74/view.do?pblancId=PBLN_000000000093420

 

혁신창업사업화자금-창업기반지원자금(청년전용창업자금)(2024년 중소벤처기업부 소관 중소기업

 

www.bizinfo.go.kr

(사실 이 자료가 아닌데, 보도자료 형식은 아무리 찾아도 못찾겠어서 비슷해 보이는 문서로 대체합니다..)

 

대충 크게 두 분류의 문서로 분류할 수 있었습니다.

 


문서별로 어떤 문제점들이 있었나요?

그렇다면 이 문서들에서 어떤 문제점이 있었고 어떻게 해결했는가?!

결론부터 말씀드리자면, 문제점은 산더미였지만, 문서 전처리 부분에서 모든 문제를 해결하진 못했습니다.

아무래도 문서가 다양한 형식을 갖고 있고, 문서의 레이아웃이 복잡하게 이뤄져 있었기 때문에 해당 문제들을 모두 해결하기 위해선 단순 pdf loader로 text를 추출하는거론 부족했기 때문입니다.

완벽하게 문서의 내용을 추출하기 위해선  vision 모델까지 사용하는 범위까지 확장됐기 때문에 모든 문제를 해결하려고 하기 보단 저희가 할 수 있는 범위 내에서 해결하려고 노력했습니다.

 

그렇다면 각 문서 전처리에 있어 어떤 어려움이 있었는지 정리해보겠습니다.

 

다양한 구분자의 존재

리포트 문서를 살펴 보면 문장 혹은 문단이 다양한 구분자에 의해서 나뉘어져 있습니다.

"▶", "-", "ISSUE", "FOCUS" 등 다양한 구분자로 이뤄져 있었고, chunk를 나눌 때 어떤 기준으로 나눌 지 고민이 많았습니다.

 

각주, 머릿글 존재

리포트 문서의 경우 항상 머릿글이 존재했습니다.

머릿글의 경우 문서의 항상 윗부분에 존재하며, 각주는 참조 문헌이나 덧붙이는 말로 주로 문서의 아랫 부분에 존재하게 됩니다. 

이 때, 문제는 pdf loader로 문서를 추출할 때 머릿글, 각주가 문서 내용 사이에 들어가게 돼 추출된 문장이 이상한 내용으로 추출될 수 있습니다.

 

다양한 표와 차트, 도식의 존재

리포트 형식과 보도자료 형식 모둔 복잡한 표가 존재했습니다.

또한 리포트 형식은 다양한 종류의 차트가 존재했고, 보도자료에는 작업 프로세스를 나타낸 복잡한 순서도가 포함돼 있었습니다.

일단 표, 차트, 순서도의 경우 단순 text 추출을 하게 되면 잘못된 내용으로 chunk를 만들게 되며, 특히 순서도의 경우 작업 순서가 뒤죽박죽 문제가 있었습니다.

 

문서 형식의 다양성

그리고 문서가 리포트, 보도자료 형식으로 이뤄져 있고 그 안에서도 문서별로 특징이 있었습니다.

따라서 모든 문서에서 최적화된 옵션값을 찾아내는 게 포인트라고 판단했습니다.


위의 문제점을 어떻게 해결했을까요?

그렇다면 위의 문제점을 어떻게 바라보고, 어떤식으로 해결했는지 작성해보도록 하겠습니다!

 

다양한 구분자의 존재

다양한 구분자가 존재했을 때 어떤 구분자로 기준으로 할까? 라는 고민을 했습니다.

그때 답은 "모든 구분자를 다 기준으로 하자!" 였습니다.

모든 구분자가 나름 내용을 구분짓는 기호라고 판단했으며, 대신 구분자에 대해 우선순위를 두고, chunk를 나누는 게 가장 합리적이라고 결론 내렸습니다.

따라서 langchain_text_splitters에서 제공하는 RecursiveCharacterTextSplitter 함수를 이용해 다양한 구분자를 기준으로 chunk를 나눴습니다.

 

각주, 머릿글 존재

각주와 머릿글은 따로 처리하기 어려웠습니다.

제대로 처리하려면 object detection을 이용해 각주와 머릿글을 인식하고 제외하는 방식으로 문제를 해결해야 할 것 같은데, 그러기엔 모델 자체가 너무 커질 것 같고 공모전 취지와도 맞지 않을거라고 생각했기 때문입니다.

따라서 각주와 머릿글은 따로 문제를 해결하진 않았습니다.

 

다양한 표와 차트, 도식의 존재

해당 문제도 제대로 처리하기 위해선 vision모델을 사용해야 완벽히 처리할 수 있다고 판단했습니다.

또한, test.csv의 질문을 보면 표, 차트, 도식과 관련된 질문들이 적었고, 차라리 우리가 하기 어려운 부분에 시간과 공수를 쏟기 보단 우리가 접근하기 좀 더 쉬운 chunk를 나누는 방법에 공수를 더 들여서 성능을 높이는 게 더 효율적이라고 판단했습니다. 

따라서 표와 차트, 도식을 따로 건드리진 않았습니다.

 

문서 형식의 다양성

문서가 크게 두 종류로 나뉘어져 있고 두 종류 안에서도 문서별로 고유의 특징을 갖고 있었습니다.

그래서 저희는 모든 문서를 한번에 처리하기 보단 문서별로 최적의 옵션 값을 찾아보자! 라는 결론을 내리게 됩니다. 

아무래도 문서별로 처리했을 때 chunk가 내용에 따라 더 잘 나눠지고 결국 질문에 대해서 완성된 답을 반환할 수 있다고 생각했기 때문입니다.

 


 

이렇게 문서 전처리(chunk)에 대해 어떤 고민이 있었고, 어떻게 해결하려고 노력했는지 알아봤습니다.

이렇게 쓰고 보니 정말 별거 없고, 뭐 제대로 해결한 게 없어보이네요(머쓱..)

그래도 그때는 치열하게 고민했고, 포기라는 것도 하나의 선택지라고 판단해서 내린 결론이었습니다.

 

다음엔 이제 RAG 나머지 부분들과 Prompt Engineering 부분을 마저 작성하도록 하겠습니다.(제발.. 다 작성할 수 있기를...)

긴 글 읽어주셔서 감사하고 의견이나 잘못된 내용에 대해서는 댓글로 둥글게(^^) 부탁드립니다.!!

 

감사합니다.

반응형