티스토리 뷰

 

파인튜닝 글에서 작은 LLM으로 질의처리기를 만들어봤지만, 표준 어순에선 잘 되다가 변형에서 무너졌고 결국 곁가지로 남았다고 적었다. 그러면 본선 질의처리기는 어떻게 됐을까. 결국 LLM을 걷어내고 규칙 기반으로 다시 만들었다.

 

사실 질의처리 글에서 이미 답이 나와 있었다 — 질의처리의 핵심은 LLM을 쓰느냐가 아니라, 검색어·필터·제거를 나누는 기준이라는 것. 이 글은 RAG 구축 고려사항 중 질의 강화·키워드 추출의 마지막 매듭이다.

1. 왜 다시 규칙이었나

LLM으로 질의를 처리하면 깔끔해 보인다. 그런데 검색 본경로에 두기엔 세 가지가 걸렸다.

 

1. 호출이 느렸고,

2. 같은 질의에 매번 결과가 조금씩 달라졌으며(비결정성)

3. 파인튜닝으로 정확도를 올려도 학습에 없던 표현에서 흔들렸다(오버피팅).

 

돌아보면 질의처리는 애초에 생성 문제가 아니라 분류 문제였다. 한 문장 안에는 날짜 같은 조건과 진짜 찾고 싶은 키워드가 섞여 있는데, 이걸 정해진 칸(슬롯)에 나눠 담는 일은 기준만 또렷하면 모델 없이도 결정론적으로 할 수 있다. 그래서 LLM 질의처리기를 들어내고, 그 자리에 규칙 기반 처리기를 끼웠다. 입력과 출력 계약은 그대로 둬서 드롭인 교체가 되게 했다.

 

다만 "규칙으로 가자"가 곧 설계도는 아니었다. 어떤 규칙으로 어떻게 나눌지는 한 번에 안 나왔다. 이것저것 만들어보고 깨지고를 반복하다, 결국 무엇을 어느 칸에 담을지 정하는 일그 판단이 맞는지 확인하는 일 두 축으로 수렴했다. 둘 다 처음부터 그려둔 그림이 아니라 검색을 만지며 부딪힌 문제에서 하나씩 끌려나온 방법이다. 아래에서 그 둘이 왜 그렇게 자리 잡았는지를 차례로 풀어본다.

2. 큰 그림 — 질의를 슬롯으로 쪼갠다

규칙 기반 처리기가 하는 일은 한 문장이다. 질의를 슬롯과 키워드로 분해한다.

슬롯은 메타데이터로 거를 수 있는 조건들이다. 시간 범위나 파일 형식, 작성자처럼 문서가 들고 있는 속성들인데, 정확히 어떤 슬롯을 둘지는 검색 대상 문서가 가진 메타데이터에 따라 달라진다. 이 슬롯에 잡히지 않고 남은 내용어가 검색 키워드가 된다. 예를 들어 "김민수가 작성한 작년 회의 자료 pdf"는 이렇게 갈린다.

질의:  김민수가 작성한 작년 회의 자료 pdf
─────────────────────────────────────────────
작성자   김민수
시간     작년 → 날짜 범위
확장자   pdf
키워드   회의, 자료
제거     가, 작성한   (조사 · 활용형)

3. Kiwi로 슬롯을 잡는다

한국어 경로의 핵심은 형태소 분석기 Kiwi다. 질의를 형태소로 쪼개 품사를 붙이면(형태소 분석이 뭔지는 별도 글에서 따로 다룬다), 어떤 토큰이 날짜·경로·확장자인지 규칙으로 잡아낼 수 있다.

 

방식은 단순하다. 날짜나 형식 같은 슬롯이 먼저 자기 토큰을 가져가고, 그렇게 이미 슬롯이 가져간 토큰을 빼고 남은 명사가 검색 키워드가 된다. 형태소 단위로 다루니, 조사나 활용형이 붙어 있어도 품사를 보고 자연스럽게 걸러진다.

 

모르는 표현이 엉뚱하게 쪼개지는 경우조차 모델의 직감이 아니라 품사 규칙으로 직접 손볼 수 있다는 게, 규칙 기반의 힘이었다.

4. 애매하면 되묻는다 — 멀티홉 확인

규칙 기반이라고 모든 걸 단정하지는 않는다. 오히려 애매한 토큰을 억지로 슬롯에 욱여넣지 않는 게 핵심이었다.

 

전형적인 골칫거리가 연도였다. "2025년 보고서"의 "2025년"은 날짜 범위일 수도, 그냥 제목의 일부("2025년 사업계획"처럼)일 수도 있다. 여기서 날짜로 강제하면 검색이 그 해로 좁혀지면서, 정작 제목에 "2025"가 든 다른 해 문서를 다 떨군다. 반대로 무조건 키워드로만 두면 "작년에 나온 보고서"를 찾는 사람의 시간 의도를 놓친다. 어느 쪽으로 찍어도 절반은 틀리는 자리다.

 

먼저 한 일은 확정할 수 있는 건 확정하는 것이었다. 연도에 월이 붙으면("2025년 5월 보고서") 기간이 명확하니 그냥 그 달로 필터를 건다. 끝까지 애매한 건 딱 하나, 연도 단독 + 내용 명사 조합이다. 이 좁은 케이스만 따로 _애매 슬롯_으로 표시해 뒀다.

 

처음엔 이 애매 슬롯을 그냥 키워드로 흘려보냈다. "확신 없으면 거르지 말고 검색어로 둔다"는 보수적인 규칙이다. 안전하긴 한데, 시간 의도가 분명한 질의까지 매번 키워드로 떨어뜨리니 아쉬웠다.

 

그래서 한 겹을 더 댔다. 멀티홉 — 애매하면 사용자에게 직접 되묻는다.

사용자:  2025년 보고서
시스템:  "2025년"을 날짜로 좁힐까요, 검색어로 둘까요?
  ├─ 날짜로  →  그 해 기간으로 필터 + 키워드 "보고서"
  └─ 검색어로 →  필터 없이 키워드로 검색

 

중요한 건 이 되묻기가 LLM 추론이 아니라는 점이다. 질문 문구는 정해진 템플릿이고, 분기는 규칙이다. 모델에게 "이 질의를 여러 단계로 추론해줘"라고 맡기는 비싼 멀티홉이 아니라, 애매한 경우에만 뜨는 한두 단계짜리 확인이다. 그래서 같은 답에는 늘 같은 결과가 나오고(결정론), 모델 호출 비용도 들지 않는다.

 

정리하면 애매함을 다루는 층이 세 겹이다.

 

(1) 확정 가능하면 바로 확정

(2) 진짜 애매한 좁은 케이스만 되묻고

(3) 그래도 답이 없으면 키워드로 폴백.

 

LLM의 비결정적 추론을 한 줄도 끼우지 않고, 애매함을 사용자의 한 번의 선택으로 결정론적으로 닫은 셈이다.

5. 규칙으로 돌아와서 좋았던 것, 감수한 것

좋았던 건 분명했다. LLM 호출이 0이라 빠르고, 같은 질의는 항상 같은 결과를 내며(결정론), 결과가 이상하면 "어느 규칙이 이렇게 잘랐나"를 그대로 추적할 수 있다. 파인튜닝에서 오버피팅으로 흔들리던 표현들도, 모델의 직감이 아니라 슬롯 규칙으로 결정론적으로 다뤘다.

 

물론 공짜는 아니다. 가장 큰 비용은 사전을 계속 손봐야 한다는 것이다. 표현을 알아보는 여러 사전과 규칙이 결국 사람이 채우고 갱신해야 하는 것들이라, 새 표현이나 신조어가 들어오면 분석기가 알아서 일반화해주지 않는다. 빠진 걸 발견할 때마다 한 줄씩 메워야 한다. 모델이라면 데이터로 흡수했을 변화를, 규칙 기반에선 운영자가 떠안는 셈이다.

 

멀티홉 규칙도 계속 손 봐야한다. 일단은 사용성 테스트에서 나온 예시들을 기반으로 만들었지만, 당연히 모든 케이스를 커버하지는 못한다.

 

모델이 알아서 일반화해주길 기대할 수 없는 대신, 동작을 내가 완전히 통제하고 설명할 수 있는 쪽을 택한 것이다. 검색 본경로처럼 빠르고 예측 가능해야 하는 자리(온디바이스 환경)에는 이 맞교환이 맞다고 생각한다.

마치며

돌아보면 길게 돌아온 셈이다. 검색을 개선하려고 평가셋을 다시 짰고, 질의처리가 진짜 문제임을 확인했고, 그걸 작은 LLM으로 풀어보려다 한계를 만났고, 결국 LLM을 걷어내고 규칙 기반으로 정착했다.

 

무엇보다 이 모든 게 온디바이스에서 돌아가야 했다는 점이 컸다. 서버의 큰 모델을 매 질의마다 부를 수 없는 환경이라, 빠르고 가볍고 예측 가능한 규칙 기반이 결국 더 잘 맞았다. 화려한 방법을 끝까지 밀어본 끝에 고른 게 가장 단순한 쪽이었다는 게, 이 시리즈에서 내가 가장 오래 기억할 부분일 것 같다.

 

질의처리기는 결국 똑똑한 모델이 아니라, 무엇을 어느 칸에 담을지에 대한 또렷한 기준으로 완성됐다. 질의처리 글에서 적어둔 그 한 줄이, 시리즈의 끝에서 그대로 답이 됐다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
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
글 보관함