요약: 이 글은 카카오페이 제 2회 해커톤에서 2등을 수상한 모즈(MOZ) 팀의 프로젝트를 다룹니다. 모즈 팀은 거래 내역을 특별한 의미와 감성을 담은 기록으로 변환하고, 자연어 기반 검색을 통해 쉽게 금융 관리를 할 수 있는 서비스를 만들었습니다. 주요 기능으로는 거래 내역에 의미 있는 메모를 간편하게 추가하고, 이를 바탕으로 시각적으로 요약된 이미지를 생성하며, 자연어 검색을 통해 특정 거래 내역을 쉽게 찾을 수 있는 기능을 포함합니다. 이 서비스는 AWS 클라우드 환경에서 Nova Canvas를 활용한 시각적 인터페이스와 Claude 3.5 모델 기반의 Text2SQL 및 tool calling 기능을 접목하여 개발되었습니다.
💡 리뷰어 한줄평
jimmy.im 카카오페이가 과거에 확보한 결제처를 사용자에게 사용하도록 유인하는 매우 효과적인 서비스 같아요!
waiki.ki 내 소비 캘린더에 그림일기를 자동으로 생성해 주는 아이디어가 매력적인 서비스입니다. AI를 활용하여 일상을 기록해 주는 서비스를 어떻게 구현했는지 궁금하신 분들에게 이 글을 추천합니다~
시작하며
안녕하세요. 제 2회 카카오페이 해커톤에서 2등을 수상한 모즈(MOZ)팀입니다.
저희는 사용자의 평범한 거래 내역을 좀 더 특별한 기억으로 변환하고, 자연어 기반 검색으로 쉽고 의미 있는 금융 관리를 돕는 서비스를 기획했습니다. 이 글을 통해, 어떤 기획 배경에서 아이디어가 시작되었으며, 이 서비스를 구현하기 위해 어떤 AI 및 클라우드 기술들을 사용했고, 왜 그 기술들을 선택하게 되었는지 저희의 경험과 고민을 나누고자 합니다.
특히 최신 기술을 활용하여 사용자 문제를 해결하고 새로운 서비스를 만들어나가는 과정에 관심 있는 개발자, 기획자, 디자이너 및 관련 분야 학생분들께 저희의 이야기가 흥미로운 사례이자 작은 영감이 되기를 바랍니다. 함께 자세히 알아보시죠!
기획 배경: 평범한 거래 내역에 특별함을 더하다
카카오페이의 통합내역 서비스를 이용해 보셨나요?
통합내역 서비스는 연결된 자산의 거래내역들을 한 곳에 모아 편리하게 관리할 수 있는 서비스입니다.
저희는 통합내역 서비스에 보이는 사용자들의 소중한 거래 내역 데이터를 풍성하게 기록하고 싶었습니다. 단순히 스쳐 지나가는 기록이 아닌, 그날의 의미와 추억을 담아 특별하게 만들고, 나아가 그 기록을 통해 하루를 되돌아볼 수 있다면 얼마나 좋을까 하는 상상에서 저희 서비스의 아이디어가 시작되었습니다.
현재 통합내역 서비스에 보이는 거래 내역에는 기본적인 내용만 노출되고 있기 때문에 어디서, 누구와, 무엇을 하며 발생한 거래 내역인지에 대한 구체적인 맥락을 파악하기 어렵습니다. 이러한 아쉬움을 달래고자 메모 기능을 활용해야 했는데, 현재 제공되는 메모 기능은 문자열 입력으로만 제공되고 있어, 입력 과정이 귀찮고 허들이 높다고 생각했습니다.
저희는 바로 이 지점에 주목했습니다.
메모 입력 과정을 쉽고 간편하게 개선하여 거래 내역에 풍부한 의미를 담고,
이 풍부한 메모 데이터를 기반으로 거래 내역을 특별하게 만들어 줄 뿐만 아니라,
더욱 편리한 검색 기능까지 제공하는 서비스를 기획하게 되었습니다.
서비스 주요 기능: 쉽고 특별하고 편리하게
저희가 해커톤을 통해 구현하고자 했던 핵심 기능은 다음과 같습니다.
1️⃣ 쉽고 간편한 메모 기록: 거래 내역에 쉽고 빠르게 의미를 부여할 수 있는 기능
2️⃣ 특별한 요약: 기록된 메모를 기반으로 시각적인 재미를 더하고 추억을 떠올릴 수 있는 기능
3️⃣ 손쉬운 검색 및 조회: 풍부한 메모 데이터를 활용하여 원하는 거래 내역을 손쉽게 찾아볼 수 있는 기능
1️⃣ 쉽고 간편한 메모 기록
저희는 사용자가 쉽고 직관적으로 거래 내역에 메모를 기록할 수 있도록 칩 선택 방식을 도입했습니다. ‘무엇을 했는지 (목적)’, ‘누구와 함께였는지 (인물)’, ‘그때 기분은 어땠는지 (감정)’ 등의 카테고리에서 간단한 칩을 선택하는 것만으로도 풍부한 정보를 기록할 수 있습니다. 뿐만 아니라, 사용자가 입력하는 텍스트를 기반으로 근접한 카테고리를 추천하여 더욱 빠르고 편리한 메모 입력을 지원합니다.
2️⃣ 특별한 요약
단순한 텍스트 메모를 넘어, 시각적으로 더욱 풍성한 경험을 제공하고자 메모 기반 이미지 생성 기능을 구현했습니다. 거래 내역과 사용자가 입력한 메모 데이터를 바탕으로 특별한 이미지를 생성하고, 이 이미지를 거래 날짜의 대표 이미지로 설정하여 나만의 개성 있는 캘린더를 만들 수 있습니다. 지난 거래들을 한눈에 특별하게 되돌아볼 수 있는 경험을 선사합니다.
3️⃣ 손쉬운 검색 및 조회
마지막 기능은 통합내역 내 검색 편의성 향상입니다. 기존의 기본적인 검색 방식에서 벗어나, 거래 내역 데이터와 사용자가 기록한 풍부한 메모 데이터를 활용한 자연어 검색 기능을 제공합니다. 사용자의 의도를 정확히 파악하여 관련 거래 내역을 찾아 보여줌으로써 사용자는 원하는 정보를 더욱 쉽고 빠르게 얻을 수 있습니다.
서비스의 전체 플로우 아키텍처
저희 서비스의 핵심 구조는 위 다이어그램에서 확인하실 수 있습니다.
사용자와 만나는 웹 애플리케이션의 프론트엔드는 AWS Amplify를 통해 개발 및 배포되었습니다. 이미지 콘텐츠는 AWS S3에 저장했으며, 거래 내역 데이터는 AWS RDS를 통해 관리하고 조회할 수 있도록 구축했습니다. 서비스의 핵심 로직을 수행하는 애플리케이션 서버는 AWS EC2 인스턴스 위에서 작동합니다.
초기에는 AWS Lambda와 AWS Bedrock Agent를 함께 활용하여 서버에서는 단순히 호출하고 응답만 받는 서버리스 구조를 생각했습니다. 하지만 서비스를 구체화하는 과정에서, 길이를 알 수 없는 거래 내역 목록을 Lambda 함수의 인자나 Bedrock Agent의 프롬프트로 전달하는 것은 비효율적일 것이라는 결론에 이르렀습니다. 따라서 서버에서 AWS Bedrock API를 호출할 때 Tool 목록과 Tool 호출에 필요한 파라미터를 함께 제시하고, 사용자 요청에 응답하기 위한 적절한 Tool을 응답으로 받아 서버에서 직접 해당 Tool의 핸들러를 실행하는 방식으로 구현했습니다.
거래내역을 기반으로 나의 하루를 담은 이미지 생성하기
나의 하루를 더욱 생생하고 의미 있게 시각화하기 위해서는 거래내역에 담겨 있지 않은 구체적인 요소들을 고려해야 했습니다. 이번 섹션에서는 거래내역을 기반으로 이미지를 생성할 때 어떤 모델을 사용했는지, 그리고 어떤 요소들을 고려하여 프롬프트를 작성했는지 자세히 살펴보겠습니다.
어떤 이미지 생성 모델을 선택할까?
이번 해커톤에서는 Amazon Titan Image Generator, Nova Canvas, Stability AI SDXL 총 3가지 모델을 사용할 수 있었습니다. 그중 저희는 Nova Canvas를 이미지 생성 모델로 선택했습니다.
Nova Canvas를 선택한 가장 큰 이유는 가장 긴 프롬프트를 입력할 수 있었기 때문입니다. Amazon Titan Image Generator G1는 최대 512자, Stability AI SDXL는 최대 77자의 프롬프트틀 입력할 수 있는 반면, Nova Canvas는 최대 1024자의 프롬프트를 입력할 수 있었습니다. 긴 프롬프트 길이 덕분에 원하는 맥락과 세부사항을 더욱 풍부하게 전달할 수 있었고, 기대 이상의 만족스러운 이미지 결과를 얻을 수 있었습니다. 또한, 같은 프롬프트로 세 개의 모델에서 반복적으로 이미지를 생성해 본 결과, 팀원 모두 Nova Canvas의 이미지가 가장 자연스럽고 예쁘다고 평가했습니다.
이미지 생성 아키텍처 소개
사용자에게 의미 있는 이미지를 생성하기 위해서는 거래내역뿐만 아니라 아래와 같이 다양한 요소를 고려해야 합니다.
- 거래 데이터 - 결제처, 거래시간(타임스탬프), 금액, 카테고리
- 사용자가 입력한 추가 정보 - 메모, 함께한 사람, 감정
- 사용자 개인데이터 - 성별, 나이, 선호하는 이미지 스타일
하지만, 위의 요소들을 모두 고려하여 개발자가 직접 프롬프트에 반영하는 방식에는 몇 가지 문제가 있었습니다. 개발자가 사전에 정의한 프롬프트만으로 이미지를 생성하면 이미지의 다양성이 부족해지고, 각 요소를 일일이 조건문으로 처리하는 번거로움도 따랐습니다. 또한 1024자라는 제한된 글자 수 내에서 모든 요소와 조건을 효율적으로 관리하기도 어려웠습니다.
따라서 더 다양한 스토리와 확장성 있는 프롬프트를 위해, 제공받은 데이터와 주어진 조건에 따라 LLM이 자동으로 프롬프트를 만들어주는 ’이미지 프롬프트 생성기‘를 개발했습니다. 이렇게 생성된 프롬프트는 Nova Canvas 모델을 통해 이미지로 변환되고, 유저는 나의 하루를 간편하게 기록할 수 있습니다.
실제 나의 일상처럼 느껴지는 이미지 만들기
단순한 거래 내역만으로는 사용자의 일상을 온전히 담아내기 어려웠습니다. ‘백화점에서 25000원 결제’라는 내역만으로는 쇼핑을 한 건지, 점심을 먹은 건지 파악할 수 없었죠. 제한된 정보로 이미지를 생성할 경우, AI가 마음대로 사용자의 하루를 예측하게 되어, 실제 경험과 괴리감이 큰 결과물이 나오기 마련이었습니다.
이번 섹션에서는 이러한 한계를 극복하고, 사용자의 경험을 생생하게 담아내며 공감되는 이미지를 만들기 위해 어떤 요소들을 고려했는지 하나씩 살펴보겠습니다.
1️⃣ 메모 데이터로 개인화된 이미지 만들기
저희는 ‘어떻게 하면 이미지에 사용자의 일상을 더 생생하게 담아낼 수 있을까?’ 고민 끝에, 사용자가 입력한 메모 데이터를 활용하기로 했습니다. 더불어 누구와 함께했는지, 그리고 당시 느낀 감정은 어땠는지 선택적으로 입력받도록 했습니다.
따라서, 똑같은 ‘백화점’ 결제 내역이더라도, ‘셔츠 구매’라는 메모가 있다면 이를 이미지의 핵심 요소로 판단하여 셔츠를 고르고 있는 모습을 보여주고, ‘영화관’에서 ‘슬픈’ 감정으로 ‘혼자’ 영화를 봤다면, 영화를 보며 눈물을 흘리는 모습을 담아냈습니다.
이렇게 사용자가 직접 남긴 메모를 통해 더 의미 있고 개인화된 이미지를 만들 수 있게 되었습니다.
2️⃣ 거래 시간과 구도로 거래 순간의 분위기 살리기
거래 순간의 분위기를 더욱 현실적으로 표현하기 위해, 저희가 주목한 요소는 거래 시간과 이미지 구도입니다.
거래 시간은 단순한 타임스탬프처럼 보이지만, 여기에는 아침, 저녁이라는 시간대와 계절감을 알 수 있는 날짜 정보들이 모두 담겨있었습니다. 따라서 “거래 시간을 통해 시간대와 계절감을 반영합니다.”라는 간단한 지시 하나로도 이미지의 분위기를 더욱 생동감 있게 바꿀 수 있었습니다. 예를 들어, 4월에는 벚꽃과 따스한 햇살이 가득한 풍경, 12월에는 눈이 내리는 풍경이 표현되었고, 이미지 속 인물의 옷차림도 여름이면 반팔, 겨울이면 코트나 패딩을 입도록 계절에 맞게 바뀌었습니다.
또, 주어진 맥락을 강조하기 위해 카메라 구도도 자연스럽게 조정해 주도록 했습니다. 예를 들어, 슬픈 감정으로 혼자 영화를 보는 상황이라면, 클로즈업으로 주인공의 표정을 강조했고, 친구와의 대화 장면처럼 2명 이상이 함께한 경우 중거리 샷으로 전체적인 분위기를 담아냈습니다.
3️⃣ ‘나’의 일상 기록하기
이미지가 ‘나’의 일상을 담아내는 것이라면, 이미지 속 주인공 역시 ‘나’와 닮아있어야 합니다. 사용자는 30대 남성인데, 생성된 이미지 속 주인공이 20대 여성으로 나온다면 사용자는 이를 자신의 일상으로 받아들이기 어렵겠죠. 이러한 문제를 해결하기 위해, 사용자의 성별과 나이 또한 이미지에 반영했습니다. 또한 한국인 사용자를 대상으로 하는 서비스이므로, 주인공의 국적도 한국인으로 고정했습니다.
4️⃣ 이미지 스타일 지정하기
이미지에 사용자의 취향을 반영할 수 있도록 애니메이션, 수채화, 픽셀 스타일 등 다양한 이미지 스타일을 선택할 수 있는 옵션도 제공했습니다. 픽셀 아트 스타일을 선택한 사용자의 이미지는 8비트 또는 16비트의 귀여운 픽셀 형태로 표현하고, 애니메이션 스타일을 선택하면 밝고 선명한 색상과 과장된 표정을 갖는 이미지를 만들 수 있도록 적절한 프롬프트를 정의해 두었습니다.
5️⃣ Nova canvas의 negative prompt 지정하기
마지막으로, 이미지의 안전성을 위해 폭력적이거나 선정적인 프롬프트는 생성되지 않아야 했습니다.
Nova canvas의 negative prompt는 AI가 이미지를 생성할 때 결과물에 포함하지 않아야 할 요소, 스타일, 또는 테마를 명시적으로 지정하는 기능입니다. 이를 통해 원치 않는 특징(예: 특정 색상, 객체, 분위기 등)을 배제하고 결과물의 방향을 더 세밀하게 제어하여 완성도를 높일 수 있습니다. 저희는 이미지에 글자나 자막, 말풍선이 포함되지 않도록 ‘text’, ‘captions’, ‘speech bubble’ 등의 단어를 지정해 주었습니다.
최종 이미지 생성 프롬프트 예시
이렇게 복합적인 요소들을 고려한 결과, 단순한 거래 내역이 얼마나 풍부한 이미지 프롬프트로 변환되는지 실제 예시를 통해 살펴볼까요?
입력한 데이터
- 거래내역: 스타벅스 -8,000원
- 거래시간: 2025-04-01 08:30:00
- 메모: 커피와 샌드위치
- 함께한 대상: 반려동물
- 감정: 행복
- 유저 정보: 20대 남성, 한국인
- 선호하는 이미지 스타일: 애니메이션
생성된 프롬프트
A cheerful young Korean man sitting at an outdoor Starbucks cafe table on a bright spring morning. He’s smiling happily while holding a sandwich in one hand. His small, cute dog sits beside him on the ground, looking up expectantly. The scene is depicted in a vibrant anime style with exaggerated expressions and bright, vivid colors. Cherry blossom petals float gently in the air. The composition is a medium shot, capturing both the man and his dog, as well as the Starbucks storefront in the background. The man has large expressive eyes and stylized hair typical of anime characters. The sandwich is prominently featured, looking appetizing and detailed. The overall atmosphere is lively and joyful, with other patrons visible in the background enjoying their morning coffee.
생성된 이미지
프롬프트에 작성된 내용대로 ‘젊은 남자가 벚꽃이 흩날리는 아침에 스타벅스 앞에서 샌드위치를 들고 행복한 표정으로 반려동물과 함께 앉아 있는 모습‘의 애니메이션 이미지가 생성되었습니다.
자연어로 거래 내역 질문 검색하기
거래 내역을 들여다보면서 ‘매달 아파트 관리비로 얼마나 나가지?’, ‘이번 달에 커피를 얼마나 마셨지?’, ‘저번 달보다 이번 달에 식비 지출이 더 큰가?’ 한 번쯤 이런 질문들을 떠올려보시지 않았나요? 자연어 거래 내역 검색은 이러한 질문에 대해 실제 데이터 기반으로 의미 있는 답변을 제공할 수 있도록 설계되었습니다.
이번 섹션에서는 어떻게 자연어 형태의 사용자 질문을 해석하고 적합한 분석 도구를 선택해, 응답 결과를 생성하는지 살펴보도록 하겠습니다.
자연어 검색 아키텍처 소개
거래 내역 질문 검색 과정이 어떤 흐름으로 동작하는지 전체적인 아키텍처 구조를 먼저 살펴본 후에 각 단계를 자세히 들여다보겠습니다.
-
자연어 형태의 사용자 질문은 AWS EC2 서버로 전달되어 SQL 쿼리 형태로 변환됩니다.
-
AWS EC2 서버에서 Amazon RDS로 쿼리 요청을 보내 사용자 질문과 연관된 거래 데이터를 조회합니다.
-
AWS Bedrock을 통해 호출되는 Claude 3.5 LLM은 전달받은 정보를 종합적으로 고려해 가장 적합한 분석 도구를 판단하는 역할을 합니다.
단계별 자연어 검색 과정
이제 자연어 검색 과정을 이해하기 쉽게 3단계로 나누어 설명드리겠습니다.
1️⃣ Text2SQL: 자연어를 SQL 쿼리로 변환하기
2️⃣ Tool Selection: 질문에 맞는 분석 도구 고르기
3️⃣ Tool Execution: 분석 도구를 실행하고 콘텐츠로 완성하기
1️⃣ Text2SQL: 자연어를 SQL 쿼리로 변환하기
자연어를 SQL 쿼리로 변환하는 과정은 LangChain 체인과 AWS Bedrock 기반 Claude 3.5 LLM을 활용하여 구성했으며, 세 단계를 거쳐 진행됩니다.
지금부터 월별로 아파트 관리비로 얼마나 나가는지 알려줘
라는 사용자 질문을 가정하고, 각 단계를 자세히 살펴보겠습니다.
1단계: 의도 분류
사용자 질문이 어떤 분석 유형에 해당하는지 판단하는 단계입니다.
분석 유형은 총 7가지(내역, 비교, 추이, 최대, 최소, 합계, 평균)로 정의되어 있으며, 이 범주에 속하지 않는 질문은 ‘그 외’로 분류되어 거래 내역 데이터를 기반으로 답변할 수 없는 질문으로 판단합니다. 의도 분류 전용 체인을 별도로 생성하여 다음 단계의 체인에 분류된 의도 정보를 넘겨줄 수 있도록 구성했습니다.
월별로 아파트 관리비로 얼마나 나가는지 알려줘
는 시간 흐름에 따른 거래 패턴을 묻는 질문이기 때문에 추이로 분류됩니다.
분류 | 설명 |
---|---|
내역 | 특정 조건에 부합하는 거래 목록을 보여달라는 요청 |
비교 | 기간/카테고리/상대방 등 기준을 나눠 거래 내역을 비교하는 요청 |
추이 | 시간 흐름에 따른 거래 변화나 패턴을 알고 싶은 요청 |
최대 | 가장 많이 지출한 항목이나 거래를 찾는 요청 |
최소 | 가장 적게 지출한 항목이나 거래를 찾는 요청 |
합계 | 거래 금액의 총합을 구하는 요청 |
평균 | 평균 지출을 계산하는 요청 |
그 외 | 거래 데이터로는 응답 불가능한 모든 요청 |
2단계: Entity 추출
분석 유형에 기반해 질문에서 의미 있는 정보(거래유형, 카테고리, 기간, 키워드 등)를 추출하는 단계입니다.
이때 추출한 정보는 SQL 쿼리 생성 단계에서 WHERE 조건문의 재료로 사용됩니다. Entity 추출 체인을 통해 수행되며, 사전에 정의된 프롬프트 지침에 따라 JSON 형태의 결괏값을 반환합니다.
{
"type": "payment",
"category": "공과금/관리비",
"time_period": "최근 3개월",
"keywords": "아파트 관리비"
}
3단계: SQL 쿼리 생성 및 검증
앞서 분석한 의도와 Entity 정보를 기반으로 SQL 쿼리를 생성 및 검증하는 단계입니다. 이 과정은 두 개의 독립적인 체인으로 구성됩니다:
- sql_generation_chain: LLM에게 현재 날짜, 데이터베이스 스키마, 분석된 질문 의도, 주요 Entity, 유사 질문 예시를 함께 제공하여 SQL 쿼리를 생성하는 체인
- sql_validation_chain: 생성된 SQL 쿼리를 다시 LLM에 전달하여 문법 오류를 검토하고 구조적 문제를 최소한의 수정으로 보완하는 체인
각 체인은 명확한 프롬프트 설계 하에 구성되며, 최종적으로 ‘SELECT *’ 구조를 유지하면서 질문 의도와 주요 Entity 정보를 반영한 필터 조건이 포함된 SQL 쿼리가 반환됩니다.
SELECT *
FROM transactions
WHERE user_id = 3
AND type = 'payment'
AND category = '공과금/관리비'
AND transaction_at >= date('2025-05-01', '-3 months')
AND (title LIKE '%아파트%' OR title LIKE '%관리비%')
ORDER BY transaction_at DESC
2️⃣ Tool Selection: 질문에 맞는 분석 도구 고르기
생성된 SQL 쿼리로 거래 내역 데이터를 조회하고 나면, 또다시 Claude 3.5 LLM이 자연어 형태의 사용자 질문을 해석하여 어떤 분석 도구를 사용할지, 각 분석 도구를 어떻게 호출할지 판단합니다.
분석 도구 사용을 위한 사전 정의
LLM이 자신이 어떤 분석 도구를 사용할 수 있는지 어떻게 알 수 있을까요?
분석 도구 판단은 단순 추론이 아니기 때문에 LLM에게 사용할 수 있는 도구의 종류와 사용법을 사전에 알려주는 과정이 필요합니다. tools 설정과 함께 LLM을 호출하면, LLM에게 분석 도구에 대한 정보를 전달해줄 수 있습니다.
request_body = {
"anthropic_version": "bedrock-2023-05-31",
"system": self._get_system_prompt(intent, sql_query, entities),
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": user_prompt
}
]
}
],
# ... 중략 ...
"tools": tools_config # 분석 도구 정보 전달
}
# Claude 3.5 LLM 호출
response = self.bedrock_client.invoke_model(
modelId=self.model_id,
body=json.dumps(request_body),
contentType="application/json",
accept="application/json"
)
tools_config는 각 분석 도구에 대한 이름 (name), 설명 (description), JSON Schema 기반의 입력 인자 명세 (input_schema) 정보를 포함한 일종의 도구 설명서 역할을 합니다.
# tools_config로 전달되는 분석 도구 목록 정보
tools_config = [
{
"name": "display_transactions",
"description": "Display lists of transaction data in a readable way",
"input_schema": {
"type": "object",
"properties": {
"filter": {
"type": "object",
"description": "Filter to apply to transactions. When filtering by date, make sure to use the correct year format (YYYY-MM-DD) and always ensure dates are in the correct chronological order."
}
},
"required": ["filter"]
},
# ...중략...
]
tools 설정을 통해 LLM은 질문의 의도에 맞는 분석 도구를 능동적으로 선택하고, 필요한 인자를 구성하는 작업을 수행할 수 있습니다.
Few-Shot 예시의 역할과 효과
LLM이 분석 유형에 맞는 도구를 더 잘 선택하고, 필요한 인자를 더 잘 구성할 수 있도록 다양한 Few-Shot 예시들을 활용하기도 했습니다.
Few-Shot은 사전 학습된 언어 모델에게 특정 작업을 유도하기 위해, 입력과 출력의 예시 몇 가지(few-shot examples)를 프롬프트에 함께 포함하는 방법입니다.
few_shot_examples = """
# ... 중략 ...
Example 5:
User query: "카페에서 얼마나 썼어?"
Thought process: User wants to know total spending on cafes without specifying a time period. This is a sum intent focused on a category.
Intent: "합계"
Tools: [
{"name": "calculate_sum", "parameters": {
"filter": {"label": "카페 지출", "category": "커피/디저트"}
}},
{"name": "display_transactions", "parameters": {
"filter": {"label": "카페 지출", "category": "커피/디저트"}
}}
]
# ... 중략 ...
"""
실제로 Few-Shot 예시들을 사전에 제공함으로써 LLM의 분석 도구 선택 오류가 줄어들고, 복잡한 요청 (ex. 비교 + 시각화 + 상세 보기)의 경우에도 분석 도구들을 올바르게 조합하여 목적에 맞는 분석 흐름을 생성할 수 있었습니다.
LLM의 Chain-of-Thought 방식의 분석 흐름
앞서 설명한 분석 도구에 대한 사전 정의와 Few-Shot 예시는 LLM이 복잡한 자연어 질문을 해석하고 적절한 분석 도구를 선택하는데 도움이 되는 핵심 요소입니다.
위의 요소를 기반으로 월별로 아파트 관리비로 얼마나 나가는지 알려줘
질문에 LLM이 Chain-of-Thought 방식으로 사고를 전개하며 계획을 수립하는 분석 흐름을 살펴보겠습니다.
🤖 아파트 관리비는 일반적으로 ‘공과금/관리비’ 카테고리에 포함돼. 그리고 특정 월을 지칭하지 않았기 때문에 최근 3개월을 기준으로 분석해야겠어.
➡️ Text2SQL 단계에서 판단한 질문의 의도, 관련된 카테고리, 시간 정보를 활용합니다. 추이 분석 시 기본적으로 최근 3개월 간의 데이터를 활용하도록 지정했습니다.
🤖 사용자가 원하는 건 월별 변화 추이니까, 시간의 흐름을 시각화할 수 있는 분석 도구가 필요해. 선형 그래프를 생성하는 analyze_trend 가 딱 맞겠어. 월별 변화만 보여주는 것보다, 각 월의 구체적인 지출 내역도 함께 보여주면 사용자가 더 쉽게 이해할 거야.
➡️ 월별 아파트 관리비 지출 추이를 시각화하고 인사이트를 제공하기 위해 analyze_trend 분석 도구와 각 월의 상세 거래 내역을 보여주는 display_transactions 분석 도구도 선택합니다.
🤖 이제 각 분석 도구에 맞는 입력값을 구성해야 해. 월별 비교를 해야 하니까, 월별로 필터를 나눠서 만들어야지. 각각의 필터에는 ‘기간’과 ‘카테고리’가 모두 포함되어야 해
➡️ 생성된 필터는 analyze_trend 와 display_transactions 분석 도구에 적용되어 각각 분석 목적에 맞는 데이터 추출을 가능하게 합니다.
3️⃣ Tool Execution: 분석 도구를 실행하고 콘텐츠로 완성하기
Claude 3.5 LLM은 분석 도구를 실행하기 위한 계획까지만 세워줄 뿐, 실제 함수 실행까지 대신해주지 않습니다.
따라서 분석 도구 별로 실행해야 하는 함수를 사전에 맵핑해 두고, LLM이 전해준 분석 도구 정보를 바탕으로 함수를 실행해 결과를 생성합니다.
분석 결과는 다음과 같이 하나의 분석 도구에 대한 JSON 응답 형태(도구 이름, 실행 성공 여부, 결과 데이터, 입력 파라미터)로 이루어지고, 여러 개의 분석 도구가 사용된 경우에는 배열 형태로 반환됩니다.
{
"tool": "analyze_trend",
"success": true,
"result": { /* 분석 결과 데이터 */ },
"parameters": {
"filters": [
{
"label": "3월 아파트 관리비",
"dateRange": {
"start": "2025-03-01",
"end": "2025-03-31"
},
"category": "공과금/관리비"
},
# ... 중략 ...
]
}
}
분석 결과는 어떻게 화면에 표현되어 사용자에게 전달될까요? 프론트엔드에서는 각 분석 도구의 응답 결과를 하나의 독립적인 UI 컴포넌트로 구성해, 사용자가 분석 결과를 직관적으로 이해할 수 있도록 했습니다.
월별로 아파트 관리비로 얼마나 나가는지 알려줘
라고 물어본 사용자는 최종적으로 다음과 같은 응답을 받게 됩니다.
마치며
이번 해커톤은 서로 다른 팀에서 각자의 업무에 매진하던 저희 팀원들이 ‘모즈(MOZ)‘라는 이름으로 하나 되어 뭉칠 수 있었던 소중한 기회였습니다. 함께 밤샘 작업을 하고 아이디어를 나누며 서비스를 만들어가는 과정은, 해커톤이 끝나는 것이 아쉬울 정도로 뜻깊고 즐거운 경험이었습니다.
일상적인 업무에 익숙해져 매너리즘에 빠져있던 시점에, 이번 해커톤은 저희가 잊고 지냈던 순수한 열정을 다시금 일깨워주었습니다. ‘아, 나 개발 좋아했지? 이래서 개발 시작했지?’, ‘같은 목표를 가진 사람들과 함께라면 뭐든 해낼 수 있구나!’라는 대화를 나눌 정도로, 모두가 초심으로 돌아가 새로운 동기부여를 얻는 값진 시간이었습니다.
이번 해커톤은 저희에게 많은 배움과 성장을 안겨주었습니다. AWS Bedrock을 통해 강력한 LLM의 잠재력을 직접 경험하고 활용해 볼 수 있었던 점이 인상 깊었습니다. Nova Canvas를 활용한 이미지 생성 과정에서는 단순히 기능을 구현하는 것을 넘어, 어떻게 하면 기술을 통해 사용자의 감정과 경험을 더 풍부하게 만들 수 있을지 고민하는 계기가 되었습니다. 또한, 자연어를 이해하여 SQL 쿼리를 생성하고, 복잡한 사용자 질문의 의도를 파악하여 필요한 분석 도구(Tool)를 스스로 선택하여 원하는 결과물을 도출해 내는 과정에서 큰 성취감을 느꼈습니다.
물론, 짧은 시간 안에 이 모든 것을 기획하고 구현하는 과정은 순탄하지만은 않았습니다. 수많은 오류와 씨름하고, 잠을 잊은 채 키보드를 두드리며 ‘어떻게 해야 할까?’ 하는 불안감에 휩싸이기도 했습니다. 하지만 팀원들과 머리를 맞대고 서로를 격려하며 문제를 하나씩 해결하고, 마침내 기획했던 기능이 완성되었을 때 환희와 안도감은 그간의 고생을 눈 녹듯 사라지게 하는, 무엇과도 바꿀 수 없는 소중한 경험이었습니다.
해커톤 부스를 운영하며 만났던 많은 분들께서 ‘실제로 이런 기능이 제공된다면 정말 좋겠다’, ‘저 당장이라도 이 서비스를 사용하고 싶어요!’, ‘이 서비스 있다면 왜 안써?‘와 같은 뜨거운 반응을 보여주셨습니다. 이러한 긍정적인 피드백은 저희에게 큰 힘이 되었으며, 언젠가 카카오페이에서 저희가 만든 서비스가 제공되는 날이 오길 기다리며 글을 마치도록 하겠습니다.
지금까지 밝은 에너지 가디, 진심 가득한 칭찬 라즈, 럭키토템 루디, 빠른 뚝딱맨 레츠, 정리왕 마쉬였습니다.
긴 글 읽어주셔서 정말 감사합니다. 🙇🏻♀️🙇🏻♂️