자작 RAG와 Bedrock Knowledge Base 비교
시리즈: AWS 자격증, 실무로 되짚기
1 / 3편
- 11편 - Gen AI 자격증과 자작 RAG지 금 읽는 중
- 22편 - 아키텍트 자격증과 Multi-AZ 운영
- 33편 - DevOps 자격증과 자동 복구
목차
날짜 검색이 자꾸 틀리던 자작 RAG를 BM25로 고쳐 놓고 나서, 같은 해법이 AWS Gen AI 자격증(AIP-C01) 범위에 개념 한 줄로 들어 있는 걸 봤습니다. 시험이 관리형 정답으로 내세우는 Bedrock Knowledge Base와, 제가 LanceDB로 검색·청킹·병합을 직접 짠 구조를 비교해 보니 겹치는 곳은 청킹 전략과 하이브리드 검색이었습니다. 시험은 어느 쪽이 정답인지는 알려 줘도 왜 그런지는 알려 주지 않습니다. 그건 직접 만들어 본 쪽이 더 잘 압니다. 반대로 자격증은 아는 카탈로그를 넓혀 줄 뿐이어서, 트레이드오프 감각은 만들어 봐야 생긴다는 한계도 확인했습니다.
“3월 15일 미팅 뭐였지?”라고 물으면 4월이 나왔습니다
제가 만들어 쓰는 개인 AI 비서에 이렇게 물으면 4월 7일 미팅을 꺼내왔습니다. 한두 번이 아니라, 날짜를 물을 때마다 거의 매번 그랬습니다.
버그는 아니었습니다. 벡터 검색은 “3월 15일 팀 미팅”과 “4월 7일 팀 미팅”을 의미가 거의 같다고 봅니다. 날짜 숫자는 의미에서 차지하는 비중이 작아서 맥락이 더 비슷한 다른 날 기록한테 밀립니다. 설계상 그렇게 도는 겁니다. 이걸 알기까지 한참 걸렸습니다.
얼마 뒤 AWS Generative AI 자격증(AIP-C01)을 준비하다가 같은 내용을 만났습니다. 시맨틱(벡터) 검색은 의미가 비슷한 문서를 찾고, 키워드 검색은 단어가 일치하는 문서를 찾으며, 둘을 합친 하이브리드 검색이 정확도를 높인다는 설명입니다.
제가 검색 결과를 하나씩 뒤져 가며 도착한 결론이 시험에서는 외워야 할 개념 하나였습니다. 그래서 자격증을 딴 뒤 제 코드를 처음부터 다시 열어봤습니다. 시험이 정답이라고 하는 구조와 제가 실제로 만든 구조를 나란히 놓고 보고 싶었습니다.
이 글은 세 편짜리 시리즈의 첫 편입니다. AWS 프로페셔널 자격증 세 개를 각각 제가 직접 만든 시스템 하나에 붙여서 시험이 그린 그림과 제 코드가 어디서 만나고 갈라지는지 봅니다.
- 1편(지금): Gen AI 자격증(AIP-C01)과 자작 RAG, 관리형 Bedrock과 LanceDB 사이
- 2편: 아키텍트 자격증(SAP-C02)과 실제 운영한 Multi-AZ 고가용성, 재해 복구 전략과 현실의 거리
- 3편: DevOps 자격증(DOP-C02)과 밤새 혼자 도는 개인 시스템의 자동 복구
한 가지 먼저 밝혀둡니다. 저는 Bedrock을 프로덕션으로 오래 운영한 적이 없습니다. 그러니 아래는 관리형을 깊게 써 본 사람의 평가가 아니라, 자작으로 굴려 본 사람이 관리형 구성을 되짚어 본 대조입니다.
시험이 답으로 주는 완성품을 저는 부품으로 조립했습니다
자격증의 RAG 파트는 사내 문서를 근거로 답하는 챗봇을 인프라 관리 부담 없이 만들 때 어떤 구성을 고를지를 다룹니다. 답은 대개 Bedrock Knowledge Base + 관리형 벡터 스토어 + 파운데이션 모델 조합으로 좁혀집니다. 문서를 넣으면 청킹·임베딩·검색·생성까지 알아서 엮어주는 완성품입니다.
이 구성을 보면서 묘한 기분이 들었습니다. 저는 같은 걸 반년 전에 직접 만들어서 매일 굴리고 있었기 때문입니다. Jarvis라는 개인 AI 비서에 장기 기억을 붙이려고 LanceDB로 벡터 검색을 짰고, 청크 크기 때문에 두 번 갈아엎었고, 앞서 말한 날짜 문제 때문에 BM25까지 붙였습니다.
두 그림을 나란히 두면 이렇습니다.
graph LR
subgraph M["시험 정답 — 관리형"]
direction TB
M1["문서 업로드"] --> M2["Bedrock<br/>Knowledge Base"]
M2 --> M3["관리형<br/>벡터 스토어"]
M3 --> M4["파운데이션 모델<br/>응답"]
end
subgraph S["내 자작 — Jarvis"]
direction TB
S1["대화 → 청크"] --> S2["Ollama<br/>로컬 임베딩"]
S2 --> S3["LanceDB<br/>벡터 + BM25"]
S3 --> S4["Claude API<br/>응답"]
end같은 자리에 뭐가 들어가는지 비교하면 트레이드오프가 선명해집니다.
| 구성 요소 | 시험 정답 (관리형) | 내 자작 (Jarvis) | 뭘 얻고 뭘 잃나 |
|---|---|---|---|
| 청킹·인덱싱 | 고정 크기·계층형·시맨틱·청킹 없음 등 설정 | 청크 기준과 변환 코드를 직접 관리 | 관리형도 크기·overlap 등을 조절할 수 있음. 사용자 정의 전처리의 운영 부담을 비교 |
| 임베딩 | Titan 등 API 모델 | Ollama 로컬 모델 | 품질은 모델·언어·문서별 평가가 필요. 로컬에도 장비·전력·운영 비용이 있음 |
| 벡터 스토어 | OpenSearch·Aurora 등 | LanceDB(파일 기반) | 관리형은 확장 쉬움. 자작은 맥미니 한 대로 충분 |
| 검색 병합 | 관리형 하이브리드 | RRF 직접 구현 | 직접 짜면 k값·가중치를 내가 만짐 |
관리를 최소화하려면 관리형을 고르라는 것이 시험의 방향이고, 맞는 말입니다. 그런데 제 경우는 반대 이유로 자작을 골랐습니다. 개인이 매일 쓰는 비서라 비용이 0에 가까워야 했고, 데이터가 사적인 대화라 임베딩 단계는 로컬에서 처리하고 싶었습니다. 검색된 청크는 결국 Claude API로 나가니 모든 데이터가 로컬에 머무는 구조는 아닙니다. 임베딩을 Ollama 로컬로 돌린 것도 이 두 가지 때문입니다.
시험은 인프라 관리 최소화라는 한 축만 봅니다. 실제 선택은 비용·프라이버시·확장성이 얽힌 다축 문제입니다.
Bedrock 공식 청킹 문서는 고정 크기의 토큰 수·overlap, 계층형·시맨틱 청킹과 사용자 정의 변환을 설명합니다. 관리형 에서 청크 단위를 바꿀 수 없다는 이전 비교표는 정정했습니다. 아래는 제 로컬 RAG 경험이며 두 시스템을 같은 평가 세트로 벤치마크한 결과는 아닙니다.
청크 크기는 두 번 갈아엎었습니다
시험에서 청킹은 고정 크기, 시맨틱, 계층형 청킹 중 상황에 맞는 것을 고르는 식으로 나옵니다. 보기 하나를 고르면 끝입니다.
저는 이 한 줄을 두 번 실패하고서야 이해했습니다. Jarvis 초기에 청크 크기를 잡는 데 예상보다 오래 걸렸습니다.
- 문장 단위로 잘랐더니 검색 결과가 파편으로 쪼개졌습니다
- 일정 토큰 수로 잘랐더니 대화 흐름이 중간에 끊겼습니다
- 결국 대화 한 덩어리(질문 하나 + 답변 하나)를 청크 한 개로 잡고서야 안정됐습니다
이 기준으로 저장한 결과가 지금의 18만 개 가까운 청크입니다. 시맨틱 청킹이 고정 크기보다 나은 경우가 있는 이유를, 저는 검색이 엉뚱한 맥락을 꺼내오는 걸 눈으로 보고 나서 납득했습니다.
시험이 준 건 선택지의 이름이고 제가 가진 건 그 선택지가 왜 필요한지 겪어 본 감각입니다. 이름을 알면 남한테 설명할 때 편하고, 겪어 봤으면 새 상황에서 어떤 이름을 골라야 할지 감이 옵니다.
BM25를 얹으니 4월 미팅이 사라졌습니다
앞에서 말한 날짜 문제로 돌아갑니다. 벡터 검색이 구조적으로 못 잡는 거라면, 단어가 실제로 박혀 있는지만 보는 검색을 옆에 세우면 됩니다. 그래서 BM25를 붙였습니다. LanceDB가 전문 검색(FTS)을 기본으로 지원해서 쓰던 벡터 DB에 인덱스만 하나 더 얹으면 됐습니다.
async function hybridSearch(queryText, queryEmbedding, limit = 10) {
// 순서대로 돌리면 두 배로 기다리니까 동시에 던짐
const [vectorResults, ftsResults] = await Promise.all([
table.search(queryEmbedding).distanceType('cosine').limit(limit * 2).toArray(),
table.search(queryText, 'fts').limit(limit * 2).toArray()
]);
return mergeResults(vectorResults, ftsResults, limit);
}두 결과를 합치는 건 RRF(Reciprocal Rank Fusion)로 했습니다. 양쪽 검색에서 모두 위에 오른 문서를 우대하는 방식입니다. k값은 원논문 기본값 60을 그대로 썼는데, 바꿔봐도 체감 차이가 없어서 그냥 뒀습니다.
하이브리드 검색이 정확도를 높인다는 한 줄이, 저한테는 날짜 검색을 거의 다 맞게 돌려놓은 실제 개선이었습니다. 응답은 한 50ms쯤 느려졌는데, 1초도 안 되는 차이라 쓰면서는 모릅니다.
시험 개념과 제 경험이 같은 지점에서 만난 것입니다. 다른 건 하나뿐입니다. 시험은 결론만 주고 저는 그 결론에 닿으려고 청크 크기와 날짜 필터와 프롬프트를 차례로 갈아봤습니다.
Guardrails, Agents, 임베딩 선택 기준
여기까지만 보면 이미 다 아는 걸 시험이 뒤늦게 확인해 준 것 아니냐고 할 수 있습니다. 절반은 맞습니다.
검색과 청킹은 손으로 팠지만 그 옆의 것들은 이름만 흐릿하게 알고 있었습니다. 이쪽은 시험 준비하면서 처음 정리했습니다.
- Guardrails: 모델 출력에서 민감 정보나 유해 표현을 거르는 관리형 장치입니다. 저는 Jarvis에서 개인정보 마스킹을 직접 규칙으로 짰는데, 관리형은 이걸 서비스로 제공한다는 걸 정리했습니다
- Agents: 모델이 도구를 호출하며 다단계로 일하는 구조입니다. Jarvis도 비슷하게 굴러가지만, 관리형이 이걸 어떤 추상화로 묶는지는 시험 준비로 봤습니다
- 임베딩 모델 선택 기준: 저는 호출당 API 요금이 없어서 로컬 모델을 골랐지만 장비·전력·운영 비용은 있으며, 시험 범위는 차원 수·언어 지원·비용을 기준으로 어떻게 고르는지 축을 정리해 줍니다
제가 만든 시스템은 검색만 깊고 나머지는 얕은 모양이었습니다. 특히 Guardrails는 좀 허탈했습니다. 개인정보 마스킹 규칙을 며칠 붙잡고 짰는데 그게 이미 서비스로 나와 있었습니다.
관리형으로 옮길지 저울질한다면 몇 가지를 따져 볼 만합니다. 임베딩 비용은 호출 단가와 토큰 수, 로컬 장비의 고정 비용·처리량·운영 시간을 함께 비교해야 합니다. 호출량만으로 어느 쪽이 저렴하다고 단정할 수 없습니다. 데이터가 사적이거나 민감하면 임베딩을 로컬에서 처리하는 편이 안전합니다. 자동 청킹이 내 데이터에 충분한지는 검색 품질로 확인해야 하고, 날짜나 고유명사 검색이 자주 틀리면 BM25 하이브리드가 필요할 수 있습니다. 가드레일이나 에이전트처럼 검색 밖 기능이 필요하다면 직접 짜는 비용과 관리형 도입 비용을 비교해 보면 됩니다.
날짜가 필수 조건인 질문은 검색 점수만 믿지 않고 날짜 메타데이터로 범위를 좁혀야 합니다. BM25도 날짜 파싱과 필터를 대신하지는 않습니다. 문서 수정·삭제와 권한 필터까지 포함한 동일 질문 세트로 평가해야 실제 품질 차이를 말할 수 있습니다.
다시 만든다면 BM25부터 깔고 시작합니다
다음에 RAG를 또 만들 일이 있으면 저는 벡터 검색을 띄우기 전에 BM25부터 깔고 시작할 겁니다. 4월 미팅을 잘못 가져오는 Jarvis를 며칠 붙잡고 있다가 얻은 결론입니다. 다음에 Guardrails 같은 걸 또 손으로 짜기 전에는 이미 서비스로 나와 있는지 한 번 찾아보겠습니다.
다음 편은 AWS Solutions Architect 자격증(SAP-C02)입니다. 시험이 그리는 재해 복구·다중 리전 전략과, 제가 실제로 운영해본 Multi-AZ 고가용성 사이에서 어디까지가 손에 익은 범위였는지 정리해보려 합니다.
