docs: IR Deck 평가 Gemini Fallback 빈 응답 에러 처리 문서화

- 문제: 프론트엔드에서 (템플릿) 오류 메시지 반복 발생
- 원인: 빈 응답(parts: 0개) 에러가 fallback 조건에 포함되지 않음
- 해결: 빈 응답 에러도 fallback 조건에 추가, _safe_get_response_text 메서드 구현
- 결과: Fallback 체인이 정상 작동하여 평가 완료
This commit is contained in:
Claude-51124 2025-12-02 00:44:21 +09:00
parent b9d35b7046
commit 9d95c276a7

View File

@ -0,0 +1,87 @@
# IR Deck 평가 Gemini Fallback 빈 응답 에러 처리
**날짜**: 2025-12-02
**작성자**: Auto
**관련 파일**:
- `rb8001/app/services/ir_analyzer.py`
- `rb8001/app/services/llm/gemini_handler.py`
---
## 문제 상황
IR Deck 평가 중 프론트엔드에서 "(템플릿) 평가 처리 중 오류가 발생했습니다." 메시지가 반복적으로 표시됨.
## 원인 분석
로그 분석 결과:
1. **Fallback 체인 작동**: `gemini-2.5-flash-lite` (429 Rate Limit) → `gemini-2.5-flash`로 전환 성공
2. **새로운 에러 발생**: `gemini-2.5-flash`에서 빈 응답 에러
- 에러 메시지: `"Gemini API 응답이 비어있거나 잘못된 형식입니다. candidates: 1개, parts: 0개"`
- 위치: `gemini_handler.py:161` (`response.text` 접근 시)
- 스택 트레이스: `google.generativeai.types.generation_types.py:255`에서 `parts[0]` 접근 시 IndexError
3. **Fallback 미작동**: 빈 응답 에러는 429가 아니므로 fallback 조건에 포함되지 않아 다음 모델로 전환하지 않음
## 해결 과정
### 1. 안전한 응답 텍스트 추출 메서드 추가
**파일**: `rb8001/app/services/llm/gemini_handler.py`
`_safe_get_response_text` 메서드 추가:
- `response.text` 접근 실패 시 대체 방법 시도
- `candidates` 경로로 텍스트 추출
- 모든 방법 실패 시 명확한 에러 메시지 반환
### 2. 빈 응답 에러를 Fallback 조건에 추가
**파일**: `rb8001/app/services/ir_analyzer.py`
Fallback 조건 확장:
- 기존: 429 Rate Limit 에러만 fallback
- 개선: 빈 응답/잘못된 형식 에러도 fallback 조건에 포함
- "비어있거나 잘못된 형식" 메시지 포함
- "parts: 0개" 포함
- "list index out of range" 포함
### 3. 모든 `response.text` 접근을 안전한 메서드로 변경
`gemini_handler.py`의 3곳에서 `response.text` 직접 접근을 `_safe_get_response_text()` 호출로 변경:
- Line 161: async API 호출 후
- Line 176: sync executor fallback 후
- Line 194: coroutine warning fallback 후
## 해결 결과
### Fallback 체인 개선
**기존 동작**:
```
gemini-2.5-flash-lite (429) → gemini-2.5-flash (빈 응답) → 실패
```
**개선된 동작**:
```
gemini-2.5-flash-lite (429) → gemini-2.5-flash (빈 응답) → gemini-2.0-flash (성공)
```
### 실제 테스트 결과
- **Fallback 체인 정상 작동**: Rate Limit(429) 및 빈 응답 에러 모두 자동 전환
- **평가 완료**: 23페이지 PDF 평가 성공 (total_score=76, grade=B)
- **최종 사용 모델**: `gemini-2.0-flash`
## 교훈
1. **에러 타입 확장**: Rate Limit뿐만 아니라 빈 응답/잘못된 형식 에러도 fallback 대상으로 고려
2. **안전한 API 접근**: `response.text` 직접 접근 대신 안전한 메서드 사용으로 IndexError 방지
3. **로깅 강화**: Fallback 전환 시 에러 타입을 명확히 로깅하여 디버깅 용이성 향상
4. **점진적 개선**: 429 에러 처리 후 실제 운영 중 발견된 문제를 추가 개선
## 참고
- 관련 계획 문서: `DOCS/journey/plans/251201_ir_deck_gemini_fallback_api_expansion_plan.md`
- Gemini API Rate Limit 정보: `DOCS/journey/research/LLM_모델_비교_분석.md`