LLM을 이용한 여행 컨시어지 만들기

2025. 3. 10.Tech

 

안녕하세요.

케이뱅크 데이터인텔리전스팀에서 Data Scientist로 일하고 있는 조용걸입니다.

 

케이뱅크에는 사내 다양한 동아리들이 있는데요. 

저는 Edit이라는 IT 동아리에서 다양한 부서 사람들과 정보도 공유하고 정규 업무와는 별개로

맘에 맞는 사람들끼리 업무 외적으로 사이드 프로젝트 또는 세미나를 진행하고 있습니다.

 

작년에(2024년 초...) Edit을 통해 호기심 차원에서 AI를 활용해서 여행 컨시어지를 만들어 보면 재밌겠다는 의뢰가 들어왔는데요.

동아리원 분들과 함께 사이드 프로젝트로 여행 컨시어지를 개발한 경험을 공유하고자 합니다.

 

(개발에 도움주신 고객인증팀 진보성님, 뱅킹서비스개발팀 김채원, 홍서연님 감사합니다🙇‍♂️)

 

여행 컨시어지

 

여행 컨시어지

 

여행 컨시어지란?

 

컨시어지(Concierge)는 프랑스에서 유래한 용어로 다양한 서비스 산업에서 고객의 요구를 해결하고 편의를 제공하는 전문가를 의미합니다. 여행이라는 접두사 붙은 여행 컨시어지는 여행객의 개별적인 취향과 요구를 반영하여 맞춤형 여행 계획을 수립하는 전문가라고 생각하면 될 것 같습니다.

 

은행과 여행

 

해외여행

 

코로나를 지나고 국내 또는 해외 여행에 대한 여행객이 폭발적으로 증가해서 작년에 해외 관광 출국자 수는 2,825만명으로 집계되었습니다. 내국인의 56% 정도가 지난해 해외여행을 다녀왔는데요. 이에 따라 시중은행들도 해외여행과 관련된 상품을 출시하였습니다. 환율 100% 우대 및 ATM 인출 수수료 면제와 같은 체크카드와 신용카드가 대히트를 쳤고, 뿐만 아니라 여행자 보험 그리고 여행 자금을 모으기 위한 예/적금 등 새로운 상품들이 많이 출시가 되었죠.

 

케이뱅크에도 여행과 연관이 있는 상품들이 여럿 존재하는데요.

 

- GLN해외 결제, 환전, 트립닷컴 할인쿠폰 서비스

- 챌린지박스 (여행을 목표로 도전하는 적금 상품)

- 여행자 보험(과거에...)

 

여행과 연관된 케이뱅크의 다양한 상품/서비스들 (2024 ver...)

 

사용자에게 맞춤형 AI 여행 서비스를 제공하면서 한편으로는, 성공적인 여행 자금 마련 또는 서비스를 제안하여 고객의 앱사용 유도를 증진시켜보자! 라는 컨셉으로 여행 컨시어지를 만들어 보았습니다.

 

LLM API와 블로그

 

LLM API

 

Web에서 사용하는 GPT는 사용자 질의에 대해 웹 검색 익스텐션 기능을 제공합니다. 모델에만 의존(할루시네이션)하는 것이 아니라 웹에서 검색한 내용을 토대로 답변을 만들어내기 때문에 더 정확하고 최신 트렌드를 반영하게 됩니다. 하지만, API를 통해 gpt를 사용하게 되면 웹 검색 기능을 제공하지 않기 때문에 직접 해당 기능을 구현해야 하는데요.

 

Langchain을 통해 쉽게 사용할 수 있는 웹 검색 Tool로서는 Google Search, Bing Search, DuckDuckGo Search 등 여러가지 도구들이 있습니다. 해당 Tool을 사용하면 손쉽게 웹에서 정보를 가져올 수 있지만, 짧은 스니펫(Summary) 내용만을 제공하고 이를 통해 답변을 생성하기 때문에 답변의 품질이 떨어질 수 있습니다.

 

블로그

 

여행지에 대한 정보를 알아볼 때 다양한 SNS를 활용하는데 특히 블로그는 여러 시각적인 정보들(사진, 동영상) 뿐만 아니라 여행 계획을 어떻게 짰었고 어떤 음식을 먹었는지 등 일기처럼 상세하게 정보를 제공합니다. 그래서 많은 사람들은 블로그를 통해 사전에 내가 가고자 하는 여행지를 검색하고 계획을 짤 때 참고하게 됩니다.

 

그래서 이번 프로젝트에서는 LLM API와 함께 웹 정보는 블로그 정보를 함께 활용하여 여행 계획을 세워주는 컨시어지를 개발하게 되었습니다.

Naver 블로그

 

 개발 프로세스

 

여행 컨시어지 프로세스

 

개발 프로세스는 총 4단계로 구성되어 있습니다.

 

1. 검색

 

여행 계획을 짤 때 우린 주로 어떤 걸 고려할까요? 주로 여행지의 음식점, 관광지, 여행 및 교통숙소를 많이 검색하게 됩니다.

 

아래는 사용자가 가고 싶은 여행지, 음식, 숙소, 활동들을 Input으로 받아 네이버 검색 API에 검색어로 만드는 과정입니다.

 

검색어 1 (음식점) : {여행지} {음식} 맛집

검색어 2 (활동) : {여행지} {선호하는 활동}

검색어 3(여행, 교통): {여행지} 여행 교통

검색어 4 (숙소) : {여행지} {숙소 종류} BEST

 

블로그에서 해당 정보를 얻기 위해, 이 검색어를 네이버 개발자센터에서 제공하는 서비스 API를 사용하여 블로그 URL을 수집합니다.

 

검색어

 

2. 웹 크롤링

 

Naver에서 제공하는 웹 서비스들은 대개 iframe으로 구성되어있습니다. 다른 일반적인 웹 사이트 크롤링처럼 BeautifulSoup와 같은 패키지로 내용을 가져오게 되면 원하는 결과가 나오지 않습니다. 따라서, Selenium을 활용해서 동적으로 파싱을 해야 블로그 안에 내용들을 온전히 가져올 수 있습니다.

 

위 검색어별로 검색 API 결과로 나오는 블로그 최대 5개 URL을 가져온 후, 매 실행 시 같은 블로그의 내용만 참조하지 않게 섞어 줍니다.

 

Blog 섞어주기

# only naver blog
results = [result for result in results if self._check_naver_url(result['link'])]
random.shuffle(results) # 동일한 결과가 안나오게 random하게 shuffle

 

 

위에서 가져온 블로그 URL에 대해 Selenium을 통해 블로그 내용들을 파싱 합니다.

 

프로세스 예시

# ----------
# Naver
with st.spinner('Naver Blog를 검색하고 있어요 ...'):

    query_types = ["food", "activity", "course", "accommodation"]
    search_quries = []

    for query_type in query_types:
        search_query = naver_crawler.generate_search_query(user_input, query_type)
        search_quries.append(search_query)

    items = naver_crawler.get_blog_infos(query_types, search_quries)

print(items)

with st.spinner('Naver Blog 정보를 가져오고 있어요 ...'):
    items = naver_crawler.get_contents(items)
# ----------

 

Naver 크롤러

 

 

 

 

3. 내용 요약

 

웹 크롤링으로 수집한 4개의 블로그(맛집, 선호 활동, 교통, 숙소) 내용 각각 들은 내용들이 굉장히 많습니다.

최종 컨시어지 내용을 생성하기 위해 각 블로그의 내용들을 LLM을 이용해서 최대 500글자 이내로 요약합니다.

 

요약 Prompt

 

"BLOG_SUMMARY": (
    "# 명령문\n"
    "당신은 여행 블로그 요약 GPT로서 여행계획플래너가 여행계획을 세울 때 참고할 수 있는 지식 소스를 추출하는 역할을 맡았습니다.\n"
    "요약은 주요 관광지, 문화, 음식, 여행 팁을 포함해야 하며, 음식점, 호텔, 관광지 이름이 반드시 들어가야 합니다.\n"
    "여행 소감과 개인적인 이야기도 일부 포함시키세요.\n"
    "정보는 지명/상호명 및 설명, 여행 팁, 가격 정보 순으로 우선순위를 두고, 가장 중요한 정보부터 시작해주세요.\n"
    "블로그 작성자 정보와 광고성 내용은 제외하고, 글자 수 절약을 위해 불필요한 조사는 최소화하며, 명사형 전성어미 사용 및 짧은 단어 사용에 유의해주세요.\n"
    "쓸모있는 정보란 여행지 현지의 교통, 통신, 입국심사, 날씨 등의 팁 또는 여행 코스 설계, 여행 경비 추정와 관련되어 여행계획플래너가 사용할 수 있는 정보를 의미합니다.\n"
    "당신이 판단해서 쓸모있는 정보가 아니면 요약에 포함시키면 절대로 안됩니다.\n\n"

    "# 출력 조건\n"
    "여행 블로그 본문에서 핵심 정보를 500자 이내로 요약 해주세요.\n"
    "생성 결과는 반드시 아래 형식을 따라주세요.\n"
    "내용:\n\n"

    "# 여행 블로그 본문\n"
    "{blog_content}"
)

 

 

4. 답변생성

 

마지막으로, 요약된 4개의 블로그 정보를 사용해서 사용자 맞춤형 여행 컨시어지 답변을 생성해 제공합니다.

 

여행 컨시어지 데모

 

 

 비동기 프로그래밍

 

비동기 프로그래밍

 

 

만약 해당 프로젝트를 동기식으로 프로그래밍 했다면 어땠을까요?

 

1. 만들어진 검색어 4개에 대해서 Naver API를 순차적으로 실행합니다.

2. 웹 파싱한 Blog 내용에 대해 요약을 위한 LLM API를 순차적으로 실행합니다.

 

Naver API / LLM API는 순차적으로 호출할 필요가 없습니다.

각 검색들 / 요약해야 할 블로그들끼리 서로 선후 관계가 존재하는 종속성이 필요 없는 프로세스이기 때문이죠.

위 내용을 동기식이 아닌 비동기식으로 프로그래밍한다면 위 그림처럼 시간을 획기적으로 줄일 수 있습니다.

 

비동기 프로그래밍 예시

    def summarize_blogs(self, items):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop = asyncio.get_event_loop()
        items = loop.run_until_complete(self._summarize_blogs(items))
        return items

    async def _summarize_content(self, item):

        content = item['content']
        summary = self.summary_prompt.format(blog_content=content)

        summary = await self.async_client.chat.completions.create(
            # gpt-4-0125-preview
            model="gpt-4o",
            messages=[
                {
                    "role": "user",
                    "content": summary
                }
            ]
        )

        item['summary'] = summary.choices[0].message.content

        return item

    async def _summarize_blogs(self, items):
        futures = [asyncio.ensure_future(self._summarize_content(item)) for item in items]
        items = await asyncio.gather(*futures)
        return items

 

(Selenium을 병렬로 실행해서 시간을 단축하는 방법도 있겠지만, 이번 프로젝트에서는 비동기 프로그래밍만 진행하였습니다.)

 

 

 마치며

 

여행 컨시어지라는 서비스를 통해 은행을 사용하는 고객들에게 편의성 서비스를(맞춤형 여행 계획) 제공하고

여행을 위한 목표(여행 자금 마련, 보험, 해외 환전 서비스 등)를 지원하기 위해 자사 상품/서비스를 연결 해보자!

라는게 이번 프로젝트에 목표 였습니다.

 

프로젝트를 진행한지 1년이 지난 지금 LLM 실제로 서비스에 적용되기도 하였고 (AI챌린지, AI 신년인사 등) 다양한 아이디어를 손쉽게 개발할 수 있는 패키지, 도구들이 다양하게 나오는 것 같습니다.

 

팀 내에서 업무만 진행하다보면 현재 닥친 문제를 해결하기 위한 생각만 하게되는데,

다양한 팀 구성원들끼리 모여서 가볍게 아이디어를 내보고 사이드 프로젝트를 진행하는 것도

머리를 환기시킬 수 있는 좋은 활동인 것 같습니다.

 

해당 프로젝트를 지원해준 Edit 동아리원 분들께 감사함을 전합니다.

 

감사합니다.

 

본 프로젝트는 사내 동아리원들과 함께 진행한 개별 사이드 프로젝트로, 사용된 Naver 블로그 크롤링 및 케이뱅크 상품/서비스와의 연계는 정규 업무와는 무관함을 알려드립니다.