GPT Assistants
gpt 모델을 활용하여 한층 강화된 모델을 사용할 수 있도록 해주는 도구 입니다.
기존 Chat GPT 3.5 모델에 추가 정보를 입력하여 모델에 참고 데이터를 제공 할 수 있습니다.
https://platform.openai.com/assistants
링크에 접속하면 UI로 어시스턴트를 생성,수정 할 수 있습니다.
Fine-tuning
좌측 탭을 보면 Fine-tuning 이라는 항목을 볼 수 있는데, 이미 훈련된 대규모 언어 모델에 특정 데이터셋을 사용하여 추가적인 학습을 수행하는 작업을 말합니다. 예를들어 Chat GPT 3.5 모델이 내가 원하는 방향으로 데이터를 제공하지 않는다면 이 항목을 통해 미세 조정을 할 수 있습니다.
챗봇을 제작할 때 답변의 형태를 일정한 형태로 유지한다던가, 항상 존댓말로 한다던가 혹은 특정 도메인에서 강점을 보이도록 하고 싶다던가 하는 식으로 모델의 작동 방향성을 정해나가는 과정입니다.
이는 프롬프트로 제어하는 것 보다 훨씬 나은 퀄리티의 결과물을 얻을 수 있고, 더 많은 데이터셋을 입력 할 수 있습니다.
api 정책을 보면 토큰당 가격을 책정하는데, 프롬프트 길이가 줄어들어서 비용도 절감됩니다.
( 1 토큰은 영어기준 대략 4개 글자 정도 )
하지만 본 글에선 사용하지 않을 계획 입니다.
그렇게 좋은데 왜 안쓰냐?
비싸고, 데이터셋을 만드는데 공수가 듭니다.
가격은 그렇다치고 데이터 수집 혹은 더미로 생성, 가공까지 해서 업로드 해야 합니다.
물론 바닥부터 LLM 모델을 직접 학습 시키는 것 보단 훨씬 쉽겠지만, 큰 고민 없이 사용해보기엔 조금 부담이 되는 부분입니다.
저는 그렇기 때문에, 본 글에서는 파인튜닝 없이 Retrieval 옵션과 프롬프트로 제어하는 방법에 대해 설명 하도록 하겠습니다.
api 활용 기본 프로세스는 아래와 같습니다.
- 어시스턴트 생성
- 스레드 생성
- 메시지 생성
- 실행
어시스턴트 생성
위에서 제공한 링크에 들어가서 UI를 통해 미리 어시스턴트를 만들어두었다면 따로 다시 만들 필요는 없습니다.
아래는 어시스턴트 생성 예시 입니다.
curl "https://api.openai.com/v1/assistants" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "OpenAI-Beta: assistants=v1" \
-d '{
"instructions": "You are a personal math tutor. Write and run code to answer math questions.",
"name": "Math Tutor",
"tools": [{"type": "code_interpreter"}],
"model": "gpt-3.5-turbo"
}'
OPEN AI 에서 발급받은 api key를 헤더에 넣고, OpenAI-Beta : assistants=v1 커스텀 헤더를 넣어줍니다.
글 쓰는 현재 기준 ( 2024. 4월 ) 아직 Beta 상태라서 커스텀 헤더를 필수로 입력 하도록 되어있습니다.
Body에는 어시스턴트의 역할, 이름, 사용할 툴, 모델 정보를 입력합니다.
- instructions : 어시스턴트가 수행해야할 역할.
- name : 어시스턴트의 이름.
- tools : 어시스턴트가 사용할 툴
- model : 기반 모델
요청 성공시 아래와 같은 응답이 옵니다.
이 응답에서 id 값을 변수에 담아둡니다. ( 나중에 이 값을 사용함 )
{
"id": "asst_id",
"object": "assistant",
"created_at": 1713284599,
"name": "Math Tutor",
"description": null,
"model": "gpt-3.5-turbo",
"instructions": "You are a personal math tutor. Write and run code to answer math questions.",
"tools": [
{
"type": "code_interpreter"
}
],
"top_p": 1.0,
"temperature": 1.0,
"file_ids": [],
"metadata": {},
"response_format": "auto"
}
스레드 생성
이후 메시지를 담을 스레드를 생성합니다.
여기서 스레드는 Chat GPT UI로 예를들면 하나의 히스토리를 의미합니다.
curl https://api.openai.com/v1/threads \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "OpenAI-Beta: assistants=v2" \
-d ''
위 형태로 요청을 보내면 스레드가 하나 생깁니다.
이렇게 만든 스레드는 현재 어떠한 어시스턴트와도 연결이 되어있지 않은 상태입니다.
이후 메시지를 생성하고 실행 하는 단계에서 어시스턴트에 스레드를 할당 해주는 작업이 필요합니다.
스레드는 현재 제공되는 공개된 API에서는 목록을 조회할 수 없고 고유 ID를 통해서만 접근이 가능합니다.
즉 ID까먹으면 삭제도 못한다는 말입니다.
물론 스레드가 한두개 더 있다고 요금이 왕창 나오진 않지만 뭔가 찝찝합니다.
다행스럽게도 스레드는 대략 60일간 아무런 접근도 없으면 이후에 자동으로 삭제된다고 합니다.
메시지 생성
이후 메시지를 생성하고 스레드에 담습니다.
curl https://api.openai.com/v1/threads/thread_abc123/messages \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "OpenAI-Beta: assistants=v2" \
-d '{
"role": "user",
"content": "How does AI work? Explain it in simple terms."
}'
메시지는 스레드 아이디를 통해 해당 스레드에 포함됩니다.
실행
어시스턴트 ID와, 스레드 ID를 포함하여 실행 요청을 보냅니다.
curl https://api.openai.com/v1/threads/thread_abc123/runs \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-H "OpenAI-Beta: assistants=v2" \
-d '{
"assistant_id": "asst_abc123"
}'
body에 어시스턴트 아이디를 넣고 스레드 아이디와 함께 보내면 연결이 안되어있던 스레드가 어시스턴트에 연결됩니다.
이후 응답은 비동기로 처리되어서 즉시 결과를 받을 수 없는 경우도 있습니다.
이를 스케쥴링을 통해 주기적으로 확인한다던가 하는 작업이 필요할 듯 합니다.
Retrieval 옵션
Retrieval enables the assistant with knowledge from files that you or your users upload. Once a file is uploaded, the assistant automatically decides when to retrieve content based on user requests.
설명엔 이렇게 써있습니다.
"검색을 통해 사용자 또는 사용자가 업로드하는 파일에서 지식을 얻을 수 있도록 해주는 옵션 입니다"
기본 베이스 모델의 외부에서 데이터를 가져오고 임베딩을 얻어 Vector DB에 저장한 뒤, 사용자가 질문을 하면 관련도가 가장 높은 임베딩을 찾아내어 모델에 제공하는 옵션 입니다.
외부 데이터를 계속 업데이트하면 최신 데이터를 답변 할 수도 있는데, 전통적인 머신러닝 방식에서 발생하는 데이터 최신화 문제는 쉽게 해결 할 수 있을 것 같습니다.
또한 전통적인 방식의 LLM 에서는 할루시네이션이라는 문제가 발생합니다.
이는 LLM 특성상 어쩔 수 없이 발생하는 문제인데, Retrieval 옵션을 켜면 직접 원본 데이터에서 값을 찾아내기에 값에 대한 근거있는 생성이 가능합니다.
파인 튜닝과 유사한 역할을 하는 옵션인데, 미묘하게 다른 모습입니다.