Python LLM 출력 JSON 파싱 오류 0% 만드는 실전 해결 방법

최근 저는 실무에서 여러 프로젝트에서 LLM을 활용해 자동 분석과 데이터 후처리를 진행하면서, 모델이 출력한 JSON을 Python에서 안정적으로 파싱하는 일이 얼마나 까다로운지 절실히 느낀 적이 있습니다. 저는 주로 LangChain을 기반으로 파이프라인을 구성하는데, 출력 형식을 JSON으로 명확하게 지정했음에도 불구하고 Python LLM 출력 JSON 파싱 과정에서 계속해서 예기치 못한 오류가 발생하더군요.

특히 파라미터 수가 적은 경량 LLM 모델을 사용할 때는 JSONDecodeError가 거의 고질병처럼 반복되었습니다. 겉보기에는 잘 생성된 것 같은 결과값이었는데, 막상 디코딩을 시도하면 “Expecting value” 같은 오류가 뜨면서 코드 흐름이 중단되는 상황이 너무 자주 발생한 겁니다. 이 문제를 해결하기 위해 제가 실제로 거쳐온 과정, 실패했던 시도들, 그리고 결국 파싱 오류를 0%까지 줄인 방식까지 정리해 보려고 합니다.

 

JSON 출력만 시키면 해결될 줄 알았다? (하지만 현실은 달랐다)

 

처음에는 LLM 프롬프트에 “JSON으로만 출력해라”라고 명확하게 지시하면 문제가 해결될 줄 알았습니다. LangChain의 JsonOutputParser를 그대로 연결해 사용하면, 이론적으로는 정돈된 Python 딕셔너리를 바로 받을 수 있다고 생각했죠.

그러나 실전에서는 이야기가 달랐습니다. LLM이 약간의 문장을 앞에 추가하거나, JSON을 마크다운 코드블록처럼 감싸거나, 심지어 쉼표 하나를 빼먹는 등의 변수가 계속 발생했습니다. 이런 사소한 차이 때문에 JsonOutputParser는 파싱을 실패하고, Python에서는 오류가 계속 쌓였죠.

결국 깨달았습니다.

문제가 LLM이 아니라, “LLM이 출력한 텍스트에서 순수 JSON만 안정적으로 분리하는 과정”에 있었다는 것.

즉, 핵심은 Python LLM 출력 JSON 파싱을 안정화하는 알고리즘 설계에 있었습니다.

 

여러 번의 시행착오: 단순 문자열 파싱으로는 부족…

 

가장 먼저 시도한 방법은 LLM의 출력을 문자열로 변환한 뒤, 마지막 {와 } 사이만 골라내 JSON으로 재구성하는 방식이었습니다. 이 시도는 간단했고 적당히 동작하는 것처럼 보였지만, 곧바로 한계가 드러났습니다.

 

Python LLM json 에러

 

  • JSON이 여러 번 등장하면 어떤 부분을 잡아야 하는가?
  • 마크다운 코드블록(“`json`)을 포함하면 rfind 방식은 무력하다.
  • LLM이 특수문자를 앞뒤로 붙이면 정상 JSON도 깨져 보일 수 있다.
  • 단일 {} 형태만 있을 때는 너무 단순하게 판단해 잘못된 결과를 반환할 수 있다.

 

즉, 단순 검색 기반 파싱은 LLM의 유연한 출력 패턴을 감당하기에 부족했습니다.

 

해결 RunnableLambda + 강화된 JSON 추출 알고리즘

 

이 문제를 해결하기 위해 선택한 방식은 LLM의 응답을 단계적으로 가공하는 파이프라인 구조였습니다. 핵심은 다음 순서를 지키는 것이었습니다.

LLM 응답에서 content만 직접 추출한다.
– StrOutputParser 대신 AIMessage 객체의 content 필드를 직접 접근.

마크다운 블록, 텍스트 혼합 구조, 중첩 JSON 등 다양한 케이스를 처리하는 JSON 추출 알고리즘 적용
– 마크다운(“`json) 여부 우선 검사 – JSON 형태 외부의 노이즈 제거 – 마지막 유효한 {}` 쌍을 안정적으로 식별
– 실패 시 적절한 예외 핸들링

정제된 JSON을 JsonOutputParser로 최종 파싱

이 방식으로 바꾼 이후, 경량 모델에서도 파싱 오류가 단 한 번도 발생하지 않았습니다.
저에게 가장 결정적이었던 점은, JSON을 무조건 “LLM이 알아서 잘 만들 것”이라고 기대하지 않고, 후처리에서 강력한 안전장치를 구축했다는 것입니다.

사실상, Python LLM 출력 JSON 파싱 파이프라인의 구조적 안정성을 확보한 것이죠.

 

JSON 출력을 안정적으로 받고 싶다면?

 

LLM을 활용한 자동화 흐름에서 JSON 파싱 실패는 전체 파이프라인을 중단시키는 치명적인 문제입니다. 특히 로컬 경량 모델을 사용하는 경우, 출력 형식이 어긋나는 일이 잦기 때문에 반드시 후처리 기반의 안정 장치가 필요합니다.

제가 구축한 방식처럼,

content를 직접 추출하고

마크다운까지 처리 가능한 JSON 파서로 전처리하고

JsonOutputParser로 최종 파싱하는 구조를 적용하면, Python LLM 출력 JSON 파싱의 실패율을 사실상 0에 가깝게 만들 수 있습니다.

만약, 저와 같이 비슷한 문제를 겪고 있다면, 이번 글에서 설명드린 내용이 충분히 도움이 될 것이라 확신합니다.