์์ฝ
1. FAQ ๋ฌธ์๋ฅผ Embedding์ ๋ง๋ค์ด Vector DB์ ์ ์ฅ
2. ์ฌ์ฉ์ ์ง์๊ฐ ๋ค์ด์ฌ ์,
2-1. ํด๋น ์ง์์ Embedding ๊ฐ์ ์ป์ ํ
2-2. cosineSimilarity๋ฅผ ์ฌ์ฉํ์ฌ, ๊ฐ์ฅ ์ ์ฌ๋๊ฐ ๋์ ๋ฌธ์๋ฅผ ๊ฐ์ ธ์ด
Embedding ์์ฑ
OpenAI์ text-embedding-ada-002 ๋ชจ๋ธ ์ฌ์ฉ
์์ : ๊ณต์ ๋ฌธ์ | cookbook
์๋ ์ฝ๋ ์์๋ Flask๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ด ์๋ํฌ์ธํธ๋ฅผ ๊ตฌํํ ๊ฒ์ผ๋ก, ์ฌ์ฉ์๊ฐ POST ์์ฒญ์ ๋ณด๋ด๋ฉด ํด๋น ์ง์์ ์๋ฒ ๋ฉ ๊ฐ์ ๋ฐํํ๋ค.
from flask import Flask, request, jsonify
from elasticsearch import Elasticsearch
import openai
app = Flask(__name__)
# OpenAI API ํค ์ค์
openai.api_key = 'YOUR_OPENAI_API_KEY' # OpenAI API ํค ์ค์
# Embedding API ํจ์ ์ ์
def get_embedding(text, model="text-embedding-ada-002"):
text = text.replace("\\n", " ")
return openai.Embedding.create(input=[text], model=model)['data'][0]['embedding']
# ์ฑ๋ด ์๋ํฌ์ธํธ
@app.route('/embedding', methods=['POST'])
def embedding():
user_message = request.json['user_message']
user_embedding = get_embedding(user_message)
return jsonify({"embedding": embedding})
if __name__ == '__main__':
app.run(debug=True)
Vector DB ์ฌ์ฉ
ElasticSearch์ Vector Database๋ฅผ ์ฌ์ฉ
์์ : cookbook
ElasticSearch๋ฅผ ์ฌ์ฉํ ์ด์
- ์ ๊ทผ์ฑ: ์ด๋ฏธ Logging ์์คํ ์ผ๋ก ํ์ฉํด๋ณธ ๊ฒฝํ์ด ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์ ๋ฌ๋์ปค๋ธ๊ฐ ๊ณ ๋ ค๋์ง ์์๋ค.
- ๋ฌด๋ฃ: ํ์ฌ ๋ด๊ฐ ์ฌ์ฉํ๋ ๋ฒ์ ๋ด์์ ๋ชจ๋ ๋ฌด๋ฃ๋ก ์ด์ฉํ ์ ์์๋ค.
์ธ๋ฑ์ค ์์ฑ
Vector Database๋ก ์ธ Index๋ฅผ ์์ฑํ๋ค.
def create_index():
index_mapping = {
"properties": {
"content": {
"type": "text",
},
"content_vector": {
"type": "dense_vector",
"dims": 1536,
"index": "true",
"similarity": "cosine"
}
}
}
es.indices.create(index="faq-vector-index", mappings=index_mapping)
- faq๋ฅผ ์ ์ฅํ
content
ํ๋์ ํด๋น faq์ embedding ๊ฐ์ ์ ์ฅํcontent_vector
ํ๋ ์์ฑ - ์ด๋, embedding ๊ฐ์ ์ ์ฅํ ํ๋๋
dense_vector
ํ์ ์ผ๋ก ์ง์ ํด์ฃผ์ด์ผ ํ๋ค. ์ด ํ์ ์ kNN search์ ์ฃผ๋ก ์ฌ์ฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, aggregations์ sorting์ด ์ง์๋์ง ์๋๋ค. dims
๋ OpenAI Embedding์ dimension๊ฐ์ธ 1536๋ก ์ง์ index
๋ง์ฝ kNN search๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ด๋ฅผ true๋ก ์ง์ ํด์ฃผ์ด์ผ ํ๋ค!- ์ด๋ฅผ true๋ก ์ง์ ํด์ฃผ์๋ค๋ฉด, ์๋
similarity
ํ์ ์ ์ค์ ํด์ฃผ์ด์ผ ํ๋ค. ์ด๋ kNN ๊ฒ์์์ ์ฌ์ฉํ ์ ์ฌ์ฑ ์ธก์ ํญ๋ชฉ์ผ๋ก,l2_norm
,dot_product
,cosine
์ด ์ธ๊ฐ์ง ๊ฐ์ด ์ฌ์ฉ๋ ์ ์๋ค. - ํด๋น ํ๋ก์ ํธ์์ ์ ๋ณด ๊ฒ์ ์์คํ
์์ ๊ฒ์ ์ฟผ๋ฆฌ์ ๋ฌธ์ ์ฌ์ด์ ์ ์ฌ์ฑ์ ํ๊ฐํ๊ณ , ๊ฐ์ฅ ๊ด๋ จ์ฑ ๋์ ๋ฌธ์๋ฅผ ๊ฒ์ ๊ฒฐ๊ณผ๋ก ๋ฐํํ๋ ๋ฐ ์ฌ์ฉ๋๋
cosine similarity
์ ์ฌ์ฉํ์๋ค.
- ์ด๋ฅผ true๋ก ์ง์ ํด์ฃผ์๋ค๋ฉด, ์๋
๋ฌธ์ ๊ฒ์
ElasticSearch ์ฟผ๋ฆฌ๋ฅผ ํตํด ์ฝ์ฌ์ธ ์ ์ฌ์ฑ์ ํ์ฉํ ๋ฒกํฐ search ์ํ
def search_similar_documents(user_embedding):
similar_docs = es.search(
index='faq-vector-index',
body={
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "cosineSimilarity(params.query_vector, 'content_vector') + 1.0",
"params": {"query_vector": user_embedding}
}
}
},
"_source": ["content"],
"size": 1
}
)
similar_contents = [hit['_source']['content'] for hit in similar_docs['hits']['hits']]
return similar_contents
script_score
: ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์๋ฅผ ๊ณ์ฐํ๋ ์ฟผ๋ฆฌsource
: ์คํฌ๋ฆฝํธ ๋ด์์cosineSimilarity
ํจ์๋ฅผ ํธ์ถํ์ฌ ์ ์ฌ์ฑ ๊ณ์ฐ.
์ด๋params.query_vector
๋ ์ฌ์ฉ์๊ฐ ์ ๊ณตํ ๋ฒกํฐ์ด๋ฉฐ,content_vector
๋ ์ธ๋ฑ์ค ๋ด ๋ฌธ์์ ๋ฒกํฐ ํ๋์ด๋ค._source
์size
ํ๋์ ์ค์ ์ผ๋ก ๊ฐ์ฅ ์ ์ฌํ ๋ฌธ์ 1๊ฐ์ content ํ๋๋ง ๋ฐํ

from flask import Flask, request, jsonify
from elasticsearch import Elasticsearch
import openai
from main.elasticsearch.elasticsearch_utils import es
app = Flask(__name__)
# OpenAI API ํค ์ค์
openai.api_key = 'YOUR_OPENAI_API_KEY' # OpenAI API ํค ์ค์
# Embedding API ํจ์ ์ ์
def get_embedding(text, model="text-embedding-ada-002"):
text = text.replace("\\n", " ")
return openai.Embedding.create(input=[text], model=model)['data'][0]['embedding']
# Elasticsearch์์ ์ ์ฌํ ๋ฌธ์ ๊ฒ์
def search_similar_documents(user_embedding):
similar_docs = es.search(
index='faq-vector-index',
body={
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "cosineSimilarity(params.query_vector, 'content_vector') + 1.0",
"params": {"query_vector": user_embedding}
}
}
},
"_source": ["content"],
"size": 1
}
)
# Elasticsearch ๊ฒฐ๊ณผ์์ ๋ฌธ์ ๋ด์ฉ ์ถ์ถ
similar_contents = [hit['_source']['content'] for hit in similar_docs['hits']['hits']]
return similar_contents
# ์ฑ๋ด ์๋ํฌ์ธํธ
@app.route('/chat', methods=['POST'])
def chat():
user_message = request.json['user_message']
user_embedding = get_embedding(user_message)
similar_docs = search_similar_documents(user_embedding)
return jsonify({"contents": similar_docs})
if __name__ == '__main__':
app.run(debug=True)
์ถ๊ฐ์์
- AI์๋ชป ์ด์๋ก(๐ข) ํ์ฌ๋ search ์, script_score๋ก ๊ฒ์ํ๊ณ ์์ง๋ง, ๋๋ถ๋ถ์ ๊ณต์ ๋ฌธ์์์๋ kNN search๋ฅผ ์ฌ์ฉํ๊ณ ์์๋ค. ์ด ๋๊ฐ์ง์ ์ฐจ์ด์ ์ ๋ค์ ํ์ ํ์ฌ ์ ์ ํ ์ฟผ๋ฆฌ๋ก ๋ณ๊ฒฝ ์์ ์ด๋ค
- ์ ์ฌ ๋ฌธ์๋ฅผ ๊ฐ์ ธ์จ ํ, openAI์ chat API๋ฅผ ์ฌ์ฉํ์ฌ, ๋ฌธ์ฅ์ ๊พธ๋ฉฐ์ค ์ ์์ ๊ฒ ๊ฐ๋ค :)
'๐ป ๊ฐ๋ฐ ์ผ์ง' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[kotlin/์ฝํ๋ฆฐ ์ฝ๋ฃจํด์ ์ ์] 5์ฅ. async์ Deferred (0) | 2024.05.21 |
---|---|
[Flask] OpenAI Embedding์ ์ฌ์ฉํ ์ ์ฌ ๋ฌธ์ ๊ฒ์ (text-embedding-3-small) (0) | 2024.04.28 |
์์ฝ
1. FAQ ๋ฌธ์๋ฅผ Embedding์ ๋ง๋ค์ด Vector DB์ ์ ์ฅ
2. ์ฌ์ฉ์ ์ง์๊ฐ ๋ค์ด์ฌ ์,
2-1. ํด๋น ์ง์์ Embedding ๊ฐ์ ์ป์ ํ
2-2. cosineSimilarity๋ฅผ ์ฌ์ฉํ์ฌ, ๊ฐ์ฅ ์ ์ฌ๋๊ฐ ๋์ ๋ฌธ์๋ฅผ ๊ฐ์ ธ์ด
Embedding ์์ฑ
OpenAI์ text-embedding-ada-002 ๋ชจ๋ธ ์ฌ์ฉ
์์ : ๊ณต์ ๋ฌธ์ | cookbook
์๋ ์ฝ๋ ์์๋ Flask๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ด ์๋ํฌ์ธํธ๋ฅผ ๊ตฌํํ ๊ฒ์ผ๋ก, ์ฌ์ฉ์๊ฐ POST ์์ฒญ์ ๋ณด๋ด๋ฉด ํด๋น ์ง์์ ์๋ฒ ๋ฉ ๊ฐ์ ๋ฐํํ๋ค.
from flask import Flask, request, jsonify
from elasticsearch import Elasticsearch
import openai
app = Flask(__name__)
# OpenAI API ํค ์ค์
openai.api_key = 'YOUR_OPENAI_API_KEY' # OpenAI API ํค ์ค์
# Embedding API ํจ์ ์ ์
def get_embedding(text, model="text-embedding-ada-002"):
text = text.replace("\\n", " ")
return openai.Embedding.create(input=[text], model=model)['data'][0]['embedding']
# ์ฑ๋ด ์๋ํฌ์ธํธ
@app.route('/embedding', methods=['POST'])
def embedding():
user_message = request.json['user_message']
user_embedding = get_embedding(user_message)
return jsonify({"embedding": embedding})
if __name__ == '__main__':
app.run(debug=True)
Vector DB ์ฌ์ฉ
ElasticSearch์ Vector Database๋ฅผ ์ฌ์ฉ
์์ : cookbook
ElasticSearch๋ฅผ ์ฌ์ฉํ ์ด์
- ์ ๊ทผ์ฑ: ์ด๋ฏธ Logging ์์คํ ์ผ๋ก ํ์ฉํด๋ณธ ๊ฒฝํ์ด ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์ ๋ฌ๋์ปค๋ธ๊ฐ ๊ณ ๋ ค๋์ง ์์๋ค.
- ๋ฌด๋ฃ: ํ์ฌ ๋ด๊ฐ ์ฌ์ฉํ๋ ๋ฒ์ ๋ด์์ ๋ชจ๋ ๋ฌด๋ฃ๋ก ์ด์ฉํ ์ ์์๋ค.
์ธ๋ฑ์ค ์์ฑ
Vector Database๋ก ์ธ Index๋ฅผ ์์ฑํ๋ค.
def create_index():
index_mapping = {
"properties": {
"content": {
"type": "text",
},
"content_vector": {
"type": "dense_vector",
"dims": 1536,
"index": "true",
"similarity": "cosine"
}
}
}
es.indices.create(index="faq-vector-index", mappings=index_mapping)
- faq๋ฅผ ์ ์ฅํ
content
ํ๋์ ํด๋น faq์ embedding ๊ฐ์ ์ ์ฅํcontent_vector
ํ๋ ์์ฑ - ์ด๋, embedding ๊ฐ์ ์ ์ฅํ ํ๋๋
dense_vector
ํ์ ์ผ๋ก ์ง์ ํด์ฃผ์ด์ผ ํ๋ค. ์ด ํ์ ์ kNN search์ ์ฃผ๋ก ์ฌ์ฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, aggregations์ sorting์ด ์ง์๋์ง ์๋๋ค. dims
๋ OpenAI Embedding์ dimension๊ฐ์ธ 1536๋ก ์ง์ index
๋ง์ฝ kNN search๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ด๋ฅผ true๋ก ์ง์ ํด์ฃผ์ด์ผ ํ๋ค!- ์ด๋ฅผ true๋ก ์ง์ ํด์ฃผ์๋ค๋ฉด, ์๋
similarity
ํ์ ์ ์ค์ ํด์ฃผ์ด์ผ ํ๋ค. ์ด๋ kNN ๊ฒ์์์ ์ฌ์ฉํ ์ ์ฌ์ฑ ์ธก์ ํญ๋ชฉ์ผ๋ก,l2_norm
,dot_product
,cosine
์ด ์ธ๊ฐ์ง ๊ฐ์ด ์ฌ์ฉ๋ ์ ์๋ค. - ํด๋น ํ๋ก์ ํธ์์ ์ ๋ณด ๊ฒ์ ์์คํ
์์ ๊ฒ์ ์ฟผ๋ฆฌ์ ๋ฌธ์ ์ฌ์ด์ ์ ์ฌ์ฑ์ ํ๊ฐํ๊ณ , ๊ฐ์ฅ ๊ด๋ จ์ฑ ๋์ ๋ฌธ์๋ฅผ ๊ฒ์ ๊ฒฐ๊ณผ๋ก ๋ฐํํ๋ ๋ฐ ์ฌ์ฉ๋๋
cosine similarity
์ ์ฌ์ฉํ์๋ค.
- ์ด๋ฅผ true๋ก ์ง์ ํด์ฃผ์๋ค๋ฉด, ์๋
๋ฌธ์ ๊ฒ์
ElasticSearch ์ฟผ๋ฆฌ๋ฅผ ํตํด ์ฝ์ฌ์ธ ์ ์ฌ์ฑ์ ํ์ฉํ ๋ฒกํฐ search ์ํ
def search_similar_documents(user_embedding):
similar_docs = es.search(
index='faq-vector-index',
body={
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "cosineSimilarity(params.query_vector, 'content_vector') + 1.0",
"params": {"query_vector": user_embedding}
}
}
},
"_source": ["content"],
"size": 1
}
)
similar_contents = [hit['_source']['content'] for hit in similar_docs['hits']['hits']]
return similar_contents
script_score
: ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์๋ฅผ ๊ณ์ฐํ๋ ์ฟผ๋ฆฌsource
: ์คํฌ๋ฆฝํธ ๋ด์์cosineSimilarity
ํจ์๋ฅผ ํธ์ถํ์ฌ ์ ์ฌ์ฑ ๊ณ์ฐ.
์ด๋params.query_vector
๋ ์ฌ์ฉ์๊ฐ ์ ๊ณตํ ๋ฒกํฐ์ด๋ฉฐ,content_vector
๋ ์ธ๋ฑ์ค ๋ด ๋ฌธ์์ ๋ฒกํฐ ํ๋์ด๋ค._source
์size
ํ๋์ ์ค์ ์ผ๋ก ๊ฐ์ฅ ์ ์ฌํ ๋ฌธ์ 1๊ฐ์ content ํ๋๋ง ๋ฐํ

from flask import Flask, request, jsonify
from elasticsearch import Elasticsearch
import openai
from main.elasticsearch.elasticsearch_utils import es
app = Flask(__name__)
# OpenAI API ํค ์ค์
openai.api_key = 'YOUR_OPENAI_API_KEY' # OpenAI API ํค ์ค์
# Embedding API ํจ์ ์ ์
def get_embedding(text, model="text-embedding-ada-002"):
text = text.replace("\\n", " ")
return openai.Embedding.create(input=[text], model=model)['data'][0]['embedding']
# Elasticsearch์์ ์ ์ฌํ ๋ฌธ์ ๊ฒ์
def search_similar_documents(user_embedding):
similar_docs = es.search(
index='faq-vector-index',
body={
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "cosineSimilarity(params.query_vector, 'content_vector') + 1.0",
"params": {"query_vector": user_embedding}
}
}
},
"_source": ["content"],
"size": 1
}
)
# Elasticsearch ๊ฒฐ๊ณผ์์ ๋ฌธ์ ๋ด์ฉ ์ถ์ถ
similar_contents = [hit['_source']['content'] for hit in similar_docs['hits']['hits']]
return similar_contents
# ์ฑ๋ด ์๋ํฌ์ธํธ
@app.route('/chat', methods=['POST'])
def chat():
user_message = request.json['user_message']
user_embedding = get_embedding(user_message)
similar_docs = search_similar_documents(user_embedding)
return jsonify({"contents": similar_docs})
if __name__ == '__main__':
app.run(debug=True)
์ถ๊ฐ์์
- AI์๋ชป ์ด์๋ก(๐ข) ํ์ฌ๋ search ์, script_score๋ก ๊ฒ์ํ๊ณ ์์ง๋ง, ๋๋ถ๋ถ์ ๊ณต์ ๋ฌธ์์์๋ kNN search๋ฅผ ์ฌ์ฉํ๊ณ ์์๋ค. ์ด ๋๊ฐ์ง์ ์ฐจ์ด์ ์ ๋ค์ ํ์ ํ์ฌ ์ ์ ํ ์ฟผ๋ฆฌ๋ก ๋ณ๊ฒฝ ์์ ์ด๋ค
- ์ ์ฌ ๋ฌธ์๋ฅผ ๊ฐ์ ธ์จ ํ, openAI์ chat API๋ฅผ ์ฌ์ฉํ์ฌ, ๋ฌธ์ฅ์ ๊พธ๋ฉฐ์ค ์ ์์ ๊ฒ ๊ฐ๋ค :)
'๐ป ๊ฐ๋ฐ ์ผ์ง' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[kotlin/์ฝํ๋ฆฐ ์ฝ๋ฃจํด์ ์ ์] 5์ฅ. async์ Deferred (0) | 2024.05.21 |
---|---|
[Flask] OpenAI Embedding์ ์ฌ์ฉํ ์ ์ฌ ๋ฌธ์ ๊ฒ์ (text-embedding-3-small) (0) | 2024.04.28 |