From 9d95c276a73ed1d4d3a1602bb4cc5184027ba1ca Mon Sep 17 00:00:00 2001 From: Claude-51124 Date: Tue, 2 Dec 2025 00:44:21 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20IR=20Deck=20=ED=8F=89=EA=B0=80=20Gemini?= =?UTF-8?q?=20Fallback=20=EB=B9=88=20=EC=9D=91=EB=8B=B5=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20=EB=AC=B8=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 문제: 프론트엔드에서 (템플릿) 오류 메시지 반복 발생 - 원인: 빈 응답(parts: 0개) 에러가 fallback 조건에 포함되지 않음 - 해결: 빈 응답 에러도 fallback 조건에 추가, _safe_get_response_text 메서드 구현 - 결과: Fallback 체인이 정상 작동하여 평가 완료 --- ...r_deck_gemini_fallback_빈응답_처리.md | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 journey/troubleshooting/251202_ir_deck_gemini_fallback_빈응답_처리.md diff --git a/journey/troubleshooting/251202_ir_deck_gemini_fallback_빈응답_처리.md b/journey/troubleshooting/251202_ir_deck_gemini_fallback_빈응답_처리.md new file mode 100644 index 0000000..2148ec1 --- /dev/null +++ b/journey/troubleshooting/251202_ir_deck_gemini_fallback_빈응답_처리.md @@ -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` +