최근 저희 팀에서는 GPT 의 fine tuning 에 앞서 GPT 의 In-context learning 을 활용하여 별도의 fine tuning 없이 활용하는 방법도 시도해보고 있습니다. 이러한 방법은 여러모로 장점도 많고, 실제로 잘 동작하는것으로 평가하고 있습니다.
GPT fine tuning 외에도 GPT 를 사용하는 입장에서 GPT in action
이라는 시리즈로 GPT API 를 기반으로 도구를 제작하는것에 대해 설명해보고자 합니다. 여러 경우의 업무 적용 가능성을 타진해보았고, 이번 포스트에서는 챗봇 구축에 대한 이야기를 해보고자 합니다.
이루다나 chatGPT 서비스와 같이 open domain 에대한 챗봇을 제외한다면, 일반적으로 기업이 원하는 챗봇은 컨트롤이 가능해야 합니다. 여기서 컨트롤이라 함은 K은행 챗봇이 W은행 상품을 홍보해선 한되는 등 입니다. 즉 어느정도 정해진 루틴 내에서 대화할수 있는 챗봇을 만들어야 하며, 이는 일반적으로 다이얼로그 플로우가 존재하는 선 내에서 대화를 진행하게 됩니다. 특히 특정 업무를 수행해야 하는 챗봇, 예를 들어 금융회사의 예금 송금 등 과 같은, 이라면 더더욱 규칙기반의 작업을 수행해야 하겠습니다.
이러한 방법은 답변하는 챗봇입장에서는 문제가 없지만 질문하는 사람 입장에서는 문제가 많습니다. 뭘 물어봐도 재대로 이해도 못하고 답도 못하는 챗봇이라서지요. 이는
이를 해결하려면
을 운영하면 될지도 모르겠습니다. 다만 하나의 챗봇을 만들자고 이 많은 노력과 인력이 투입되어야 한다면 CS 팀이 효과적일지도 모르겠습니다.
GPT-3 의 등장과 함께 위의 문제중 5번은 해결이 되었고, 다이얼로그 플로우와 함께 주어진 문장을 변형해서 답변하게 하므로 좀더 자연스러운 챗봇을 구현하는 등의 시도등이 있었습니다. 하지만 이는 여전히 의도를 파악하고 이에 대한 적절한 답변을 구사하는 챗봇과는 거리가 있습니다.
그리고 '23년 현재, gpt-4 및 chatGPT (gpt-3.5) 의 등장과 함께, 완벽할순 없지만 상당부분 위 문제가 해결이 되었고 정말 말귀를 알아듣고 적절한 답변을 하는 챗봇이 나온것 같습니다. 특히 이 chatGPT, gpt-4 가 매우 똑똑해서 의도를 적절히 설명하고 명령하는것만으로도 우리가 원하는 custom chatbot 을 구성해 볼 수 있습니다. 이를위한 별도의 fine-tuning 은 필요하지 않습니다.
이하의 내용은 매우 개인적인 의견들입니다. 참고만 부탁드립니다.
포스트를 작성하는 현재 시점으로, chatbot 을 만들수 있는 api 는 openai 의 gpt-3.5 및 gpt-4 뿐으로 판단됩니다. 우선 국내외 다른 gpt 도 많지만 타사의 모델에서는 chat api 를 지원하지 않을 뿐더러, 아래 설명하는 수준의 고난도 언어 테스크의 수행은 gpt-3 가 아닌 gpt-3.5, gpt-4 의 매우 고성능을 필요로 합니다.
openai 에서는 chat task 에 대한 api 를 별도로 지원합니다 (https://platform.openai.com/docs/guides/chat/introduction). 이 api 에서 주요한 점은 message 에 3가지의 role, i.e. system
, user
, assistant
가 나누어 져 있고, system
을 통해 in-context learning 을 수행할 수 있습니다. 예를 들면 아래와 같습니다.
openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "너는 K은행의 친절한 은행원이야."},
{"role": "user", "content": "사용자 질문 1"},
{"role": "assistant", "content": "답변 1"},
{"role": "user", "content": "사용자 질문 2"}
]
)
대화의 구현은 해당 api 에 대화를 추가하는 형식으로 진행하면 됩니다. 단 대화가 길어질수록 토큰이 길어지니 비용이 비싸지고, 넘우 길어질 경우 길이제한에 overflow 가 일어나므로 적절히 과거 대화를 지워야 합니다.
위 방법을 통해 자유대화를 할 수 있는 챗봇을 만들 수 있습니다. 이 챗봇은 이미 사용자의 의도를 충분히 잘 파악할 수 있고, 어느정도 지식 (parametric memory) 를 갖추고 있어 웬만한 대화가 가능하며, 형식적인 답변이 아닌 다양한 답변을 할 수 있는 챗봇입니다. 즉 앞에서 문제가 되었던 부분의 대부분을 해결할 수 있습니다만, 우리의 의도 또는 특정 도메인 (회사) 의 답변을 하지는 못합니다.
위 예시에서 system 메시지를 통해 in-context learning 을 수행할 수 있다고 하였습니다. 즉 우린 system message 의 내용을 통해 이 챗봇을 친절한 K은행 챗봇으로도, 무서운 X사채의 챗봇으로도 만들수 있습니다. 뿐만 아니라, 우리가 원하는 의도 및 특정 도메인의 정보를 기반으로 답변할 수 있도록 이 system message 넣고 nonparametric 정보를 통해 답변을 도출시킬수 있습니다. 즉 우린 이 api system message 에 user query 에 적당한 문서를 찾고, 이를 넣어 적당히 답변하도록 명령하는것입니다.
user query 에 맞는 context 의 문서를 찾기위해서 일반적인 검색엔진을 사용할 수 있겠습니다. 또는 gpt-3 를 검색용으로 사용할 수도 있습니다. api 로 공개된 모델 중 text-embedding-ada-002
은 주어진 텍스트에 대한 임베딩을 만들어주는 모델로, 두 문장의 임배딩 유사도를 계산함으로서 문맥적 검색을 수행할 수 있습니다. 즉 챗봇이 대답하고자 하는 내용을 포함한 FAQ 가 있다고 가정하면, 이를 임베딩 벡터 데이터베이스로 만들어두고, 사용자의 요청을 벡터화 해서 임베딩 벡터 데이터베이스의 벡터들과 유사도를 측정, 가장 유사한 내용을 가지고 오는것입니다. 참고로 gpt-3 의 embedding 을 통한 검색은 엉망입니다. 공식문서 (https://openai.com/blog/new-and-improved-embedding-model) 에 설명하고 있지만, 웬만한 encoder 모델의 embedding 성능에 비하면 한참 떨어집니다.
embedding api 사용법에 대해서는 openai 공식문서에 잘 설명되어 있습니다.(https://platform.openai.com/docs/guides/embeddings/what-are-embeddings). 유사도 측정은 faiss 라이브러리의 cosine similarity 를 이용하면 빠르고 편리합니다 (https://github.com/facebookresearch/faiss).
위 설명 내용을 그림으로 그려보면 다음과 같습니다.
위 구성에서는 두개의 모델, gpt-3 및 gpt-3.5/gpt-4 가 사용됩니다. gpt-3 는 embedding 수행을 통해 FAQ 문서중 질문의 맥락적으로 가장 유사한 문서를 찾습니다. gpt-3.5/gpt-4 는 유사한 문서와 사용자의 질문, 시스템 명령 (회사규정이나 답변 스타일 등) 그리고 이전의 사용자와의 질문답변 내용을 모두 종합하여 적절한 답변을 하게 됩니다.
엄청 단순한 구성입니다. 이게 진짜 작동할까요? gpt-3 의 검색도 시원찮은데도요? 네 정말 오롯히 gpt-3.5 및 gpt-4 의 성능에 의존하여 잘 작동됩니다. 위 시스템의 구현은 사실상 두번의 api call 로 이루어지기에 그 코드도 몇줄 되지 않습니다.
참고로 아래 코드는 gpt-4 가 짜준 코드입니다. 작동시켜보진 않았는데, 일단 제가 짠 코드보다 퀄리티는 좋아 보입니다 :) 코드 작성에 있어서는 gpt-4 가 확실히 잘하는것 같습니다.
🐰 Dongyoung:
다음은 챗봇 시스템 설명이야. 이 챗봇은 사용자의 입력을 받고, 관련된 내용을 사전에서 찾고, 그 내용을 기반으로 대답하는 챗봇이야.
우선 사용자의 입력이 오면 그 입력을 embedding api 를 콜해서 embedding 을 만들고, 기존에 가지고 있는 임베딩 사전을 이용, cosine similarity 를 최대한 빠르게 (faiss 이용) 계산해서 유사한 문서를 사전에서 찾아내고, 그 문서의 내용과 사용자의 입력, 그리고 시스템 메시지를 더해서 채팅 api 를 호출해서 답변을 만들어. 이 과정은 반복되고 채팅 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']
채팅 api 는 다음과 같아
import openai openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Who won the world series in 2020?"}, {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."}, {"role": "user", "content": "Where was it played?"} ] )
채팅 api 에 들어가는 시스템 메시지는 다음과 같아 "너는 친절한 K사 은행원이야. K은행이라고 소개하고 모르는 답변이 있으면 고객센터 1234-5678 로 연락달라 그래." + 유사 문서 내용
채팅 api 에 들어가는 user 메시지는 사용자의 입력이야
만약 이전에 대화 내용이 있다면 user 메시지와 assistant 메시지를 이전 내용으로 채워서 채팅 api 에 넣어줘.
위 내용을 바탕으로 챗봇 백엔드 시스템을 python 으로 만들어줘🦄 ChatGPT:
아래는 챗봇 백엔드 시스템을 Python 클래스로 구현한 예제입니다. 필요한 라이브러리들을 설치하고 코드를 실행해보세요.import openai import faiss import numpy as np class Chatbot: def __init__(self, index, embeddings, documents, system_message): self.index = index self.embeddings = embeddings self.documents = documents self.system_message = system_message self.chat_history = [] def get_embedding(self, text, model="text-embedding-ada-002"): text = text.replace("\n", " ") return openai.Embedding.create(input=[text], model=model)["data"][0]["embedding"] def find_similar_document(self, user_embedding): _, top_indices = self.index.search(np.array([user_embedding]), 1) top_index = top_indices[0][0] return self.documents[top_index] def chat(self, user_input): user_embedding = self.get_embedding(user_input) similar_document = self.find_similar_document(user_embedding) system_message = self.system_message + " " + similar_document messages = [{"role": "system", "content": system_message}] for message in self.chat_history: messages.append(message) messages.append({"role": "user", "content": user_input}) response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=messages ) assistant_message = response.choices[0].message.content self.chat_history.append({"role": "user", "content": user_input}) self.chat_history.append({"role": "assistant", "content": assistant_message}) return assistant_message # 데이터 및 사전 생성 예시 documents = ["문서1 내용", "문서2 내용", "문서3 내용"] embeddings = [get_embedding(doc) for doc in documents] embedding_matrix = np.array(embeddings) index = faiss.IndexFlatL2(embedding_matrix.shape[1]) index.add(embedding_matrix) system_message = "너는 친절한 K사 은행원이야. K은행이라고 소개하고 모르는 답변이 있으면 고객센터 1234-5678 로 연락달라 그래." # 챗봇 객체 생성 chatbot = Chatbot(index, embeddings, documents, system_message) # 사용자 입력 처리 예시 user_input = "예금 계좌 개설 방법이 어떻게 되나요?" response = chatbot.chat(user_input) print(response)
위 코드는 챗봇 시스템을 구현한 예시입니다. 사용자 입력을 받아 적절한 응답을 생성하는 방식으로 작동합니다. 이 코드를 실행하려면 먼저 필요한 라이브러리들을 설치해야 합니다.
아래 그림은 이런 방식으로 구현한 챗봇의 실제 동작 예시 입니다. 아래와 같은 작업을 다이얼로그 플로우 등 기존의 챗봇으로 구현하려면 상당히 난이도가 높다는걸, 해보신분들은 더 잘 아실것 같습니다. 여기서 놀라운건 이런 챗봇의 구현이 단순히 gpt-3.5 api call 로만 가능하다는 것입니다.
gpt 의 성능을 보면, 이런 챗봇 테스크는 쉬운것 같습니다. 사실 이미 자유대화와 인지능력이 있는 모델로 특정 도메인으로 제한하는건은 단순히 명령을 내리는 수준에서 충분히 가능합니다.
chatbot 을 만드는 입장에서, 단순 질문 답변 및 대화 외에도, backend system 과 연계시켜 업무를 처리하는 등의 시나리오 작업이 가능합니다. 이런경우에도 search gpt 와 적절히 연계하여 그 답변을 업무로 나가게끔 한다면 업무처리가 가능한 챗봇으로도 사용 가능할 것 같습니다. 다만 이와 같은 방법은 여전히 다이얼로그 플로우 기반으로 작동되는 챗봇같습니다.
대화는 gpt 가 스스로 판단해서 잘 하는데 업무라고 못할까요? gpt 가 어떤 업무를 할지 판단하고, 업무 방법을 배워서 수행하게 하면 되지 않을까요? 저는 개인적으로 충분히 가능하다고 봅니다. 본 포스트 작성일 기준 어제 일자로 Microsoft 에서 gpt-4 에 대한 일련의 실험결과를 작성했고, 해당 보고서 5장에 이러한 접근이 가능함을 보여주는 내용이 있습니다. (Bubeck, S., Chandrasekaran, V., Eldan, R., Gehrke, J., Horvitz, E., Kamar, E., Lee, P., Lee, Y. T., Li, Y., Lundberg, S., Nori, H., Palangi, H., Ribeiro, M. T., & Zhang, Y. (2023). Sparks of Artificial General Intelligence: Early experiments with GPT-4. https://arxiv.org/abs/2303.12712v1).
이렇게 되면, 정말 인공지능이 사람을 대체하는건 얼마 남지 않은것 처럼 보입니다. 또는 벌써 시작된것 같습니다.
시리즈 전부 정말 잘 읽었습니다. 궁금한 부분들을 푸는 데에 큰 도움이 되었습니다. 감사합니다.