본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 03. 11:03

사내 문서를 위한 AI 챗봇 구축: 성공 사례와 실패 사례

요약

사내 문서 검색을 위한 AI 챗봇 구축 과정에서의 시행착오와 RAG 최적화 방법을 다룹니다. 단순 임베딩과 로컬 LLM의 한계를 넘어, 의미론적 청킹과 하이브리드 검색을 통한 정확도 향상 전략을 제시합니다.

핵심 포인트

  • 단순 고정 크기 청킹 대신 문맥 보존을 위한 의미론적 청킹 필요
  • 벡터 검색의 한계를 보완하기 위해 BM25 기반 키워드 검색 결합
  • 하이브리드 검색(Vector + Keyword)을 통한 검색 정확도 및 재현율 개선
  • 비용 효율성과 모델 성능 사이의 트레이드오프 고려 필수

몇 달 전, 우리 팀은 난관에 봉착했습니다. 우리의 사내 문서가 Confluence 페이지, Google Docs, 그리고 Slack 스레드가 뒤섞인 혼란스러운 정글처럼 변해버렸기 때문입니다. 신입 사원들은 기본적인 질문에 대한 답을 찾는 데만 몇 주가 걸렸습니다. 저는 "AI 챗봇을 만들자"라고 생각했습니다. 간단해 보이죠?

스포일러: 시행착오를 거치는 데 두 달이 걸렸습니다. 하지만 저는 검색 증강 생성 (RAG, Retrieval-Augmented Generation)과 이것이 실제 운영 환경에서 제대로 작동하게 만드는 방법이 무엇인지에 대해 엄청난 것을 배웠습니다.

문제점

우리는 사용자가 "VPN 비밀번호를 어떻게 재설정하나요?"라고 물었을 때, 인용구와 함께 간결한 답변을 얻을 수 있는 시스템이 필요했습니다. 전체 정책의 요약이나 환각 (Hallucination)된 단계가 아니라, 정확한 절차만을 제공해야 했습니다.

처음 시도했던 것들

뻔한 경로: OpenAI Embeddings + Pinecone

모든 문서를 가져와서 50자 중첩 (Overlap)을 포함한 500자 단위의 조각 (Chunk)으로 나누고, text-embedding-ada-002로 임베딩 (Embedding)을 생성한 뒤 Pinecone 인덱스에 로드했습니다. 그런 다음 GPT-4를 사용하여 검색된 조각들을 바탕으로 답변하도록 했습니다.

첫 번째 쿼리에서는 작동했습니다. 하지만 청구서가 날아왔습니다. 우리에게는 50,000페이지의 문서가 있었습니다. 임베딩 생성 비용만 수백 달러가 들었습니다. 그리고 GPT-4 사용량은요? CTO가 질문을 하기 시작했다고만 해두죠.

오픈 소스 우회로: LlamaIndex + 로컬 LLM

임베딩을 위해 sentence-transformers/all-MiniLM-L6-v2를 사용하고, Ollama를 통해 로컬 7B 모델을 사용하는 LlamaIndex로 전환했습니다. API 비용은 들지 않았습니다! 하지만 정확도가 급격히 떨어졌습니다. 로컬 모델은 복잡한 지시 사항을 따르지 못했고, 임베딩은 도메인 특화 전문 용어(예: "VPN PAM" 또는 "SAML SSO")를 제대로 포착하지 못했습니다.

핵심 통찰: 청킹 (Chunking)과 하이브리드 검색 (Hybrid Search)

재현율 (Recall)과 지연 시간 (Latency) 문제로 머리를 싸매고 고민한 끝에, 해결책은 더 나은 모델이 아니라 더 나은 검색 (Retrieval)에 있다는 것을 깨달았습니다.

청킹 전략

기술 문서에는 고정된 청크 크기가 통하지 않습니다. 200단어 크기의 청크는 표를 반으로 잘라버릴 수도 있습니다. 저는 spaCy 문장 경계 (Sentence boundaries)를 사용하는 의미론적 청킹 (Semantic chunking)으로 전환한 다음, 250 토큰 (Token)을 초과할 때까지 문장을 병합했습니다. 이를 통해 문맥 (Context)을 보존할 수 있었습니다.

import spacy
from langchain.text_splitter import RecursiveCharacterTextSplitter

...

하이브리드 검색 (Hybrid Search): 벡터 + 키워드

벡터 검색 (Vector search)은 유의어와 개념을 찾는 데는 훌륭하지만, "VPN 비밀번호 재설정"과 같은 정확한 일치 (Exact match)에는 매우 취약합니다. BM25는 정확한 키워드를 잡아내지만 의미적 유사성 (Semantic similarity)을 놓칩니다. 이 둘을 함께 사용하면 매우 강력한 도구가 됩니다.

저는 간단한 하이브리드 검색기 (Hybrid retriever)를 구축했습니다:

from sentence_transformers import SentenceTransformer
from rank_bm25 import BM25Okapi
import numpy as np
...

그 다음, 크로스 인코더 (Cross-encoder, cross-encoder/ms-marco-MiniLM-L-6-v2)를 사용하여 리랭킹 (Reranking) 단계를 추가했습니다. 이는 검색된 청크 (Chunk)들을 쿼리 (Query)와 비교하여 점수를 매기고 순서를 재조정했습니다. 약 200ms의 시간이 추가되었지만, 답변의 품질은 두 배로 향상되었습니다.

돌파구: 완벽할 필요는 없다

저는 임베딩 모델 (Embedding model)과 청크 크기 (Chunk size)를 조정하는 데 몇 주를 보냈습니다. 마침내 시스템을 사용 가능하게 만든 것은 간단한 폴백 (Fallback) 전략이었습니다. 만약 가장 상위에 검색된 청크의 신뢰도 (Confidence)가 임계값 (Threshold) 미만이라면, 봇은 "문서에서 해당 내용을 찾을 수 없습니다. 질문을 다시 구성하거나 #it-help 채널을 확인해 주세요."라고 답변하도록 했습니다. 사용자들은 자신 있게 틀린 답을 내놓는 것보다 정직하게 "모릅니다"라고 말하는 것을 선호했습니다.

배운 점

  1. 임베딩 모델보다 청킹 (Chunking)이 더 중요하다. 의미론적 청킹 (Semantic chunking)과 약 2문장 정도의 중첩 (Overlap)을 사용하는 것이 가장 좋은 결과를 냈습니다.
  2. 사내 문서의 경우 하이브리드 검색이 순수 벡터 검색보다 우수하다. 코드 스니펫 (Code snippets), 에러 메시지, 제품명은 정확한 일치 (Exact-match) 쿼리입니다.
  3. 리랭킹 (Reranking)은 비용이 저렴하면서도 영향력이 크다. 가벼운 크로스 인코더 (Cross-encoder)는 재현율 (Recall)을 크게 향상시킵니다.
  4. 모든 쿼리에 GPT-4를 사용하지 마라. 간단한 사실 관계 답변에는 더 작은 모델 (GPT-3.5 또는 로컬 7B 모델 등)로도 충분합니다. 답변이 명확하지 않을 때만 더 큰 모델로 넘기십시오.

다르게 했을 점

"최고의" 임베딩 모델을 쫓는 대신, 첫날부터 하이브리드 검색기 (Hybrid retriever)로 시작했어야 했습니다. 또한, 초기에 간단한 평가 프레임워크 (Evaluation harness)를 구축했더라면 좋았을 것입니다. 예를 들어, 도메인 전문가에게 100개의 쿼리와 그에 대한 정답 청크 (Ground-truth chunks)를 라벨링하도록 요청하는 방식 말입니다. 그랬다면 몇 주간의 추측성 작업 시간을 아낄 수 있었을 것입니다.

만약 여러분이 이와 유사한 것을 구축하고 있다면, 최신 AI 모델에 현혹되지 마십시오. 여러분의 병목 현상 (bottleneck)은 생성 (generation)이 아니라, 거의 확실하게 검색 (retrieval) 단계에 있을 것입니다.

실제 서비스 가능한 버전 (production-ready version)을 위해, 저는 나중에 관리형 검색 서비스 (managed retrieval service, 예: https://ai.interwestinfo.com/)를 사용하여 구조를 단순화했지만, 처음부터 직접 구축해 본 과정이 더 많은 것을 가르쳐 주었습니다.

사내 AI 도구를 구축한 여러분의 경험은 어떠신가요? 여러분도 동일한 청킹 (chunking) 문제에 부딪혔나요? 댓글로 알려주세요!

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0