티스토리 뷰

개발/AI

RAG 검색 개선기: 회고

애쿠 2026. 8. 11. 10:56

 

BM25로 키워드 검색을 뜯어본 것부터 시작해서, 평가셋, 질의처리기, 하이브리드 검색, 한국어 임베딩, 리랭커까지 왔다. 검색 하나를 붙들고 꽤 오래 적은 셈이다. 검색 개선기를 완결 짓기 전에 한 번 정리해두려고 한다.

 

뭘 만들었고, 뭐가 아쉬웠고, 다음은 어디로 갈 것 같은지도 생각해봤다.

결과물

최종 결과물은 온디바이스에서 도는 RAG 기반 검색기를 만들었다.

 

별도의 온프렘/클라우드 서버는 없고 사용자 기기 안에서 돌아가는 구조라, 2B급 소형 모델을 중심으로 붙였다.

 

개선기에 적어둔 것들이 그 안에 하나씩 들어가 있다. 전체를 늘어놓으면 이런 구조다.

질의  "지난달 회의 자료"
  │
  ├ 질의처리       슬롯(기간·종류)과 키워드로 쪼갠다
  │
  ├ 1차 검색       키워드(BM25) ─┐
  │                벡터(임베딩) ─┴→ 순위 융합(RRF)
  │
  ├ 2차 재정렬     리랭커가 상위 후보만 다시 채점
  │
  └ 결과
        ↑
   평가셋과 지표로 매 단계를 재고 판단

질의를 슬롯과 키워드로 나누는 규칙 기반 질의처리기, 키워드와 벡터를 합치는 하이브리드, 1차 결과를 다시 세우는 리랭커, 한국어에 맞춘 임베딩 모델. 그리고 그 모든 판단의 근거가 된 평가셋과 지표.

 

이 중 어느 것도 처음부터 이 모양이었던 건 아니다. 질의처리기는 원래 LLM에게 맡기려던 걸 규칙 기반으로 걷어냈고, 임베딩 모델은 바꾸고도 한동안 효과를 확인하지 못했다. 리랭커는 켜자마자 멀쩡하던 결과를 망가뜨리기도 했다. 결국 남은 건 각 단계를 어디까지 믿고 어디서 멈출지를 하나씩 정해간 기록에 가깝다.

 

아쉬운 것

LLM 성능.

qwen이 3에서 3.5로, 젬마가 3에서 4로 오면서 엄청나게 개선됐다. 그런데도 아쉽다. 온디바이스에 올릴 수 있는 크기에서는 아직 여유가 없다.

 

한계가 성능에서 속도로 옮겨갔다.

이게 이번에 제일 크게 느낀 것이다. 예전엔 작은 모델이 못 알아들어서 문제였다면, 지금은 알아듣긴 하는데 시간이 걸려서 문제다. 검색기는 1초 안에 결과가 나와야 하는데, 거기에 LLM을 끼우면 그 예산을 지키기가 쉽지 않다. 그래서 리랭커 글에서도 순위를 더 잘 매기는 LLM 대신 작고 빠른 크로스인코더를 골랐고, 질의처리기도 LLM을 걷어내고 규칙 기반으로 돌아갔다. 정확도를 조금 내주고 시간을 산 선택이 반복됐다.

 

쌓이는 벡터.

임베딩 결과물인 dense vector는 모든 조각을 대상으로 만들어진다. 그러니 검색 대상 파일이 늘수록 벡터도 계속 늘어난다. 줄이는 방법은 있어도 늘어나는 성질 자체를 없앨 수는 없다. 이건 끝까지 해결하지 못할 것 같다.

 

AI가 붙었다는 걸 사용자가 느끼기 어렵다.

검색 UI에 AI 기능을 얹는 방식 자체의 문제인 것 같다. 수동으로 조작할 필터가 많으면 결국 예전 검색기처럼 쓰게 되고, 질문형으로 물어볼 수 있다고 해도 그게 검색창 안에 있으면 사용자는 그냥 검색으로 받아들인다. 검색기 UI 앞에 앉은 사용자는 검색이 잘 되기를 바라지, 그 뒤에 뭐가 붙었는지는 궁금해하지 않는다. 기술을 넣는 것과 그게 전달되는 건 다른 문제였다.

잘한 것

정량적으로 테스트할 수 있는 환경을 만들어간 것.

처음부터 있었던 게 아니라 하나씩 늘려갔다. 평가셋을 만들고, 지표를 붙이고, 나중엔 어려운 질의로 다시 짰다. 그 환경이 생기고 나서야 "좋아진 것 같다"가 아니라 "0.02 올랐다"로 말할 수 있게 됐다.

그 과정에서 평가셋 자체가 틀릴 수 있다는 것도 겪었다. 한국어 임베딩 글이 그랬다. 모델을 바꿨는데 점수가 0.876 대 0.874로 나왔다. 오차 수준이라 "모델 차이가 없나" 싶었는데, 파보니 문제는 모델이 아니라 평가셋이었다. 질의의 단어가 문서에 그대로 들어 있는 쉬운 질의가 많아서 어떤 임베딩을 써도 다 맞혔던 것이다. 정답 단어를 뺀 어려운 셋으로 다시 짜고 나서야 차이가 드러났다. 도구를 만들었으면 그 도구도 의심해야 한다는 걸 여기서 배웠다.

 

트레이드오프를 보려고 RAG의 세부 기능을 대부분 들여다본 것.

뭘 고를지 정하려면 각각이 뭘 내주고 뭘 받는지를 알아야 했다. 그래서 키워드도, 벡터도, 융합도, 리랭커도, 양자화도 한 번씩 열어봤다. 개선기가 길어진 이유이기도 한데, 덕분에 "이건 좋다더라" 대신 "이건 이걸 내주고 이걸 받는다"로 말할 수 있게 됐다.

 

확신이 없을 때 손대지 않는 쪽을 택한 것.

이게 개선기 내내 반복된 원칙이었다. 질의처리기에서는 날짜나 문서 종류를 잘못 뽑았을 때 아예 결과가 안 나오는 게 무서워서, 확신이 없으면 하드 필터로 걸지 않고 그냥 검색어로 남겼다. 리랭커에서도 마찬가지였다. 켜고 보니 평균은 오르는데 멀쩡히 1등이던 정답을 끌어내리는 개악이 같이 생겼다. 그래서 점수 차가 충분히 확실할 때만 순서를 바꾸고, 애매하면 1차 결과를 존중하게 했다. 전체 평균을 올리는 것과 누군가의 검색을 망치지 않는 건 다른 문제라, 후자를 우선했다.

 

통념을 말로 넘기지 않고 재본 것.

"디스크에 두면 느리다"는 말은 대체로 맞다. 그런데 키워드 인덱스를 디스크로 옮기는 걸 검토하면서 실제로 재봤더니, 정확도는 소수점 셋째 자리까지 같고 속도는 오히려 빨랐다. 메모리는 수십 분의 일로 줄었고. 인덱스가 있는 경우엔 전체를 읽는 게 아니라 필요한 자리만 읽기 때문이었다. 재보지 않았으면 통념을 근거로 그냥 넘겼을 것이다.

배운 것

정성적인 평가는 한계가 있다.

눈으로 보고 "이게 낫네" 하는 건 시작점으로는 쓸 수 있어도 거기서 멈추면 안 된다. 정량적인 평가가 반드시 뒤따라야 한다. 평가지표 글을 마지막에 쓰면서도 든 생각인데, 어쩌면 그게 가장 먼저 짚었어야 할 부분이었다.

다만 정량이라고 다 믿을 수 있는 것도 아니었다. 위에 적은 것처럼 쉬운 평가셋은 모델 차이를 통째로 가려버린다. 숫자가 나왔다고 안심할 게 아니라, 그 숫자가 나온 조건을 같이 봐야 했다.

 

제한된 하드웨어에서는 최선의 선택이 항상 최적이 되지 않는다.

더 정확한 모델, 더 좋은 기법이 있어도 메모리와 지연이라는 예산 안에 안 들어오면 못 쓴다. 이 개선기에서 반복해서 나온 결론이 결국 이거였다. 무엇이 더 좋으냐가 아니라, 이 비용으로 어디에 쓰느냐.

 

더하면 좋아진다는 생각이 자꾸 틀렸다.

하이브리드 검색에서는 벡터를 많이 섞을수록 똑똑해질 줄 알았는데, 벡터 가중을 올릴수록 맨 위 정답률이 오히려 떨어졌다. 의미가 비슷한 다른 문서가 키워드가 딱 맞힌 1등을 밀어내는 것이다. 리랭커도 항상 켜두면 좋은 게 아니라 1차가 약한 구간에서만 값을 했다. 기능을 얹는 건 더하기가 아니라 균형 맞추기에 가까웠고, 그 균형점은 데이터 성격마다 달라서 매번 다시 찾아야 했다.

 

실제로 각 단계가 무엇을 얻고 무엇을 내줬는지 모아보면 이렇다.

 

 

내가 재고 있는 게 무엇의 숫자인지부터 확인해야 한다.

메모리를 조사하다가 "시작에 17초가 걸려서 그동안 검색을 못 한다"고 적어뒀는데, 나중에 보니 제품은 그 작업을 백그라운드로 미리 하고 있었다. 내가 잰 17초는 내가 만든 실험 도구의 것이었다. 같은 검색기를 쓴다고 같은 동작을 하는 게 아니었는데, 한쪽을 재놓고 다른 쪽 얘기를 하고 있었다. 숫자가 틀린 게 아니라 그 숫자가 무엇의 숫자인지를 안 본 것이다.

앞으로의 발전 방향

두 가지를 보고 있다.

 

챗봇 형태로 다시 만들고 있다. 위에 적은 아쉬움, 검색 UI로는 AI가 붙었다는 게 사용자에게 잘 전달되지 않는다는 문제 때문이다. 형태를 바꾸면 자연스럽게 물어보고 되물을 수 있다. 진척은 꽤 있다.

 

그래프 형태의 저장 방식(온톨로지)도 보고 있다. 지금 제일 자주 겪는 문제가 비슷한 유형의 문서가 너무 많으면 정답에 가까운 문서가 오히려 멀어지는 것이라 그렇다. 서로 닮은 것들 사이에 묻히는 것이다. 결국 후보를 좁혀야 하는데, 사용자에게 되물어서 좁혀가는 멀티홉이 그 길인 것 같다. 지금은 챗봇에 어늦어도 반영이 됐지만 템플릿 형태로 되묻는 수준이라 더 디테일하게 만들 여지가 있어 보인다.

 

다만 이건 될지 안 될지 모르겠다. 그래프를 만들려면 문서에서 무엇이 노드이고 무엇이 관계인지 뽑아내는 정제 과정을 거쳐야 하는데, 그 일을 온디바이스에 올릴 수 있는 작은 모델이 해낼 수 있을 것 같지 않다. 정제가 부실하면 엉뚱한 관계로 엮인 그래프가 나오고, 그건 없느니만 못하다. 가능성이 있다면 노드와 관계의 종류를 미리 제한해서 좁게 만드는 쪽일 텐데, 이것도 재봐야 알 것 같다.

 

기술적으로 되느냐와 별개로, 해야 하느냐도 고민이다. 지금 골든셋 성능이 90%를 넘는다. 여기서 95%, 99%로 올리는 데 드는 노력은 초기에 50%도 안 나오던 걸 90%까지 끌어올릴 때보다 수십 배는 더 들 것이다. 뒤로 갈수록 남는 게 어려운 질의뿐이라 그렇다.

 

그 비용으로 얻을 몇 퍼센트가 값을 하는지 판단이 잘 안 선다. 결국 이것도 트레이드오프인 셈이다.

마치며

돌아보면 이 개선기는 기법을 덥썩 덥썩 얹은게 아니라 차근차근 얹을지 말지를 스텝바이 스텝으로 정해간 기록이었다.

 

하이브리드도 리랭커도 임베딩 교체도 전부 "쓰면 좋아진다"가 아니라 "여기선 값을 하고 저기선 아니다"로 끝났다. 그리고 그걸 판단하게 해준 건 매번 실측이었다.

 

테스트를 해보지 않았으면 벡터를 더 섞었을 것이고, 리랭커를 항상 켜뒀을 것이고, 통념대로 인덱스를 계속 메모리에 들고 있었을 것이다. 

 

아직 남은 게 많다. 쌓이는 벡터는 답을 못 찾았고, 온톨로지는 어떻게 손대야 할지도 모르겠다... 갑자기 백엔드에서 AI 솔루션 개발로 업무를 틀었던만큼 공부할 양이 많았는데 어느정도 정리가 된 느낌이다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/08   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함