Azure AI Search와 Blob Storage 연동하기, RAG 시스템 구축을 위한 실전 아키텍처
지난 3개월간 RAG(Retrieval-Augmented Generation) 시스템을 구축하면서 깨닫게 된 게 있다. LLM의 가장 큰 문제는 “모르는 것도 마치 아는 것처럼 답변한다”는 거다. 이를 hallucination이라고 부르는데, 정말 위험하다. 금융 상담을 한다고 했는데 완전히 잘못된 정보를 제시하면? 의료 조언을 한다고 했는데 엉뚱한 약을 추천하면? 재앙이다.
하지만 여기 완벽한 해결책이 있다. RAG 시스템이 바로 그거다. 사용자의 질문에 관련된 정보를 먼저 검색한 후, 그 정보를 LLM에게 제공해서 답변하게 하는 거다. 이렇게 하면 LLM이 알고 있는 정보만으로 답변하게 돼서, hallucination을 크게 줄일 수 있다.
Azure에서는 이를 구현하기 위한 완벽한 도구들이 있다. AI Search는 강력한 검색 엔진이고, Blob Storage는 문서를 저장하는 공간이다. 이 둘을 연동하면 엔터프라이즈급 RAG 시스템을 만들 수 있다. 내가 실제로 여러 프로젝트에서 이 아키텍처를 구현해봤고, 성능과 비용 측면에서 최적화된 방법을 배웠다. 그 경험을 공유하려고 한다.
RAG 시스템이 정확히 뭐 하는 거?
먼저 RAG의 기본 개념부터 정리하자. RAG는 “검색 후 생성(Retrieval-Augmented Generation)”의 약자다. 프로세스는 이렇다.
사용자가 질문을 한다. “우리 회사의 2024년 분기별 매출은?” 이 질문이 LLM에 바로 가는 게 아니라, 먼저 검색 엔진에 들어간다. 검색 엔진이 “2024년 분기별 매출”과 관련된 문서들을 찾는다. 관련 문서들을 찾으면, 그 내용을 LLM과 함께 사용자 질문에 전달한다. LLM은 “아, 이 정보들을 바탕으로 답변해야 하는구나”라고 이해하고 정확한 답변을 생성한다.
이게 왜 중요한가? 두 가지 이유가 있다.
첫째, hallucination 방지다. LLM은 훈련 데이터에 없는 것은 모른다. 하지만 모르는 걸 모른다고 말하지 않고 그럴듯하게 지어낸다. 특히 최신 정보나 조직의 내부 정보는 훈련 데이터에 없으니까 틀린 답변을 할 가능성이 높다. RAG 시스템을 쓰면 실제로 있는 정보만 바탕으로 답변하게 돼서 이 문제가 해결된다.
둘째, 최신 정보 활용이다. GPT-4의 훈련 데이터는 2024년 4월까지다. 그 이후의 정보는 모른다. 하지만 Blob Storage에 최신 문서들을 계속 업로드하고, 그것을 AI Search에서 인덱싱하면? LLM이 최신 정보를 알 수 있게 된다. 실제로 운영하는 회사들은 이걸로 엄청난 이득을 본다.
셋째, 조직의 프라이빗 데이터 활용이다. 회사의 내부 정책, 고객 정보, 기술 문서 같은 것들은 LLM의 훈련 데이터에 절대 들어갈 수 없다. 이런 데이터들을 RAG 시스템에 넣으면, LLM이 회사 특화된 답변을 할 수 있게 된다.
아키텍처 설계, 어떻게 연결할 것인가
이제 실제 아키텍처를 생각해보자. 여러 구성 방법이 있는데, 내가 가장 효과적이라고 생각하는 구조는 이렇다.
최하단에 Blob Storage가 있다. 여기에 모든 문서들이 저장된다. PDF, Word, 텍스트 파일 등 다양한 형식이 들어올 수 있다. 이 파일들이 자동으로 처리되어야 한다. 누군가 새로운 문서를 업로드하면, 자동으로 다음 단계로 진행되어야 한다는 뜻이다.
중간에 처리 레이어가 있다. 여기서는 Blob Storage의 문서들을 텍스트로 변환하고, 청킹(Chunking)한다. Azure Document Intelligence(예전의 Form Recognizer)를 써서 PDF 같은 복잡한 형식의 파일을 추출할 수 있다. 그리고 추출된 텍스트를 작은 단위로 나눈다. 보통 1000~2000 토큰 정도 크기의 청크로 나눈다.
그 다음이 임베딩 단계다. 각 청크를 벡터로 변환한다. Azure OpenAI의 text-embedding-ada-002 모델을 쓰거나, 최신 모델들을 쓸 수 있다. 이 벡터들이 의미론적 검색의 기초가 된다.
상단에 AI Search가 있다. 청크들과 임베딩들이 인덱싱된다. 사용자 질문이 들어오면, AI Search가 관련 청크들을 찾는다. 여기서는 키워드 검색과 의미론적 검색을 조합하는 하이브리드 검색이 가장 좋다.
가장 위에는 LLM이 있다. AI Search에서 찾은 관련 청크들을 사용자 질문과 함께 LLM에 전달한다. LLM이 이 정보들을 바탕으로 최종 답변을 생성한다.
이 전체 흐름이 자동화되어야 한다는 게 핵심이다. Azure Data Factory나 Logic Apps를 써서 전체 파이프라인을 오케스트레이션한다.
실제 구현, 한 단계씩
이제 구체적인 구현을 해보자. 파이썬을 기준으로 설명한다.
먼저 필요한 라이브러리들을 설치한다. azure-storage-blob, azure-search-documents, openai 같은 것들이다. 그리고 Azure 계정에 필요한 리소스들을 만든다. Storage Account, AI Search Service, OpenAI Account. 이들 각각의 엔드포인트와 키를 얻어야 한다.
첫 번째 단계는 Blob에서 문서를 가져오는 거다. Azure Blob Storage에는 회사의 기술 문서, 정책, 자주 묻는 질문 같은 것들이 저장되어 있다고 하자. 이걸 읽는 코드는 간단하다. BlobClient를 만들고, download_blob() 메서드로 내용을 가져온다.
PDF인 경우 추가 처리가 필요하다. pdfplumber나 PyPDF2 같은 라이브러리를 쓰거나, Azure Document Intelligence를 쓸 수 있다. Document Intelligence는 더 정확하게 레이아웃까지 보존하면서 텍스트를 추출한다. 특히 표나 복잡한 구조가 있는 PDF라면 Document Intelligence를 쓰는 게 낫다.
추출된 텍스트를 청킹한다. 간단하게는 길이 기반으로 나누면 되지만, 더 정교하게는 문장 기반이나 의미 기반으로 나눌 수 있다. 나는 주로 최대 2000 토큰, 오버랩 200 토큰으로 설정한다. 오버랩을 두는 이유는 청크 경계에서 중요한 정보가 잘려나가는 걸 방지하기 위해서다.
각 청크를 임베딩한다. OpenAI의 text-embedding-ada-002를 쓸 수 있다. 비용도 저렴하고 성능도 좋다. 청크들을 배치로 보내서 한 번에 처리하면 효율적이다.
이제 AI Search에 인덱싱한다. 인덱스 스키마를 먼저 정의해야 한다. 필드는 문서 ID, 청크 내용, 임베딩 벡터, 메타데이터(출처 파일, 작성 날짜 등)를 포함한다. 인덱스를 만든 후, SearchClient를 사용해서 문서들을 업로드한다.
이 과정이 자동화되어야 한다. Azure Data Factory를 쓰면 파이프라인으로 만들 수 있다. 매일 정해진 시간에 Blob Storage를 체크해서, 새로운 파일이 있으면 자동으로 전체 처리를 진행한다.
검색과 답변 생성, RAG의 실제 동작
사용자가 질문을 하면 어떻게 되는가?
먼저 질문을 임베딩한다. 같은 모델(text-embedding-ada-002)로 질문을 벡터로 변환한다.
그 다음 AI Search에 질의한다. 두 가지 검색을 병행한다. 첫째, 키워드 검색(BM25). 사용자가 입력한 단어들이 직접 포함된 청크들을 찾는다. 둘째, 의미론적 검색. 질문의 벡터와 유사한 청크 벡터들을 찾는다. 이 둘의 결과를 합친다. 이를 하이브리드 검색이라고 한다.
검색 결과에서 가장 관련성 높은 청크들을 선택한다. 보통 상위 5~10개 정도다. 이들을 다시 관련성 순으로 정렬한다.
선택된 청크들과 사용자 질문을 LLM(GPT-4나 GPT-4o)에 전달한다. 프롬프트는 대략 이런 식이다. “다음 문서들을 참고해서 사용자의 질문에 답변해주세요. 문서에 없는 내용이면 ‘문서에서 찾을 수 없습니다’라고 말해주세요.” 그리고 문서들과 질문을 함께 전달한다.
LLM이 문서들을 바탕으로 답변을 생성한다. 생성된 답변과 함께, 출처도 표시해야 한다. “이건 XXX 문서의 XXX 섹션에서 찾은 정보입니다”라는 식으로.
이 전체 과정이 몇 초 내에 일어난다. 사용자는 마치 AI가 조직의 모든 문서를 알고 있는 것처럼 느낀다.
실무에서 자주 겪는 문제들과 해결방법
지난 3개월간 구현하면서 여러 문제에 직면했다.
첫 번째는 청킹 크기의 최적화다. 너무 크면 검색 결과에 불필요한 정보가 많이 섞인다. 너무 작으면 문맥이 부족해서 LLM이 제대로 이해하지 못한다. 나는 수동으로 여러 크기를 시도해본 후, 1500 토큰이 최적이라고 결론지었다.
두 번째는 중복 처리다. 같은 내용이 여러 문서에 나타날 수 있다. 검색 결과에도 중복이 나타난다. 이걸 제거하는 로직을 추가했다. 의미론적으로 유사한 청크들을 감지해서 중복을 제거한다.
세 번째는 hallucination의 완전한 제거는 불가능하다는 거다. RAG를 써도 LLM은 가끔 검색 결과를 왜곡한다. 예를 들어 “문서에는 A라고 적혀있지만, 실제로는 B이므로 B라고 답변하겠습니다”라는 식으로. 이를 방지하려면 프롬프트 엔지니어링이 정말 중요하다. “반드시 문서의 내용에만 기반해서 답변하세요. 문서에 없는 내용은 추측하지 마세요”라는 강한 지시가 필요하다.
네 번째는 검색 품질의 편차다. 어떤 질문에는 정확하게 답변하지만, 어떤 질문에는 완전히 무관한 청크를 찾는다. 이건 질문의 표현 방식에 따라 크게 달라진다. 사용자들이 자연스러운 질문을 할 때 더 정확도가 높다. 반대로 단편적인 키워드 검색 형식의 질문에는 약하다.
다섯 번째는 비용 관리다. 매일 많은 문서를 처리하고, 많은 검색과 임베딩을 진행하면 비용이 빠르게 증가한다. 나는 임베딩 결과를 캐싱해서 같은 청크를 다시 임베딩하지 않도록 했다. 그리고 쿼리 캐싱을 사용해서, 같은 질문이 여러 번 들어올 때 재사용한다.
비용 최적화와 성능 튜닝
실무에서 가장 중요한 게 비용이다. RAG 시스템의 비용은 몇 가지 요소로 구성된다.
AI Search는 SKU에 따라 월 가격이 정해진다. 기본 SKU는 월 약 10만 원이다. 괜찮은 가격이지만, 검색량이 많으면 더 비싼 SKU로 올려야 한다.
OpenAI의 임베딩 비용이 생각보다 크다. text-embedding-ada-002는 1백만 토큰당 $0.02다. 만약 하루에 1백만 토큰 정도를 임베딩한다면, 월 600달러 정도가 든다. 꽤 크다.
GPT-4로 답변을 생성하는 비용도 있다. 입력 토큰이 $0.03, 출력 토큰이 $0.06이다. 평균적으로 하나의 쿼리당 $0.1 정도가 든다고 생각하면 된다. 매일 1000개 쿼리가 들어온다면 월 300달러다.
비용을 줄이려면 몇 가지 방법이 있다. 첫째, GPT-4 대신 GPT-4o나 GPT-3.5-turbo를 써보는 것. 가격이 훨씬 싸면서도 성능이 괜찮다. 둘째, 배치 처리다. OpenAI는 배치 API를 제공하는데, 이걸 쓰면 50% 할인을 받을 수 있다. 단, 24시간 지연이 있다. 실시간이 중요하지 않은 작업이라면 이걸 사용하자. 셋째, 임베딩 캐싱. 같은 텍스트를 여러 번 임베딩하지 말자.
성능 측면에서도 튜닝이 필요하다. 검색 응답 시간이 중요하다. 사용자는 몇 초 안에 답변을 받기를 기대한다. 나는 검색 결과를 5개로 제한하고, 임베딩 검색만 하는 경우도 추가했다. 속도가 중요한 경우 의미론적 검색만 하고, 정확성이 중요한 경우 하이브리드 검색을 한다.
보안 고려사항
RAG 시스템에는 민감한 정보들이 저장된다. 회사의 기술 비밀, 고객 정보, 재무 정보 같은 것들 말이다.
Blob Storage에는 액세스 제어를 꼭 설정해야 한다. 누구나 접근할 수 있으면 안 된다. Azure RBAC를 사용해서 필요한 사람들만 접근 가능하게 한다.
AI Search도 마찬가지다. 검색 권한을 제어해야 한다. 특정 사용자는 특정 카테고리의 문서만 검색할 수 있도록 설정할 수 있다. 쿼리에 필터를 추가해서 사용자별로 다른 검색 결과를 제공하는 거다.
OpenAI API의 key도 보안이 중요하다. 절대 코드에 직접 넣으면 안 되고, Azure Key Vault에 저장해야 한다. 그리고 Managed Identity를 사용해서 안전하게 접근한다.
통신도 암호화되어야 한다. HTTPS를 반드시 사용한다. Private Endpoint를 설정해서 인터넷을 통하지 않고 Azure 내부 네트워크로만 통신하는 것도 좋은 방법이다.
결론: RAG는 이제 선택이 아닌 필수
3개월간 RAG 시스템을 구축하면서 느낀 건, 이제 LLM을 프로덕션 환경에서 쓰려면 RAG는 거의 필수라는 거다. 순수 LLM만 쓰면 hallucination 때문에 신뢰할 수 없다. 하지만 RAG를 적용하면 상황이 완전히 달라진다. LLM의 강력함과 데이터의 정확성을 결합할 수 있다.
Azure의 도구들이 정말 잘 만들어져 있다는 것도 깨달았다. Blob Storage로 문서 관리, AI Search로 검색, OpenAI로 답변 생성. 이 세 개를 조합하면 엔터프라이즈급 RAG 시스템이 나온다.
처음에는 복잡해 보일 수 있다. 하지만 한 번 구축하고 나면, 유지보수는 정말 간단하다. 문서를 업로드하기만 하면, 나머지는 자동으로 된다.
만약 당신이 조직 내에서 AI를 도입하려고 한다면, RAG는 꼭 고려해봐야 할 기술이다. LLM의 신뢰성을 크게 향상시킬 수 있기 때문이다.