일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- ChatGPT
- vision-language navigation
- GPT
- 디스코드봇
- Rust
- Hexagonal Architecture
- s3
- 블록체인
- Ai
- backend
- discord
- web3.0
- embodied ai
- data discovery
- embodied
- datahub
- airflow
- video understanding
- frontend
- Spark
- MLFlow
- 챗봇
- vln
- lambda
- bricksassistant
- 디스코드
- Golang
- 웹3.0
- databricks
- 디스코드챗봇
- Today
- Total
BRICKSTUDY
[BricksAssistant] 디스코드 AI 챗봇 구축기 - (3) chatGPT 연동하기 본문
📌 Intro
안녕하세요!! Brickstudy 김민준입니다.
BricksAssitant 지난 블로그 글을 통해 디스코드 챗봇 설정은 완료했고, 이번엔 해당 챗봇을 통해 chatGPT와 대화할 수 있는 기능을 구현합니다.
GPT 연동의 핵심은 이전 대화내용을 기반으로 chatGPT에 요청을 보내 이전 히스토리를 기반으로 한 질문으로 더 정확한 답변을 제공하고자하는 목표로 합니다.(+프로젝트에 특화된 GPT 제작!!)
현재는 위의 목표를 달성하기 위해 간단히 프롬프팅을 활용해 기능을 구현하지만, 추후 RAG를 사용하여 좀 더 고도화된 GPT 제작을 진행할 예정입니다.
🗂️ Table of Contents
1. AI 챗봇 요구 사항
2. 시스템 구성
3. 코드 아키텍처
4. GPT 프롬프팅
5. 챗봇 동작 확인
💡 Background
이전 블로그 글
[BricksAssistant] 디스코드 AI 챗봇 구축기 - (1) 기획 [링크]
[BricksAssistant] 디스코드 AI 챗봇 구축기 - (2) 디스코드 연동하기 [링크]
Project Github [링크]
1. AI 챗봇 요구 사항
A. 이전 대화 내용을 기반으로 AI와 대화가 필요
- 질문에 대한 히스토리를 디스코드 대화상에 기록
→ "디스코드 쓰레드 기능 활용" - 질문 하나에 대한 답변이 아닌 이전 대화 내용을 기반으로 GPT에 요청하여 더 정확도 높은 답변 구성
→ "이전 대화내용 DB 적재 후 다음 대화에 사용"
B. 확장 가능한 형태로 기능 개발 필요
- 챗봇의 경우 사용자의 피드백을 받아 개선 및 기능 추가(Claude, RAG)가 계속될 예정이라 확장 가능한 형태의 코드 구성 필요
→ "Python 개발 시 Hexagonal Architecture + 추상화 계층 사용"
2. 시스템 구성
A. Chatbot 시스템 구성
- 이전 대화 내용 History 저장을 위해 DocumentDB 사용
- 사용자 피드백에 따라 시스템 구성이 달라질 수 있어 정해진 스키마보단 유연하게 대처할 수 있는 NoSQL 선택
- 여러 NoSQL 시스템 중 AWS DocumentDB는 AWS에서 관리되어 데이터베이스 인프라를 직접 관리할 필요X
- 프리티어를 제공하기 때문에 비용 절약
- ChatGPT의 경우 "GPT-4o mini" 모델 사용
- 챗봇의 특성 상 높은 수준의 문제 해결 질의 보단 빠르고 가벼운 작업을 위한 모델이 적합할 것으로 판단
- GPT-4o mini 모델은 소형 모델 중 가장 발전된 모델로 챗봇에 사용하기에 가장 적합할 것으로 선택
- GPT 모델의 경우 추가적인 리서치와 챗봇의 발전 방향에 따라 변경될 수 있음.
- https://platform.openai.com/docs/models/gpt-4o-mini
3. 코드 아키텍처
A. Project Tree
.
├── README.md
├── app.py # bot 실행파일
├── requirements.txt # 라이브러리 설치
├── src
│ ├── __init__.py
│ ├── adapter # adapter 폴더(infra, application 연결)
│ │ ├── __init__.py
│ │ ├── bot.py # bot adapter 코드
│ │ ├── database.py # database adapter 코드
│ │ └── gpt.py # gpt dapter 코드
│ ├── application # application 폴더
│ │ ├── __init_.py
│ │ ├── command.py # 내부 service와 adapter 코드
│ │ ├── entity.py
│ │ └── service # 내부 Domain service 코드
│ │ ├── __init__.py
│ │ └── request_answer.py # GPT응답 요청 처리
│ └── infra # infra 폴더
│ ├── __init__.py
│ ├── database # Database infra 폴더
│ │ ├── __init__.py
│ │ ├── abs_database.py
│ │ └── dynamodb.py
│ └── gpt # gpt infra 폴더
│ ├── __init__.py
│ ├── abs_gpt.py
│ └── chatgpt.py
└── tests # 테스트 코드 폴더
├── application
│ ├── __init__.py
│ └── service
│ ├── __init__.py
│ └── test_request_answer.py
└── infra
├── __init__.py
├── database
│ └── test_dynamodb.py
└── gpt
└── test_chatgpt.py
B. 세부 사항
- Hexagonal Architecture
- infra, application, adapter 3개의 폴더로 구성
- infra : 비즈니스 도메인 영역을 처리하는 외부 요소 정의 (ex. database, gpt)
- application : 비즈니스 도메인 영역 처리 (ex, command, service)
- command : 외부 요소를 받아 service 영역에 전달해주는 역할
- service : 도메인 영역을 처리하는 코드
- adapter : infra, application 영역 연결
- 주의!! application에서 외부 요소를 불러올 때, infra영역 코드를 불러오는 것이 아닌 adapter을 통해서 불러와야 함
- 이를 위해 팩토리 패턴 활용(application은 팩토리에서 어떤 종류의 데이터베이스를 썼는지 알 필요 없음!!)
- 파이썬의 경우 별도의 인터페이스가 없기 때문에 팩토리 패턴과 아래에 있는 추상화 계층 활용
▼ 팩토리 패턴(src/adapter/database.py)
from src.infra.database.dynamodb import Dynamodb
class DatabaseFactory:
@staticmethod
def create_database_gpt(db_type: str = "dynamodb"):
if db_type == "dynamodb":
return Dynamodb()
else:
raise ValueError(f"Unknown database type: {db_type}")
- 추상화 계층
- 시스템 확장성을 고려하여 시스템 유지 보수성을 향상하기 위해 사용
- 장점
- 복잡성 감소
- 유지보수성 증가
- 코드 재사용성 향상
- 협업 용이성 증가
- 독립적인 개발 및 테스트 가능
▼ 추상화 클래스 정의(src/infra/database/abs_database)
from abc import ABC, abstractmethod
from src.application.entity import GPTConversationInfo
class AbstractDatabaseGPT(ABC):
@abstractmethod
def insert_item(self, item: GPTConversationInfo):
"""데이터베이스에 GPT 요청 응답 데이터 삽입하는 추상화 메서드"""
pass
@abstractmethod
def get_item(self, thread_id: str):
"""데이터베이스에 특정 thread_id 기준 응답을 가져오는 추상화 매서드"""
pass
@abstractmethod
def delete_item(self, thread_id: str, request_time: str):
"""데이터베이스에 특정 thread_id 기준 응답을 삭제하는 추상화 매서드"""
pass
▼ 추상화 클래스 상속받아 코드 구현(src/infra/database/dynamodb.py)
import os
import boto3
from boto3.dynamodb.conditions import Key
from src.infra.database.abs_database import AbstractDatabaseGPT
class Dynamodb(AbstractDatabaseGPT):
def __init__(self) -> None:
dynamodb = boto3.resource('dynamodb',
aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
aws_secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"),
region_name=os.getenv("AWS_DEFAULT_REGION"))
self.table = dynamodb.Table("brickstudy-gpt")
def insert_item(self, item: dict):
if item:
self.table.put_item(Item=item)
def get_item(self, thread_id: str):
try:
response = self.table.query(
KeyConditionExpression=Key('thread_id').eq(thread_id)
)
return response["Items"]
except Exception:
return []
def delete_item(self, thread_id: str, request_time: str):
self.table.delete_item(Key={
'thread_id': thread_id,
"request_time": request_time
})
4. GPT 프롬프팅
A. 기본 role 지정
- brickAssitant라는 이름 지정
- 이전 History를 assitant Role로 전달해줌을 지정
- 마지막에 GPT의 답변 내용을 영어로 요약해주도록 설정
- 영어로 요약하는 이유는 토큰을 조금이라도 줄이기 위해(?)
self.model = "gpt-4o-mini"
self.messages = [
{
"role": "system",
"content": "Your name is brickAssistant. Respond in Korean. "
+ "The role of assistant's message is the content of your previous conversation with me. "
+ "At the end of your response, summarize the key points in bullet form. "
+ "Provide the summary in English and indicate it as [Summary] followed by the bullet points."
}
]
B. 이전 대화 내용을 Assitant로 전달
# src/application/service/request_answer.py
class GPTRequestService:
def request_answer(self, client, db, info: GPTConversationInfo):
# find history
history = []
if info.thread_id:
response = db.get_item(info.thread_id)
for idx, r in enumerate(reversed(response)):
if idx == 5: break # 최근 5개만 저장
history_q = r["question"]
hisotry_a = r["record"]
content = f"user: {history_q}, brickAssistant: {hisotry_a}"
history.append(content)
# request gpt
response = client.request_gpt(info.question, history)
all_answer = response.choices[0].message.content
-------------
# src/infra/gpt/chatgpt.py
def request_gpt(self, msg: str, history: list = []):
try:
# history를 message에 추가
for old_msg in history:
self.messages.append(
{"role": "assistant", "content": old_msg}
)
self.messages.append(
{"role": "user", "content": msg}
)
response = self.client.chat.completions.create(
model=self.model,
messages=self.messages
)
return response
5. 챗봇 동작 확인
A. 서버 실행
- 클라우드 가상 서버에 배포
B. 디스코드 실행 후 채널에 챗봇추가
- 기존에 채널이 있는 경우 챗봇이 해당 채널에 있는지 확인
C. "!GPT "로 질문하기
- !GPT과 함께 질문하면 챗봇이 인식하여 답변을 위해 쓰레드 생성
C. 동일한 쓰레드에 질문 시 이전 답변을 기억하여 답변
정상 동작됨을 확인!!
실제 모임 내에서 운영하여 피드백을 통해 챗봇을 점차 개선해 나갈 예정입니다!!
'프로젝트' 카테고리의 다른 글
5년, 10년 뒤를 바라보는 기술 탐방기 (0) | 2024.09.21 |
---|---|
[바이럴 탐지 프로젝트] (1) 바이럴, 이것 뭐에요~? (0) | 2024.08.25 |
[BricksAssistant] 디스코드 AI 챗봇 구축기 - (2) 디스코드 연동하기 (0) | 2024.08.03 |
Video understanding 분야 찍먹하기 (0) | 2024.07.28 |
[BricksAssistant] 디스코드 AI 챗봇 구축기 - (1) 기획 (0) | 2024.07.25 |