프로젝트 목록

AI Gateway

LLM 호출의 인증·할당량·캐시·라우팅·장애 대응을 공통 파이프라인으로 구현한 게이트웨이입니다. 테스트 모델로 정책 순서와 캐시 재사용, 재시도 한도 초과 시 호출 중단을 검증했습니다.

개인 프로젝트 · Java·WebFlux API와 정책 파이프라인 구현 · 2026.06 · AI

역할
개인 프로젝트 · Java·WebFlux API와 정책 파이프라인 구현
기간
2026.06
분야
AI
코드·테스트
주요 코드 3개 · 관련 테스트 3개

해결한 문제와 담당 역할

LLM 기능을 여러 서비스에 붙이면 모델 연동, 장애 대응, 토큰 예산, 캐시, 호출 기록을 서비스마다 따로 만들게 됩니다.

OpenAI 호환 API를 만들고, 인증 뒤에 공통 정책이 정해진 순서대로 돌게 했습니다.

캐시(똑같은 요청, 비슷한 질문), 할당량, 모델 선택, 재시도 한도, 서킷 브레이커, 대체 모델 전환을 넣었습니다.

일반 응답, SSE 스트리밍, 도구 호출, 관리 화면까지 테스트했습니다.

핵심 요구사항

  • 할당량이나 예산을 넘긴 요청은 모델을 부르기 전에 끝납니다.
  • 똑같은 요청이 캐시에 있으면 유사도 검색도, 모델 호출도 하지 않습니다.
  • 재시도 한도를 다 쓰면 다음 대체 모델을 부르지 않습니다.
AI Gateway처리 흐름
  1. 01API 키 인증, 조직 확인
  2. 02할당량 검사
  3. 03입력 검사
  4. 04캐시 조회
  5. 05모델 선택
  6. 06외부 모델 호출
  7. 07실패하면 대체 모델
  8. 08출력 검사
  9. 09요청 기록
OpenAI 호환 요청이 인증, 할당량, 캐시, 모델 선택, 대체 모델을 거치는 구성도. 주요 흐름은 API 키 인증, 조직 확인 → 할당량 검사 → 입력 검사 → 캐시 조회 → 모델 선택 → 외부 모델 호출 → 실패하면 대체 모델 → 출력 검사 → 요청 기록 순서로 이어집니다.

기술 선택과 이유

OpenAI 호환 API 하나로

적용 방식
모든 서비스가 OpenAI 호환 /v1/chat/completions로 호출합니다.
검토한 대안
서비스마다 전용 API를 두거나 모델 SDK를 직접 붙이기
선택 이유
이미 OpenAI SDK를 쓰는 코드는 주소만 바꾸면 되고, 정책은 게이트웨이에서 한 번에 적용됩니다.

정책 순서는 코드로

적용 방식
인증 이후 할당량, 입력 검사, 캐시, 모델 선택·호출, 대체 모델, 출력 검사와 기록 순서를 파이프라인에 명시했습니다.
검토한 대안
기능마다 WebFilter로 등록하고 순서는 설정에 맡기기
선택 이유
할당량 검사가 모델 호출보다 먼저 도는지 테스트로 확인할 수 있어야 했습니다. 설정에 맡기면 순서가 바뀌어도 알기 어렵습니다.

재시도에는 한도를

적용 방식
재시도 한도와 서킷 브레이커를 거친 뒤에만 대체 모델로 넘어갑니다.
검토한 대안
성공할 때까지 모델을 돌아가며 호출
선택 이유
기본 모델 장애가 무제한 재시도로 이어지지 않도록 호출 횟수와 후보 범위를 제한하기 위한 선택입니다.

주요 구현과 관련 테스트

핵심 로직과 동작을 확인한 테스트를 함께 정리했습니다.

주요 구현

GatewayPipeline.execute

backend/src/main/java/com/example/gateway/api/GatewayPipeline.java

QuotaOutcome quota = quotaGuard.evaluate(request, estimatedTokens);
if (quota != QuotaOutcome.ALLOWED) {
    return rejected(request, mode, quota, elapsed(start));
}

구현 내용

예상 토큰으로 조직 할당량부터 확인하고, 넘으면 모델을 부르기 전에 끝냅니다.

관련 테스트

RequestLogStoreTest.quotaRejectPathCreatesRowWithNullProviderAndOutcomebackend/src/test/java/com/example/gateway/observability/RequestLogStoreTest.java

테스트 결과정책 순서와 모델 호출 여부가 예상대로 나옵니다.

추가 구현

TwoStageCache.lookup

backend/src/main/java/com/example/gateway/cache/TwoStageCache.java

if (exactLookup.hit()) {
    return exactLookup;
}
return semantic.lookup(request);

구현 내용

똑같은 요청은 바로 캐시에서 돌려주고, 없을 때만 비슷한 질문을 찾습니다.

관련 테스트

TwoStageCacheTest.differentlyWordedSimilarPromptFallsThroughToSemanticHitbackend/src/test/java/com/example/gateway/cache/TwoStageCacheTest.java

테스트 결과일반, 스트리밍, 도구 호출 응답 형식이 맞게 나옵니다.

추가 구현

FallbackChain.dispatch

backend/src/main/java/com/example/gateway/resilience/FallbackChain.java

lastErrorType = RETRY_BUDGET_EXHAUSTED;
events.add(FallbackEvent.failed(
    attempt, candidate.provider(), candidate.model(), lastErrorType
));
return FallbackResult.ofFailure(attempt, lastErrorType, events);

구현 내용

재시도 한도를 다 쓰면 다음 모델을 부르지 않고 실패 이벤트를 남깁니다.

관련 테스트

FallbackChainTest.exhaustedBudgetBlocksFallbackWithoutCallingProviderbackend/src/test/java/com/example/gateway/resilience/FallbackChainTest.java

테스트 결과서버 없이도 요청 흐름과 모델 선택 결과를 둘러볼 수 있습니다.

테스트 결과

테스트 방법 보기
AI Gateway 테스트 결과
구분테스트 방법결과
단위 테스트할당량, 캐시, 모델 선택, 대체 모델을 가짜 모델로 하나씩 돌려 봅니다.정책 순서와 모델 호출 여부가 예상대로 나옵니다.
통합 테스트WebFlux API로 일반 요청과 SSE 요청을 각각 보냅니다.일반, 스트리밍, 도구 호출 응답 형식이 맞게 나옵니다.
정적 데모관리 화면을 정적 파일로 빌드합니다.서버 없이도 요청 흐름과 모델 선택 결과를 둘러볼 수 있습니다.

프로젝트 범위

검증 한계와 미구현 범위

  • 기본 실행은 테스트 모델·임베딩과 메모리 저장소입니다. 실제 모델 호출·과금·클라우드 배포는 검증하지 않았습니다.
  • Redis Testcontainers 테스트와 운영 환경 검증은 구분합니다. PostgreSQL·pgvector의 운영 성능과 고가용성은 검증하지 않았습니다.
  • SSE는 완성된 가짜 응답을 잘라서 보내는 방식이라, 실제 모델 토큰을 실시간으로 중계한 건 아닙니다.

향후 개선

  • 실제 모델을 붙여서 정책별 비용과 지연을 따로 재 보려고 합니다.

관련 자료

설계 문서 테스트 소스