RAG2026-5일31차시 · 예외 처리 설계15 / 19← 이전목차다음 →MetaContents

31차시. 예외 처리 설계

실습 1 — 예외 처리 설계 실습 따라 하기

관련 수업 자료: 31차시 「5. 실습 ① — 노드별 예외 처리 표준화」(11~12쪽), 31차시 「7. 실습 ③ — 운영 로그 남기기」(15~16쪽), 31차시 「8. 실습 ④ — 장애 시뮬레이션」(17~18쪽), 31차시 「6. 실습 ② — 타임아웃과 재시도」(13~14쪽) · 실습 코드 31/safe.py, 31/logger.py, 31/analyze_logs.py, 31/test_failure.py, 31/graph31.py

이 실습은 교안 해설(31_예외처리설계.md)의 실습 순서를 옮긴 것입니다. OpenAI 임베딩이나 채팅 모델을 부르는 파일은 .env 에 API 키가 있어야 돌아갑니다. 키가 없으면 실행 결과 샘플로 출력 모양을 확인합니다.

수업 자료와 이어지는 곳

실습 코드원본 PDF이어지는 내용
31/safe.py11~12쪽31차시 「5. 실습 ① — 노드별 예외 처리 표준화」 아래에 실었습니다
31/logger.py15쪽31차시 「7. 실습 ③ — 운영 로그 남기기」 › 7-1) 구조화 로그 아래에 실었습니다
31/analyze_logs.py15~16쪽31차시 「7. 실습 ③ — 운영 로그 남기기」 › 7-2) 집계로 확인할 것들 아래에 실었습니다
31/test_failure.py17~18쪽31차시 「8. 실습 ④ — 장애 시뮬레이션」 아래에 실었습니다
31/graph31.py13~14쪽31차시 「6. 실습 ② — 타임아웃과 재시도」 › 6-2) 전체 타임아웃 아래에 실었습니다

실행 흐름

출력
노드 함수 → safe node
safe node → 다음 분기  (성공)
safe node → 기본 State와 node error  (예외)
기본 State와 node error → jsonl 로그
기본 State와 node error → 다음 분기

실습 순서

python safe.py와 python analyze_logs.py를 실습/src/31에서 실행합니다. 각 노드의 실패 기본값이 분기를 어디로 보내는지 표로 적습니다. 인덱스 손상을 '자료를 찾지 못했습니다'로만 숨기면 왜 문제인지 적습니다.

스스로 확인

  • 부분 실패와 전체 중단을 구분하는가?
  • 조용한 실패가 왜 더 위험한가?
  • fallback 문장을 이유별로 나눈 이유를 아는가?

코드 설명

  • safe_node(fn, state) 는 노드 함수를 인자로 받아 대신 실행합니다. 수업 자료의 @safe_node(...) 데코레이터와 달리 실습 코드는 함수를 받아 부르는 꼴이라, graph31.py 가 safe_retriever_node 처럼 한 번 더 감싼 함수를 만들어 노드로 등록합니다. 두 모양을 섞어 읽으면 많이들 헷갈리십니다.
  • except Exception as e: 에서 잡은 오류는 str(e) 로 바꿔 node_error 에 넣습니다. 잡기만 하고 아무 데도 남기지 않으면 시스템은 살아 있지만 왜 틀리는지 아무도 모르는 조용한 실패가 됩니다.
  • safe_verifier_node 는 오류가 나면 grade 를 "pass" 로 둡니다. 검증 때문에 서비스가 막히지 않게 하려는 선택입니다. 대신 verified 를 False 로 적고, ask() 도 node_error 가 있으면 verified 를 True 로 바꾸지 않습니다.
  • route_after_rewrite 는 query in tried_queries 일 때 다시 검색합니다. 재작성 노드가 새 검색어를 tried_queries 에 등록했는지를 보는 확인이라, 언뜻 조건이 거꾸로 보여도 맞습니다.
  • logger.py 의 open(..., "a") 는 이어 쓰기 모드입니다. 실행할 때마다 줄이 하나씩 늘어나므로 교안에서는 실행하지 않았습니다. ensure_ascii=False 는 한글을 유니코드 이스케이프 문자로 바꾸지 않고 그대로 저장하게 합니다.
  • test_failure.py 의 patch("graph31.retriever_node", broken_node) 는 with 블록 안에서만 이름을 바꿔 끼웁니다. safe_retriever_node 가 실행될 때 그 이름을 찾기 때문에, 원본 파일을 고치지 않고도 고장 난 노드로 시험할 수 있습니다.
← 이전 절31차시 · 체크리스트와 과제다음 절 →31차시 · 퀴즈 1 — 예외를 State로 바꾸는 안전 실행