문서 RAG를 관리자와 공개 서비스에 함께 붙인 구조

문서 RAG를 처음 만들 때는 “문서를 검색하고 모델에 넣으면 된다”는 설명이 충분해 보입니다. 실제 서비스에 붙이기 시작하면 질문이 달라집니다. 문서를 언제 나누고, 어떤 기준으로 다시 색인하며, 관리자 문서와 공개 문서를 어떻게 분리하고, 답변의 근거를 사용자가 어떻게 확인하게 할 것인가가 중요해집니다.

듀오랩스는 하나의 RAG 기반을 관리자 문서함과 공개 웹 서비스에서 함께 사용하되, 검색 공간과 공개 범위는 분리했습니다. 이 글에서는 그 구조와 선택 이유를 정리합니다.

전체 흐름

문서가 답변으로 바뀌는 과정은 크게 색인 단계와 질의 단계로 나뉩니다.

문서 저장
→ 헤딩 기준 청킹
→ 내용 해시 비교
→ 임베딩 생성
→ 검색 공간별 색인

사용자 질문
→ 의미 검색 + 키워드 검색
→ 결과 융합 및 재정렬
→ 근거 묶음 생성
→ 스트리밍 답변과 출처 표시

색인은 문서를 검색 가능한 형태로 준비하는 과정이고, 질의는 그 색인에서 근거를 찾아 답변을 만드는 과정입니다. 두 단계를 분리하면 답변 요청 때마다 문서를 다시 처리하지 않아도 됩니다.

문서를 글자 수로만 자르지 않은 이유

긴 문서를 일정한 글자 수로 나누는 방법은 구현하기 쉽지만 문맥이 끊기기 쉽습니다. 제목은 앞 청크에 있고 설명은 다음 청크에 들어가거나, 표의 헤더와 행이 서로 분리될 수도 있습니다.

그래서 Markdown 헤딩을 먼저 인식하고 섹션 단위로 나눈 뒤, 너무 긴 섹션만 추가로 분할했습니다. 각 청크에는 문서 제목과 헤딩 경로를 함께 넣었습니다.

문서: 고객 지원 운영 기준
경로: 장애 대응 > 우선순위 판정
본문: ...

이렇게 하면 검색 결과가 짧은 본문 조각이어도 모델은 그 조각이 어떤 문맥에 속하는지 알 수 있습니다. 사용자에게 근거를 표시할 때도 “어느 문서의 어느 절인지” 설명하기 쉽습니다.

의미 검색과 키워드 검색을 함께 사용했습니다

임베딩 기반 의미 검색은 표현이 달라도 뜻이 비슷한 문서를 찾는 데 강합니다. 반면 제품명, 오류 코드, 함수명처럼 정확한 문자열이 중요한 질문에서는 키워드 검색이 유리합니다.

예를 들어 사용자가 “로그인이 계속 풀려요”라고 물으면 의미 검색이 세션 만료 문서를 찾을 수 있습니다. MissingPluginException을 그대로 검색한다면 키워드 검색이 더 정확합니다.

두 결과는 순위 기반 융합 방식으로 합쳤습니다. 점수의 단위를 억지로 맞추기보다 각 검색에서 높은 순위를 받은 문서를 우선하는 방식입니다.

검색 방식 | 잘 찾는 질문 | 놓치기 쉬운 경우
의미 검색 | 표현이 다른 자연어 질문 | 고유명사와 짧은 코드
키워드 검색 | 정확한 명칭, 오류 코드 | 동의어와 우회 표현
하이브리드 검색 | 두 유형이 섞인 실제 질문 | 평가 없이 가중치를 정한 경우

해시 기반 증분 색인

모든 문서를 매번 다시 임베딩하면 문서 수가 늘수록 시간과 비용이 커집니다. 문서 내용과 검색에 필요한 메타데이터로 해시를 만들고 이전 값과 비교하면 변경된 문서만 다시 처리할 수 있습니다.

새 문서는 청킹하고 임베딩합니다.

내용이 바뀐 문서는 기존 청크를 교체합니다.

바뀌지 않은 문서는 건너뜁니다.

삭제되거나 검색 범위에서 제외된 문서의 청크는 제거합니다.

증분 색인은 성능 최적화이면서 운영 안전장치입니다. 전체 색인을 다시 만드는 긴 작업 없이도 문서 변경을 빠르게 반영할 수 있기 때문입니다.

관리자와 공개 서비스는 검색 공간을 분리합니다

같은 RAG 코드를 사용하더라도 모든 문서를 하나의 색인에 넣어서는 안 됩니다. 관리자 문서함에는 내부 운영 문서와 프로젝트 자료가 있고, 공개 서비스는 외부에 공개된 문서만 근거로 사용해야 합니다.

검색 공간을 명시적인 식별자로 분리했습니다.

admin:global 관리자 전역 문서
admin:project:* 프로젝트별 자료실
public:web 외부 공개 문서

질의가 들어오면 서버가 사용자의 권한과 요청 경로에 따라 검색 공간을 결정합니다. 클라이언트가 임의로 내부 공간을 지정할 수 없게 하는 것이 핵심입니다.

이 구조에는 두 가지 장점이 있습니다.

하나의 청킹·임베딩·검색 구현을 재사용할 수 있습니다.

문서 공개 범위는 검색 단계에서부터 분리됩니다.

답변을 만든 뒤 민감한 문장을 지우는 방식보다, 처음부터 접근할 수 없는 문서를 검색 대상에서 제외하는 편이 안전합니다.

답변보다 근거 확인이 먼저입니다

문서 AI의 답변은 그럴듯함보다 대조 가능성이 중요합니다. 그래서 답변 문장에 각주를 연결하고, 사용자가 근거 원문을 바로 펼쳐볼 수 있도록 구성했습니다.

답변에서 출처 번호를 선택합니다.

해당 문서와 섹션을 확인합니다.

검색된 원문을 답변과 나란히 비교합니다.

필요하면 검색 범위를 폴더, 태그, 기간으로 좁힙니다.

이 기능은 모델의 실수를 완전히 없애지 않습니다. 대신 사용자가 실수를 빠르게 발견하고 원문으로 돌아갈 수 있게 합니다.

스트리밍은 기능이 아니라 피드백입니다

답변은 SSE를 이용해 생성되는 즉시 전달했습니다. 긴 답변이 모두 만들어질 때까지 빈 화면을 보여주는 대신, 요청이 처리되고 있다는 사실을 바로 알려줄 수 있습니다.

다만 스트리밍은 애플리케이션 코드만으로 끝나지 않습니다. 프록시나 CDN이 응답을 버퍼링하면 서버가 토큰을 나눠 보내도 브라우저에는 한꺼번에 도착합니다. 이 운영 문제는 시리즈의 별도 글에서 자세히 다룹니다.

구현 체크리스트

청크에 문서 제목과 헤딩 경로가 포함되어 있나요?

의미 검색과 정확한 문자열 검색을 함께 평가했나요?

변경된 문서만 다시 처리할 수 있나요?

삭제·비공개 전환된 문서의 청크가 제거되나요?

관리자, 프로젝트, 공개 검색 공간이 서버에서 분리되나요?

답변에서 근거 원문으로 바로 이동할 수 있나요?

스트리밍이 실제 운영 프록시를 통과하는지 확인했나요?

듀오랩스가 보는 관점

문서 RAG의 핵심은 모델 호출 한 번이 아닙니다. 문서의 구조를 보존해 나누고, 변경을 정확히 반영하고, 권한에 맞는 공간에서 검색하며, 사용자가 근거를 확인할 수 있게 만드는 전체 흐름이 제품의 품질을 결정합니다.

답변 모델은 교체할 수 있지만, 문서와 권한의 경계를 잘못 설계하면 나중에 고치기 어렵습니다. 그래서 듀오랩스는 모델 선택보다 검색 공간과 근거 추적 구조를 먼저 설계합니다.

다음 글에서는 한국어 임베딩 검색의 임계값을 실측으로 정하고, 오래된 문서와 최신 문서가 충돌할 때 답변을 교정한 과정을 살펴보겠습니다.

문서 RAG 구축기 시리즈

27B보다 2.4B가 더 나았던 문서 RAG 모델 선택기

문서 RAG를 관리자와 공개 서비스에 함께 붙인 구조

RAG 검색 임계값을 감으로 정하면 안 되는 이유

로컬에서는 정상인데 운영에서만 깨진 AI 스트리밍

내부 문서를 공개 AI에 연결할 때 필요한 안전장치

데스크톱 AI 화면을 모바일에서 과감히 제거한 이유

배포 문서 한 줄이 AI 기능 전체를 막을 뻔한 이유