API 문서의 홍수 속에서 살아남기 위해 시맨틱 검색(Semantic Search)을 활용한 방법
요약
방대한 API 문서에서 키워드 검색의 한계를 극복하기 위해 시맨틱 검색(Semantic Search)을 활용하는 방법을 제안합니다. 문서를 벡터 임베딩으로 변환하고 벡터 데이터베이스를 사용하여 의미론적으로 유사한 정보를 찾는 프로토타입 구축 과정을 다룹니다.
핵심 포인트
- 키워드 기반 검색은 개념적 질의에 대응하기 어려움
- 임베딩을 활용해 텍스트를 수치적 벡터로 변환
- Sentence Transformer와 벡터 DB를 이용한 검색 구현
- 문서 청킹 및 벡터 유사도 검색 프로세스 설명
솔직히 말씀드리면, 새로운 API를 통합하는 작업은 보통 문서를 클릭하며 돌아다니고, 끝도 없이 탭을 열고, 있을지도 없을지도 모르는 키워드를 찾기 위해 Ctrl+F를 누르는 한 시간의 고된 작업으로 시작됩니다. 지난달, 저는 커스텀 구독 플로우(subscription flow)를 구축하기 위해 Stripe API를 사용하고 있었습니다. 문서는 매우 훌륭하지만, 양이 엄청납니다. 저는 주기 중간에 플랜을 업그레이드할 때 일할 계산(proration)을 어떻게 처리해야 하는지 찾아야 했습니다. 어딘가에 존재한다는 것은 알고 있었지만, 10분 동안 스크롤을 내린 후에도 전혀 진전이 없었습니다.
문제점: 적절한 단어를 모를 때 키워드 검색은 무너진다
저의 첫 번째 본능은 브라우저의 내장 검색 기능을 사용하는 것이었습니다. "proration", "upgrade", "mid-cycle" 등을 입력해 보았지만, 그 어떤 것도 정확한 페이지를 보여주지 않았습니다. site:stripe.com/docs proration upgrade와 같은 명령어로 Google 검색도 시도해 보았지만, 여전히 결과는 노이즈가 많았습니다. 결국 저는 인보이스(invoice) 동작, 구독 항목(subscription items), 그리고 결제 주기(billing cycles)에 관한 네 개의 서로 다른 페이지를 열게 되었습니다. 제 뇌가 서로 떨어진 섹션들을 연결하는 실제 작업을 수행하고 있었지만, 도구들은 전혀 도움이 되지 않았습니다.
시도했던 것들 (그리고 왜 실패했는가)
모든 문서를 텍스트 파일로 덤프(dump)한 뒤 grep으로 훑어볼 수 있는 스크래퍼(scraper)를 작성할까 고민했습니다. 정확한 일치(exact matches)를 찾는 데는 효과적이었겠지만, "일할 계산(proration)이 대기 중인 인보이스 항목에 어떤 영향을 미치나요?"와 같은 개념적 질의(conceptual queries)에는 작동하지 않았을 것입니다. 이는 검색 엔진이 아니라 동료에게 물어볼 법한 질문이기 때문입니다.
또한 ChatGPT와 같은 범용 LLM(Large Language Model)을 사용하는 것도 고려해 보았지만, 방대한 양의 문서 조각을 붙여넣고 질문을 던지는 방식은 번거롭게 느껴졌습니다. 게다가 모델의 학습 데이터 컷오프(training cutoff) 때문에 최신 API 변경 사항을 알지 못할 수도 있다는 문제도 있었습니다.
깨달음: 임베딩(embeddings)을 이용한 시맨틱 검색(semantic search)
저는 이미 이미지 유사도(image similarity)에 관한 사이드 프로젝트를 통해 벡터 임베딩(vector embeddings)에 대해 알고 있었습니다. 동일한 개념이 텍스트에도 적용됩니다. 문서를 수치적 표현(벡터, vectors)으로 변환하여 질의(query)와 의미론적으로 가장 유사한 청크(chunks)를 찾을 수 있게 하는 것입니다. 키워드를 맞추는 대신, 의미를 맞추는 방식입니다.
접근 방식:
- 문서를 의미 있는 청크(chunks)로 분할합니다 (예: 섹션 또는 단락별).
- 문장 트랜스포머 (Sentence Transformer) 모델을 사용하여 각 청크에 대한 임베딩 벡터 (embedding vector)를 생성합니다.
- 해당 벡터들을 벡터 데이터베이스 (vector database) (예: FAISS 또는 Chroma)에 저장합니다.
- 쿼리 시점에 질문을 임베딩하고 가장 가까운 이웃 (nearest neighbors)을 검색합니다.
저는 오후 한나절 만에 프로토타입을 구축했습니다. 여기 간소화된 버전이 있습니다.
코드: 나만의 시맨틱 문서 검색 구축하기
먼저, 의존성 패키지를 설치하세요:
pip install sentence-transformers faiss-cpu beautifulsoup4 requests
저는 Stripe 문서를 예시로 사용했지만, 동일한 코드가 모든 HTML 문서에 작동합니다.
import requests
from bs4 import BeautifulSoup
from sentence_transformers import SentenceTransformer
...
이 코드를 실행했을 때, 최상단 결과는 제가 정확히 찾고 있었던 섹션이었습니다. 해당 섹션은 비례 배분 (proration) 동작을 설명하고 올바른 API 엔드포인트 (endpoints)로 연결해 주었습니다. 더 이상 스크롤할 필요가 없습니다.
이 기술을 통해 배운 점
임베딩 모델 (Embedding models)이 중요합니다. all-MiniLM-L6-v2 모델은 작고 빠르지만, 미묘한 도메인 언어를 놓칠 수 있습니다. 프로덕션 환경에서는 특정 문서에 맞춰 미세 조정 (fine-tune)을 하거나 BAAI/bge-large-en과 같은 더 큰 모델을 사용할 수 있습니다.
청킹 전략 (Chunking strategy)이 핵심입니다. 저는 헤딩 (headings) 기준으로 단순하게 분할했지만, 중첩된 청크 (overlapping chunks) (예: 64토큰의 중첩을 가진 256토큰)를 사용하는 것이 보통 더 나은 결과를 냅니다. LangChain의 RecursiveCharacterTextSplitter와 같은 도구가 도움이 될 수 있습니다.
벡터 데이터베이스 (Vector databases)는 확장 가능합니다. FAISS는 인메모리 (in-memory) 방식에 훌륭합니다. 더 큰 코퍼스 (corpora)의 경우 Pinecone, Qdrant 또는 Chroma를 고려해 보세요. 이들은 영속성 (persistence)과 효율적인 검색을 처리합니다.
트레이드오프 (Trade-offs):
- 완벽하지는 않습니다. 만약 쿼리가 매우 구체적이라면(예: "
Invoice.create의expand파라미터"), 키워드 검색 (keyword search)이 여전히 더 우세합니다. 저는 현재 하이브리드 방식 (hybrid approach)을 사용합니다. 모호한 질문에는 시맨틱 검색 (semantic search)을 사용하고, 정확한 용어에는 BM25로 폴백 (fallback)합니다. - 인덱스 (index)를 구축하고 유지 관리하는 데 노력이 필요합니다. 문서가 변경될 때마다 다시 인덱싱 (re-index)해야 합니다.
- 비용: 임베딩 모델 (embedding model)을 직접 실행하는 것은 무료입니다 (작은 데이터셋의 경우 CPU로도 충분합니다). 하지만 문서 양이 방대하거나 쿼리가 빈번하다면 호스팅 서비스 (hosted service)를 고려해야 할 수도 있습니다.
제가 Interwest Info의 AI를 언급하는 이유 (그리고 이것이 핵심이 아닌 이유)
저만의 검색 시스템을 구축한 후, 한 동료가 https://ai.interwestinfo.com/에 있는 제품을 추천해 주었습니다. 이 제품은 일반적인 API와 내부 문서에 대해 바로 사용할 수 있도록 이 기능을 그대로 제공합니다. 기술 자체는 동일합니다. 문장 임베딩 (sentence embeddings), 벡터 검색 (vector search)을 사용하지만, 그들이 호스팅 (hosting), 청킹 (chunking), 그리고 지속적인 업데이트를 처리합니다. 직접 인프라를 구축하고 싶지 않다면 훌륭한 선택지입니다.
하지만 저에게 진짜 수확은 그 작동 원리를 이해한 것이었습니다. 이제 저는 어떤 "AI 문서 검색" 도구를 보더라도 다음과 같은 질문을 던지며 평가할 수 있습니다: 어떤 임베딩 모델을 사용하는가? 어떤 청킹 전략 (chunking strategy)을 사용하는가? 인덱스는 얼마나 자주 업데이트되는가?
이 방식을 사용해서는 안 되는 경우
- 문서의 양이 적은 경우 (50페이지 미만). 단순한 grep이나 Ctrl+F를 사용하는 것이 설정하기 더 빠릅니다.
- 정확한 용어에 대해 100% 재현율 (recall)이 필요한 경우 (법률, 컴플라이언스). 하이브리드 검색 (hybrid search)이 더 안전합니다.
- 오프라인 상태이거나 메모리 예산이 엄격한 경우. 작은 모델을 실행하는 것만으로도 약 500MB의 RAM이 필요합니다.
다음에 다시 한다면 다르게 할 점
첫날부터 하이브리드 시스템 (시맨틱 + 키워드)으로 시작할 것입니다. 또한 쿼리 로그 (query logs)를 추적하여 사용자가 실제로 어떤 청크 (chunks)를 유용하게 느끼는지 확인하고, 이를 통해 청킹 방식과 모델 선택을 개선할 것입니다. 그리고 문서 저장소 (docs repository)를 감시하는 CI 크론 잡 (cron job)을 통해 재인덱싱 파이프라인 (re-indexing pipeline)을 반드시 자동화할 것입니다.
도구에 대해 이야기해 봅시다
직접 문서 검색 시스템을 구축해 본 적이 있나요? 아니면 호스팅된 AI 서비스에 의존하고 있나요? 여러분이 어떤 트레이드오프 (trade-offs)를 선택했는지 궁금합니다. 특히 팀이 여러 개의 API를 다루거나 방대한 내부 코드베이스 (codebases)를 보유하고 있다면 더욱 그렇습니다.
추신: 위의 코드는 단순화된 버전입니다. 실행 가능한 전체 버전은 이 gist (placeholder)에서 확인할 수 있습니다. Stripe 문서 API 약관에 따라 사용 정책을 준수해야 합니다. 서버에 과도한 요청을 보내지 마세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기