개발 slecs

생성형 AI 응답이 파싱을 깨트리던 버그 수정

목차

블로그 포스트를 자동으로 생성하는 시스템에서 LLM이 만든 본문 텍스트가 JSON 파싱을 망쳐서 서비스가 중단되는 문제가 있었다. 이번에 센티널 기반 분리 방식으로 해결했고, 여기 그 과정을 정리해본다.

왜 LLM 응답 파싱이 자주 깨질까

생성형 AI API(Claude, GPT 등)를 사용해서 텍스트를 생성한 뒤 JSON으로 파싱하려면, 응답이 well-formed JSON 형식이어야 한다. 그런데 현실은 그렇지 않다:

  • LLM은 항상 안전한 JSON을 보장하지 않는다. 요청을 아무리 명확히 해도, 생성된 텍스트에 ", {, }, \n 같은 특수문자가 들어갈 수 있다
  • 이스케이프 처리의 한계. 생성된 본문에 큰따옴표나 백슬래시가 많으면, 이를 모두 안전하게 escape 하지 못할 수 있다
  • 모델마다 다르다. 어떤 모델은 더 strict한 포맷을 지키려 하고, 어떤 모델은 창의성을 우선한다

블로그 시스템에서 뉴스 포스트나 주간 보고를 생성할 때, 본문(body) 필드가 꽤 길고 복잡한 마크다운 또는 HTML을 포함하기 쉽다. 이게 JSON 구조 속에 들어가면 파싱 실패 확률이 높아진다.

센티널 기반 분리: JSON 밖으로 꺼내기

이 문제를 푸는 여러 방법이 있다:

방법 장점 단점
모든 특수문자 escape 간단한 JSON 유지 매우 복잡함, 실패 가능성 높음
Base64 인코딩 안전함 가독성 떨어짐, 추가 decode 필요
별도 필드 + 마커(센티널) 본문 안전성 보장, 구조 명확 파싱 로직 이중화
다중 모델 프롬프팅 유연함 비용 증가, 복잡도 상승

이번에는 센티널 기반 분리를 택했다. 핵심 아이디어:

JSON 메타데이터 (title, metadata...)
---BODY_START---
본문 텍스트 (어떤 특수문자든 OK, JSON 형식 불문)
---BODY_END---

이렇게 하면:
1. 구조화된 필드(제목, 메타데이터 등)는 JSON으로 안전하게 파싱
2. 복잡한 본문은 JSON 밖에서 순수 텍스트로 처리
3. 센티널(---BODY_START---, ---BODY_END---)로 경계를 명확히

코드 변경 및 재시도 로직

변경된 파일들과 역할:

  • blog/common.py: 센티널 기반 파싱 함수 추가. JSON과 본문을 분리해서 처리하는 공통 로직
  • blog/post_news.py, blog/post_weekly.py: LLM 응답에서 센티널을 기준으로 본문을 추출해서 처리
  • opsvoro/generate.py: 동일한 파싱 패턴 적용해서 생성 로직 안정화

파싱 실패 시 1회 재시도 로직도 추가했다. 왜냐하면:

  • 네트워크 지연: 첫 요청이 timeout 되었을 가능성
  • 모델 일시적 오류: LLM API가 일시적으로 부정확한 응답을 줄 수 있음
  • 프롬프트 변화: 재시도 시 조건이 조금 달라져서 더 나은 응답을 받을 수도 있음

재시도는 지수 백오프(exponential backoff)를 따르지는 않지만, 한 번의 딜레이 후 단순 재시도하는 방식이다. 과하면 타임아웃이나 비용 증가의 원인이 되기 때문.

팀 협업과 구조 설계의 의미

이런 오류는 사용자에게 직접 노출되지 않더라도 내부 자동화 파이프라인을 중단시킨다. 블로그 생성 시스템이 매일 밤 자동으로 돌아야 하는데, 파싱 크래시 때문에 아침에 뉴스나 주간 보고가 없으면 팀 신뢰도가 떨어진다.

이번 수정으로:
- 가용성 향상: 빈번한 파싱 오류 제거해서 파이프라인 안정성 확보
- 디버깅 용이성: 센티널이 명확하면 로그에서 파싱 실패 지점을 쉽게 추적 가능
- 다른 프로젝트 교훈: 유사한 LLM 응답 처리가 필요한 다른 모듈(opsvoro 등)도 같은 패턴 도입

팀 리딩 관점에서 보면, 개발자들이 "왜 LLM을 썼을 때 이게 안 되나" 하고 좌절하는 걸 자주 본다. 하지만 실제로는 이게 정상이고, 구조적으로 JSON과 자유로운 텍스트를 분리하는 설계가 더 견고하다는 걸 깨닫는 게 중요하다. 작은 버그 하나를 고치면서 전체 팀의 아키텍처 감각이 함께 높아진다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.