[TeamBlog] SSE_스트리밍_오류처리_이력(AI).md - 100-hours-a-week/9-team-Devths-WIKI GitHub Wiki
SSE 스트리밍 오류 처리 이력 (AI)
9-team-Devths-AI 저장소에서 채팅 SSE 스트리밍·리포트 모드·504/422 대응을 위해 진행한 커밋을 시간 흐름순으로 정리한 문서입니다.
1. API 스키마·Swagger 보강
1.1 ChatRequest Swagger 예시 및 면접 리포트 예시 추가
| 항목 |
내용 |
| 커밋 |
108cbc79 |
| 메시지 |
ChatRequest Swagger 예시에 model 필드 추가 및 면접 리포트 예시 추가 |
처리 내용
- Swagger(OpenAPI) 문서에서
ChatRequest 예시에 model 필드를 추가해 클라이언트가 어떤 값을 보내야 하는지 명확히 함.
- 면접 리포트 모드 사용 예시를 문서에 추가해, 리포트 모드 호출 시 요청 형식을 안내.
목적
- API 스키마 불일치로 인한 422 Validation Error를 예방하기 위한 문서·예시 정리.
2. 리포트 모드 및 채팅 API 스키마 리팩터
2.1 리포트 모드 추가 및 채팅 API 스키마 정리
| 항목 |
내용 |
| 커밋 |
3c92d4bb |
| 메시지 |
Add report mode and refactor chat API schema |
처리 내용
- 면접 리포트 모드 기능 추가: 스트리밍 채팅과 구분된 리포트 생성 플로우 구현.
- 채팅 API 스키마 리팩터: 리포트 모드에 맞는 요청/응답 구조 정리 및 스키마 통일.
목적
- 면접 종료 후 한 번에 리포트를 받는 use case 지원 및 스키마 일관성 확보.
3. 422 검증 오류 대응
3.1 로깅 개선 및 422 검증 오류 처리 추가
| 항목 |
내용 |
| 커밋 |
fc88d09b |
| 메시지 |
로깅 개선 및 422 검증 오류 처리 추가 |
처리 내용
- 422 Unprocessable Entity(요청 바디 검증 실패) 발생 시 로그를 보강해 원인 파악이 쉽도록 함.
- 422 상황에 대한 서버 측 처리(예: 예외 핸들링·에러 메시지 정리) 추가.
목적
- 리포트 모드·일반 채팅 요청 시
model 등 필드 누락/형식 오류로 422가 나는 문제를 진단·대응.
3.2 면접 리포트 모드 422 검증 오류 처리
| 항목 |
내용 |
| 커밋 |
b38257a1 |
| 메시지 |
Handle 422 validation error for interview report mode |
처리 내용
- 면접 리포트 모드 전용 422 처리 로직 추가.
- 리포트 모드 요청에서 필수 필드 누락·타입 불일치 시 적절한 에러 응답과 메시지 반환.
- 클라이언트가 수정할 수 있도록 어떤 필드에서 검증에 실패했는지 명시.
목적
- 리포트 모드 호출 시 422가 나는 경우를 줄이고, 나더라도 원인을 빠르게 파악할 수 있도록 함.
4. 504 타임아웃 방지 (로깅·SSE Heartbeat)
4.1 로깅 개선 및 SSE Heartbeat로 504 방지
| 항목 |
내용 |
| 커밋 |
4a06f0e2 |
| 메시지 |
Improve logging and add SSE heartbeat for 504 timeout prevention |
처리 내용
- SSE heartbeat 도입: 스트리밍 중 오래 걸리는 LLM 응답 구간에서도 주기적으로 빈 데이터(또는 heartbeat 전용 이벤트)를 보내 연결이 유지되도록 함.
- 로깅 개선: 스트리밍 구간·에러 구간에서 로그를 추가해 504 발생 직전 상황을 추적 가능하게 함.
목적
- 프록시·로드밸런서·클라이언트에서 일정 시간 데이터가 없으면 연결을 끊어 504 Gateway Timeout이 나는 문제를 완화.
5. SSE 포맷 표준화 및 ChromaDB None 필터
5.1 SSE 포맷 통일 및 ChromaDB None 필터링
| 항목 |
내용 |
| 커밋 |
08916a45 |
| 메시지 |
Standardize SSE format and add ChromaDB None filtering |
처리 내용
- SSE 포맷 표준화:
event, data, 주석 라인 등 SSE 스펙에 맞게 형식을 통일해 다양한 클라이언트·프록시에서 안정적으로 파싱되도록 함.
- ChromaDB None 필터링: RAG/벡터 검색 시
metadata 등에 None이 들어가 ChromaDB 쿼리 오류가 나는 경우를 방지하기 위해, 쿼리 전에 None 값을 제거하거나 필터 조건에서 제외하는 처리 추가.
목적
- SSE 파싱 오류 및 ChromaDB 예외로 인한 스트리밍 중단을 줄이기 위함.
6. 채팅 엔드포인트 SSE 헤더 추가
6.1 채팅 엔드포인트에 SSE 헤더 추가
| 항목 |
내용 |
| 커밋 |
9b712c3b |
| 메시지 |
Add SSE headers to chat endpoint |
처리 내용
- 채팅 스트리밍 응답에 SSE용 HTTP 헤더 명시적 설정:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
- 필요 시
X-Accel-Buffering: no (Nginx 버퍼링 비활성화) 등.
- 클라이언트와 중간 프록시가 응답을 SSE 스트림으로 올바르게 인식하도록 함.
목적
- 브라우저·프록시가 응답을 일반 JSON으로 취급하거나 버퍼링해 스트리밍이 깨지는 현상을 방지.
7. 머지 커밋 (PR 반영)
7.1 PR #38 머지 — SSE 포맷 및 ChromaDB None 필터
| 항목 |
내용 |
| 커밋 |
1b0268fd |
| 메시지 |
Merge PR #38 (Fix: sse 포맷 & chromadb none filter) |
처리 내용
- 위 5번 항목(SSE 포맷 표준화 + ChromaDB None 필터링)을 포함한 PR #38을
develop(또는 해당 기본 브랜치)에 반영.
7.2 PR #39 머지 — SSE 헤더 추가
| 항목 |
내용 |
| 커밋 |
5bc83a8e |
| 메시지 |
Merge PR #39 (feat: Add SSE headers to chat endpoint) |
처리 내용
- 위 6번 항목(채팅 엔드포인트 SSE 헤더 추가)을 포함한 PR #39를 기본 브랜치에 반영.
- 변경 파일:
app/api/routes/ai.py (+9, -1).
8. 문서 작성 이후 추가·수정 사항 (현재 코드베이스 기준)
아래 내용은 기존 문서(§1~§7) 작성일 이후에 AI 서버(3.model)에 반영된 SSE·예외 처리·보안 관련 변경을 정리한 것입니다.
9-team-Devths-AI 저장소 커밋 또는 로컬 6.Final_Project/3.model 기준으로 참고하세요.
8.1 예외 처리 개선 및 SSE 에러 핸들링 추가 (fix 커밋)
| 항목 |
내용 |
| 관련 커밋 |
5631976 (fix: 예외 처리 개선 및 SSE 에러 핸들링 추가), PR #104 머지 |
| 처리 내용 |
채팅·면접 구간 예외 처리 보강 및 SSE 스트림 내 에러 이벤트 전송 로직 정리. |
| 목적 |
스트리밍 중 예외 발생 시에도 HTTP 200 + error 이벤트로 클라이언트/BE에 안정적으로 전달. |
8.2 API v1/v2 분리 및 v2 채팅 SSE 구조
| 항목 |
내용 |
| 관련 커밋 |
017e20a (feat: API routes v1/v2 분리 및 모듈화), 43d8043 (feat: 아키텍처 모듈화) |
| 처리 내용 |
채팅·마스킹·텍스트 추출 등 API를 v1(하위 호환) / v2(현재) 로 분리. v2 채팅은 POST /ai/chat 에서 스트리밍(SSE) 제공. |
| 목적 |
스키마·동작 정리 및 SSE 엔드포인트 일원화. |
8.3 SSE 에러 이벤트 통일 포맷 (v2)
| 항목 |
내용 |
| 파일 |
app/api/routes/v2/_sse_errors.py |
| 처리 내용 |
백엔드(Spring)가 SSE 스트리밍 중 에러를 인식할 수 있도록, 모든 에러를 통일된 JSON 포맷으로 전송하는 sse_error_event(code, status, message, fallback) 도입. |
| SSE 이벤트 타입 |
chunk(정상 텍스트), summary(채팅방 제목), session_state(면접 세션), error(에러 발생), [DONE](스트림 종료). |
| 에러 payload |
type: "error", error: { code, status, message }, fallback(사용자 표시용). |
| 목적 |
BE·프론트가 에러 시 동일한 구조로 파싱하여 처리·UX 일관성 확보. |
8.4 v2 채팅 엔드포인트 예외 처리 (SSE 에러 코드)
| 에러 코드 |
HTTP status |
발생 상황 |
fallback 메시지 예시 |
| PROMPT_BLOCKED |
400 |
프롬프트 인젝션 차단(RiskLevel.BLOCK) |
프롬프트 인젝션 관련 안내 |
| VECTORDB_ERROR |
404 |
VectorDB에 문서 없음(분석 모드) |
업로드된 이력서/채용공고를 찾을 수 없습니다 |
| INTERNAL_ERROR |
500 |
일반 채팅·면접 진행 중 미처리 예외 |
일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요. |
| PARSE_FAILED |
500 |
면접 질문 세트 JSON 파싱 실패, 꼬리질문 JSON 파싱 실패 |
질문 세트/꼬리질문 생성 중 오류 안내 |
| SESSION_NOT_FOUND |
404 |
면접 세션에서 현재 질문 ID를 찾을 수 없음 |
세션 오류: 현재 질문을 찾을 수 없습니다. |
| LLM_ERROR |
500 |
면접 리포트 생성 중 LLM 예외 |
면접 리포트 생성 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요. |
- 모든 경우 HTTP 200 유지, 본문에
data: {"type":"error", ...}\n\n 형태로 전송 후 필요 시 data: [DONE]\n\n 으로 스트림 종료.
8.5 422 Validation Error 전역 핸들러 (main.py)
| 항목 |
내용 |
| 파일 |
app/main.py |
| 처리 내용 |
RequestValidationError 전역 exception_handler 등록. 422 발생 시 요청 URL, Method, Body(최대 2000자), Errors(detail) 를 로그에 기록 후 JSONResponse(status_code=422, content={"detail": exc.errors()}) 반환. |
| 목적 |
422 원인(필드 누락·타입 불일치) 디버깅 용이. |
8.6 프롬프트 인젝션 방어 및 SSE 연동
| 항목 |
내용 |
| 관련 커밋 |
ce21bed (feat: 면접 기능 개선 및 보안 강화), 19d5537 (프롬프트 인젝션 로깅에도 safe_warning 적용) |
| 파일 |
app/utils/prompt_guard.py, v2 chat.py 진입 시점 |
| 처리 내용 |
사용자 메시지에 대해 check_prompt_injection() 수행. BLOCK 시 sse_error_event(PROMPT_BLOCKED, 400, ...) 전송 후 data: [DONE]\n\n 반환. WARNING 시 로깅만 하고 계속 진행. |
| 목적 |
시스템 프롬프트 탈취·역할 변경·인젝션 명령어 등 위험 입력 차단 및 SSE로 클라이언트에 명시적 에러 전달. |
8.7 로그 인젝션(Log Injection) 방어
| 항목 |
내용 |
| 관련 커밋 |
26aa75a, be738c0 (Potential fix Log Injection), 32b1530 (security: Fix Log Injection with sanitize), 615960f (task_id 로깅 시 sanitize) |
| 파일 |
app/utils/log_sanitizer.py, 채팅·마스킹 등 로깅 구간 |
| 처리 내용 |
로그에 기록되는 사용자 입력·task_id 등에 sanitize 적용(개행·제어 문자 제거). safe_info, safe_warning 등으로 CRLF Injection 방어. |
| 목적 |
로그 인젝션·개인정보 노출 위험 완화 및 코드 스캔 알림 대응. |
8.8 v2 채팅 SSE 헤더
| 항목 |
내용 |
| 파일 |
app/api/routes/v2/chat.py — StreamingResponse |
| 처리 내용 |
media_type="text/event-stream", Cache-Control: no-cache, Connection: keep-alive, X-Accel-Buffering: no 명시. |
| 목적 |
Nginx 등 프록시 버퍼링 비활성화 및 스트리밍 인식 안정화(기존 §6과 동일 정책, v2 적용). |
요약: 오류 유형별 대응
| 오류/현상 |
대응 커밋/위치 |
조치 요약 |
| 422 Validation Error |
108cbc79, 3c92d4bb, fc88d09b, b38257a1, main.py 전역 핸들러 |
Swagger 예시·스키마 정리, 리포트 모드 전용 처리, 422 시 Body/Errors 로깅 |
| 504 Timeout |
4a06f0e2 |
로깅 개선, SSE heartbeat로 유휴 구간에도 데이터 전송 |
| SSE 파싱/연결 문제 |
08916a45, 9b712c3b, 1b0268fd, 5bc83a8e, v2 SSE 헤더 |
SSE 포맷 표준화, SSE 헤더 명시, ChromaDB None 필터 |
| SSE 스트림 내 에러 |
v2 _sse_errors.py, chat.py |
통일된 error 이벤트 포맷(code/status/message/fallback), BE 연동 용이 |
| 프롬프트 인젝션 |
ce21bed, prompt_guard.py |
BLOCK 시 400 + PROMPT_BLOCKED SSE 전송, WARNING 시 로깅 |
| 로그 인젝션 |
log_sanitizer.py, 32b1530 등 |
sanitize_log_input, safe_info/safe_warning 적용 |
문서 이력
| 날짜 |
작성/수정 |
내용 |
| (최초 작성일) |
|
§1~§7: 9-team-Devths-AI 저장소 SSE·422/504·ChromaDB·머지 커밋 정리 |
| 2026-02-08 |
보완 |
§8 추가: 문서 작성 이후 추가·수정 사항(v2 SSE 에러 포맷, 예외 처리, 프롬프트/로그 인젝션 방어, 요약표·문서 이력 보강) |