본문 바로가기
Spring

스프링에서 gpt api 사용해보기

by 이숴 2024. 1. 16.
반응형

프로젝트에서 ai 활용을 하는 기능을 개발하게 되었습니다.

따라서 gpt api를 활용하기 전 먼저 api가 어떻게 되어있는지 테스트를 진행해보았습니다.

 

스프링에서 지원하는 spring ai api가 있긴했지만 사용하기가 어려워서 직접 http를 전송하는 것으로 시도해보았습니다.

 

사용법은 비교적 간단했습니다. openai 서버 endpoint에 개인별 api-key를 헤더에 추가하여 인증을 하고, 모델을 정해서 메세지를 보내기만 하면 됩니다.

 

Gpt 모델에 메세지는 다음 2가지의 형식으로 보내게 됩니다.

# 단순 메세지만 전송
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'
  
  # 옵션을 설정하여 메세지를 같이 전송
  {
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "model": "gpt-3.5-turbo-0613",
  "system_fingerprint": "fp_44709d6fcb",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "\n\nHello there, how may I assist you today?",
    },
    "logprobs": null,
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

위 명령어에 맞게 형식을 맞춰서 http 요청을 보내면 response를 받을 수 있습니다.

 

openai 서버로 보낼 restTemplate 만들기

먼저 http 요청을 보내기 위해선 restTemplate이 필요합니다. 따라서 restTemplate을 설정할 config 파일을 생성해줘야합니다.

@Configuration
public class GptConfig {

    @Value("${gpt.api-key}")
    private String apiKey;

    @Bean
    public RestTemplate restTemplate(){
        RestTemplate template = new RestTemplate();
        template.getInterceptors().add((request, body, execution) -> {
            request.getHeaders().add(
                    "Authorization"
                    ,"Bearer " + apiKey);
            request.getHeaders().setContentType(APPLICATION_JSON);
            return execution.execute(request, body);
        });

        return template;
    }
}

 

gpt 서버에 보내기 위해선 인증키가 헤더에 포함되어야하기 때문에 개인 api key가 필요한데요. 본인의 api 키는 https://platform.openai.com/api-keys 에서 생성하시면 됩니다.

api-key

 

전송 request 생성

request안에 데이터

스프링에서는 json 구조를 dto를 생성해서 보내면 간단히 구조를 만들 수 있습니다.

@Getter
public class GptRequestDto {

    private String model;           // 모델명
    private List<Message> messages; // 질문들
    private float temperature;      // 답변 다양성
    private int max_tokens;         // 답변 최대 길이
    private int top_p;              // 답변 다양성
    private int frequency_penalty;  // 답변 중복 방지
    private int presence_penalty;   // 답변 중복 방지
}

@Getter
public class Message {

    private String role;
    private String content;
}

저는 다음과 같은 구조로 request 객체를 만들었습니다.

 

 

model과 messages이외에 다른 옵션은 필요하지 않았지만, 이후 옵션 테스트를 해보고 싶어 추가해 두었습니다.

각각 옵션의 설명을 하겠습니다.

  • model: 사용할 모델의 ID입니다. 모델의 종류는 https://platform.openai.com/docs/models 여기서 찾아보실 수 있습니다.
  • messages: gpt 모델에게 물어볼 메세지 내용입니다. messages 객체가 list인 이유는 누적된 대화를 가져올 수 있게 하기 위함입니다.
  • temperature: 값이 높을수록 출력이 더 무작위로 만들어지고, 값이 낮을수록 더 집중적이고 결정적이게 됩니다.
  • max_tokens: 채팅 완료 시 생성할 수 있는 최대 토큰 수입니다. 반환 메세지의 길이를 제한합니다.
  • top_p: 값이 높을수록 생성된 텍스트의 다양성이 증가합니다.
  • frequency_penalty: 모델이 같은 단어나 구를 반복하는 것을 억제합니다. 높은 값은 모델이 동일한 내용을 반복하는 것을 더 많이 피하도록 합니다. 일반적으로 값이 1이상이면 이상한 값을 도출하기 때문에 0으로 설정하고 진행한다고 합니다.
  • presence_penalty: 모델이 이미 언급된 단어나 구를 다시 사용하는 것을 억제하는 데 사용됩니다. 위 옵션과 유사하지만 단어의 존재 여부에 좀 더 중점을 두고 연산되는 옵션입니다.

role은 대화 상황에서 각 메시지가 어떤 역할을 하는지를 나타내는 것입니다. 이는 대화형 시나리오에서 메시지의 맥락을 이해하는 데 도움을 줍니다.

 

 

메세지 전송

이렇게 생성된 request는 다음과 같이 사용됩니다.

public GptResponseDto chat(String model, String prompt, String endpointCharged) {
        List<Message> prompts = List.of(
                new Message("user", prompt));
        GptRequestDto request = new GptRequestDto(model, prompts, 1, 256, 1, 0, 0);

        // OpenAI server로 restTemplate을 통해 request를 보내고 response를 받는다.
        GptResponseDto gptResponse = restTemplate
        			.postForObject(endpointCharged, request, GptResponseDto.class);
        if (gptResponse != null) {
            return gptResponse;
        } else {
            throw new RuntimeException("Error parsing response from OpenAI Server");
        }
    }

메소드에서 입력받는 각 파라미터를 말씀드리겠습니다.

 

model: 사용할 GPT 모델을 지정합니다. 여기에는 gpt-3.5, gpt-3.5-turbo, gpt-4 등이 올 수 있습니다. 이는 모델의 성능과 특징에 따라 선택됩니다.
prompt: 사용자 또는 시스템이 모델에게 보내는 메시지 내용입니다. 이 입력값에 기반하여 모델이 응답을 생성합니다.
endpointCharged: GPT 서비스를 제공하는 서버의 API 엔드포인트 주소입니다. 이 주소는 요청을 보내고 응답을 받는 데 사용됩니다.

 

 

이제 이 입력값들을 request 객체로 감싸고 RestTemplate를 사용하여 GPT 서버로 요청을 보내게됩니다.

 

만약 여기서 요청을 받아온다면 GptResponseDto 객체로 매핑이 되고, 어떠한 문제가 발생한다면 예외를 발생시키도록 작성했습니다.

 

GptResponse는 다음과 같은 형태입니다.

각 필드별 설명은 https://platform.openai.com/docs/guides/text-generation/json-mode 에 자세히 나와있습니다.

@Getter
public class GptResponseDto {

    private List<Choice> choices;
    private String id;
    private String model;
    private String object;
}

@Getter
public class Choice {

    private int index;
    private Message message;
}

 

이렇게 생성된 response는 다음의 형태로 받게 됩니다.

gpt 메세지 출력

 

 

그런데 쓰고 보니 글을 너무 두서없이 쓴 것같습니다..

제 레포에서 코드만 쏙 야무지게 뽑아가셔요!!

https://github.com/angelSuho/gptTest

 

GitHub - angelSuho/gptTest: gpt api를 실제 적용해보기전에 테스트를 진행하는 장소입니다.

gpt api를 실제 적용해보기전에 테스트를 진행하는 장소입니다. Contribute to angelSuho/gptTest development by creating an account on GitHub.

github.com

 

 

참고

https://platform.openai.com/docs/overview

https://platform.openai.com/docs/models

https://platform.openai.com/docs/api-reference

반응형

댓글