본문 바로가기
Tech Insights

파이썬을 활용한 OpenAI Assistants API 기초 사용법

by Kudos IT Daily 2023. 12. 15.
반응형

파이썬을 활용한 Assisants API 기초 사용법

목차

  • Assistants API, 파이썬 환경 설정
  • AI 어시스턴트에게 간단한 질문하기
  • 마치며

 

안녕하세요. 지난 시간에는 OpenAI DevDay때, 소개되었던 Assistants API에 대해 소개드렸습니다. OpenAI가 출시한 Assistants API는 어떤 기능인지 알아보고, 동작되는 원리에 대해 알아보았습니다. 추가로, OpenAI에서 제공하는 Playground 환경을 통해 간단하게 어시스턴트를 구성하고 동작하는 실습을 진행했습니다. 지난 포스팅의 내용이 궁금하신 분께서는 읽어보고 오시는 것을 추천드립니다.

 

 

OpenAI 신규 기능! Assistants API 활용하는 방법

OpenAI 신규 기능! Assistants API 활용하는 방법 목차 Assistants API 소개 Assistants playground 사용법 마치며 안녕하세요. OpenAI DevDay 콘퍼런스를 진행한 지 어느덧 한 달이 되어 가는 것 같습니다. GPT-4 Turbo, G

kudositdaily.tistory.com

 


 

지난 시간에는 Playground를 활용해서 어시스턴트를 생성하는 과정을 살펴봤습니다. 오늘은 파이썬 코드를 활용해 어시스턴트 생성하고 다루는 과정을 진행하도록 하겠습니다. Playground를 사용하면 프로그래밍 지식 없이도 노코드(No-code)로 어시스턴트를 쉽게 생성하고 설정할 수 있습니다.

 

하지만, 프로그래밍이 가능한 사용자라면 Assistant API를 더욱 효과적으로 활용할 수 있습니다. Assistants API는 기존에 LLM(Large Language Model, 대규모 언어 모델)을 만드는 데 필요한 시간을 크게 줄일 수 있고, 이 시간을 다른 SDK, API와 연동하거나 애플리케이션을 완성도 있게 최적화하는 데 투자함으로써 더욱 강력한 애플리케이션을 만들 수 있습니다. 오늘은 그에 대한 시작으로 지난 Playground에서 진행했던 내용들을 어떻게 파이썬 코드로 구현할 수 있을지 알아보도록 하겠습니다.

 

 

Assistants API, 파이썬 환경 설정

오늘 진행할 Assistants API 사용은 현재(23년 12월 15일) 기준, 베타 기능으로 제공되고 있습니다. Assistants API를 활용하기 위해서는 OpenAI의 API 키 발급이 사전에 필요합니다. 금일 포스팅에서는 API키가 있다는 가정 하에 진행하도록 하겠습니다. 추후, 필요한 분들을 위해 OpenAI API키를 발급받는 방법에 대해서도 다룰 수 있도록 하겠습니다.

 

OpenAI API키를 가지고 계시다면, 다음 필요한 것은 관련 파이썬 라이브러리를 설치하는 것입니다. 이번 예제에서는 구글 코랩(Colab)에서 제공하는 주피터 노트북(Jupyter Notebook)을 활용해서 진행하도록 하겠습니다. 로컬 환경에서 openai 패키지를 설치한 후, 진행하셔도 무방합니다. 우선, 아래와 같이 openai 패키지를 설치 혹은 업그레이드합니다.

 

!pip install openai --upgrade

 

 

openai 패키지 설치, 업그레이드가 정상적으로 완료된 후, 제대로 설치되었는지 확인해 볼까요? 단, OPENAI_API_KEY에 자신의 API 키를 입력해주셔야 합니다. 아래의 과정은 지난 포스팅에서 진행했던 Math Tutor를 파이썬 코드로 직접 생성하는 과정입니다. 단, 지난 포스팅에서 사용했던 어시스턴트의 이름과 혼선이 없도록 "Math Tutor Example"로 이름을 부여했습니다.

 

from openai import OpenAI

openai_api_key = "OPENAI_API_KEY"

model = OpenAI(api_key=openai_api_key)
assistant = model.beta.assistants.create(
    name="Math Tutor Example",
    instructions="You are a personal math tutor. Write and run code to answer math questions.",
    tools=[{"type": "code_interpreter"}],
    model="gpt-4-1106-preview"
)

 

 

위 과정을 수행하는 데, 아무런 문제가 없었다면 OpenAI 홈페이지에서 어시스턴트가 정상적으로 생성되었는지 확인해 보겠습니다. https://platform.openai.com/assistants 혹은 OpenAI 홈페이지의 Assistants 탭에 들어가시면 생성된 어시스턴트 목록을 확인할 수 있습니다. 위 코드를 수행한 결과 아래 사진과 같이 'Math Tutor Example' 어시스턴트가 생성된 것을 확인할 수 있습니다.

 

OpenAI Assistants

 

 

위 사진을 보시면, 사용자가 생성했던 어시스턴트의 이름, 설명, ID를 확인할 수 있습니다. 여기서 표시되는 ID를 활용하면 위 코드처럼 어시스턴트를 다시 생성하지 않고 ID만 등록해서 사용할 수 있습니다. 또한 해당 페이지에서 어시스턴트를 수정하거나 Playground에서 바로 사용해 볼 수 있습니다. 이어지는 예제에서 생성된 어시스턴트를 사용해 보도록 하겠습니다.

 

AI 어시스턴트에게 간단한 질문하기

앞선 예제에서 'Math Tutor Example' 어시스턴트를 생성했으니, 어시스턴트를 사용하는 예제를 살펴보도록 하겠습니다. 본격적으로 사용하기에 앞서 어시스턴트가 동작하는 과정에 대해 간단히 짚고 넘어가도록 하겠습니다. Assistants API 동작 과정에는 아래와 같은 핵심요소가 있습니다.

 

  • Assistant: 우리가 생성한 AI 어시스턴트입니다. 필요에 따라서 Code interpreter, 검색(Retrieval), 함수 호출 등을 수행합니다.
  • Thread: 어시스턴트와 사용자가 대화를 진행하는 세션(session)입니다. 대화가 진행되는 동안 메시지가 저장되고 필요에 따라 자동으로 요약이 수행됩니다.
  • Message: 어시스턴트와 사용자가 생성한 메시지입니다. 메시지는 텍스트, 이미지, 기타 파일 정보로 구성되고, 스레드에 리스트 형태로 저장됩니다.
  • Run: 스레드에서 어시스턴트를 호출하는 것입니다. 어시스턴트는 설정된 정보와 메시지를 사용해서 모델, 여러 Tool을 호출하고 요청에 대한 작업을 수행합니다.
  • Run Step: 어시스턴트가 작업을 수행하는 과정의 상세 목록으로 실행 단계(Run Step)를 중간중간 점검할 수 있습니다.

 

How Assistants work

 

 

위 그림을 보면서 핵심 요소들이 어떻게 동작하는지 살펴보겠습니다. 우리가 생성한 'Math Tutor Example' 어시스턴트는 Thread라는 공간에서 사용자와 대화를 진행합니다. 어시스턴트와 사용자가 진행하는 대화는 Message의 형태로 전달됩니다. 어시스턴트가 동작(Run) 할 때마다 생성된 Message는 스레드에 리스트의 형태로 저장되게 됩니다. 이제 위 과정을 코드를 보면서 하나씩 살펴보도록 하겠습니다.

 

스레드 생성하기

스레드를 생성하는 함수는 아래와 같습니다. 아래와 같이 threads.create() 함수를 수행하면 스레드 객체가 생성됩니다. 

 

thread = client.beta.threads.create()
print(thread)

 

 

print 함수를 통해 thread 정보를 확인해 보도록 하겠습니다. 출력 결과, 스레드 객체에 대한 여러 정보가 출력되었습니다. 이후 코드에서 해당 thread id를 통해 실행(run)을 하거나 thread 내부 정보를 조회할 수 있습니다.

 

Thread(id='thread_RfaxjUOy00YlzP0rqPQVCduO', created_at=1702590051, metadata={}, object='thread')

 

메시지 생성하기

'Math Tutor Example' 어시스턴트에게 수학 질문을 해보도록 하겠습니다. 우리의 질문은 메시지(Message) 형태로 어시스턴트에게 전달됩니다. 질문 메시지는 아래와 같은 형태로 생성됩니다. 아래의 코드를 보시면 질문을 하기 위해 방금 생성한 스레드의 ID와 역할 정보(role), 질문 내용(content)을 전달합니다.

 

message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="I need to solve the equation `3x + 11 = 14`. Can you help me?"
)
print(message)

 

 

위 코드를 수행하여 출력되는 결과를 확인해 보면, MessageContentText에 우리가 질문한 정보가 포함된 것을 확인할 수 있고, 역할(role), 스레드의 ID 정보도 확인할 수 있는 것을 알 수 있습니다.

ThreadMessage(id='msg_0FOJ5w4vyjxF3WHh4JeAWO1U', assistant_id=None, content=[MessageContentText(text=Text(annotations=[], value='I need to solve the equation `3x + 11 = 14`. Can you help me?'), type='text')], created_at=1702590513, file_ids=[], metadata={}, object='thread.message', role='user', run_id=None, thread_id='thread_RfaxjUOy00YlzP0rqPQVCduO')

 

질문 수행하기

생성된 질문을 실행해 보도록 하겠습니다. 실행하기 위해 스레드 ID, 어시스턴트 ID, 추가적인 지시사항 등을 전달합니다. 저는 어시스턴트를 새로 생성하지 않고, 기존에 생성한 어시스턴트의 ID 정보를 전달했습니다.

 

run = client.beta.threads.runs.create(
  thread_id=thread.id,
  assistant_id=assistant_id,
  instructions="Please address the user as Kudos IT Daily. The user has a premium account."
)
print(run)

 

 

run을 생성하면, 어시스턴트의 ID, 스레드 ID, 사용된 모델, 지시사항, 현재 상태, 어떤 Tool을 사용하는지 등 여러 가지 정보를 확인할 수 있습니다.

Run(id='run_6a4NDnp6Y5fPlyE2Ts5uvhoD', assistant_id='어시스턴트의 ID', cancelled_at=None, completed_at=None, created_at=1702591061, expires_at=1702591661, failed_at=None, file_ids=[], instructions='Please address the user as Kudos IT Daily. The user has a premium account.', last_error=None, metadata={}, model='gpt-4-1106-preview', object='thread.run', required_action=None, started_at=None, status='queued', thread_id='thread_RfaxjUOy00YlzP0rqPQVCduO', tools=[ToolAssistantToolsCode(type='code_interpreter')])

 

 

이후, retrieve 함수를 수행해서, run의 실행결과를 확인해 보도록 하겠습니다. 우리가 run을 생성하자마자 모든 결과가 처리되는 것은 아닙니다. 어시스턴트가 요청받은 결과를 처리하는 데, 시간이 소요되기 때문에 retrieve를 통해 우리 요청이 정상 처리되었는지 확인하는 과정이 필요합니다. retrieve 과정을 수행할 때, 어떤 스레드에서 수행되고 있는지, 우리가 수행했던 run의 ID는 무엇인지 입력해야 합니다.

 

run = client.beta.threads.runs.retrieve(
  thread_id=thread.id,
  run_id=run.id
)
print(run)

 

 

retrieve를 수행한 결과, 현재 상태(status)가 완료 상태(completed)로 변경된 것을 확인할 수 있습니다. 우리가 요청한 결과가 정상 처리된 것 같네요. 이제, 저희가 첫 번째로 전달한 메시지 처리는 완료된 것 같습니다.

Run(id='run_6a4NDnp6Y5fPlyE2Ts5uvhoD', assistant_id='어시스턴트의 ID', cancelled_at=None, completed_at=1702591081, created_at=1702591061, expires_at=None, failed_at=None, file_ids=[], instructions='Please address the user as Kudos IT Daily. The user has a premium account.', last_error=None, metadata={}, model='gpt-4-1106-preview', object='thread.run', required_action=None, started_at=1702591061, status='completed', thread_id='thread_RfaxjUOy00YlzP0rqPQVCduO', tools=[ToolAssistantToolsCode(type='code_interpreter')])

 

 

처리 결과 확인하기

어시스턴트, 스레드를 생성하고, 요청사항을 메시지에 작성 후, 실행하고, 처리가 완료된 것을 확인했습니다. 이제 처리된 결과를 출력해서 확인해 볼까요? 스레드 ID 정보를 입력해서 스레드 내부에 생성된 메시지 리스트를 가져오도록 하겠습니다.

 

messages = client.beta.threads.messages.list(
  thread_id=thread.id
)
print(messages)

 

 

한눈에 보기에는 불편하지만 리스트 내부에 사용자의 역할과 요청사항, 어시스턴트의 역할과 답변 등이 포함되어 있는 것을 볼 수 있습니다. 이를 보기 편하게 수정하는 작업을 진행해 보겠습니다.

SyncCursorPage[ThreadMessage](data=[ThreadMessage(id='msg_C2mFA4gmDsvBCHDf1KA8oNrv', assistant_id='어시스턴트의 ID', content=[MessageContentText(text=Text(annotations=[], value='The solution to the equation \\( 3x + 11 = 14 \\) is \\( x = 1 \\).'), type='text')], created_at=1702591080, file_ids=[], metadata={}, object='thread.message', role='assistant', run_id='run_6a4NDnp6Y5fPlyE2Ts5uvhoD', thread_id='thread_RfaxjUOy00YlzP0rqPQVCduO'), ThreadMessage(id='msg_0FOJ5w4vyjxF3WHh4JeAWO1U', assistant_id=None, content=[MessageContentText(text=Text(annotations=[], value='I need to solve the equation `3x + 11 = 14`. Can you help me?'), type='text')], created_at=1702590513, file_ids=[], metadata={}, object='thread.message', role='user', run_id=None, thread_id='thread_RfaxjUOy00YlzP0rqPQVCduO')], object='list', first_id='msg_C2mFA4gmDsvBCHDf1KA8oNrv', last_id='msg_0FOJ5w4vyjxF3WHh4JeAWO1U', has_more=False)

 

 

메시지 리스트 안에는 사용자가 생성한 메시지, 어시스턴트가 생성한 메시지가 존재합니다. 우리가 대화를 진행할수록 메시지가 스택(Stack)처럼 차곡차곡 쌓이게 되는데요. 리스트를 순회하면서 메시지를 확인하면 순서가 반대로 되어 있습니다. 따라서, 전체 메시지의 순서를 역순으로 전환한 후, 메시지 내용을 출력해 보도록 하겠습니다.

 

messages = list(messages)
messages.reverse()

for message in messages:
  if message.role == 'assistant':
    print(f"어시스턴트: \n{message.content[0].text.value}")
  elif message.role == 'user':
    print(f"사용자: \n{message.content[0].text.value}")

 

 

메시지 리스트 내부를 확인해 보니, 저희가 생성한 질문, 그에 대한 답변이 잘 생성된 것을 확인할 수 있습니다.

사용자:
I need to solve the equation `3x + 11 = 14`. Can you help me?
어시스턴트:
The solution to the equation \( 3x + 11 = 14 \) is \( x = 1 \).

 

 

마치며

지난 시간에 Assistants API를 Playground에서 사용해 봤다면, 이번 시간에는 파이썬 코드를 통해 어시스턴트를 생성하고, 질문을 하는 과정을 진행했습니다. Assistants API를 사용하기 위해 알아야 하는 핵심 기능에 대해 간략하게 설명드리면서 코드를 하나씩 작성해 봤는데요. 코드를 차근차근 따라오셨다면 의외로 간단하게 어시스턴트를 구성할 수 있다는 것을 알 수 있습니다.

 

이제 Assistants API의 기본 기능을 확인했으니, 앞으로 여러 분야에 적용해 보는 일만 남았습니다. 앞으로 진행되는 포스팅에서는 Assistants API를 더 심도 있게 활용해서 도움이 되는 다양한 어시스턴트를 만들어보도록 하겠습니다. 오늘 포스팅이 도움이 되셨기를 바라면서 글 마치도록 하겠습니다. 고맙습니다.

반응형