GPT API 적용해보기

JIWOO YUN·2023년 7월 17일
0
post-thumbnail

팀프로젝트에서 서술형 정답 체크 부분에 대해서 이야기를 나누다가 키워드 매칭으로 단순하게 하는 것보단 ai채점까지 추가해서 하는게 좋을 거 같다는 의견을 받고 gpt api를 적용해보았다.

GPT API 적용하기

GPT API를 처음 사용하게되면서 처음에 방법에 대해 이해하는데 꽤 걸렸는데 다른 분이 사용한 것을 보고나니 많이 이해됬습니다.

https://waveofmymind.github.io/posts/springboot+chatgpt/ (설명을 잘 적어주셔서 따라하시면 금방 이해 될거라고 생각합니다.)

  1. GPT API 사이트에서 회원 가입을 진행하거나 이미 있는 구글 계정을 연결합니다.
  2. GPT API에서 내 정보를 들어 간 뒤 API keys를 가게되면 create new secrectKey가 존재하게 되는데 그걸 누르면 이름을 작성하면 시크릿키가 하나 생성됩니다. 주의점으로는 시크릿키 창을 끄게 되면 다시는 볼수 없습니다! → 무조건 안전한 곳에 복사를 해두는 것을 추천합니다. 아니면 저처럼 처음에 만들고 복사를 안해놔서 시크릿키를 다시만드는 참사가 발생할 수 있습니다.

  1. 결제 카드를 등록합니다. → 결제 카드를 등록하지 않으면 사용이 불가능합니다.
  2. https://platform.openai.com/docs/libraries/community-libraries 외부 라이브러리를 현재 자신이 사용하고 있는 언어에 맞춰서 넣어줍니다.
    1. 저희 프로젝트는 자바 스프링부트 이기 때문에 자바 라이브러리를 넣어줍니다.
    2. Gradle형식을 사용 중 이기 때문에 dependency에 넣어줍니다.
    3. 위에는 api이고 밑에는 service를 사용하는건데 service를 사용할 경우 빠르게 사용이 가능하다고 해서 받아줬습니다.

  1. 일반적으로 외부라이브러리를 사용시 Config같은걸 안만들어도 사용이 가능하지만 bean에 등록해서 사용하기 위해서 gpt Config를 추가해서 bean에 등록

  1. gpt 3.5버전부터는 chat Completion만 제공해줍니다.(Completions에서 향상된 버전)

    1. 다이얼로그로 남아서 학습이 가능하다.
    2. 둘의 차이에 대해서 물어본것을 대답해준 stackoverflow
    3. https://stackoverflow.com/questions/76192496/openai-v1-completions-vs-v1-chat-completions-end-points
  2. gptService 생성

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.theokanning.openai.completion.chat.ChatCompletionRequest;
    import com.theokanning.openai.completion.chat.ChatCompletionResult;
    import com.theokanning.openai.completion.chat.ChatMessage;
    import com.theokanning.openai.completion.chat.ChatMessageRole;
    import com.theokanning.openai.service.OpenAiService;
    import com.twenty.inhub.base.appConfig.GptConfig;
    import com.twenty.inhub.boundedContext.answer.controller.dto.AnswerDto;
    import com.twenty.inhub.boundedContext.answer.controller.dto.QuestionAnswerDto;
    import com.twenty.inhub.boundedContext.gpt.dto.GptResponseDto;
    import io.micrometer.core.annotation.Timed;
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Slf4j
    @Service
    @RequiredArgsConstructor
    @Timed(value = "gpt.service")
    public class GptService {
    
        private final OpenAiService openAiService;
        private final ObjectMapper objectMapper;
    
        public ChatCompletionResult generated(List<ChatMessage> chatMessages) {
    
    				//기본적으로 라이브러리에서 제공해주는 틀
            ChatCompletionRequest build = ChatCompletionRequest.builder()
                    .messages(chatMessages)
                    .maxTokens(GptConfig.MAX_TOKEN)
                    .temperature(GptConfig.TEMPERATURE)
                    .topP(GptConfig.TOP_P)
                    .model(GptConfig.MODEL)
                    .build();
    
            return openAiService.createChatCompletion(build);
        }
    
    		//gpt에게 물어볼 메세지 생성
        public List<ChatMessage> generatedQuestionAndAnswerMessage(QuestionAnswerDto questionAnswerDto) {
            String prompt = Prompt.generateQuestionPrompt(questionAnswerDto.getContent(), questionAnswerDto.getAnswer());
    
            log.info("생성된 프롬프트 : {}", prompt);
    
            ChatMessage userMessage = new ChatMessage(ChatMessageRole.USER.value(), prompt);
    
            return List.of(userMessage);
        }
    
    		//메세지를 물어보고 답변을 위한 툴
    		//GptResponseDto는 gpt에게 받은 데이터를 json으로 파싱한 값을 받아서 전달하기위해서 만들었습니다.
        public GptResponseDto askQuestion(QuestionAnswerDto questionAnswerDto) {
            List<ChatMessage> chatMessages = generatedQuestionAndAnswerMessage(questionAnswerDto);
            ChatCompletionResult result = generated(chatMessages);
    
            String gptAnswer = result.getChoices().get(0).getMessage().getContent();
            log.info("GPT 답변: {}", gptAnswer);
            // JSON 문자열을 파싱하여 결과 값을 추출
            try {
                JsonNode jsonNode = objectMapper.readTree(gptAnswer);
                String score = jsonNode.get("score").asText();
                String feedback = jsonNode.get("feedback").asText();
    
                log.info("점수 : {}",score);
                log.info("피드백 : {}",feedback);
    
                // 결과를 담을 GptResponseDto 객체 생성
                GptResponseDto response = new GptResponseDto();
                response.setScore(Double.parseDouble(score));
                response.setFeedBack(feedback);
    
                return response;
            } catch (JsonProcessingException e) {
                log.error("Error parsing GPT response JSON: {}", e.getMessage());
                return null;
            }
        }
    
    }
  3. Prompt 생성

    1. GPT에게 물어볼 메세지 prompt를 만들어둡니다.
package com.twenty.inhub.boundedContext.gpt;

public class Prompt {
    //학습 시킬 형식
    public static String generateQuestionPrompt(String Question,String Answer){
        String prompt= """
                I'll give you questions and answers.
                                
                question : %s
                                
                answer : %s
                                
                Now, please grade the answers to the questions on a 100-point scale.
                                
                If you want to give feedback, please keep it in korean as short as possible (3 lines or less).
                                
                Also, if the answer doesn't make much sense, give it a 0.
                                
                Finally, when you respond to me, respond in JSON format below.
                                      
                                
                {
                    "score" : "",
                    "feedback" : ""
                }
                """;

        return String.format(prompt,Question,Answer);
    }
}

이렇게 만들어 두면 Controller에서 gptService를 생성자로 받아두면 사용이 가능해집니다.

외부 라이브러리를 사용하기 때문에 속도가 살짝 느리긴합니다.

profile
열심히하자

2개의 댓글

comment-user-thumbnail
2023년 7월 18일

잘 읽었습니다. 좋은 정보 감사드립니다.

답글 달기
comment-user-thumbnail
2025년 4월 7일

안녕하세요! 글 너무 잘 읽었습니다 🙌
GPT API 기반 자동 채점 로직과 프롬프트 설계까지 직접 구현하신 과정이 정말 인상 깊네요.
저희도 현재 AI 기반 기술 튜토리얼 플랫폼 Insty를 만들고 있는데,
러너의 설치 흐름을 돕는 GPT 챗봇, 영상 추천, 자동 태깅 등 다양한 AI 기능을 API 기반으로 직접 설계/연동하고 있습니다.

작성하신 경험이 저희 팀에서 고민하고 있는 방향과 정말 잘 맞는다고 느꼈고,
혹시 괜찮으시다면 편하게 커피챗 한 번 나눌 수 있을까요?
사이드 프로젝트이지만 진심으로 재미있게 달리고 있어요 :)

holaworld 게시글 링크: https://holaworld.io/study/67f30444f675c05ce9c28316

궁금하시다면 instyhelp@gmail.com 이나
오픈채팅 https://open.kakao.com/o/siI0EBoh 통해 편하게 연락 주세요!
감사합니다!

답글 달기