아무튼, 쓰기
밥토리(Bobtory): 혼밥을 더 자유롭고 편하게 만드는 프로젝트 본문
프로젝트 소개
안녕하세요! 디프만 15기에서 백엔드 개발자로 참여하여 밥토리(Bobtory)라는 혼밥 식당 추천 서비스를 개발한 경험을 공유하고자 합니다.
밥토리 서비스: https://bobtory.com/home
프로젝트 상세: https://www.behance.net/gallery/239027413/-Bobtory-
혼자 밥 먹는 것이 어색하고 불편한 분들을 위해 기획된 밥토리는, 혼밥 난이도별로 식당을 추천하고 맞춤형 필터링 기능을 제공하는 서비스입니다. 사용자의 혼밥 레벨(Lv.1~4)에 따라 적합한 식당을 추천하며, 좌석 형태, 메뉴 카테고리, 가격대 등 다양한 커스텀 필터를 통해 나에게 딱 맞는 혼밥 장소를 찾을 수 있습니다.
프로젝트의 핵심 기능
- 혼밥 레벨별 맞춤 추천: 입문자(편의점 도시락, 패스트푸드)부터 고수(고급 레스토랑)까지
- 상세 필터링: 칸막이, 바 좌석, 1인석 등 좌석 형태와 메뉴 카테고리별 검색
- 지도 기반 탐색: 위치 기반으로 주변 혼밥 맛집 탐색
- 식당 제보 기능: 사용자가 직접 혼밥하기 좋은 식당을 제보
- AI 기반 검색: 임베딩 벡터를 활용한 의미론적 검색 기능
기존의 지도 기반 검색이나 단순 키워드 검색이 아닌,
식당 이름·메뉴·맥락을 함께 이해하는 검색 경험을 제공하는 것이 핵심 기획 의도였습니다.
특히 혼밥 상황에서는
- 고기 먹고 싶은데 혼자 가기 부담 없는 곳
- 조용하게 한 끼 먹기 좋은 식당
처럼 정확한 키워드로 표현하기 어려운 검색 니즈가 많습니다.
이 문제를 해결하기 위해 밥토리에서는 임베딩 벡터 기반 검색을 도입했고,
저는 해당 검색 기능의 백엔드 설계 및 구현을 담당했습니다.
검색 기능 구현의 여정: 왜 임베딩 벡터를 선택했을까?
1. 사이드 프로젝트에서 검색 기능의 어려움
사이드 프로젝트에서 검색 기능은 구현하기 까다로운 영역입니다. 밥토리에서도 식당 이름과 메뉴를 검색하는 요구사항이 생겼고, 여러 검색어가 자연스럽게 호환되는 검색 기능이 필요했습니다. 하지만 제한된 리소스와 짧은 개발 기간 안에 고품질의 검색 기능을 구현해야 하는 과제에 직면했습니다.
2. 검토한 검색 방법들
2.1 SQL LIKE 검색
SELECT *
FROM menu
WHERE name LIKE '%고기%';
장점:
- 구현이 가장 빠르고 간단함
- 추가 인프라 불필요
단점:
- 완전 일치하는 단어만 검색 가능
- 유사어나 관련어 검색 불가 (예: "고기" 검색 시 "스테이크"를 찾지 못함)
- 대소문자, 띄어쓰기에 민감
2.2 Full Text Index (PostgreSQL)
SELECT *
FROM menu
WHERE to_tsvector('simple', name) @@ to_tsquery('고기');
장점:
- Index Scan 지원으로 성능 향상
- 전문 검색 기능 제공
단점:
- 한국어의 경우 공백 기준으로만 토큰화
- 짧은 단어나 메뉴명에 적합하지 않음
- 의미론적 유사성을 파악하지 못함
2.3 외부 검색 엔진 (Elasticsearch, OpenSearch)
장점:
- 강력한 역색인(inverted index) 기술
- 다양한 분석기와 필터 지원
- 대규모 데이터 처리에 최적화
단점:
- 별도 인프라 구축 필요
- 시스템 리소스 추가 소요
- 사이드 프로젝트 규모에 과도한 스펙
밥토리 팀의 상황: 최소한의 인프라로 운영 중이었기 때문에 외부 검색 엔진에 투자할 리소스가 부족했습니다.
임베딩 벡터: 우리가 선택한 솔루션
임베딩이란?
임베딩(Embedding)은 고차원의 데이터를 저차원의 벡터 공간으로 변환하는 기술입니다. 텍스트를 수치 벡터로 표현하면, 의미가 유사한 단어들은 벡터 공간에서 가까운 위치에 배치됩니다.
예를 들어:
- "삼겹살" ≈ "고기", "돼지고기", "구이"
- "파스타" ≈ "스파게티", "면 요리", "이탈리안"
왜 임베딩 벡터를 선택했을까?
- 의미론적 검색 가능: 사용자가 "고기"를 검색하면 "삼겹살", "갈비", "스테이크" 등 관련 메뉴를 모두 찾을 수 있습니다
- 리소스 효율적: 기존 PostgreSQL에 pgvector 확장만 추가하면 됨
- NCP Clova Studio 지원: 네이버 클라우드 플랫폼에서 한국어에 최적화된 임베딩 API를 제공
Ncloud 서비스 활용
사용한 NCP 서비스
밥토리 프로젝트에서는 다음과 같은 NCP 서비스를 활용했습니다:
- CLOVA Studio - 임베딩 v2 API
- 한국어 텍스트를 768차원 벡터로 변환
- HyperCLOVA X 기반의 고성능 임베딩 모델
- Server (Compute)
- 애플리케이션 서버 호스팅
- VPC 환경에서 안정적인 운영
아키텍처 구성
[사용자]
↓
[Application Server (NCP Server)]
↓
├─→ [CLOVA Studio API] (임베딩 생성)
NCP CLOVA Studio 임베딩 API 적용 과정
밥토리(Babtori) 프로젝트에서 검색 및 추천 기능을 위해 NCP CLOVA Studio의 임베딩 API를 적용한 구체적인 구현 과정입니다.
1. 임베딩 생성 로직 구현
단순히 가게 이름만 임베딩하는 것이 아니라, 가게의 다양한 속성을 하나의 텍스트로 결합하여 풍부한 문맥을 가진 벡터를 생성했습니다.
텍스트 구성 (Text Construction)
StoreEmbeddingService에서 가게의 메타데이터를 조합하여 임베딩용 텍스트를 생성합니다.
private String buildStoreText(Store store) {
StringBuilder sb = new StringBuilder();
// 1. 가게 기본 정보
sb.append("가게명: ").append(store.getName()).append("\n");
sb.append("설명: ").append(store.getDescription()).append("\n");
// 2. 혼밥 난이도 (핵심 피처)
sb.append("혼밥 난이도: ").append(store.getHonbobLevel().getDescription())
.append(" (레벨 ").append(store.getHonbobLevel().getValue()).append(")\n");
// 3. 카테고리 및 위치
sb.append("주요 카테고리: ").append(store.getCategories().getPrimaryCategory().getPrimaryType()).append("\n");
sb.append("주소: ").append(store.getAddress().getAddress()).append("\n");
// 4. 메뉴 정보 (가격 포함)
List<Menu> menus = menuRepository.findByStore(store);
String menuText = menus.stream()
.map(menu -> menu.getName() + " (" + formatPrice(menu.getPrice()) + "원)")
.collect(Collectors.joining(", "));
sb.append("메뉴: ").append(menuText).append("\n");
// 5. 좌석 유형
String seatText = seatOptionRepository.findByStore(store).stream()
.map(seat -> seat.getSeatType().name())
.distinct()
.collect(Collectors.joining(", "));
sb.append("좌석 유형: ").append(seatText).append("\n");
return sb.toString().trim();
}
이렇게 생성된 텍스트는 다음과 같은 형태가 됩니다:
가게명: 밥토리 식당
설명: 조용하고 아늑한 한식당
혼밥 난이도: 프로 혼밥러 (레벨 1)
주요 카테고리: 한식
주소: 서울시 강남구 ...
메뉴: 김치찌개 (8,000원), 제육볶음 (9,000원)
좌석 유형: 1인석, 2인석
이 텍스트를 ClovaEmbeddingClient를 통해 NCP CLOVA Studio API로 전송하여 1024차원의 벡터를 얻습니다.
2. 벡터 유사도 검색 구현
PostgreSQL의 pgvector 확장을 사용하여 벡터 유사도 검색을 구현했습니다. JPA만으로는 벡터 연산을 처리하기 어려워 Native Query를 사용했습니다.
검색 쿼리 (Native SQL)
StoreEmbeddingQueryRepository에서 코사인 거리(Cosine Distance, <=>) 연산자를 사용하여 유사한 가게를 검색합니다.
public List<StoreEmbedding> findSimilarEmbeddingsWithCursor(
List<Float> embedding,
Float lastScore,
int limit
) {
// List<Float>를 pgvector 포맷 문자열로 변환 (e.g., "[0.1, 0.2, ...]")
String vectorLiteral = PgVectorUtils.toLiteral(embedding);
// 커서 기반 페이징을 위한 점수 초기화
if (lastScore == null) {
lastScore = 0.0f;
}
String sql = """
SELECT
se.*
FROM store_embedding se
JOIN store s ON s.id = se.store_id
WHERE (se.embedding <=> CAST(:embedding AS vector(1024))) > :lastScore
ORDER BY (se.embedding <=> CAST(:embedding AS vector(1024))) ASC, s.id ASC
LIMIT :limit
""";
Query query = em.createNativeQuery(sql, StoreEmbedding.class);
query.setParameter("embedding", vectorLiteral);
query.setParameter("limit", limit);
query.setParameter("lastScore", lastScore);
return query.getResultList();
}
핵심 포인트
<=>연산자: 코사인 거리를 계산합니다. 값이 작을수록 유사도가 높습니다.- 커서 페이징 (Cursor Pagination): 대량의 데이터에서도 성능 저하 없이 검색하기 위해
OFFSET대신 마지막 검색된 거리(lastScore)보다 큰 항목을 조회하는 방식을 사용했습니다. - 인덱스 활용:
store_embedding테이블의embedding컬럼에hnsw또는ivfflat인덱스를 적용하여 검색 속도를 최적화했습니다.
Ncloud 사용 소감
만족했던 점
1. 완벽한 한글 지원
NCP의 가장 큰 장점은 모든 서비스와 문서가 한글로 제공된다는 것입니다. CLOVA Studio 가이드부터 API 문서까지 모두 한글로 작성되어 있어, 개발하면서 이해하기 쉬웠고 빠르게 적용할 수 있었습니다.
2. CLOVA Studio의 한국어 특화 성능
HyperCLOVA X 기반의 임베딩 모델은 한국어 처리에 최적화되어 있습니다. "삼겹살", "곱창", "된장찌개" 같은 한국 음식명의 의미를 정확히 파악하여, 다른 글로벌 모델보다 우수한 검색 결과를 제공했습니다.
3. 임베딩 API 중 가장 저렴
시중에 나와있는 임베딩 API를 다 비교하였지만 클로바 임베딩 API가 압도적으로 가장 저렴하였습니다.
4. Green Developers 프로그램의 크레딧 지원
디프만과 제휴된 Green Developers 프로그램을 통해 최대 100만 원의 크레딧을 지원받았습니다. 사이드 프로젝트에서 클라우드 비용은 큰 부담인데, 이 지원 덕분에 서버, 데이터베이스, AI API를 마음껏 사용하며 개발에 집중할 수 있었습니다.
아쉬웠던 점
1. 일부 서비스 레퍼런스 부족
CLOVA Studio 임베딩은 상대적으로 최신 기술이다 보니, OpenAI나 Pinecone 같은 글로벌 서비스에 비해 커뮤니티 레퍼런스가 적은 편입니다. 하지만 점점 더 많은 한국 개발자들이 사용하면서 자료가 늘어나고 있는 추세입니다.
2. 서비 비용 다소 비쌈
AWS ec2와 비교하였을 때 같은 스펙 대비 가격이 조금 높은 감이 있습니다.
Green Developers 프로그램 참여 소감
Green Developers 프로그램은 예비·주니어 개발자들에게 정말 훌륭한 기회입니다. 단순히 크레딧 지원뿐만 아니라, 실무 수준의 클라우드 인프라를 경험하고, AI 서비스를 부담 없이 시도해볼 수 있다는 점이 큰 장점입니다.
디프만과 같은 IT 동아리와 제휴하여 제공되는 이 프로그램 덕분에, 우리 팀은 비용 걱정 없이 기술적 도전을 할 수 있었고, 의미론적 검색이라는 고급 기능을 밥토리에 구현할 수 있었습니다.
앞으로도 더 많은 개발자들이 Green Developers 프로그램을 통해 NCP를 경험하고, 한국어에 최적화된 클라우드 서비스의 강점을 느꼈으면 좋겠습니다.
마지막 한마디
흥미로웠던 점: 임베딩 벡터의 효과
처음에는 "단순 LIKE 검색도 충분하지 않을까?"라고 생각했지만, 임베딩 벡터를 도입한 후 검색 품질이 확연히 개선되었습니다. 사용자가 "고기"를 검색하면 "삼겹살집", "소고기 전문점", "스테이크 하우스"가 모두 나타나고, "혼밥"을 검색하면 1인석이 있는 식당들이 자연스럽게 검색되는 것을 보며, AI 기술의 실용성을 직접 체감할 수 있었습니다.
향후 NCloud 활용 계획
밥토리는 현재 베타 버전으로 운영 중이며, 앞으로 다음과 같은 기능을 추가로 개발할 계획입니다:
- CLOVA Chatbot 연동: 사용자와 대화하며 맞춤형 식당을 추천하는 챗봇
- CLOVA OCR: 사용자가 업로드한 메뉴판 사진을 분석하여 자동 메뉴 등록
Green Developers 프로그램에 대한 피드백
Green Developers 프로그램은 단순한 크레딧 지원을 넘어, 예비 개발자들에게 실무 경험을 쌓을 수 있는 플랫폼을 제공합니다. 다만 다음과 같은 점이 개선되면 더 좋을 것 같습니다:
- 더 많은 기술 세미나: CLOVA Studio, AI 서비스 활용 사례를 공유하는 온라인/오프라인 세션
- 프로젝트 우수 사례 발굴: Green Developers로 만든 프로젝트 중 우수 사례를 선정하여 홍보 및 추가 지원
프로젝트를 마치며
밥토리 프로젝트는 디프만이라는 멋진 커뮤니티에서, NCP Green Developers 프로그램의 지원 아래 완성할 수 있었습니다. 혼밥이 더 이상 외롭거나 어색한 경험이 아닌, 자유롭고 편안한 일상이 되길 바라는 마음으로 만든 서비스입니다.
혹시 혼밥을 고민하고 계신다면, 밥토리를 방문해주세요!
🍚 https://bobtory.com/home
기술적으로 더 궁금하신 점이 있다면 언제든 편하게 물어봐주세요. 감사합니다!