티스토리 뷰
6월 16일에 OpenAI가 업데이트 되었다.
function call 기능과 함께 토큰 수가 증가 되었다.
무려 4k에서 16k로 4배나 증가 되었다.
GPT-4도 GPT-3.5와 마찬가지로 16k 업데이트 되었다.
토큰 수가 업데이트되면서, 이전 대화를 기억하게 하는 기능을 적극적으로 활용할 수 있게 되었다.
(기존 4천개로는 너무 적었음...)
구현 방식은 여러가지가 있을 것 같다.
가볍게 떠오르는건 두 가지정도인데,
1. FE는 질문만 전달, BE가 이전 질문과 답변을 저장하고 있다가 답변 생성
2. FE가 어차피 화면에 그려줘야하니까, 질문과 답변을 모두 보내주기
상용화될 앱이라면 1번이 맞다고 생각되어 1번으로 구현해봤다.
시작!
chat API 연동
먼저 fegin client로 chat API를 연동했다.
Configuration
public class OpenAIHeaderConfiguration {
@Value("${spring.openAI.APIKey}")
String openAIAPIKey;
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
requestTemplate.header("Authorization", openAIAPIKey);
requestTemplate.header("USER-AGENT", "Mozilla/5.0");
requestTemplate.header("Content-Type", "application/json");
};
}
}
Client
@FeignClient(name = "OpenAIClient", url = "https://api.openai.com/v1", configuration = {OpenAIHeaderConfiguration.class})
public interface OpenAIFeignClient {
@RequestMapping(method = RequestMethod.POST, value = "/chat/completions")
ChatResponseDto chatCompletion(@RequestBody ChatRequestDto chatRequestDto);
}
Impl
public ChatResponseDto getChatCompletion(List<ChatMessage> messages) {
ChatResponseDto chatResponseDto = openAIFeignClient.chatCompletion(
ChatRequestDto.builder().model(CHAT_GPT_MODEL).messages(messages).maxTokens(maxTokens).temperature(temperature).build());
return chatResponseDto;
}
API 구현
요청 객체
@Data
public class RequestMessageDto {
private String cacheId;
@NotNull @NotEmpty
private String message;
}
API
@PostMapping("/question/memorize")
public ResponseEntity<Object> saveMessageSingle(@Valid @RequestBody RequestMessageDto requestMessageDto) {
List<ChatMessage> chatList = new ArrayList<>();
RequestMemorizeMessageDto requestMemorizeMessageDto = new RequestMemorizeMessageDto();
if(ObjectUtils.isEmpty(requestMessageDto.getCacheId())) {
chatList.add(new ChatMessage("system", "당신은 중국집 요리사입니다."));
} else {
requestMemorizeMessageDto = cacheService.getMemorizeMessageCache(requestMessageDto.getCacheId());
chatList = requestMemorizeMessageDto.getChatList();
cacheService.clearCache(requestMemorizeMessageDto.getCacheId());
}
chatList.add(new ChatMessage("user", requestMessageDto.getMessage()));
ChatResponseDto chatResponseDto = pilotService.getGptAnswer(chatList);
chatList.add(new ChatMessage(chatResponseDto.getChoices().get(0).getMessage().getRole(), chatResponseDto.getChoices().get(0).getMessage().getContent()));
requestMemorizeMessageDto.setChatList(chatList);
String id = cacheService.saveMemorizeMessageCache(requestMemorizeMessageDto);
chatResponseDto.setCacheId(id);
// Usage에 totalTokens를 보고 16k가 넘어갔을 때 처리
return new ResponseEntity<>(chatResponseDto, HttpStatus.OK);
}
요청 메시지는 POST 전달 받았다. 질문이 엄청나게 길 수도 있고, 특수 문자가 포함될 수 있기 때문이다.
그리고 만약 이전에 답변이 나간 이력이 있다면, cache에서 데이터를 꺼내와야하므로 cacheId도 받는다.
캐시는 이전 게시글 참고
API 를 정리해보면,
1. 첫 요청은 cacheId가 없기 때문에, 당신은 중국집 요리사라는 프롬프트를 작성해줬다.
2. 요청 객체에서 질문을 받아와서, "user"에 값을 채워 넣어준다.
3. openAI에 요청 getGptAnswer는 내부에는 openAI에게 Chat API를 요청한다.
4. 응답을 받고, chatList에 role과 content를 저장하고 캐시를 갱신한다.
5. 응답
잘되나 확인
위 대화를 보면 서로 대화가 지속되고 있다는 것을 확인할 수 있다.
또한 total_tokens가 계속 증가하기 때문에 토큰 갯수 제한도 핸들링할 수 있다.
다만, 위 구현에서 마지막 대화의 캐시 삭제가 빠져있는데, 캐시 삭제는 FE에서 대화가 끝났다는 신호를 던져주면 된다.
(나라면 별도의 API를 구현할 것 같다.)
혹은 토큰 수가 16k를 오버했을 때 리스트를 통째로 삭제하는 등의 전략을 세울 수 있다.
마치며
이번 포스팅은 openAI의 새로운 기술 소개보다는 앞서 포스팅한 걸 조합해 구현하는 방식을 공유해봤다.
다음은 openAI의 진짜 새로운 기술인 function call을 사용해 볼 것 같음
'개발 > chatGPT' 카테고리의 다른 글
ChatGPT를 이용한 데이터 시각화 및 데이터 분석 (0) | 2023.07.24 |
---|---|
ChatGPT Function calling 기능 소개 및 Spring Boot에서 사용해보기 (0) | 2023.07.07 |
Chat GPT의 입력 Token 수를 세보자(Jtokkit 소개) (0) | 2023.05.24 |
Chat GPT API에서 사용하는 SSE(Server-Sent Events) 뜯어보기 (2) | 2023.05.14 |
ChatGPT API의 새기능? chat API를 써보자 - 2 (프롬프트와 SSE) (1) | 2023.05.13 |
- Total
- Today
- Yesterday
- 티스토리챌린지
- ChatGPT
- CloudFront
- openAI API
- JWT
- elasticsearch
- java
- GIT
- Log
- 후쿠오카
- 스프링부트
- cache
- AWS EC2
- OpenAI
- MySQL
- docker
- OpenFeign
- AWS
- lambda
- Kotlin
- EKS
- S3
- terraform
- Elastic cloud
- 오블완
- AOP
- Spring
- 람다
- serverless
- springboot
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |