일단 하고 보는 사람

나중보단 지금에 집중하되, 지금보단 나중에 완벽해지자💪🏻

LLM

[RAG 서비스별 설계] 세션 기반 RAG vs 단건 질의 RAG, 운영하면서 생긴 차이들

JanginTech 2026. 3. 3. 12:39

2026-03-02: 작성 (03일 배포)

2026-03-03 18시 27분:  단어 '채널'을 '사용 서비스'로 수정

 

🧩 배경

회사에서 내부 지식문서를 기반으로 답변을 생성하는 자유질의 서비스를 운영하고 있다.
흥미로운 점은 같은 파이프라인을 공유하면서도 서로 다른 서비스에서 동작 방식이 조금씩 다르다는 거다.

외부인의 입장에서 무슨 소리인가 싶을 수도 있겠지만

서비스별로 사용 목적에 차이가 있다보니
히스토리 사용 여부, 필터 정책, 검색 결과 개수(K라고 하겠다), 프롬프트 커스터마이징 같은 요소들이 자연스럽게 갈라져 있었다.

 

이에 대한 설명을 듣고 싶어 하는 팀원들에게 로직을 설명하기로 했다.

당연하게도 팀원들이 다 같은 일을 하는 것은 아닌 데다, 이 업무는 내가 전적으로 맡았다

정작 내가 “왜 이렇게 설계됐는지”를 명확히 말하기가 어려웠다. 어떻게 하면 더 전달력 있게 해당 서비스에 대한 지식이 없는 살마들에게 전달할 수 있을까? 고민하게 됐다.

그래서 기록을 남길 겸, 흐름을 처음부터 다시 뜯어보기 시작했다.

 

💭 고민의 내용

헷갈렸던 포인트는 대체로 이랬다(사실은 더 많은데..).

  • “문서검색”이라는 말이 정확히 무엇을 포함하는가?
  • Multi-Query(LLM이 만들어낸 3개의 질의)는 검색 단계에서 어떻게 활용되는가?
  • 키워드 검색과 벡터 검색은 “필터 조건 안에서” 도는 게 맞는가?
  • LongContextReorder는 정확히 무엇을 기준으로 재정렬하는가?

특히 LongContextReorder는 이름 때문에
“추가 랭킹 알고리즘이 붙는 단계”라고 착각하기 쉬웠다(나만 그럴 수도..).

그런데 실제로는 langchain_community.document_transformers.LongContextReorder를 사용하고 있었고
이건 새로운 점수를 계산하는 rerank가 아니라 입력 문서의 순서를 재배치하는 성격이 강했다.

그리고 또 하나의 현실적인 고민이 있었다.

검색 단계에서 문서를 많이 가져오는 건 Recall에는 좋을 수 있지만
그걸 그대로 RAG 컨텍스트에 던지면 오히려 답변 품질이 나빠질 수 있다.

“많이 찾는 것”과 “잘 읽히게 넣는 것”은 완전히 다른 문제였다.

 

🛠️ 해결을 위한 시도들

 

내가 한 일은 결국 “정리”였다.

정리할 것도 많고 전할 말도 많아서 복잡해질 때는 다 쏟아내고(?) 필터링하는 것이 가장 좋을 것 같다고 판단했다. 

  1. 깔끔하지 않아도 괜찮다! 파이프라인을 단계별로 다시 그려보기
  2. 서비스 별 차이를 표로 분해하여 표현하기(한눈에 비교되도록)
  3. Multi-Query → 키워드/벡터 검색 흐름을 코드 기준으로 따라가기
  4. K가 실제로 적용되는 위치를 확인하기
  5. LongContextReorder가 하는 일을 라이브러리 기준으로 확인하기

 

 

정리해 보니 흐름은 아래처럼 단순해졌다.

  • (서비스에 따라) 히스토리 병합 여부가 다름
  • 질문 재정의는 두 서비스 모두 수행하되, 입력이 다름
  • LLM이 3개의 Multi-Query를 생성
  • 각 Query로 형태소 기반 키워드 검색 + 벡터 검색을 수행 (Hybrid)
  • 상위 K건 문서를 가져옴 (한 서비스만 K 설정 가능, 기본값 20)
  • LongContextReorder로 문서 순서를 “LLM이 읽기 유리한 형태”로 재배치
  • 최종 답변은 제한된 수의 근거만 인용하도록 제어

또 하나 흥미로웠던 디테일은
Multi-Query 3개에서 키워드가 중복되어도 중복 제거 없이 진행한다는 점이었다.
“여러 질의에 반복되는 단어는 중요 신호일 수 있다”는 판단이 깔려 있었다.

 

📈 변화

정리 전에는 기능을 이렇게밖에 설명 못 했을 것 같다.

검색하고 재정렬해서 답변 만든다. 내부 설정 모드에 따라 응답 토큰 수에 차이가 있겠고 A는 프롬프트 커스텀이 되는데 B는 안 되고..

 

지금은 최소한 이 정도로는 말할 수 있게 됐다.

서비스별 정책으로 문서 후보를 제한한 뒤 LLM이 생성한 Multi-Query로 Hybrid 검색을 수행해 상위 K건을 확보 -> LongContextReorder로 입력 순서를 최적화한 후(터널링 최소화) -> 제한된 근거 기반으로 답변을 생성한다.

 

적어놓고 보니 거기서 거기인 것 같긴 한데 이상하게도 마음은 더 편해졌다.
“모르는데 아는 척”하는 느낌이 사라졌기 때문일까?

 

📌 회고 & 다음 목표

이번 기록으로 얻은 인사이트는 두 가지다.

  1. Retrieval과 Generation은 목적이 다르다.
    • Retrieval은 Recall/Precision 싸움이고
    • Generation은 “노이즈를 줄여서 잘 읽히게” 만드는 싸움이다.
  2. LongContextReorder는 만능이 아니다.
    • 문서 수를 줄여주진 않고
    • ‘lost-in-the-middle’ 같은 맥락 손실을 완화하려는 배치 전략에 가깝다.

다음 목표는 꽤 현실적이다.

  • K=20이 진짜 적절한지(비용/지연/정확도) 실험해 보기(30으로 하자는 의견이 나왔었음)
  • LongContextReorder 이후 실제 LLM에 투입되는 컨텍스트 양을 더 명확히 관리하기
  • 호출하는 서비스별 차이를 “기술적 이유 vs 운영 정책”으로 분리해 설명할 수 있게 만들기(문서조회 방식 재구성을 검토하는 중임)