ElasticDocs GPT 로직
- UI를 통해 사용자가 질의를 입력한다.
- Elastic 하이브리드에 검색을 요청한다.
- 영문 데이터를 수집하여 elasticsearch에 저장하고 vectorization을 하여 학습한다.
- 문서 본문과 URL을 반환한다.
- Open API Chat Completion에서 API를 호출하낟.
- 도메인 지식을 활용한 답변을 반환한다.
- Python에서 생성된 응답을 출력한다.
준비물
- ML 노드가 활성화 된 Elastic Cloud 계정
- Search용 크롤링 인덱스
- Open API key
- Elastic Cloud에 준비된 모델
1. 수집 준비 하기
데이터 크롤링은 Elastic crawler을 사용하였다.
(1) Integrations > web crawler 에서 index를 생성한다.
(2) index name과 domain url을 설정한다.
(3) Crawl rule을 설정한다.
이 포스팅에서는 영어만 긁어올 수 있도록 하였다. 설정은 위의 목록이 최우선으로 작동한다.
(4) Mapping 조정을 위해 Dev Tools에서 아래 Query를 실행한다.
POST search-elastic-docs/_mapping
{
"properties": {
"title-vector": {
"type": "dense_vector",
"dims": 768,
"index": true,
"similarity": "dot_product"
}
}
}
(5) (3)에 이어서 Pipeline을 아래와 같이 설정한다.
(6) Add inference pipeline에서 아래와 같이 설정하여 Create한다.
2. 크롤링 하기
(1) Search > Contecnt > Elasicsearch indices 에 접근하여 Crawl 한다.
(2) Overview에서 Document count가 늘어나는 것을 확인할 수 있다.
(3) DevTool에서 document 모양새를 확인할 수 있다.
GET search-elastic-docs/_mapping
GET search-elastic-docs/_search
{
"size": 10,
"query": {
"bool": {
"must": [
{
"match": {
"title": {
"query": "how to create index",
"boost": 1
}
}
}
],
"filter": [
{
"exists": {
"field": "title"
}
}
]
}
},
"knn": {
"field": "title-vector",
"k": 1,
"num_candidates": 20,
"query_vector_builder": {
"text_embedding": {
"model_id": "sentence-transformers__all-distilroberta-v1",
"model_text": "how to create index"
}
},
"boost": 24
}
}
위 재료로 vector search를 진행할 수 있다.
3. Python으로 구현하기
Elasticsearch NLP 검색을 이용한 CHatGPT 답변을 구현한다. 이때 UI는 Streamlit을 사용했다.
(1) Open AI, Streamlit, Localtunnel을 설치한다.
!pip install openai==0.28
!pip install streamlit
!npm install localtunnel
!pip install -U typing_extensions
!pip install elasticsearch
(2) 코드 작성을 한다.
%%writefile elastic_gpt_app.py
import os
import streamlit as st
import openai
from elasticsearch import Elasticsearch
# openai apy key 입력
openai_api = ''
openai.api_key = openai_api
model = "gpt-3.5-turbo-0301"
def es_connect(cid, user, passwd):
es = Elasticsearch(cloud_id=cid, http_auth=(user, passwd))
return es
# Elasticsearch Search
def search(query_text):
# ES Cloud ID, Username, Password 입력
cid = ''
cu = ''
cp = ''
es = es_connect(cid, cu, cp)
# Elasticsearch query (BM25) and kNN configuration for hybrid search
query = {
"bool": {
"must": [{
"match": {
"title": {
"query": query_text,
"boost": 1
}
}
}],
"filter": [{
"exists": {
"field": "title"
}
}]
}
}
knn = {
"field": "title-vector",
"k": 1,
"num_candidates": 20,
"query_vector_builder": {
"text_embedding": {
"model_id": "sentence-transformers__all-distilroberta-v1",
"model_text": query_text
}
},
"boost": 24
}
fields = ["title", "body_content", "url"]
index = 'search-elastic-docs'
resp = es.search(index=index,
query=query,
knn=knn,
fields=fields,
size=1,
source=False)
body = resp['hits']['hits'][0]['fields']['body_content'][0]
url = resp['hits']['hits'][0]['fields']['url'][0]
return body, url
def truncate_text(text, max_tokens):
tokens = text.split()
if len(tokens) <= max_tokens:
return text
return ' '.join(tokens[:max_tokens])
# Chat_gpt 답변 생성
def chat_gpt(prompt, model="gpt-3.5-turbo", max_tokens=1024, max_context_tokens=4000, safety_margin=5):
# Truncate the prompt content to fit within the model's context length
truncated_prompt = truncate_text(prompt, max_context_tokens - max_tokens - safety_margin)
response = openai.ChatCompletion.create(model=model,
messages=[{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": truncated_prompt}])
return response["choices"][0]["message"]["content"]
st.title("ElasticDocs GPT")
# 입력창
with st.form("chat_form"):
query = st.text_input("You: ")
submit_button = st.form_submit_button("Send")
# 답변 출력
negResponse = "I'm unable to answer the question based on the information I have from Elastic Docs."
if submit_button:
resp, url = search(query)
prompt = f"Answer this question: {query}\nUsing only the information from this Elastic Doc: {resp}\nIf the answer is not contained in the supplied doc reply '{negResponse}' and nothing else"
answer = chat_gpt(prompt)
if negResponse in answer:
st.write(f"ChatGPT: {answer.strip()}")
else:
st.write(f"ChatGPT: {answer.strip()}\n\nDocs: {url}")
4. Web UI로 확인하기
(1) Streamlit 실행하기
!streamlit run /content/elastic_gpt_app.py &>/content/logs.txt &
(2) Endpoint IP 출력하기
import urllib
print("IP Endpoint:",urllib.request.urlopen('https://ipv4.icanhazip.com').read().decode('utf8').strip("\n"))
(3) 임시 URL 발급하기
!npx localtunnel --port 8501
(4) (2)에서 나온 IP를 submit한다.
'Cloud > ElasticSearch' 카테고리의 다른 글
[실습] Elasticsearch NLP - Vector Image Search 하기 (0) | 2024.01.02 |
---|---|
[실습] Elasticsearch NLP - Sentiment Analysis 하기 (0) | 2024.01.02 |
[실습] Elasticsearch NLP - Text Embedding과 KNN search 하기 (0) | 2024.01.02 |
[개념] Elastic NLP (0) | 2024.01.02 |
[실습] Elasticsearch에서 Machine Learning 사용하기 (0) | 2023.12.29 |