[CS] OPEN AI API로 간단한 메시지 보내고 받아보기

2025. 11. 19. 23:07·CS/백엔드

자바로 OpenAI API를 보내보려한다.

 

API키를 발급하려면 https://deepdaive.com/openai-api-key/

 

OpenAI API Key 발급 방법 (2025년) - DeepdAive

이번 포스팅에서는 OpenAI API Key를 발급 받는 방법을 소개하겠습니다.

deepdaive.com

이걸 참고하면된다. API 키를 발급받으면 결제창이 뜨는데 나중에 결제한다고하고 넘어갈 수 있다.

 

문제는 결제를하지 않고 넘어가면 요청을 보낼 수 없다. 최소 5달러는 결제해놓고 거기서 보내는 메시지에 따라 돈을 좀 차감하는 식으로 사용해야한다. 요즘 달러환율이 올라서 5달러에 세금 0.5달러해서 5.5달러, 8600원인가가 나갔다. 나 머플로 사야하는데


공식웹페이지의 코드를 보면서 치려고했는데, 버전도 안맞고 약간씩 오류가 있어서 블로그 몇 개를 참고해가며 다시 새로 쳤다.

 

원래는 이전에 간단하게나마 써봤던 WebClient로 요청을 보낼까했는데, RestTemplate로 요청을 보내는게 더 간편해서 그걸 사용하려한다.

 

package com.jamongsalguclub.RFR.Config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class OpenAiConfig {
    @Value("${openai.api.key}")
    private String apiKey;

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

}

그러므로 앞으로 보낼 RestTemplate을 사전설정하고 빈에 등록했다.

앞으로 생성자를 통한 호출이 아니라 스프링 컨테이너에서 RestTemplate를 주입받으면 이 RestTemplate를 주입받게되어 직접 하나하나 불편하게 설정파일을 만지지 않아도 된다.

 

저 코드가 실행되면 앞으로 스프링에서 주입받은 RestTemplate로 요청을 보내면 헤더에

Authorization="Bearer {{apikey}}"

이 추가되어 요청이 보내질 것이다. Bearer 뒤에 띄어쓰기 하나 추가해야하는거 중요!


요청보내기

package com.jamongsalguclub.RFR.ChatSendTest;

import com.jamongsalguclub.RFR.DTO.GPTRequest;
import com.jamongsalguclub.RFR.DTO.GPTResponse;
import com.jamongsalguclub.RFR.DTO.MessageDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ChatSendTest {
    @Value("${openai.bef.prompt}")
    private String befPrompt;

    @Value("${openai.model}")
    private String model;

    @Value("${openai.api.url}")
    private String apiUrl;

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("chat")
    public String chat(@RequestParam(name="prompt") String prompt) {
        GPTRequest request = new GPTRequest(model, prompt, befPrompt);
        GPTResponse response = restTemplate.postForObject(apiUrl, request, GPTResponse.class);
        return response.getChoices().get(0).getMessage().getContent();
    }
}

그리고 요청을 보내는 부분인데,


보낼 메시지 정리하기

한 줄씩 뜯어보면

GPTRequest request = new GPTRequest(model, prompt, befPrompt)

GPTRequest는 DTO이름이다.

 

package com.jamongsalguclub.RFR.DTO;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;

import java.util.ArrayList;
import java.util.List;

@Data
public class GPTRequest {

    private String model;
    private List<MessageDTO> messages;

    public GPTRequest(String model, String prompt, String befPrompt) {
        this.model = model;
        this.messages = new ArrayList<>();

        this.messages.add(new MessageDTO("system", befPrompt));
        this.messages.add(new MessageDTO("user", prompt));
    }
}

이렇게 모델이름과 보낼 메시지들을 정리한다.

befPrompt가 내가 application.properties에 저장하고있는 프롬프트고, prompt 변수가 실제 유저가 입력한 값이다.

package com.jamongsalguclub.RFR.DTO;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MessageDTO {
    private String role;
    private String content;
}

그리고 보낼 메시지의 실제 값은 MessageDTO에 저장되어있다.

content가 진짜 유저가 보낸 메시지고, role은 Chat-GPT에게 이 메시지가 어떤 특성을 지니고 있는지 알려준다.

 

GPT의 답변을 받는 일반메시지는 "user",

프롬프트 같이 사전설정 메시지는 "system",

GPT가 반환해주는 메시지는 "assistant" (아닐수도있음. 기억안남) 로 설정된다.

 

GPTRequest에서 메시지들이 리스트에 담아서 이동하는데, 여러 메시지를 받아도 GPT가 알아서 role 값과 메시지를 구분하여 답변한다.

 

    public GPTRequest(String model, String prompt, String befPrompt) {
        this.model = model;
        this.messages = new ArrayList<>();

        this.messages.add(new MessageDTO("system", befPrompt));		//사전 프롬프트 메시지를 넘김
        this.messages.add(new MessageDTO("user", prompt));		//실제 유저메시지
    }

그래서 생성자 부분을 보면 인스턴스 변수 model과 messages를 설정해 넘기는데, model은 어떤 모델을 사용할지 정하고, (아직 어느 모델을 사용할지 안정해져서 application.properties에서 받아서 사용 중이다.) messages에 MessageDTO를 여러 개 넘긴다.


요청 받기

GPTResponse response = restTemplate.postForObject(apiUrl, request, GPTResponse.class);

RestTemplate으로 요청을 보내고 요청을 받아온다. GPTResponse는 DTO이름이다.

 

package com.jamongsalguclub.RFR.DTO;

import lombok.*;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class GPTResponse {
    private List<Choice> choices;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Choice {
        private int index;
        private MessageDTO message;
    }
}

 

 

{
  "id": "chatcmpl-xxxx",
  "object": "chat.completion",
  "model": "gpt-4o-mini",
  "created": 123456789,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "GPT가 반환하는 내용"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 123,
    "completion_tokens": 456,
    "total_tokens": 579
  }
}

GPT에게 물어본 OpenAI API의 리턴예시이다. GPT가 메시지를 반환하면 여러 메타데이터와 함께 choices 부분에 반환메시지를 담아서 반환한다.

 

그래서 여기서 반환값을 받아 GPTResponse(DTO)에 저장하면 JSON 중 GPTResponse에서 정의하고있는 choice 부분만 JSON에서 GPTResponse로 매핑되게되고 나머지 부분은 버려진다.

이거는 Jackson(ObjectMapper)와 RestTemplate 덕분이라고한다. 나중에 이 둘 좀 파헤쳐봐야겠다.

 

중요한 것은 이 메시지를 받는 GPTResponse에 있는데, 만약 실제로 전해주는 변수의 이름과 GPTResponse에 저장된 변수의 이름이 다르다면 매핑에 실패하여 NPE가 발생하게된다. 주의할 것

 

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Choice {
        private int index;
        private MessageDTO message;
    }

처음에 MessageDTO의 변수명을 message가 아닌 messageDTO로 설정했다가 한 번 에러가 발생했다.


최종반환

return response.getChoices().get(0).getMessage().getContent();

그래서 이거는 DTO에서 게터를 통해서 메시지만 가져오는 과정이다.

Response DTO 내부에 Choices가 있고 그 배열의 0번째요소에서 Message를 받아와 그 Content를 가져와서 반환하도록한다.

 

이렇게 GPT에게 요청도 보내고 반환도 받으며 값을 공유할 수 있다.


이게 간단하게 GPT와 텍스트를 주고받는 방식이다.

 

이렇게 실제로 메시지를 보내보고 답도 받을 수 있다.

원래는 실제 GPT처럼 대화하듯이 반환메시지를 전해주는데, 프롬프팅을 통해 JSON만 반환하도록 설정해놨다.

프롬프팅.. 처음해보니까 재밌긴한데 약간 자연어로 코딩하는 느낌이라 아주 새롭다.

 

다만 유효성검사나 할루시네이션 검증은 개발자가 담당해야한다.

또 지금은 RequestParam 어노테이션을 통해 쿼리파라미터로 검색어를 받고 있지만 나중에는 HTTP 요청의 body에 검색어가 들어오게 할 수도 있고

 

지금 생각해보고 있는 프로젝트가 하나 있는데 백단은 하루이틀이면 다 완성할 것 같은데 이제 다시 시험기간이라..

자바의 정석도 읽어보고 읽고싶은 책도 생기고 RestTemplate 관련된 스프링인액션도 좀 읽어야하고 할 게 많다.

 

열심히해보자

끝

'CS > 백엔드' 카테고리의 다른 글

CSRF 공격이란 무엇인가?  (0) 2025.11.25
AI를 이용할 때 할루시네이션 막아보기  (0) 2025.11.21
WebSocketConfig로 사전 세팅하기  (0) 2025.11.04
HttpSession을 통한 세션로그인 구현해보기  (0) 2025.11.03
[백엔드] slf4j로 로그 남기기  (0) 2025.10.27
'CS/백엔드' 카테고리의 다른 글
  • CSRF 공격이란 무엇인가?
  • AI를 이용할 때 할루시네이션 막아보기
  • WebSocketConfig로 사전 세팅하기
  • HttpSession을 통한 세션로그인 구현해보기
Radiata
Radiata
개발을 합니다.
  • Radiata
    DDD
    Radiata
  • 전체
    오늘
    어제
    • 분류 전체보기 (211) N
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59) N
        • JVM (12)
        • 백엔드 (20) N
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • CS
    • 언어공부
    • 개인 프로젝트
    • 팀 프로젝트
    • 알고리즘
    • 고찰
    • 신년사
    • 컬러잇 개발블로그
  • 링크

    • 컬러잇 개발블로그
  • 공지사항

  • 인기 글

  • 태그

    144
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Radiata
[CS] OPEN AI API로 간단한 메시지 보내고 받아보기
상단으로

티스토리툴바