spring-ai 를 사용하던 중 아래와 같은 로그가 발생하였습니다.
2024-07-16T14:54:29.306+09:00 WARN 69522 --- [tech-swipe-batch] [tSummarizeJob-3] o.s.a.a.r.SpringAiRetryAutoConfiguration : Retry error. Retry count:4
org.springframework.ai.retry.NonTransientAiException: 400 - {
"error": {
"message": "This model's maximum context length is 16385 tokens. However, your messages resulted in 18988 tokens. Please reduce the length of the messages.",
"type": "invalid_request_error",
"param": "messages",
"code": "context_length_exceeded"
}
}
예외의 내용은 제가 사용하고 있는 모델(gpt3.5)에 요청을 보낼 수 있는 최대 토큰 수가 초과되었다는 내용이었습니다.
그런데 이 예외가 발생했을 때 spring-ai 에서 요청을 재시도하고 있었습니다.
우선은 로그에 NonTransientAiException
예외가 찍혀있었는데, 'NonTransient 라면 재시도되지 않아야하지 않은가?' 라는 생각을 했습니다.
spring-ai 를 좀 더 살펴봤을 때 아래 사항을 알게되었습니다.
ResponseErrorHandler
를 통해서 클라이언트의 예외를 TransientAiException
과 NonTransientAiException
으로 변환하고, RetryTemplate
으로 재시도 로직을 처리하고 있었습니다.RetryTemplate
, ResponseErrorHandler
빈을 주입받아 생성되고 있었습니다.OpenAiChatModel
도 RetryTemplate
과 ResponseErrorHandler
을 사용하고 있었죠.이제 RetryTemplate
과 ResponseErrorHandler
이 생성되는 부분을 보겠습니다.
우선은 spring-ai-spring-boot-autoconfigure 안에 있는 SpringAiRetryAutoConfiguration
을 보겠습니다.
RetryTemplate
빈이 생성되는 부분은 아래와 같습니다.
조금 이상해보이는 부분이 있다면... NonTransientAiException
이 발생했을 때 재시도가 된다는 점입니다.
이제 ResponseErrorHandler
빈이 생성되는 부분을 보겠습니다.
재시도 하지 않을 예외를 NonTransientAiException
으로 처리하는 것을 알 수 있습니다.
프로퍼티들 관련해서는 공식문서를 확인해보시면 더 잘 이해가 되실겁니다.
RetryTemplate
과 ResponseErrorHandler
생성하는 곳은 SpringAiRetryAutoConfiguration
만이 아니었습니다.
spring-ai-retry 안의 RetryUtils
에는 RetryTemplate
과 ResponseErrorHandler
의 디폴트 객체가 있는데, 이는 OpenAiChatModel
, OpenAiApi
를 생성할 때 RetryTemplate
과 ResponseErrorHandler
객체를 넘겨주지 않았을 경우 기본으로 사용하는 것입니다.
이 중 RetryTemplate
의 생성을 확인해보겠습니다.
TransientAiException
에서 재시도하는 것을 확인했습니다.
SpringAiRetryAutoConfiguration
에서 RetryTemplate
생성할 때 NonTransientAiException
에서 재시도하는 재시도 조건이 잘못된 것이 맞는지 조금 더 확인해보고 싶어서 이곳저곳 뒤져봤는데, RetryUtils
를 확인하고 잘못된 것이 맞다고 생각하여 해당 부분을 수정해서 spring-ai 에 PR 을 하게되었습니다.