본문 바로가기

← 블로그

AI/RAG

집 데스크톱에 로컬 RAG 구축하기

흩어진 개인 파일을 못 찾겠어서 집 데스크톱 한 대(RTX 4070 Super 12GB)에 임베딩과 재정렬, 생성 스택을 로컬로 올린 과정. 12GB 예산 안에 세 모델을 욱여넣고 골든셋으로 검색 품질을 계측한 기록입니다.

파일이 너무 흩어져서 정작 내가 쓴 것도 못 찾는 지경이 됐습니다. 그래서 집 데스크톱에 검색용 RAG를 직접 올렸습니다. 개인 파일이라 클라우드로 통째로 보내기는 싫었고, 집 GPU(RTX 4070 Super, 12GB)는 작아서, 처음부터 목표가 “외부로 안 보내고, 작은 메모리 안에서”였습니다.

왜 전부 로컬이어야 했나


RAG 한 벌은 보통 세 모델입니다. 검색용 임베더, 검색 결과를 다시 세우는 재정렬 모델, 답을 만드는 생성 모델입니다. 셋 다 외부 API로 부르면 편하지만, 내 파일과 메모를 남의 서버에 올리는 셈이라 내키지 않았습니다. 그렇다고 12GB짜리 집 GPU에 세 모델을 동시에 올릴 수도 없었습니다. 그래서 전부 로컬로, 메모리 예산 안에서 돌리는 구조를 짰습니다.

RAG는 어떻게 도나


RAG는 크게 두 흐름입니다. 미리 문서를 잘게 잘라 임베딩해 벡터로 저장하는 색인 흐름, 그리고 질문이 들어오면 임베딩해 비슷한 조각을 찾고 재정렬한 뒤 생성 모델에 넘겨 답을 만드는 질의 흐름입니다.

색인 흐름 (미리) 문서 / 코드 청킹 + 임베딩 벡터 인덱스 질의 흐름 (실시간) 질문 임베딩 검색 재정렬 생성 LLM 인덱스 조회

12GB에 세 모델 올리기


가장 큰 숙제는 세 모델을 12GB 안에서 굴리는 것이었습니다. 결론은 한꺼번에 올리지 않는 것입니다. 무거운 색인(임베딩 일괄 생성)은 질의와 분리해 미리 돌려 두고, 질의 시점에는 필요한 모델만 번갈아 올립니다. 모델별 메모리 상주 시간(keep_alive)을 다르게 주고, 재정렬이 필요 없는 질의에서는 재정렬 모델을 내리고, 생성 모델의 KV 캐시를 줄여 점유를 낮췄습니다.

코드까지 검색되게


문서만이 아니라 내 코드도 검색 대상이었습니다. 코드는 두 갈래로 겹쳐 색인했습니다. 함수나 심볼 단위로 자른 심볼 청크, 그리고 설명을 담기 좋은 더 넓은 패시지 청크입니다. “이 함수 어디 있지” 같은 지점 검색과 “이거 어떻게 동작하지” 같은 서술형 질문을 한 코퍼스에서 모두 받기 위해서입니다.

감이 아니라 계측으로 튜닝한다


“잘 되는 것 같다”는 느낌으로는 튜닝할 수 없습니다. 대표 질문 서른 개로 골든셋을 만들고 회귀 스크립트를 붙였습니다. 정답이 상위 k개 안에 들었는지(recall@k), 평균 몇 번째에 떴는지(MRR), 엉뚱한 출처가 얼마나 섞였는지를 측정해, 청크 크기나 재정렬 여부를 바꿀 때마다 기준선과 비교했습니다.

한번은 평가 코드 자체가 틀려 있었습니다. 그 위에서 아무리 모델을 조정해도 방향이 어긋납니다. 허점 두 개를 찾아 고치고 나서야 수치를 믿을 수 있었습니다. 약한 구간은 덮지 않고 원인을 남겼습니다.

이후에는 검색과 답변 요청마다 지연 시간, 결과 수, 점수 분포를 append-only로 남기는 계측 레이어를 뒀습니다. 질문 원문은 해시로만 저장하고, 로깅이 실패해도 검색이 멈추지 않게 분리했습니다.

한 번 만들고 여러 곳에서


파일 검색으로 시작했지만, 같은 엔진을 다른 데도 붙이고 싶어졌습니다. 색인과 검색 품질을 한 곳에서 관리하고 입구만 얇게 얹는 구조로 두면, 새 쓰임이 생길 때마다 코퍼스를 새로 만들 필요가 없습니다.

파일 검색 이력서 챗봇 단일 검색 엔진 색인과 검색 품질을 한 곳에서 관리

실제로 이 접근을 이 사이트의 챗봇에도 그대로 재사용했습니다. 같은 색인과 검색 코어 위에 이력서 데이터를 얹은 것이 그 챗봇입니다.

외부로 안 보낸다는 제약과 작은 메모리가 출발점이었습니다. 그 제약이 오히려 색인과 서빙을 나누고 엔진을 재사용 가능한 형태로 만들게 했습니다.