로컬 모델들이 JSON 출력을 망가뜨리는 모든 방식을 기록하고 복구 라이브러리를 구축했습니다. 288번의 모델 호출을 통해 발견한 결과는
요약
작성자는 OpenRouter에서 Llama 3, Mistral 등 다양한 오픈 소스 및 폐쇄형 모델들을 대상으로 총 288번의 구조화된 출력 프롬프트를 실행하여 LLM의 JSON 출력 실패 패턴을 조사했습니다. 그 결과, 실패 모드는 전반적으로 유사하며 빈도에 차이가 있을 뿐입니다. 가장 흔한 실패 유형으로는 마크다운 펜스 포함, 트레일링 콤마, Python 타입 사용(True/False), 토큰 잘림, 이스케이프되지 않은 따옴표 등이 있습니다. 이에 대응하여 JSON 스키마 검증 및 15가지 복구 전략을 구현한 Python 라이브러리 [outputguard]를 개발했습니다.
핵심 포인트
- LLM의 구조화된 출력 실패 모드는 모델 종류와 관계없이 전반적으로 유사하다.
- 주요 실패 패턴으로는 마크다운 펜스, 트레일링 콤마, Python 타입 사용(True/False), 토큰 잘림 등이 있다.
- 기존의 'JSON 모드'나 '제약된 문법'만으로는 부족하며, 복잡한 오류 처리가 필요하다.
- 작성자는 JSON 스키마 기반 검증과 15단계의 순차적 복구 전략을 가진 Python 라이브러리 [outputguard]를 개발하여 이 문제를 해결했다.
- 이 라이브러리는 JSON 외에도 YAML, TOML, Python 리터럴 형식까지 처리할 수 있다.
지난 몇 달 동안 OpenRouter에서 Llama 3, Mistral, Command R, DeepSeek, Qwen 및 OpenRouter의 다른 모든 모델과 일반적인 폐쇄형 소스(closed-source) 모델들을 대상으로 구조화된 출력(structured output) 프롬프트를 실행해 왔습니다. 총 288번의 호출을 수행했습니다. 저는 실제로 무엇이 망가지는지, 얼마나 자주 발생하는지, 그리고 오픈 모델(open models)이 API 전용 모델들과 다르게 실패하는지 알고 싶었습니다.
짧은 답변을 드리자면: 별로 다르지 않습니다. 실패 모드(failure modes)는 전반적으로 거의 동일합니다. *빈도(rate)*는 다릅니다. 어떤 모델은 거의 모든 호출에서 마크다운 펜스(markdown fences)를 포함하고, 다른 모델은 프롬프트를 특정 방식으로 작성했을 때만 발생하지만, 망가지는 범주는 어디나 동일합니다.
제가 가장 많이 목격한 것들을 대략적인 순서대로 나열하면 다음과 같습니다:
- JSON을 감싸는 마크다운 펜스 (모델이 도움이 된다고 생각함)
- trailing commas (학습 데이터로부터 온 JS 습관)
- JSON의
true/false/null대신 Python의True/False/None사용 - 응답 중간에 토큰(tokens)이 소진되어 잘린 객체(truncated objects)
- 문자열 값 내부의 이스케이프 처리되지 않은 따옴표(unescaped quotes)
- JSON 내부의
//또는#주석 - 모델이 게을러져서 모든 데이터를 생성하지 않고 문자 그대로
...를 남기는 경우
제가 특히 이곳에 글을 올리는 이유는 다음과 같습니다. 이 문제를 다루는 대부분의 조언이 "그냥 JSON 모드(JSON mode)를 사용하세요" 또는 "제약된 문법(constrained grammar)을 사용하세요"이기 때문입니다. 네, 그것들이 사용 가능할 때는 도움이 됩니다. 하지만 로컬에서 실행하는 많은 것들은 신뢰할 수 있는 JSON 모드가 없고, 문법 기반 생성(grammar-based generation)은 나름의 트레이드오프(tradeoffs, 속도, 호환성)가 있으며, 구문적으로 유효한 JSON을 얻더라도 여전히 스키마 위반(schema violations)이나 잘림(truncation) 현상이 발생할 수 있습니다.
결국 저는 JSON 스키마(JSON Schema)를 기준으로 검증하고, 문제가 발생했을 때 특정 순서에 따라 15가지 복구 전략을 실행하는 Python 라이브러리(outputguard)를 구축하게 되었습니다. 순서를 정하는 것이 예상보다 더 중요하다는 것을 알게 되었습니다. 구조를 수정하기 전에 인코딩을 먼저 수정하고, 이후의 수정이 이전의 수정을 되돌리지 않도록 각 전략 사이에 다시 파싱(re-parsing)하는 과정이 필요했습니다.
또한 YAML, TOML, 그리고 Python 리터럴(literals)도 처리합니다. JSON 모드(JSON mode)가 없어서 모델이 원하는 대로 아무 형식이나 출력해 버리는 모델들을 다루기 시작하니, 생각했던 것보다 훨씬 더 자주 발생하더군요.
상세한 내용이 궁금하신 분들을 위해 전체 조사 결과는 블로그 포스트에 작성해 두었습니다: What Breaks When You Ask an LLM for JSON
2,001개의 테스트, MIT 라이선스, LLM 제공업체에 대한 의존성 없음. pip install outputguard
다른 분들의 경험은 어떠했는지 궁금합니다. 제가 설명한 것과 동일한 실패 패턴을 보고 계신가요, 아니면 제가 설명하는 것과는 다르게 동작하는 모델이나 양자화(quants) 모델이 있나요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Reddit AI Engineering의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기