SingleStore는 다양한 비즈니스 사용 사례를 지원하도록 설계된 강력한 다중 모델 데이터베이스 시스템 및 플랫폼입니다. 이 독특한 기능을 통해 기업은 여러 데이터베이스 시스템을 단일 플랫폼으로 통합할 수 있으며, 이는 총 소유 비용(TCO)을 줄이고 복잡한 통합 도구의 필요성을 없애 개발자 작업 흐름을 단순화합니다.
이 기사에서는 SingleStore가 웹 분석 회사의 이메일 캠페인을 어떻게 변화시킬 수 있는지 살펴보며, 개인화되고 매우 타겟팅된 이메일 콘텐츠를 생성할 수 있는 방법을 설명합니다.
기사에서 사용된 노트북 파일은 GitHub에서 확인할 수 있습니다.
소개
웹 분석 회사는 고객과의 소통을 위해 이메일 캠페인에 의존합니다. 그러나 고객을 타겟팅하는 일반적인 접근 방식은 비즈니스 잠재력을 극대화할 기회를 종종 놓치게 됩니다. 더 효과적인 솔루션은 대형 언어 모델(LLM)을 사용하여 개인화된 이메일 메시지를 작성하는 것입니다.
사용자 행동 데이터가 MongoDB와 같은 NoSQL 데이터베이스에 저장되고, 가치 있는 문서가 Pinecone과 같은 벡터 데이터베이스에 위치하는 시나리오를 고려해 보십시오. 이러한 여러 시스템을 관리하는 것은 복잡하고 자원을 많이 소모할 수 있으며, 통합 솔루션의 필요성을 강조합니다.
SingleStore는 다양한 데이터 형식을 지원하는 다목적 멀티 모델 데이터베이스로, JSON을 포함하여 여러 데이터 형식을 지원하며 내장 벡터 함수를 제공합니다. 이는 LLM과 원활하게 통합되어 여러 데이터베이스 시스템을 관리하는 강력한 대안이 됩니다. 이 기사에서는 SingleStore가 MongoDB와 Pinecone을 모두 대체할 수 있는 방법을 소개하고, 기능을 희생하지 않고 운영을 간소화하는 방법을 보여줄 것입니다.
예제 애플리케이션에서는 LLM을 사용하여 고객을 위한 고유한 이메일을 생성할 것입니다. 고객을 타겟팅하는 방법을 LLM에 학습시키기 위해 여러 유명한 분석 회사들을 LLM의 학습 자료로 사용할 것입니다.
또한 사용자 행동에 기반하여 콘텐츠를 사용자 정의할 것입니다. 고객 데이터는 MongoDB에 저장되고, 사용자 행동의 다양한 단계는 Pinecone에 저장됩니다. 사용자 행동은 LLM이 개인화된 이메일을 생성할 수 있도록 합니다. 마지막으로 MongoDB와 Pinecone에 저장된 데이터를 SingleStore를 사용하여 통합할 것입니다.
SingleStore 클라우드 계정 만들기
이전 기사에서 무료 SingleStore 클라우드 계정을 만드는 단계를 보여주었습니다. 우리는 Standard Tier를 사용하고 Workspace Group과 Workspace에 대한 기본 이름을 사용할 것입니다. 또한 SingleStore Kai를 활성화할 것입니다.
OpenAI API Key와 Pinecone API Key를 시크릿 보관함에 저장하고, 각각 OPENAI_API_KEY
와 PINECONE_API_KEY
를 사용할 것입니다.
노트북 가져오기
우리는 GitHub에서 노트북을 다운로드할 것입니다.
SingleStore 클라우드 포털의 왼쪽 네비게이션 창에서 “DEVELOP” > “Data Studio”를 선택할 것입니다.
웹 페이지의 오른쪽 상단에서 “새 노트북” > “파일에서 가져오기”를 선택할 것입니다. 우리는 GitHub에서 다운로드한 노트북을 찾아 가져오는 마법사를 사용할 것입니다.
노트북 실행하기
일반적인 이메일 템플릿
우리는 먼저 일반적인 이메일 템플릿을 생성한 다음 LLM을 사용하여 각 고객을 위해 맞춤 메시지로 변환할 것입니다. 이렇게 하면 각 수신자를 이름으로 지칭하고 우리의 웹 분석 플랫폼의 혜택을 소개할 수 있습니다.
다음과 같이 일반적인 이메일을 생성할 수 있습니다:
people = ["Alice", "Bob", "Charlie", "David", "Emma"]
for person in people:
message = (
f"Hey {person},\n"
"Check out our web analytics platform, it's Awesome!\n"
"It's perfect for your needs. Buy it now!\n"
"- Marketer John"
)
print(message)
print("_" * 100)
예를 들어, Alice는 다음 메시지를 볼 것입니다:
Hey Alice,
Check out our web analytics platform, it's Awesome!
It's perfect for your needs. Buy it now!
- Marketer John
다른 사용자들은 각자의 이름이 들어간 동일한 메시지를 받게 됩니다.
2. 큰 언어 모델 (LLM) 추가
우리는 역할을 제공하고 일부 정보를 주어 응용 프로그램에 손쉽게 LLM을 가져올 수 있습니다.
system_message = """
You are a helpful assistant.
My name is Marketer John.
You help write the body of an email for a fictitious company called 'Awesome Web Analytics'.
This is a web analytics company that is similar to the top 5 web analytics companies (perform a web search to determine the current top 5 web analytics companies).
The goal is to write a custom email to users to get them interested in our services.
The email should be less than 150 words.
Address the user by name.
End with my signature.
"""
LLM을 호출하는 함수를 생성할 것입니다:
def chatgpt_generate_email(prompt, person):
conversation = [
{"role": "system", "content": prompt},
{"role": "user", "content": person},
{"role": "assistant", "content": ""}
]
response = openai_client.chat.completions.create(
model = "gpt-4o-mini",
messages = conversation,
temperature = 1.0,
max_tokens = 800,
top_p = 1,
frequency_penalty = 0,
presence_penalty = 0
)
assistant_reply = response.choices[0].message.content
return assistant_reply
사용자 목록을 반복하고 LLM을 호출하여 고유한 이메일을 생성할 것입니다:
openai_client = OpenAI()
# Define a list to store the responses
emails = []
# Loop through each person and generate the conversation
for person in people:
email = chatgpt_generate_email(system_message, person)
emails.append(
{
"person": person,
"assistant_reply": email
}
)
예를 들어, Alice가 볼 수 있는 것은 다음과 같습니다:
Person: Alice
Subject: Unlock Your Website's Potential with Awesome Web Analytics!
Hi Alice,
Are you ready to take your website to new heights? At Awesome Web Analytics, we provide cutting-edge insights that empower you to make informed decisions and drive growth.
With our powerful analytics tools, you can understand user behavior, optimize performance, and boost conversions—all in real-time! Unlike other analytics platforms, we offer personalized support to guide you every step of the way.
Join countless satisfied customers who have transformed their online presence. Discover how we stack up against competitors like Google Analytics, Adobe Analytics, and Matomo, but with a focus on simplicity and usability.
Let us help you turn data into your greatest asset!
Best,
Marketer John
Awesome Web Analytics
다른 사용자들에게도 고유한 이메일이 생성됩니다.
3. 사용자 행동에 따른 이메일 콘텐츠 사용자화
사용자의 행동 단계에 따라 사용자들을 분류함으로써, 그들의 특정 요구에 맞춰 이메일 내용을 더욱 맞춤화할 수 있습니다. LLM은 사용자가 다양한 단계로 발전하도록 유도하는 이메일을 작성하는 데 도움을 줄 것이며, 궁극적으로 다양한 서비스에 대한 이해와 사용을 개선할 것입니다.
현재 사용자 데이터는 다음과 유사한 레코드 구조를 가진 MongoDB 데이터베이스에 저장되어 있습니다:
{
'_id': ObjectId('64afb3fda9295d8421e7a19f'),
'first_name': 'James',
'last_name': 'Villanueva',
'company_name': 'Foley-Turner',
'stage': 'generating a tracking code',
'created_date': 1987-11-09T12:43:26.000+00:00
}
데이터를 가져오기 위해 MongoDB에 연결하겠습니다:
try:
mongo_client = MongoClient("mongodb+srv://admin:<password>@<host>/?retryWrites=true&w=majority")
mongo_db = mongo_client["mktg_email_demo"]
collection = mongo_db["customers"]
print("Connected successfully")
except Exception as e:
print(e)
<password>
와 <host>
를 MongoDB Atlas의 값으로 교체하겠습니다.
사용자 행동 단계는 여러 가지가 있습니다:
stages = [
"getting started",
"generating a tracking code",
"adding tracking to your website",
"real-time analytics",
"conversion tracking",
"funnels",
"user segmentation",
"custom event tracking",
"data export",
"dashboard customization"
]
def find_next_stage(current_stage):
current_index = stages.index(current_stage)
if current_index < len(stages) - 1:
return stages[current_index + 1]
else:
return stages[current_index]
행동 단계에 대한 데이터를 사용하여 LLM에게 이메일을 더욱 맞춤화하도록 요청하겠습니다:
limit = 5
emails = []
for record in collection.find(limit = limit):
fname, stage = record.get("first_name"), record.get("stage")
next_stage = find_next_stage(stage)
system_message = f"""
You are a helpful assistant, who works for me, Marketer John at Awesome Web Analytics.
You help write the body of an email for a fictitious company called 'Awesome Web Analytics'.
We are a web analytics company similar to the top 5 web analytics companies.
We have users at various stages in our product's pipeline, and we want to send them helpful emails to encourage further usage of our product.
Please write an email for {fname} who is on stage {stage} of the onboarding process.
The next stage is {next_stage}.
Ensure the email describes the benefits of moving to the next stage.
Limit the email to 1 paragraph.
End the email with my signature.
"""
email = chatgpt_generate_email(system_message, fname)
emails.append(
{
"fname": fname,
"stage": stage,
"next_stage": next_stage,
"email": email
}
)
예를 들어, 여기 마이클을 위해 생성된 이메일이 있습니다:
First Name: Michael
Stage: funnels
Next Stage: user segmentation
Subject: Unlock Deeper Insights with User Segmentation!
Hi Michael,
Congratulations on successfully navigating the funnel stage of our onboarding process! As you move forward to user segmentation, you'll discover how this powerful tool will enable you to categorize your users based on their behaviors and demographics. By understanding your audience segments better, you can create tailored experiences that increase engagement and optimize conversions. This targeted approach not only enhances your marketing strategies but also drives meaningful results and growth for your business. We're excited to see how segmentation will elevate your analytics efforts!
Best,
Marketer John
Awesome Web Analytics
4. 이메일 내용 추가 맞춤화
사용자의 진행을 지원하기 위해 Pinecone의 벡터 임베딩을 사용하여 각 단계에 대한 관련 문서로 사용자를 안내할 수 있습니다. 이러한 임베딩은 사용자를 필수 리소스로 쉽게 안내할 수 있게 하여, 제품과의 상호작용을 더욱 향상시킵니다.
pc = Pinecone(
api_key = pc_api_key
)
index_name = "mktg-email-demo"
if any(index["name"] == index_name for index in pc.list_indexes()):
pc.delete_index(index_name)
pc.create_index(
name = index_name,
dimension = dimensions,
metric = "euclidean",
spec = ServerlessSpec(
cloud = "aws",
region = "us-east-1"
)
)
pc_index = pc.Index(index_name)
pc.list_indexes()
임베딩을 다음과 같이 생성하겠습니다:
def get_embeddings(text):
text = text.replace("\n", " ")
try:
response = openai_client.embeddings.create(
input = text,
model = "text-embedding-3-small"
)
return response.data[0].embedding, response.usage.total_tokens, "success"
except Exception as e:
print(e)
return "", 0, "failed"
id_counter = 1
ids_list = []
for stage in stages:
embedding, tokens, status = get_embeddings(stage)
parent = id_counter - 1
pc_index.upsert([
{
"id": str(id_counter),
"values": embedding,
"metadata": {"content": stage, "parent": str(parent)}
}
])
ids_list.append(str(id_counter))
id_counter += 1
Pinecone에서 일치하는 항목을 검색하겠습니다:
def search_pinecone(embedding):
match = pc_index.query(
vector = [embedding],
top_k = 1,
include_metadata = True
)["matches"][0]["metadata"]
return match["content"], match["parent"]
데이터를 사용하여 LLM에게 이메일을 추가로 맞춤화하도록 요청할 수 있습니다:
limit = 5
emails = []
for record in collection.find(limit = limit):
fname, stage = record.get("first_name"), record.get("stage")
# Get the current and next stages with their embedding
this_stage = next((item for item in stages_w_embed if item["stage"] == stage), None)
next_stage = next((item for item in stages_w_embed if item["stage"] == find_next_stage(stage)), None)
if not this_stage or not next_stage:
continue
# Get content
cur_content, cur_permalink = search_pinecone(this_stage["embedding"])
next_content, next_permalink = search_pinecone(next_stage["embedding"])
system_message = f"""
You are a helpful assistant.
I am Marketer John at Awesome Web Analytics.
We are similar to the current top web analytics companies.
We have users at various stages of using our product, and we want to send them helpful emails to encourage them to use our product more.
Write an email for {fname}, who is on stage {stage} of the onboarding process.
The next stage is {next_stage['stage']}.
Ensure the email describes the benefits of moving to the next stage, and include this link: https://github.com/VeryFatBoy/mktg-email-flow/tree/main/docs/{next_content.replace(' ', '-')}.md.
Limit the email to 1 paragraph.
End the email with my signature: 'Best Regards, Marketer John.'
"""
email = chatgpt_generate_email(system_message, fname)
emails.append(
{
"fname": fname,
"stage": stage,
"next_stage": next_stage["stage"],
"email": email
}
)
예를 들어, 여기 멜리사를 위해 생성된 이메일이 있습니다:
First Name: Melissa
Stage: getting started
Next Stage: generating a tracking code
Subject: Take the Next Step with Awesome Web Analytics!
Hi Melissa,
We're thrilled to see you getting started on your journey with Awesome Web Analytics! The next step is generating your tracking code, which will allow you to start collecting valuable data about your website visitors. With this data, you can gain insights into user behavior, optimize your marketing strategies, and ultimately drive more conversions. To guide you through this process, check out our detailed instructions here: [Generating a Tracking Code](https://github.com/VeryFatBoy/mktg-email-flow/tree/main/docs/generating-a-tracking-code.md). We're here to support you every step of the way!
Best Regards,
Marketer John.
일반 템플릿을 정제하고 꽤 타겟이 된 이메일을 개발한 것을 알 수 있습니다.
싱글스토어 사용
별도의 데이터베이스 시스템을 관리하는 대신, 우리는 SingleStore를 사용하여 운영을 간소화할 것입니다. JSON, 텍스트 및 벡터 임베딩을 지원함으로써, 필요한 모든 데이터를 한 곳에 효율적으로 저장하고 TCO를 줄이며 개발 프로세스를 단순화할 수 있습니다.
다음과 유사한 파이프라인을 사용하여 MongoDB에서 데이터를 수집할 것입니다:
USE mktg_email_demo;
CREATE LINK mktg_email_demo.link AS MONGODB
CONFIG '{"mongodb.hosts": "<primary>:27017, <secondary>:27017, <secondary>:27017",
"collection.include.list": "mktg_email_demo.*",
"mongodb.ssl.enabled": "true",
"mongodb.authsource": "admin",
"mongodb.members.auto.discover": "false"}'
CREDENTIALS '{"mongodb.user": "admin",
"mongodb.password": "<password>"}';
CREATE TABLES AS INFER PIPELINE AS LOAD DATA LINK mktg_email_demo.link '*' FORMAT AVRO;
START ALL PIPELINES;
우리는 <primary>
, <secondary>
, <secondary>
및 <password>
를 MongoDB Atlas의 값으로 교체할 것입니다.
고객 테이블은 파이프라인에 의해 생성됩니다. 행동 단계에 대한 벡터 임베딩은 다음과 같이 생성할 수 있습니다:
df_list = []
id_counter = 1
for stage in stages:
embedding, tokens, status = get_embeddings(stage)
parent = id_counter - 1
stage_df = pd.DataFrame(
{
"id": [id_counter],
"content": [stage],
"embedding": [embedding],
"parent": [parent]
}
)
df_list.append(stage_df)
id_counter += 1
df = pd.concat(df_list, ignore_index = True)
데이터를 저장할 테이블이 필요합니다:
USE mktg_email_demo;
DROP TABLE IF EXISTS docs_splits;
CREATE TABLE IF NOT EXISTS docs_splits (
id INT,
content TEXT,
embedding VECTOR(:dimensions),
parent INT
);
그런 다음, 테이블에 데이터를 저장할 수 있습니다:
df.to_sql(
"docs_splits",
con = db_connection,
if_exists = "append",
index = False,
chunksize = 1000
)
다음과 같이 SingleStore에서 일치를 검색할 것입니다:
def search_s2(vector):
query = """
SELECT content, parent
FROM docs_splits
ORDER BY (embedding <-> :vector) ASC
LIMIT 1
"""
with db_connection.connect() as con:
result = con.execute(text(query), {"vector": str(vector)})
return result.fetchone()
데이터를 사용하여 LLM에 이메일을 다음과 같이 맞춤 설정해 달라고 요청할 수 있습니다:
limit = 5
emails = []
# Create a connection
with db_connection.connect() as con:
query = "SELECT _more :> JSON FROM customers LIMIT :limit"
result = con.execute(text(query), {"limit": limit})
for customer in result:
customer_data = customer[0]
fname, stage = customer_data["first_name"], customer_data["stage"]
# Retrieve current and next stage embeddings
this_stage = next((item for item in stages_w_embed if item["stage"] == stage), None)
next_stage = next((item for item in stages_w_embed if item["stage"] == find_next_stage(stage)), None)
if not this_stage or not next_stage:
continue
# Get content
cur_content, cur_permalink = search_s2(this_stage["embedding"])
next_content, next_permalink = search_s2(next_stage["embedding"])
# Create the system message
system_message = f"""
You are a helpful assistant.
I am Marketer John at Awesome Web Analytics.
We are similar to the current top web analytics companies.
We have users that are at various stages in using our product, and we want to send them helpful emails to get them to use our product more.
Write an email for {fname} who is on stage {stage} of the onboarding process.
The next stage is {next_stage['stage']}.
Ensure the email describes the benefits of moving to the next stage, then always share this link: https://github.com/VeryFatBoy/mktg-email-flow/tree/main/docs/{next_content.replace(' ', '-')}.md.
Limit the email to 1 paragraph.
End the email with my signature: 'Best Regards, Marketer John.'
"""
email = chatgpt_generate_email(system_message, fname)
emails.append(
{
"fname": fname,
"stage": stage,
"next_stage": next_stage["stage"],
"email": email,
}
)
예를 들어, 다음은 Joseph을 위해 생성된 이메일입니다:
First Name: Joseph
Stage: generating a tracking code
Next Stage: adding tracking to your website
Subject: Take the Next Step in Your Analytics Journey!
Hi Joseph,
Congratulations on generating your tracking code! The next step is to add tracking to your website, which is crucial for unlocking the full power of our analytics tools. By integrating the tracking code, you will start collecting valuable data about your visitors, enabling you to understand user behavior, optimize your website, and drive better results for your business. Ready to get started? Check out our detailed guide here: [Adding Tracking to Your Website](https://github.com/VeryFatBoy/mktg-email-flow/tree/main/docs/adding-tracking-to-your-website.md).
Best Regards,
Marketer John.
요약
이 실용적인 시연을 통해 우리는 SingleStore가 다중 모델 기능과 AI 기반 개인화로 이메일 캠페인을 어떻게 개선하는지 확인했습니다. SingleStore를 우리의 단일 진실 출처로 사용함으로써, 우리는 워크플로를 간소화하고 이메일 캠페인이 고객에게 최대의 영향과 가치를 제공하도록 보장했습니다.
감사의 말
이 기사를 위해 조정된 원래 데모 코드를 제공한 Wes Kennedy에게 감사드립니다.
Source:
https://dzone.com/articles/how-to-build-a-chatgpt-super-app