뭐요

OpenAI GPT 모델을 활용한 추천 문구 작성 본문

Etc

OpenAI GPT 모델을 활용한 추천 문구 작성

욕심만 많은 사람 2023. 9. 3. 01:16

공식 지원 언어

OpenAI에서 공식적으로 지원해주는 라이브러리는 Python, Node.js밖에 없다. 공식적으로 지원하지는 않지만 다른 개발자들이 만들어놓은 라이브러리 중 OpenAI가 검토한 언어별 라이브러리가 존재한다.

(OpenAI의 document 참고)

Theo Kanning이 개발한 자바 라이브러리를 사용할지, 공식적으로 지원하는 Python 라이브러리를 사용하기 위해 AWS Lambda를 활용할지 고민을 했다.

고민을 하는 데에 있어서 가장 중요한 부분은 라이브러리의 안정성이다. Python을 사용하는 경우 공식적으로 지원하는 라이브러리이기 때문에 라이브러리의 안정성은 좋을 것이라고 생각했다. 하지만 불필요하게 AWS Lambda, AWS Gateway 등 써드 파티 서비스를 활용을 하는 것을 지양하고 싶었다. (물론 ChatGPT AI 모델을 사용하는 것 자체는 어쩔 수 없다.)

개발의 편의성을 위해 자바 라이브러리를 사용하고자, 나름대로 선정 기준을 세워보았다.

(전자를 Python, 후자를 Java라고 하겠다)

라이브러리 선정의 고민

1. 지속적으로 지원하는가?

전자의 경우에는 공식 라이브러리이기 때문에 지속적으로 지원이 보장된다고 할 수 있다. 하지만 후자의 경우는 지속적일지는 미지수이다.

2. 충분히 빠른가?

전자의 경우와 후자의 경우가 코드 자체만으로는 성능이 유사하다고 할 수 있었다. 다만 파이썬을 사용하는 경우에는 AWS Lambda를 사용할 계획인데, AWS Lambda가 다소 느리고, Cold Start할 수 있기 때문에 전자의 경우가 훨씬 느릴 수 있다고 판단했다.

3. 얼마나 빠르게 도입 가능한가?

프로젝트 마감을 위해 충분한 시간이 없다. 두 방법 모두 도입해보고 직접 적용해보면 좋겠지만, 시간이 없기 때문에 하나의 방법을 선택한다면 철회할 수 없을 것이라 판단했다. 그렇기 때문에 더 충분한 고민이 필요했다.

아마도 후자의 경우가 도입을 하는 데는 훨씬 빠를 거라고 생각한다.

4. 라이브러리의 안정성

전자의 경우는 OpenAI가 공식적으로 지원하기 때문에 의심의 여지가 없지만, 후자의 경우에는 안정성을 보장할 수 없다. 하지만 충분한 사용자에 의해 테스트 되었다고 생각해서 전자, 후자 모두 안정적이라고 판단했다.

막상막하다.. 어쩔 수 없이 둘 다 사용해보도록 하자

Java 활용

implementation 'io.github.flashvayne:chatgpt-spring-boot-starter:1.0.4'

다음 코드를 삽입해 gradle에 의존성을 추가했다. 이후 ChatGptService 객체를 생성해서 간단하게 sendMessage()를 하면 gpt 모델을 사용할 수 있다.

아무런 설정없이 위와 같이 코드를 작성해서 실행해보니 해당 API를 날리면 약 10초가 걸렸다. 문장 요약을 위해서 chatGPT 모델을 활용하는데 10초 이상 걸리는 것은 너무 오버헤드가 컸다.

2023-08-24 13:34:50.051  INFO 64514 --- [nio-8080-exec-1] c.s.caart.global.config.LoggingConfig    : [LifeStyleService.getRecommendationByLifestyle(RecommendationRequest)] FINISH // Return(RecommendationResponse) : {"palisadeImage":"https://caart-app-s3-bucket.s3.ap-northeast-2.amazonaws.com/image/palisade.png","model":{"modelName":"펠리세이드","modelPrice":54910000,"trim":{"trimName":"Calligraphy","trimPrice":51060000},"engine":{"engineName":"디젤 2.2","enginePrice":1480000},"wheelDrive":{"wheelDriveName":"4WD","wheelDrivePrice":2370000},"bodyType":{"bodyTypeName":"7인승","bodyTypePrice":0}},"colors":[],"options":[{"optionImage":"https://caart-app-s3-bucket.s3.ap-northeast-2.amazonaws.com/image/option/additional/110.jpg","optionName":"적외선 무릎워머","optionPrice":300000,"recommendationMessage":"보면 \u0027무릎에 편안함을 주는 최상의 차량 옵션을 경험해보세요., 추운 날씨에도 무릎은 항상 따뜻한 상태를 유지할 수 있게 해줍니다. 건강까지 지켜주는 놀라운 옵션을 경험해보세요. 겨울 운전 중 저체온증을 예방해주며 더 이상 거친 바람의 위협에서 벗어날 수 있게 해줍니다. 기분 좋은 따뜻한 운전을 해보세요. 해요!"},{"optionImage":"https://caart-app-s3-bucket.s3.ap-northeast-2.amazonaws.com/image/option/additional/115-2.jpg","optionName":"20인치 블랙톤 전면 가공 휠","optionPrice":840000,"recommendationMessage":" 라고 묻는다면 스타일과 안정성을 강조하는 20인치의 블랙톤 전면 가공 휠은 도시의 스트릿과 고속도로에서 빛나는 스타일로 선택해줘요."}],"totalPrice":56050000}
2023-08-24 13:34:50.052  INFO 64514 --- [nio-8080-exec-1] c.s.caart.global.config.LoggingConfig    : EXECUTION TIME : 11596 ms
2023-08-24 13:34:50.054  INFO 64514 --- [nio-8080-exec-1] c.s.caart.global.config.LoggingConfig    : [LifeStyleController.getRecommendation(RecommendationRequest)] FINISH // Return(ResponseDto) : {"data":{"palisadeImage":"https://caart-app-s3-bucket.s3.ap-northeast-2.amazonaws.com/image/palisade.png","model":{"modelName":"펠리세이드","modelPrice":54910000,"trim":{"trimName":"Calligraphy","trimPrice":51060000},"engine":{"engineName":"디젤 2.2","enginePrice":1480000},"wheelDrive":{"wheelDriveName":"4WD","wheelDrivePrice":2370000},"bodyType":{"bodyTypeName":"7인승","bodyTypePrice":0}},"colors":[],"options":[{"optionImage":"https://caart-app-s3-bucket.s3.ap-northeast-2.amazonaws.com/image/option/additional/110.jpg","optionName":"적외선 무릎워머","optionPrice":300000,"recommendationMessage":"보면 \u0027무릎에 편안함을 주는 최상의 차량 옵션을 경험해보세요., 추운 날씨에도 무릎은 항상 따뜻한 상태를 유지할 수 있게 해줍니다. 건강까지 지켜주는 놀라운 옵션을 경험해보세요. 겨울 운전 중 저체온증을 예방해주며 더 이상 거친 바람의 위협에서 벗어날 수 있게 해줍니다. 기분 좋은 따뜻한 운전을 해보세요. 해요!"},{"optionImage":"https://caart-app-s3-bucket.s3.ap-northeast-2.amazonaws.com/image/option/additional/115-2.jpg","optionName":"20인치 블랙톤 전면 가공 휠","optionPrice":840000,"recommendationMessage":" 라고 묻는다면 스타일과 안정성을 강조하는 20인치의 블랙톤 전면 가공 휠은 도시의 스트릿과 고속도로에서 빛나는 스타일로 선택해줘요."}],"totalPrice":56050000},"success":true,"statusCode":200,"message":"Success"}

ChatgptProperties 객체에 model이라는 field가 있었고, 여러 model이 존재한다는 것을 알게 되어 이 model을 본 프로젝트의 목적에 맞게 변경해야겠다고 생각했다.

위 사진에서 보다시피, ChatGptService에서 사용하는 model은 text-davinci-003 이다. 공식 문서에서 확인해본 결과 해당 model은 현재 Legacy 버전이다. 오히려 다행이라고 생각했다… model을 변경하면 속도가 빨라지길 기대한다.

model을 못바꾼다. DeafultChatGptService 밖에 만들 수 없고 해당 객체는 model이 Legacy 버전의 text-davinci-003로 고정이다.

AWS Lambda와 Python의 공식 라이브러리를 활용해야겠다.

Python을 활용

1. API Key 발급

https://platform.openai.com/overview

2. OpenAI Python package 설치

pip install openai --target <<local path>>

3. Labmda Layer 생성

4. 람다 함수 생성

5. API Key 등록

6. OpenAI 결제 정보 등록

RateLimitError가 발생해서 한참 삽질했다.. 원인은 카드 결제 정보를 등록하지 않아서이다. 결제 정보를 등록하면서 기본적으로 5 달러 이상을 선결제해야한다. 내돈..!

7. 코드 작성

일단 테스트를 위해 document에 존재하는 예시 코드를 활용해서 다음과 같이 작성했다.

import json
import openai
import boto3

def lambda_handler(event, context):
    
    model_to_use = "text-davinci-003"
    reasons = ["블랙톤 휠은 높은 부하에도 안정적인 주행을 보장합니다.", "N 퍼포먼스는 차량 부품의 품질에서 타협하지 않습니다.", "최신 기술력과 디자인이 결합된 완벽한 차량 옵션입니다.", "블랙톤 휠은 차량의 드라이브 편의성을 높여줍니다.", "N 퍼포먼스의 기술력은 세계 최고 수준입니다.", "블랙톤 휠은 차량의 스타일을 업그레이드 시켜줍니다.", "브레이크의 반응성이 뛰어나, 빠른 제동이 가능합니다.", "믿을 수 있는 N 퍼포먼스의 기술력이 담긴 브레이크와 휠입니다.", "알콘 브레이크는 최고의 부품 재료로 제작되었습니다.", "알콘 브레이크는 급제동 시에도 안정적입니다.", "알콘 브레이크는 제동시 덜한 소음으로 조용한 주행을 가능하게 합니다.", "차량의 전반적인 외관을 향상시키는 블랙톤 휠입니다.", "알콘 브레이크는 운전자의 안전을 최우선으로 합니다.", "안정성과 스타일을 동시에 추구하는 운전자에게 최적의 선택입니다.", "알콘 브레이크는 제동시 덜한 소음으로 조용한 주행을 가능하게 합니다.", "20인치 블랙톤 전면 가공 휠은 차량의 고급스러움을 강조합니다.", "믿음직한 브레이크와 세련된 휠 디자인의 완벽한 조합입니다.", "알콘 단조 브레이크와 20인치 블랙톤 휠은 차량의 완성도를 한 단계 높여줍니다.", "알콘 단조 브레이크는 우수한 내구성을 자랑합니다.", "알콘 브레이크는 최고의 부품 재료로 제작되었습니다.", "N 퍼포먼스는 차량 부품의 품질에서 타협하지 않습니다.", "블랙톤 휠은 도로의 여러 조건에서도 안정적인 주행을 보장합니다.", "긴급 상황에서도 믿을 수 있는 알콘 브레이크입니다.", "알콘 브레이크는 유지 보수가 쉽습니다.", "N 퍼포먼스는 차량 부품의 품질에서 타협하지 않습니다.", "알콘 브레이크는 세밀한 조정이 가능해 제동감이 좋습니다.", "믿을 수 있는 N 퍼포먼스의 기술력이 담긴 브레이크와 휠입니다.", "성능과 스타일, 두 마리 토끼를 다 잡는 패키지입니다.", "알콘 브레이크는 고속 주행에서도 안정적인 성능을 보여줍니다.", "차량의 완성도를 높여주는 휠 패키지입니다.", "알콘 브레이크는 유지 보수가 쉽습니다.", "알콘 단조 브레이크는 우수한 내구성을 자랑합니다.", "N 퍼포먼스의 노하우가 담긴 이 패키지는 강력히 추천됩니다.", "20인치 블랙톤 휠은 독특한 디자인을 자랑합니다.", "알콘 브레이크는 운전자의 안전을 최우선으로 합니다.", "알콘 브레이크는 안정적인 제동력을 제공합니다.", "블랙톤 휠은 차량의 스포티한 면모를 강조합니다.", "블랙톤 휠은 뛰어난 내구성을 가지고 있습니다.", "믿음직한 브레이크와 세련된 휠 디자인의 완벽한 조합입니다.", "믿음직한 브레이크와 세련된 휠 디자인의 완벽한 조합입니다.", "블랙톤 휠은 도로의 불규칙성을 잘 흡수합니다.", "블랙톤 휠은 다양한 도로 조건에 대응할 수 있습니다.", "블랙톤 휠은 차량의 스포티한 면모를 강조합니다.", "알콘 브레이크는 고속 주행에서도 안정적인 성능을 보여줍니다.", "블랙톤 휠은 도로의 불규칙성을 잘 흡수합니다.", "알콘 브레이크는 계절, 기후와 관계없이 안정적인 성능을 보장합니다.", "20인치 블랙톤 전면 가공 휠은 차량의 고급스러움을 강조합니다.", "20인치 블랙톤 휠은 운전자의 개성을 드러내줍니다.", "블랙톤 휠은 오랜 시간 동안 변색이나 손상 걱정이 없습니다.", "알콘 브레이크는 빠르게 냉각되어 오버히트 걱정이 없습니다.", "20인치 블랙톤 휠은 차량의 라인을 더욱 돋보이게 합니다.\n"]
    input_prompt = ' '.join(reasons) + " 위 문장을 고객에게 추천하듯이 정확히 하나의 문장으로 요약하고 '요'자로 끝나게 만들어줘"
    

    
    openai.api_key = "???"
    response = openai.ChatCompletion.create(
      # 사용 모델
      model=model_to_use,
      # 전달 메세지
      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": input_prompt}
        ]
    )
    print(response)
    return {
        'statusCode':200,
        'body': {
            'response' : response.choices[0].message.content
        }
    }

Lambda를 호출하면 다음과 같이 gpt가 대답한다. 생각보다 멍청한 거 같아서 큰일이다. 좀 더 목적에 맞게 커스텀해야 한다.

{
  "statusCode": 200,
  "body": {
    "response": "블랙톤 휠은 높은 부하에도 안정적인 주행을 보장하며, N 퍼포먼스는 품질에서 타협하지 않는 완벽한 차량 옵션입니다. 차량의 스타일을 업그레이드 시키는데 도움이 되며, 브레이크의 반응성이 뛰어나 빠른 제동을 가능케 합니다. 알콘 브레이크는 최고의 부품 재료로 제작되어 급제동 시에도 안정적이며, 조용한 주행을 할 수 있습니다."
  }
}

위 코드에서 보면 gpt-3.5 모델을 사용한다. gpt-4 모델을 사용하면 좀 더 똑똑하지 않을까? 프로젝트 발표가 얼마 안남은 시점에서 빠르게 해결하고싶었다. 돈은 아깝지 않았다…😥

{
  "statusCode": 200,
  "body": {
    "response": "블랙톤 휠과 N 퍼포먼스, 그리고 알콘 브레이크는 높은 부하에도 안정적이고 품질에서 타협하지 않는 최고 수준의 기술력으로 주행 편의성과 스타일을 높이며, 빠르고 안정적인 제동력과 조용한 주행 경험을 제공해요."
  }
}

확실히 더 똑똑한 거 같다

그렇지만 약 9초가 걸린다. Lambda가 Cold Start 하는 경우 호출 시간이 1초는 더 늘어날 것이다..

REPORT RequestId: f707a555-9505-41a1-bd3f-444fb9b69a97	Duration: 9751.28 ms	Billed Duration: 9752 ms	Memory Size: 128 MB	Max Memory Used: 75 MB	Init Duration: 646.71 ms

최종적으로 아래 코드로 Lambda 함수를 구현했고 정상 동작하는 것을 확인했다.

import json
import openai
import boto3

def lambda_handler(event, context):
    # print("event")
    # print(event)
    
    reasons = ["(블랙톤 휠은 높은 부하에도 안정적인 주행을 보장합니다.", "N 퍼포먼스는 차량 부품의 품질에서 타협하지 않습니다.", "최신 기술력과 디자인이 결합된 완벽한 차량 옵션입니다.", "블랙톤 휠은 차량의 드라이브 편의성을 높여줍니다.", "N 퍼포먼스의 기술력은 세계 최고 수준입니다.", "블랙톤 휠은 차량의 스타일을 업그레이드 시켜줍니다.", "브레이크의 반응성이 뛰어나, 빠른 제동이 가능합니다.", "믿을 수 있는 N 퍼포먼스의 기술력이 담긴 브레이크와 휠입니다.", "알콘 브레이크는 최고의 부품 재료로 제작되었습니다.", "알콘 브레이크는 급제동 시에도 안정적입니다.", "알콘 브레이크는 제동시 덜한 소음으로 조용한 주행을 가능하게 합니다.)"]
    input_prompt = ' '.join(reasons) + " 괄호 안에 문장을 고객에게 추천하듯이 정확히 하나의 문장으로 요약해줘. 대신 '해요'로 문장이 끝나야하고 30자 이내로 요약해줘"
    
    openai.api_key = "???"
    response = openai.ChatCompletion.create(
      # 사용 모델
      model="gpt-4",
      # 전달 메세지
      messages=[
            {"role": "assistant", "content": input_prompt}
        ]
    )
    print(response)
    return {
        'statusCode':200,
        'body': {
            'response' : response.choices[0].message.content
        }
    }

마무리

당장 성능은 크게 신경쓰지 않도록 했다. 하나의 문장으로 요약하는 데 9초가 걸리는 것은 꽤나 큰 오버헤드이다. 사용 여부를 재검토하는 중인데 인공지능에 대한 지식이 얕기 때문에 좀 더 학습해보고 최적화가 가능한지 판단해야하겠다~~

'Etc' 카테고리의 다른 글

Ubuntu time zone 변경 명령어  (0) 2023.10.26
SSH 편하게 접속하기 (feat. Host)  (0) 2023.10.26
Github 위키 꾸미기  (0) 2023.07.16