엔지니어링 딥다이브

완전관리형 RAG는 우리가 만든 파이프라인을 이겼을까

학교 보건교사용 의료자문 챗봇을 운영하고 있다. 규칙은 하나다. 공식 공문서에 적힌 내용만 근거로 답한다. 감염병 예방·위기대응 매뉴얼, 학교보건 기본방향 같은 문서들이다. 근거가 없으면 지어내지 않고, 답을 거절한 뒤 전문 교수에게 넘긴다.

그래서 이 서비스의 품질은 LLM의 문장력에서 갈리지 않는다. 검색에서 갈린다. "수두 등교중지 기준"을 물으면 표 셀에 박힌 "모든 수포가 가피화될 때까지(발진 후 최소 5일)"를 정확히 끌어와야 한다. 그걸 못 끌어오면 챗봇은 입을 다문다.

이 검색을 우리는 직접 만든 파이프라인으로 돌려 왔다. 그런데 2026년 6월 Amazon Bedrock의 완전관리형 Knowledge Base가 GA됐다. 진입 장벽이던 고정비가 사라졌다. 그래서 궁금해졌다. AWS가 통째로 관리해 주는 RAG가 우리가 손으로 빚은 파이프라인을 이길까? 솔직히 반쯤은 질 거라 봤다.

직접 만든 pgvector 파이프라인과 Amazon Bedrock 완전관리형 Knowledge Base 비교
직접 만든 pgvector 파이프라인(좌) vs Amazon Bedrock 완전관리형 Knowledge Base(우)

우리 파이프라인

평범한 구조다. 그게 장점이다.

PDF가 들어오면 opendataloader로 파싱한다. 단순 텍스트 추출이 아니라 제목·문단·표 구조를 살려서 뜯어낸다. 그다음 단계가 핵심인데, 한국어 구조 인식 청킹이다. 토큰 N개씩 기계적으로 자르는 대신 문서의 섹션·제목 경계를 따라 자른다. "등교중지 기준" 표가 헤더와 함께 한 덩어리로 남도록.

자른 조각은 Titan Text Embeddings v2로 임베딩해 Aurora PostgreSQL의 pgvector에 넣는다. 인덱스는 HNSW, 거리는 코사인. 질의가 들어오면 상위 k개 청크를 뽑아 컨텍스트 블록을 만들고, "발췌에 있는 내용만 쓰고 문장 끝에 [n]으로 출처를 달라"는 시스템 프롬프트와 함께 Claude에 넘긴다.

자르는 방식, k값, 어떤 문서를 켜고 끌지가 전부 우리 코드 안에 있다. 무엇이든 직접 만질 수 있다.

완전관리형

반대편은 그 결정을 전부 AWS에 맡긴다. 파싱·청킹·임베딩·검색이 한 박스에 묶여 있고, 우리가 조정할 수 있는 건 거의 없다. 대신 운영 부담이 0이다.

띄우는 것부터 걸렸다. 이 완전관리형 KB는 서울 리전에 없고 도쿄에만 있다. 그래서 corpus를 S3로 도쿄에 복제하고 거기에 KB를 세웠다. 임베딩은 관리형이라 모델 액세스 신청조차 필요 없었다. 여기까지는 편했다.

공정하게 비교하려고 생성 단계는 양쪽 모두 같은 Claude, 같은 프롬프트로 못 박았다. 관리자 화면에 비교 엔드포인트를 하나 만들고 질문 하나를 세 갈래로 동시에 쐈다. ① 우리 파이프라인, ② 관리형에서 검색만 떼어 같은 Claude에 물린 것, ③ 관리형 통짜 RAG. 각 갈래의 답·출처·지연을 같은 표에 적었다.

실험

대표 질문 30개를 단일 질의로 던졌다. 발열 대응 절차, 질병별 등교중지 기간, 위기경보 단계별 조치, 보고 체계까지. 현장에서 실제로 들어오는 질문들이다.

여기에 후속 질의 8세트를 더했다. 맥락을 기억하는지 확인하려는 거였다. "인플루엔자 등교중지는?"이라 묻고, 답이 나오면 곧장 "그럼 수두는?"이라 되묻는다. "수두" 뒤에 생략된 "등교중지 기간"을 직전 턴에서 복원해야만 제대로 답할 수 있다.

결과

맥락 기억은 무승부였다. 8세트 전부 양쪽 다 "그럼 수두는?", "그건 누구한테 보고하지?" 같은 지시어를 직전 대화에서 정확히 메웠다. 대화 이력만 제대로 넘기면 모델이 알아서 한다.

승부는 표에서 났다. 우리 파이프라인은 셀 값을 그대로 짚었다. 구강검진 "3~11월", 수두 "가피화될 때까지, 발진 후 최소 5일", 페이지 번호까지. 관리형은 같은 표를 자주 흘렸다. "텍스트를 읽을 수 없다"면서 말이다. 지연은 평균 5.4초 대 4.8초로 관리형이 조금 빨랐는데, 못 읽으면 빨라야 소용이 없다.

③번 통짜 RAG는 30문항 전부 실패했다. 처음엔 이걸 두고 "관리형은 검색과 생성을 묶는 모드를 아예 지원하지 않는다"고 적었다. 틀린 판단이었다. 나중에 공식 문서를 보니 내가 부른 API가 애초에 관리형용이 아니었다.1 이건 관리형의 한계가 아니라 내가 엉뚱한 문을 두드린 착오다.

결과는 분명했다. 한국어 표 문서에선 직접 만든 쪽이 앞선다. 다만 그 이유를 제대로 짚기까지 헛다리를 몇 번 더 짚는다.

내가 틀린 곳

처음 진단은 이랬다. "관리형이 공짜 기본 파서로 떨어져서 표를 못 읽는다. OCR을 안 도는 거다."

문서를 다시 읽고 나니 틀린 진단이었다. 이 관리형 KB는 처음부터 가장 똑똑한 파서로 돌고 있었다. 그게 기본값이고 다른 선택지도 없다.2 파서를 의심한 건 헛다리였다.

확인 차 같은 문서를 똑똑한 파서로 명시해 재인제스트했다. 30개 중 6개가 "못 찾음"에서 정답으로 살아났다. 홍역 등교중지는 "찾을 수 없음"에서 "7일간 등교 중지"로 복원됐다. 그런데 바로 옆 같은 표의 수두 행은 그대로 안 나왔다.

범인은 파싱이 아니라 청킹이었다.

완전관리형의 기본 청킹은 약 300토큰 고정 길이에 20% 오버랩이고, 의미 단위로 자르는 옵션은 없다.3 이 고정 길이가 질병 표를 행 한복판에서 잘라 버렸다. 홍역 행은 운 좋게 한 청크에 통째로 담겼고, 수두 행은 청크 경계에 걸쳐 두 동강이 났다. 파싱을 고쳐도 그 뒤에 숨은 청킹은 손댈 수가 없었다. 자르는 방식을 바꿀 권한이 우리에게 없었기 때문이다.

한 번 더 틀린 곳

청킹이 범인이라는 것도 절반만 맞았다. 글을 닫기 전에 KB를 다시 세워 검색을 직접 찔러봤더니, 결과가 또 한 번 나를 정정했다.

핵심 행은 인덱스에 멀쩡히 있었다. "모든 수포에 가피가 형성될 때까지, 발진 후 최소 5일." 잘려 사라진 게 아니었다.

문제는 회수였다. "수두 격리 기준은?"이라는 자연어 질문으로는 그 행이 상위에 안 떴다. 결과 개수를 20개로 늘리고 매니지드 리랭커도 켜봤지만1 순위는 그대로였다. 리랭킹은 회수가 빠뜨린 걸 끌어올리지 못한다. 없는 걸 재정렬할 수는 없으니까.

그러니 정확히는 이렇다. 사실은 인덱스에 있는데 자연어 질문이 그걸 못 끌어온다. 그리고 그 회수를 우리 쪽에서 손볼 방법이 없다. 챗봇 사용자는 키워드를 욱여넣지 않는다. 그냥 "수두는 며칠 쉬어요?"라고 묻는다.

비슷한 과제를 다루고 계신가요?30분 무료 진단 받기

돈은 어디서 새는가

겉만 보면 완전관리형이 싸 보인다. 벡터 DB를 직접 안 띄우는 데다 임베딩과 리랭킹 모델도 공짜로 끼워준다.4 함정은 "벡터 DB를 직접 안 띄운다"는 그 전제에 있다.

우리는 이미 띄우고 있다. 이 서비스는 RAG가 없어도 Aurora를 돌린다. pgvector는 그 위에 컬럼 하나와 HNSW 인덱스 하나를 더 얹는 정도다. 이미 돌아가는 DB 위에 얹기 때문에 RAG가 새로 무는 고정비는 거의 없다. 완전관리형은 반대다. RAG 전용 자원이 하나 더 서고, 인제스트·검색·스토리지가 전부 새 줄로 청구서에 찍힌다. 거기에 우리 건 도쿄에 있었으니 리전 간 전송까지 붙는다.

무엇에 돈을 내나pgvector (우리)완전관리형 KB
벡터 저장소이미 도는 Aurora에 컬럼·인덱스 추가 (한계비용 ≈ 0)전용 관리형 스토리지 (새 고정비)
적재ECS 일회성 태스크 (수 분)인제스트 요청당 과금
검색기존 DB 쿼리 + Titan 임베딩 1회검색 요청당 과금 (임베딩·리랭킹 포함)
리전 간 전송없음 (서울 단일)도쿄 크로스리전 전송 + corpus 복제
생성동일 Claude동일 Claude

그래서 비교는 질문 하나로 갈린다. DB를 이미 돌리고 있나. 우리는 돌리고 있으니 pgvector의 RAG 비용은 거의 공짜다. 만약 DB 한 대 없는 맨바닥에서 시작했다면 계산은 뒤집힌다. 전용 벡터 스토어를 24시간 켜두는 고정비가 진짜 부담이 되고, 검색당 과금하는 완전관리형이 저트래픽에선 더 쌀 수도 있다.

세 번째 선택지, OpenSearch

비교에서 일부러 뺀 후보가 하나 더 있다. OpenSearch다. KB의 파싱·청킹은 쓰면서 검색만 직접 제어하는 중간 지점이다. 끌리는 이유는 분명하다. 우리가 막혔던 회수 문제를 정면으로 겨냥하기 때문이다. BM25 키워드 점수와 kNN 벡터 점수를 함께 섞고, 한국어 형태소 분석기 nori를 붙이면 "수두"·"등교중지" 같은 단어의 키워드 매칭이 정확해진다.

문제는 돈이다. OpenSearch Serverless는 트래픽이 0이어도 최소 유닛이 항상 돌아 월 수백 달러가 바닥으로 깔린다.5 문서 2개에 저트래픽인 우리 프로젝트엔 과한 비용이다. 코퍼스가 커지고 자연어 회수 정확도가 사업적으로 중요해지면 OpenSearch 하이브리드가 답이 될 수 있다. 지금의 우리에겐 아니다.

결정

운영은 우리 파이프라인을 유지하기로 했다.

관리형은 똑똑했다. 다만 우리에게 필요한 제어권을 안 줬다. 한국어 표를 온전히 보존하려면 자르는 위치를 우리가 정해야 하는데 그 권한이 없다. 자연어 질문에서 핵심 행의 회수가 불안한데 그걸 손볼 길도 없다. 거기에 도쿄에 묶이고, 가만 둬도 스토리지·쿼리 요금이 샌다.

남는 것

RAG 품질은 파싱 × 청킹 × 검색이다. 더하기가 아니라 곱이라, 한 항이 0에 가까우면 나머지가 아무리 좋아도 결과는 0이다. 이번에도 파싱을 풀자마자 청킹이 다음 0으로 튀어나왔고, 청킹인 줄 알았더니 회수가 또 발목을 잡았다.

"완전관리형이니 알아서 최적이겠지"라는 기대는 빗나갔다. 관리형은 비싼 정교함 대신 안전한 기본값으로 수렴하고 미세조정 옵션을 숨긴다. 영어 산문이었다면 그 기본값으로 충분했을지 모른다. 표로 짜인 한국어 공문서 앞에서 그게 약점이 됐다.

마지막으로, 틀린 진단은 지우지 않고 그대로 남겨 뒀다. "파서 문제"라던 첫 판단을 두 번 뒤집는 과정이 이 비교에서 건진 제일 쓸모 있는 기록이라고 생각한다.


이런 한국어·규제 도메인의 RAG 설계와 검증은 AX 컨설팅데이터 & ML 엔지니어링에서 다루는 일의 일부입니다. "AI로 자동화하고 싶다"가 운영에서 살아남게 만드는 게 핵심입니다.

참고 자료

본문의 AWS 동작·제약은 아래 공식 문서로 확인했다. 비교 수치(단일턴 30문항, 후속 8세트, retrieve 실측)는 우리 코퍼스로 직접 측정한 값이다. 확인 시점: 2026-06.

Footnotes

  1. Amazon Bedrock — Retrieving information from data sources. Retrieve / RetrieveAndGenerate 비교, Retrieve에 reranking·결과 수 옵션 제공. 2

  2. Amazon Bedrock API — ParsingConfiguration · Parsing options. 관리형 KB는 Smart Parsing만 허용.

  3. Amazon Bedrock — Customize ingestion for a managed knowledge base. 기본 청킹 300토큰/20% 오버랩, semantic 청킹 미지원.

  4. Amazon Bedrock — Build a managed knowledge base. 관리형 임베딩·리랭킹 무료.

  5. AWS Solutions — QnABot on AWS, Cost. OpenSearch 기반 RAG 월 비용 예시.

이런 작업, 직접 맡기고 싶다면.

30분 무료 상담으로 방향부터 잡아드립니다.

이미 24개 팀과 함께 — 금융·헬스케어·미디어·공공
30분 무료 진단 받기
30분 무료 진단 받기