현재 재직중인 회사에서 사내 서비스를 개선하는 아이디어를 만들어 볼 수 있는 좋은 기회를 얻게 되었습니다. 컬리의 리뷰 서비스를 좀 더 고도화 해보았고 돈 걱정 없이 AI 기술을 적극 활용해 볼 수 있는 아주 좋은 기회였습니다.
컬리의 리뷰는 아주 많은 데이터가 있지만 원하는 리뷰를 찾기에는 아직 어렵다고 느껴졌습니다. 타 서비스에서는 리뷰를 작성할때마다 어떤 부분이 좋았는지 강제로 선택하게 하여 요약된 결과를 제공하거나, 이미 있는 리뷰의 키워드들을 카운팅해서 노출해주어 어떤 리뷰가 주로 작성되어있는지 다 읽어보지 않고도 파악할 수 있게 해줍니다.
그래서 리뷰에서 어떤 키워드가 많이 나오는지 주요키워드로 보여주고, 언급된 키워드만으로 조회해 쉽게 접근할 수 있게 하여 '사용자가 원하는 리뷰에 빠르게 도달시키자' 라는 목표를 세웠습니다.
태그 클라우드(키워드 리뷰) 서비스 아키텍처
다음 그림은 해커톤 기간 총 2.5일간 구현한 서비스 아키텍처 입니다.
실제 컬리 프론트 화면을 구현하지 않고도, 실제 컬리 프론트 위에서 구동하는 것처럼 보이기 위해 클라이언트를 크롬 익스텐션을 이용해 구현하였습니다.
1. 워드 클라우드 데이터 구축
사용자가 제품의 리뷰를 한 눈에, 더 쉽게 파악하기 위해서 다음 UI를 구성하는 것을 목표로 잡았습니다.
키워드 개수를 카운팅 하기 위해서 리뷰에 등장한 키워드들을 추출하고 개수를 세어야 합니다.
이를 구현하기 위해서 워드클라우드를 구축하기로 결정하였습니다.
워드클라우드란?
LLM (GPT api) 을 통한 각 리뷰 키워드 추출
리뷰를 키워드로 바꾸어 워드클라우드로 구축해야합니다. 실제 리뷰 내용에는 해당 상품을 특정하는 정보와 관련없는 내용(ex. 합니다, 써보다, 좋아요, 이용하다, 구입하다 등) 이 많이 포함되어있습니다. 이 내용들을 모두 포함하여 워드클라우드로 구축하면 실제 상품의 사용기를 특정하는 내용보다는 쓸모없는 내용들로 워드클라우드 데이터가 채워지게 됩니다. 양질의 워드클라우드를 구축하기 위해선 각 리뷰에서 사용자가 느끼는 감정이나 특징, 혹은 제품의 특징이 담긴 키워드를 추출해내야 합니다. 수십만 건의 리뷰데이터에서 사람이 하나씩 추출해낼 순 없으므로 LLM을 이용합니다.
리뷰 추출에 이용한 프롬프트
프롬프트의 효율과 정확성을 올리기 위하여 다음 4단계를 적용하였습니다.
1. 역할을 부여하고,
2. 지침을 정확히 지시하며
3. 키워드 추출에 대한 기준을 명시하고
4. 응답형식과 예시를 알려줍니다. (Few Shot 적용)
system_msg = """너는 리뷰를 읽고 키워드를 추출해주는 에이전트야.
# 지침
1. 입력으로 여러 개의 리뷰가 주어질 거야. 각 리뷰는 번호가 매겨져 있어.
2. 각 리뷰마다 키워드를 추출해줘.
3. 키워드는 한 단어로만 표현돼.
# 키워드 추출 기준
- 포함해야할 키워드:
* 리뷰에 직접 언급된 내용 (예: 촉촉함, 발색력, 광택감)
* 사용자가 느끼는 감정이나 특징 (예: 만족도, 가성비)
* 제품에 대한 특징 (예: 지속력, 향기)
- 포함하지 말아야할 키워드:
* 고유 명사 (예: 브랜드명, 제품명)
* 제품 구성 (예: 세트, 패키지)
* 단순히 '좋다', '별로' 같은 추상적인 키워드
# 응답 형식
- 반드시 다음과 같은 JSON 형식으로 반환해야 함:
{
"1": "키워드1,키워드2,키워드3",
"2": "키워드1,키워드2,키워드3"
}
- 각 키워드는 쉼표(,)로 구분
- 키워드가 없는 경우 빈 문자열("") 반환
- 코드 블록(```)이나 다른 마크다운 형식을 사용하지 말 것
# 예시
입력:
1. 색상이 너무 예쁘고 발색도 좋아요
2. 배송이 빨라서 좋네요
3. 가격이 비싸서 망설였는데 품질이 좋네요
출력:
{
"1": "예쁨,발색력",
"2": "빠른배송",
"3": "고가,품질"
}"""
Few shot
LLM 의 응답 성능을 더 높이기 위해 Few Shot을 적용합니다.
적용된 부분
"""
... (생략)
# 예시
입력:
1. 색상이 너무 예쁘고 발색도 좋아요
2. 배송이 빨라서 좋네요
3. 가격이 비싸서 망설였는데 품질이 좋네요
출력:
{
"1": "예쁨,발색력",
"2": "빠른배송",
"3": "고가,품질"
}"""
Batch Request
서비스 개발시 사용한 Azure OpenAI API 에는 분당 API 요청 개수가 정해져 있었습니다. 키워드를 추출해야하는 리뷰의 수가 수십만 건이라면 제한되어있는 요청의 수로 키워드를 추출하기 위해 많은 시간이 소요되어야하는 상황입니다. 그래서 API 요청 한번에 1개의 리뷰를 처리하는 것이 아닌, 50개의 리뷰씩 리스트 형식으로 응답을 받도록 구현하였습니다.
"""
... (생략)
# 응답 형식
- 반드시 다음과 같은 JSON 형식으로 반환해야 함:
{
"1": "키워드1,키워드2,키워드3",
"2": "키워드1,키워드2,키워드3"
}
...
# 예시
입력:
1. 색상이 너무 예쁘고 발색도 좋아요
2. 배송이 빨라서 좋네요
3. 가격이 비싸서 망설였는데 품질이 좋네요
출력:
{
"1": "예쁨,발색력",
"2": "빠른배송",
"3": "고가,품질"
}"""
비동기 동시 요청
분당 요청 개수가 정해져있기 때문에 최대한으로 이용하기 위하여 비동기로 동시요청을 하였습니다.
(넣을지 말지 고민)
워크클라우드 생성 및 LLM 을 이용한 보정
리뷰의 키워드가 다 추출되고나서, 이제 상품별로 모든 키워드를 모아 워드클라우드를 구축하였습니다. 하지만 리뷰 추출 단계에서 LLM 추출한 키워드에서도 약간의 보정이 필요하였습니다. '가격이 싼, 가성비, 저렴' 같은 키워드는 사실 사용자가 보기엔 같은 의미이기때문에 같은 키워드로 카운팅 되어합니다. 이런 비슷한 의미가 키워드가 여러개로 분산되어있으면, 상위 5개의 키워드만 보여준다고 했을때 사용자가 볼 수 있는 키워드 종류가 적어집니다.
ex. 상위 3개의 키워드가 (가격이싼, 가성비, 저렴) 인 것 보다는, (가성비, 촉촉한, 향기로운) 같이 좀 더 다양한 키워드가 있다면 사용자 입장에서 제품을 파악하기가 쉽습니다.
프롬프트
system_prompt = """
당신은 word_cloud 데이터를 읽고 비슷한 의미를 가진 word 끼리 합치는 전문가 입니다.
요청 예시) 유사한 의미를 가진 단어들을 하나로 합치고, count를 합산한 뒤 percentage를 다시 계산해주세요.
입력 JSON 예시:
{
"words": [
{
"word": "가격이 싼",
"count": 3,
"percentage": 0.2
},
{
"word": "저렴",
"count": 3,
"percentage": 0.2
}
]
}
응답은 반드시 다음 JSON 형식으로 작성해주세요:
{
"merged_words": [
{
"word": "가성비",
"count": 6,
"percentage": 0.4
}
]
}
비슷한 의미를 가진 단어들을 하나로 합치고, count는 합산하고, percentage도 다시 계산해주세요.
"""
워드 클라우드 구축 결과
워드 클라우드가 구축되었습니다.
그런데 사실은 사용자에게 제공될 정보는 워드클라우드 이미지가 아닌, 이미지를 만들기 위해 생성된 '데이터' 입니다.
여기서 한번 더 LLM 보정 과정을 거치면,
system_prompt = """
당신은 단어를 적절한 형용사로 변환하는 전문가입니다.
주어진 단어들을 해당 상품의 특성을 잘 나타내는 긍정적인 형용사로 변환해주세요.
형용사로 변환하기 어려운 경우 '변환불가'를 반환하세요. 각 단어에 대해 '원본단어:변환결과' 형식으로 응답해주세요.
'광택' 이라면 '광택이 있는' 같이 해당 단어를 포함하여 형용사로 변환해주면 됩니다.
예시 단어들:
{
"광택": "광택이 있는",
"발색": "발색력이 뛰어난",
"가격": "가격이 착한"
}
JSON 응답 예시:
{
"원본단어1": "변환결과1",
"원본단어2": "변환결과2",
"원본단어3": "변환결과3"
}
"""
주요 키워드 데이터를 제공할 수 있게 됩니다.
2. RAG 구축 - Search AI
이제 해시 태그로 표시된 키워드를 클릭하면 관련된 리뷰만 보이도록 구현하기 위해 Search AI를 구축해야합니다.
Azure AI Search
https://learn.microsoft.com/ko-kr/azure/search/search-what-is-azure-search
AI Search 는 한마디로 '자연어로' '질의'가 가능한 검색 서비스 입니다.
일단 LLM(gpt) 에게 자연어로 컬리의 리뷰 데이터를 물어본다면, 정확히 답할 수 없습니다. GPT는 컬리의 리뷰 데이터를 가지고 있지 않기 때문입니다. 반대로, 컬리의 리뷰데이터는 '자연어로' 질의할 수 없습니다. DB의 데이터를 검색하기 위해선 SQL문을 작성해야합니다. AI Search 는 이 두 가지 방법을 합쳐서 '자연어로' 우리 데이터에 '질의'할 수 있게 해주는 기술 입니다.
자연어로 질의할 수 있게 된다면, 많은 가능성이 열립니다. 예를들어 "가성비와 관련된 리뷰를 정성스러운 순으로 5개 뽑아줘." 같은 자연어로 질의가 가능해 집니다. 이 질문을 SQL로는 구현해낼 수 없습니다. SQL로 '정성스러운' 이라는 추상적인 기준을 정할 수 없고 '~와 관련된' 같은 의미를 담을 수 없습니다. 하지만 LLM 모델은 이런 추상적인 의미를 이해할 수 있기 때문에 가능합니다.
텍스트 임베딩 및 벡터화
우리의 목적은 AI Search 에게 자연어로 묻고(keyword: "가성비가 있는" 와 관련된 내용을 찾아줘.
) 원하는 상품으로 데이터의 개수를 지정해 질의하는 것입니다. 자연어로 질의하기 위해선 먼저, 데이터를 임베딩하여 '벡터화'를 해야합니다.
텍스트 임베딩이란,
- 임베딩은 고차원 공간 상의 특정 표현(Representation)을 의미합니다.
- 텍스트, 이미지, 오디오 등 비정형 데이터를 고정 길이(예: 768, 1024 차원 등) 벡터로 변환합니다.
- 임베딩은 의미나 맥락이 비슷한 데이터가 벡터 공간 상에서도 유사한 위치에 놓이도록 학습됩니다.
컬리의 리뷰 데이터 (Raw Data)를 전처리 과정을 거치고, 텍스트 임베딩 모델을 통해 데이터의 '특징'을 추출합니다. 딥러닝 임베딩 모델이 리뷰 데이터가 담고있는 중요한 의미나 패턴, 구조를 벡터 공간에 압축하여 표현합니다. '벡터화된 숫자값'으로 표현하면 이를 활용해 의미 기반의 검색이 가능해집니다.
┌───────────────────────────┐
│ 1) Raw Data │
│ (텍스트, 이미지, 오디오) │
└───────────────────────────┘
│
│ (전처리: 토큰화, 정규화 등)
▼
┌───────────────────────────┐
│ 2) Preprocessing │
│ (필요 없는 기호 제거, │
│ 텍스트 정규화 등) │
└───────────────────────────┘
│
│ (임베딩 모델에 입력)
▼
┌───────────────────────────┐
│ 3) Embedding Model │
│ (text-embedding-ada-003) │
└───────────────────────────┘
│
│ (임베딩 모델을 통해 특징 추출)
▼
┌───────────────────────────┐
│ 4) N-Dimensional Vector │
│ (3072 차원에 표현) │
└───────────────────────────┘
벡터 공간에 텍스트를 표현하게 되면 컴퓨터는 서로 다른 텍스트들에서 임베딩 간의 거리를 계산하여 이들간의 관계를 이해합니다.
벡터화된 공간에선 단순히 키워드 일치가 아니라 '의미 기반'으로 검색할 수 있게 됩니다. (king - queen)간의 관계가 벡터 공간 안에서 표현되는 방식은 (man - woman) 같이 서로 반대되는 의미가 벡터 공간에 표현 되는 방식은 서로 비슷합니다.
컬리의 리뷰데이터를 GPT의 text-embedding3 모델을 이용하여 텍스트 임베딩을 하였습니다. 다음의 절차를 거쳐 리뷰데이터를 임베딩하면, 각 row마다 n-tokens 값과 vector 값이 생성됩니다. 이렇게 구축된 벡터값은 추후에 의미 기반으로 리뷰를 검색할 때 사용됩니다.
Azure에서 AI Search를 구축하려면 다음의 순서를 거칩니다.
- Data Source (임베딩된 데이터) 를 업로드하고,
- 인덱서에게 데이터소스의 어떤 필드를 어떻게 인덱스로 구성할지 설정하여 인덱스 문서를 만듭니다.
┌───────────────────────────┐
│ Data Sources │
│ (Blob, Cosmos DB, SQL DB) │
└─────────────┬─────────────┘
│ (인덱서가 주기적으로 데이터를 가져옴)
▼
┌───────────────────────┐
│ Indexer │
│ ┌─────────────────┐ │
│ │ Skillset(AI) │ │
│ │ (OCR, NLP 등) │ │
│ └─────────────────┘ │
└─────────────┬─────────┘
│ (전처리 & AI로 분석된 결과를 인덱스에 저장)
▼
┌───────────────────────┐
│ Index │
│ (문서, 필드, 메타정보)│
└─────────────┬─────────┘
│ (사용자가 검색 쿼리를 보냄)
▼
┌───────────────────────┐
│ Query │
│ (검색, 필터, 정렬 등) │
└───────────────────────┘
참고: https://www.youtube.com/watch?v=MOOHK1b4Syk
이제 다음과 같이 코드를 구성하면 자연어로 구축된 AI Search 에게 질의가 가능해집니다.
- vector_query: AI Search에게 자연어로 질의하기 위해 question(질의 내용) -> embedding 해서 -> 벡터화된 쿼리로 만듭니다.
- filter: 검색할 상품 기준 (실제 sql 처럼 정확히 특정 상품 안에서만으로도 질의가 가능해집니다.)
- select: 원하는 데이터 select
- top: 유사도 순으로 개수 지정
client = AzureOpenAI(
azure_endpoint = azure_endpoint,
api_key = api_key,
api_version = api_version
)
def search(productNumber: str = "111111", badgeKeyword: str = "촉촉함"):
search_client = SearchClient(endpoint=endpoint, index_name=index_name, credential=credential, api_version=api_version)
question = "keyword: " + badgeKeyword + " 와 관련된 내용을 찾아줘. 키워드와 관련된 내용이 꼭 포함되어 있어야 하고 정성스러워야해."
embedding = client.embeddings.create(input = question, model=embedding_model_name).data[0].embedding
vector_query = VectorizedQuery(vector=embedding, k_nearest_neighbors=15, fields="content_vector", exhaustive=True)
results = search_client.search(
search_text=f"contents: '{badgeKeyword}'",
filter=f"productNumber eq {productNumber}",
vector_queries=[vector_query],
select=["sno", "productNumber", "contents"],
top=15
)
# 결과를 리스트로 변환
results_list = []
for result in results:
results_list.append({
"sno": result["sno"],
"productNumber": result["productNumber"],
"contents": result["contents"]
})
return {"results": results_list}
현재 response
{
results: [
{
"sno": "1111",
"productNumber": "11111",
"contents": "좋아요 촉촉하니 이거쓰고 건조함을 잘못느끼네요"
},
...
}
이제 특정 키워드와 관련된 리뷰까지는 조회가 가능합니다. 이제 형광펜으로 리뷰의 어떤 내용이 키워드의 내용을 포함해주고 있는지를 같이 응답해주어야 클라이언트에서 형광펜으로 하이라이팅을 해줄 수 있습니다. 이를 LLM 을 이용하면 쉽게 구현이 가능합니다.
system_msg = """
# 당신은 전문 뷰티 리뷰 분석가 입니다.
보내주는 리뷰를 읽고 같이 보내주는 키워드와 가장 유사한 부분의 하이라이트 텍스트를 반환해 주세요.
하이라이트 텍스트는 보내주는 리뷰에 꼭 포함되어있어야 하는 텍스트입니다.
하이라이트 텍스트는 2~3단어 미만으로 구성해주세요.
유사한 부분이 없다면 빈 문자열로 보내주세요.
# 예시 요청
{
"texts": [
{
"id": 0,
"keyword": "향기",
"text": "진작부터 써보고 싶었던 제품이에요. 1+1으로 구매해 기분이 좋아요. 제형은 세럼과 토너의 중간쯤인 거 같아요. 향이 좋아서 하루에도 여러 차례 뿌리게 되네요. 처음엔 조금 진한듯 하지만, 시간이 지날수록 은은하게 남은 잔향이 더욱 좋아요."
},
... 20개
]
}
# 예시 JSON 응답
{
"highlighted_texts": [
{
"id": 0,
"keyword": "향기",
"highlighted_text": "향이 좋아서"
},
... 20개
]
}
"""
이제 어떤 부분을 하이라이팅할지까지 클라이언트에게 응답하면, '리뷰키워드로 검색후 하이라이팅' 구현이 완료됩니다.
마무리
사실 네이버 쇼핑에서는 이미 키워드 리뷰 검색 기능을 제공하고 있습니다. 이를 태그 구름 서비스라고 부릅니다. 네이버 쇼핑에서 잘 쓰고 있는 기능이 컬리에도 도입되었으면 하는 바람에 해커톤 아이디어로 구현해보았습니다. 특히 화장품을 판매하고 있는 뷰티컬리에서는 사용자들이 필수적으로 사용후기를 확인하고 있었지만, 오히려 후기가 너무 많아 제대로 활용되지 못하는 부분을 개선해보고 싶었습니다.
서비스 컨셉 기획과 구현, 발표자료 모두 2일안에 만드느라 고생을 많이 했습니다. 결국 구현을 완료했다는 것에 성취함이 엄청 느껴졌고 팀원에게 너무 고마웠습니다. 수상은 하지 못했지만 나에게는 많은 것이 남은 해커톤이었습니다. GPT api만 사용할줄 알던 내가 RAG 까지 구축을 하는 경험을 했다는 것 자체가 너무 귀하고 감사하다는 생각입니다.
조금 더 생각해볼 부분들
안좋은 후기는 어떻게 처리할 것인가?
내용이 안좋은 후기에 대해서는 일부러 보여주지 않을 필요는 없다고 생각했습니다. 안좋은 내용을 확인하고 싶은 사용자도 당연히 있을 것이고, 리뷰 시스템에서 안좋은 내용의 후기를 일부러 노출하지 않을 책임은 없다고 생각합니다. 상품에 대해 평이 안좋은 것은 리뷰시스템에서 해결할 부분이 아니고 상품 품질을 관리하는 부분이 신경써야한다고 생각했습니다. 하지만 단순 부정후기가 아닌 '악성' 후기에 대해선 리뷰 시스템에서 막을 책임은 있을 것 같습니다.
리뷰 개수가 적은 서비스에서는 제공하지 못하는 기능 아닌가?
아이디어의 시작 자체는 '리뷰 데이터가 너무 많아 원하는 리뷰를 찾아보기 힘들다' 에서 출발하였습니다. 리뷰 개수가 적다면 사용자는 오히려 리뷰를 파악하기쉬워 이 기능까지는 필요없지 않을까 생각합니다.
LLM api 를 사용하는 부분에 대한 성능과 비용이슈는?
- 리뷰 -> 키워드 추출
- 텍스트 임베딩
- 키워드 -> 형용사로 변환
- AI Search 질의
- AI Search 결과 -> 하이라이팅할 텍스트 찾기
리뷰 키워드 추출 최적화가 가능하다.
신기능에 대해선 AI 비용이 당연히 드는 것이 사실입니다. 하지만 좀 더 효율적으로 사용하는 방법에 대해선 고민이 필요합니다. 리뷰 데이터에서 키워드로 추출하는 부분에 대해서는 각 row 하나마다 키워드를 추출하는 방식에서 같은 상품의 리뷰를 몇개 합쳐서 최대 토큰수(8196)개에 근접하게 만들면 리뷰 데이터 row수가 많이 줄어들 수 있습니다. 키워드가 필요한 부분은 사실 '각 리뷰'가 아닌 '상품별' 이기 때문입니다. 실제로 리뷰 데이터들 중에서 짧아서 내용이 별로 없는 리뷰는 제거하고, 남은 리뷰를 몇개씩 합친뒤 키워드 추출을 해보았습니다. row 수가 많이 줄어 임베딩하는 속도와 효율이 많이 증가했고, 주요 키워드의 워드클라우드 데이터는 거의 비슷하게 구축이 되었습니다.
AI Search 결과에서 하이라이팅할 텍스트 찾기
실시간으로 조회된 리뷰에서 하이라이팅할 텍스트를 찾기 때문에 API call이 5초가량 소요됩니다. 조회하는 리뷰의 양이 많을 수록 API 응답속도가 길어집니다. 해커톤 당시에는 사용자가 어떤 키워드로 검색할 지 모르기 때문에 하이라이팅 텍스트를 미리 저장하지 못하는 것 아닌가? 라고 생각했습니다. 끝나고 다시 생각해보니 주요 키워드가 이미 추출된 상태라면 각 리뷰에서도 주요 키워드에 따라 어떤 부분을 하이라이팅 할지 미리 설정하는 것은 불가능하진 않아보였습니다.
LLM api를 사용하는 곳이 많다.
실시간응답을 빠르게 하기 위해 미리미리 LLM을 이용해 데이터를 만들어 놓는다고 하더라도, 리뷰 하나에 api가 여러번 사용됩니다. 실제 리뷰 수는 수백만 건이기 때문에 이 수백만 건마다 api 호출이 여러번이라면 비용이 많이 들 수 있습니다. 이 부분은 아직은 잘 모르겠습니다. 얼마를 투자하고 전환률을 얼마나 올리는데에 드는 비용을 잘 모르기 때문에 판단하기가 어려웠습니다. 그래도 LLM 적극적으로 이용한다면 기존에 없던 기능이 만들어지고 경쟁력을 확보하는데에 좋지 않을까 라는 생각을 하며... (이런 쪽으로 투자 많이 했으면 좋겠는 개인적인 바람)
소감
개인적인 도전으로는 요즘 푹 빠져있는 Windsurf를 이용해서 '한번도 써보지 않는 기술스택으로도 Windsurf와 함께라면 개발이 가능할까?' 라는 도전을 이번에 해봤습니다. 정말 신기하게도 성공했고, 파이썬 언어는 다룰줄 알지만 API를 구축해본적은 없던 상황에서 Windsurf로 Fast API로 서버를 구축하였습니다. 이로써 알게된 것은 어느정도 다룰줄 아는 언어라면 간단하게 서비스를 구현해내는 것은 정말 쉬워졌다는 것입니다.
여러 개발 언어를 테스트해보고 있는데 느낀 점은 아래 표와 같습니다.
언어 수준 | 개발 효율 증가 (with. Windsurf) | 느낀점 |
주로 사용함, 잘 알고 있음 (Java, Spring) | Low | 귀찮은 작업을 대신 해줌 |
주로 사용하진 않지만 알고 있음 (Python) | High | '주로 사용함' 레벨과 근접하게 사용하게 해줌 |
잘 모름 (Typescript, Next.js) | Medium | 어느정도 구현은 가능하지만 Windsurf가 잘못된 방향으로 가는 순간 망함 |
일단 전체적으로 사용하지 않는 것 보다는 '훨씬' 좋습니다. GPT에 매번 내 코드 컨텍스트를 학습시키는 비용이 들지 않고 그냥 '내 코드베이스 전체를 파악해서 답변해줘' 라는 말만 맨 앞에 넣으면 되기 떄문입니다.
앞으로는 이렇게 얻은 AI 관련 기술들을 사이드 프로젝트에서 적극적으로 활용해볼 계획입니다. 특히 Function Calling 기능도 가능성이 무궁무진해 보였습니다. 길고 두서없는 어려운 글 읽어주셔서 감사합니다. 나중에 내가 보더라도 이해할 수 있게 작성하려고 노력했으니 미래의 내가 판단해줄 것이라고 생각합니다.