기술

RAG 검색에서 저장소가 멈추면 빈 결과가 아니라 503 으로 답하게 했습니다

2026.11.069분 읽기

사내 문서를 찾아 주는 검색 엔진이 있습니다. 문서 본문과 청크, 벡터를 파일 DB 하나에 담아 운영했습니다. 이 엔진 위에는 채팅이 붙어 있습니다. 채팅은 검색 결과를 근거 자료로 받아 사람에게 문장으로 답합니다. 검색 결과로 LLM 이 답을 만드는 RAG 구조입니다.

이 저장소를 그래프 DB(문서와 관계)와 벡터 DB(청크와 벡터)로 나눠 옮겼습니다. 문서 사이의 관계를 질의로 따라가고 싶었고, 글자 검색과 벡터 검색을 한 엔진에서 같이 실행하고 싶었습니다. 옮기는 작업보다 옮기면서 정해야 할 것이 더 어려웠습니다. 결정은 세 가지였습니다.

어디까지 한 번에 옮기나

속도와 검색 결과가 충돌하면 무엇을 지키나

저장소가 멈췄을 때 검색과 채팅은 어떻게 답하나

앞의 둘은 이관에 관한 결정입니다. 셋째는 이 시스템이 사람에게 틀린 말을 할 수 있는 경로에 관한 결정입니다. 이 글의 중심은 셋째입니다.


문서만 먼저 옮기는 계획은 조인 하나로 무산됐습니다

처음에는 단계를 나누는 쪽이 안전해 보였습니다. 문서만 그래프 DB 로 먼저 옮기고 청크는 파일 DB 에 두는 방식입니다. 그런데 글자 검색이 문서와 청크를 조인해서 동작하고 있었습니다. 둘이 다른 저장소로 나뉘면 그 조인을 실행할 수 없습니다.

그래서 문서와 청크를 한꺼번에 옮기고 파일 DB 를 없앴습니다. 호출량과 비용 계측 한 종류만 파일 DB 에 남겼습니다. 이관을 쪼갤 수 있는지는 일정이 아니라 질의의 모양이 정했습니다.

문서 1,356건 → 그래프 DB 의 문서 노드

청크 19,630건 → 벡터 DB 의 글자 검색용 컬렉션

벡터 18,758건 → 벡터 DB 의 벡터 컬렉션(벡터 키만 옮겼고, 다시 임베딩한 건은 0건)


전문검색 색인은 붙여 쓴 말을 찾지 못했습니다

글자 검색을 어떤 색인으로 바꿀지 재현율(찾아야 할 결과 중 실제로 찾은 비율)부터 쟀습니다. 운영 청크 19,630건에 키워드 29개를 넣고, 옛 파일 DB 의 부분문자열 검색 결과를 기준으로 삼았습니다.

방식

재현율

벡터 DB 전문검색 word

61%

벡터 DB 전문검색 prefix

73%

벡터 DB 전문검색 multilingual

66%

그래프 DB 의 한국어(CJK) 색인

56%

두 글자 색인 + 부분문자열 재확인 (채택)

100%

이 표는 제품 비교가 아닙니다. 그래프 DB 의 한국어 색인이 가장 낮게 나온 이유는 우리 문서의 붙여쓰기입니다. 회사 이름이 공백 없이 붙어 있으면, 그 안의 두 글자로 찾을 때 1% 만 찾히는 경우가 있었습니다.

공백으로 단어가 나뉘는 언어라면 전문검색 색인이 더 낫습니다. 56% 라는 숫자는 이 문서 조건에서만 의미가 있습니다.

채택한 방식은 2단 구조입니다. 글을 두 글자 단위로 잘라 만든 색인으로 후보를 걸러 내고, 후보의 본문에서 부분문자열로 다시 확인합니다.

두 글자 색인으로 후보 청크를 걸러 낸 뒤 부분문자열로 재확인해 재현율 100% 를 얻는 2단 검색 흐름

속도는 입력에 따라 달라졌습니다. 드문 말은 101ms 에서 17ms 로 빨라졌고, 흔한 말은 132ms 에서 786ms 로 느려졌습니다. 같은 색인이 한쪽은 약 6배 빠르게, 다른 쪽은 약 6배 느리게 만든 것입니다. 그래서 '데이터가 커져도 덜 느려진다'는 말은 드문 말에만 맞는다고 기록해 뒀습니다.

그래도 재현율 100% 쪽을 골랐습니다. 빠른 쪽을 택하면 재현율이 61~73% 입니다. 검색이 빠뜨린 문서는 위의 채팅에서 '그런 자료가 없다'는 답으로 바뀝니다. 느린 응답은 눈에 보이지만 빠진 결과는 눈에 보이지 않습니다.

이 선택은 지금 규모에 맞춘 것입니다. 청크 2만 건 수준에서 786ms 는 참을 수 있지만 10배가 되면 참기 어렵다고 봅니다. 그때 바꿀 것은 색인이 아니라 순위 방식이라고 미리 정해 뒀습니다. 이 판단은 아직 검증되지 않았습니다.


저장소가 멈췄을 때 빈 결과는 틀린 답이 됩니다

셋째 결정의 선택지는 둘이었습니다. 저장소 예외를 삼키고 결과 0건을 반환하거나, 오류로 답하는 것입니다. 빈 결과는 화면이 깨지지 않는다는 장점이 있습니다.

선택지

저장소가 멈췄을 때 일어나는 일

판단

빈 결과

예외를 삼키고 0건을 반환합니다. 화면은 유지되지만 채팅이 0건을 받아 '자료에 없습니다'라고 답합니다

채택 안 함

503

검색과 채팅이 오류와 원인 문구로 답합니다. 화면은 쓸 수 없지만 틀린 답은 나가지 않습니다

채택

문제는 검색이 혼자 쓰이지 않는다는 데 있습니다. 채팅은 0건을 받으면 근거가 없다고 판단하고, 그 판단을 문장으로 만듭니다. 문서는 저장소에 그대로 있는데 답은 '자료에 없습니다'가 됩니다.

사용자는 그 문장이 장애의 결과인지 알 방법이 없습니다. 아래층이 0건을 반환하면 위층도 '없다'와 '못 읽었다'를 구분할 수 없습니다. 생성 모델은 구분하지 못한 0건을 확신에 찬 오답으로 바꿉니다. RAG 에서 이 차이는 성능이 아니라 신뢰의 문제입니다.

그래서 두 상태의 응답 모양을 나눴습니다.

저장소 정상 + 결과 0건  → 200 + 빈 목록       (데이터가 없다)
저장소 읽기 실패        → 503 + 원인 문구      (데이터를 못 읽었다)

저장소가 멈췄을 때 빈 결과는 채팅의 틀린 답으로 이어지고 503 은 오류 안내로 끝나는 두 경로 비교

값이 없는 것과 아직 못 읽은 것을 같은 빈칸으로 두면 생기는 문제는 대시보드에서도 같습니다.


헬스체크는 저장소가 멈춰도 200 이었습니다

응답을 고치고 나니 감시가 남았습니다. 엔진의 헬스체크(서버가 정상인지 답하는 경로)는 저장소가 멈춰도 200 을 반환했습니다. 엔진 프로세스는 떠 있었기 때문입니다. 감시는 이 경로만 보고 있어서 아무 알림도 보내지 않는 구조였습니다.

의존 저장소를 확인하지 않는 헬스체크는 실패할 수 없는 검사입니다. 늘 통과하므로 아무것도 알려 주지 않고 안심만 줍니다. 헬스체크는 프로세스가 떠 있는지가 아니라 요청을 처리할 수 있는지를 답해야 했습니다.

감시에 저장소 항목을 새로 넣었습니다. 옛 감시 스크립트로 시험해 3건이 실패로 잡히는 것도 확인했습니다.

프로세스만 보는 헬스체크는 저장소가 멈춰도 200 이고 저장소 항목을 넣은 감시는 실패를 잡는다는 비교

겉으로 정상이면서 틀린 내용이 지나가는 일은 LLM 응답에서도 나옵니다. 그 기록에서도 응답은 전부 200 이었습니다.


이관의 안전장치는 세 겹으로 뒀습니다

배포 전 비교: 옛 저장소와 새 저장소에 같은 입력을 넣어 결과를 맞춰 보는 명령을 만들었습니다. 실서버에서 11초가 걸렸고 차이는 0이었습니다

백업과 복원 리허설: 그래프 노드 덤프와 벡터 스냅샷을 매일 받습니다. 하루 약 341MB, 일간 7개와 주간 4개를 보관해 약 3.7GB 입니다. 복원 결과가 운영 데이터와 일치하는 것도 확인했습니다

옛 데이터 보관: 옛 파일은 지우지 않고 보관 폴더로 옮겼습니다. 마지막 일간 백업 사본(81MB)도 같이 남겼습니다

파일 DB 에 의존하던 운영 스크립트 9개도 정리했습니다. 일회용은 지우고 나머지는 새 저장소로 옮긴 뒤, 적용 전 모의 실행으로 전후 건수가 같은지 확인했습니다.

이 안전장치에도 한계가 있습니다. 차이 0은 비교 명령이 넣어 본 입력 범위 안에서만 맞는 말입니다. 운영에서 들어오는 질의 분포와 같다는 뜻은 아닙니다. 복원 리허설도 한 번 실행한 것이라, 백업 형식이나 저장소 버전이 바뀌면 다시 해야 합니다.


503 이 늘 맞는 답은 아닙니다

검색이 거드는 보조 기능이고 결과가 없어도 화면이 성립한다면, 오류로 막는 쪽이 더 나쁠 수 있습니다. 기준은 빈 결과가 위층에서 사실 주장으로 바뀌는가입니다.

검색 결과를 문장으로 옮기는 층이 위에 있다면 503 으로 답합니다

사람이 목록을 직접 보는 화면이라면 빈 결과에 안내 문구를 더하는 것으로도 충분합니다


검색 위에 LLM 을 붙였다면 확인할 것

검색 결과 0건과 저장소 읽기 실패가 같은 응답 모양으로 나가고 있지 않은가

0건을 받은 LLM 이 '없습니다'라고 단정하는 경로가 있는가

헬스체크가 의존 저장소까지 확인하는가, 그 실패를 시험으로 확인했는가

색인을 바꿀 때 속도보다 재현율을 먼저 쟀는가

백업을 실제로 복원해 본 적이 있는가

세 결정 모두 그대로 배포했습니다. 문서는 그래프 DB 에, 청크와 벡터는 벡터 DB 에 있습니다. 글자 검색은 재현율 100% 를 유지했고 흔한 말은 느려졌습니다. 저장소가 멈추면 검색과 채팅은 503 으로 답하고 감시의 새 항목이 그 상태를 알립니다. 화면을 쓰지 못하는 시간은 생기지만, 있는 자료를 없다고 답하지는 않습니다.

#RAG#503#장애응답#헬스체크#저장소이관#그래프DB#벡터DB#전문검색#한국어색인#재현율#백업