AI가 뱉는 JSON이 자꾸 깨지는 이유: 프롬프트 탓이 아니다
LLM의 구조적 한계와 토큰 생성 메커니즘을 이해하고, 단순한 지시어를 넘어 시스템 레벨에서 안정적인 구조화 데이터를 확보하는 실전 전략을 분석합니다.
많은 개발자와 프로덕트 매니저들이 LLM(대규모 언어 모델)을 서비스에 도입할 때 가장 먼저 부딪히는 벽은 바로 ‘출력의 불안정성’입니다. 특히 AI의 응답을 파싱하여 데이터베이스에 저장하거나 API로 전달해야 하는 상황에서, AI가 갑자기 JSON 형식을 무시하고 서술형 문장을 덧붙이거나 쉼표 하나를 빼먹어 전체 시스템이 런타임 에러로 멈추는 경험은 이제 흔한 일이 되었습니다.
대부분의 팀은 이 문제를 해결하기 위해 프롬프트를 수정하는 데 매달립니다. “반드시 JSON으로만 답해줘”, “설명은 생략하고 코드 블록만 출력해” 같은 지시어를 추가하고, 심지어는 “실수하면 해고될 거야” 같은 극단적인 페르소나를 부여하기도 합니다. 하지만 냉정하게 말해, 프롬프트 최적화는 임시방편일 뿐 근본적인 해결책이 될 수 없습니다. 왜냐하면 이 문제는 언어 모델의 ‘작동 원리’ 그 자체에 뿌리를 두고 있기 때문입니다.
확률적 생성 모델과 결정론적 데이터 구조의 충돌
LLM은 기본적으로 다음에 올 가장 확률 높은 토큰을 예측하는 확률적 생성기입니다. 반면 JSON은 단 하나의 문자만 잘못되어도 전체 구조가 파괴되는 엄격한 결정론적 규칙을 따릅니다. 이 두 세계관의 충돌이 바로 ‘불안정한 JSON’의 핵심 원인입니다.
모델이 텍스트를 생성하는 과정에서 특정 토큰의 확률 분포가 비슷할 때, 모델은 문법적으로는 자연스럽지만 JSON 규격으로는 틀린 토큰을 선택할 수 있습니다. 특히 응답 길이가 길어질수록 모델은 앞서 생성한 문맥을 유지하는 데 더 많은 자원을 소모하며, 결과적으로 닫는 중괄호(“)를 잊거나 이스케이프 문자를 잘못 처리하는 실수를 범하게 됩니다. 이는 프롬프트를 아무리 정교하게 짜더라도 모델의 추론 과정에서 발생하는 무작위성을 완전히 제거할 수 없음을 의미합니다.
프롬프트를 넘어선 기술적 구현 전략
안정적인 JSON 출력을 위해서는 ‘모델에게 부탁하는 것’이 아니라 ‘모델이 틀릴 수 없는 환경’을 만들어줘야 합니다. 현재 업계에서 가장 효과적으로 사용되는 세 가지 접근 방식은 다음과 같습니다.
- Constrained Decoding (제약적 디코딩): 모델이 다음 토큰을 생성할 때, JSON 문법에 어긋나는 토큰의 확률을 강제로 0으로 만드는 방식입니다. 이는 모델 내부의 로짓(Logits) 단계에서 개입하여 문법적으로 유효한 토큰만 선택하게 함으로써 100% 유효한 JSON 출력을 보장합니다.
- JSON Mode 및 Function Calling: OpenAI나 Anthropic 같은 주요 API 제공사들이 제공하는 전용 모드입니다. 이는 모델이 내부적으로 구조화된 데이터를 생성하도록 튜닝된 특수 토큰을 사용하게 하여, 일반 텍스트 생성 모드보다 훨씬 높은 안정성을 제공합니다.
- Schema Validation & Retry Loop: Pydantic과 같은 라이브러리를 사용하여 출력값을 즉시 검증하고, 스키마 위반 시 에러 메시지와 함께 다시 생성을 요청하는 루프를 구축하는 것입니다. 이는 모델의 자가 수정(Self-correction) 능력을 활용하는 전략입니다.
접근 방식별 장단점 비교
| 방식 | 장점 | 단점 | 추천 상황 |
|---|---|---|---|
| 프롬프트 엔지니어링 | 구현 속도가 매우 빠름 | 신뢰도 낮음, 엣지 케이스 취약 | 프로토타이핑 단계 |
| JSON Mode / Tool Use | 표준화된 인터페이스, 높은 안정성 | 특정 모델 종속성 발생 | 상용 서비스 운영 단계 |
| 제약적 디코딩 (Guidance/Outlines) | 문법적 완벽함 보장 | 추론 오버헤드, 설정 복잡도 | 엄격한 데이터 정합성 필요 시 |
실무 적용 사례: 복잡한 데이터 추출 파이프라인
최근 한 이커머스 기업은 수만 개의 상품 리뷰에서 감성 분석 결과와 핵심 키워드를 JSON 형태로 추출하는 시스템을 구축했습니다. 초기에는 프롬프트에 JSON 예시(Few-shot)를 넣어 해결하려 했으나, 리뷰 내용에 따옴표(“)나 줄바꿈 문자가 포함될 경우 JSON 파싱 에러가 빈번하게 발생했습니다.
이들은 전략을 수정하여 ‘Pydantic 기반의 스키마 정의 $\rightarrow$ Function Calling 호출 $\rightarrow$ 유효성 검증 $\rightarrow$ 실패 시 재시도’ 프로세스를 도입했습니다. 특히 모델이 생성한 결과물을 바로 사용하지 않고, 중간 검증 레이어를 두어 타입 불일치나 필수 필드 누락을 잡아냈습니다. 그 결과, 파싱 에러율을 15%에서 0.1% 미만으로 낮출 수 있었으며, 이는 단순한 프롬프트 수정으로는 절대 도달할 수 없는 수치였습니다.
실무자를 위한 단계별 액션 아이템
지금 당장 AI의 출력 불안정성으로 고통받고 있다면, 다음 순서대로 시스템을 개선해 보십시오.
- 스키마의 명시적 정의: JSON의 키 이름과 값의 타입을 명확히 정의한 JSON Schema를 작성하십시오. 모호한 설명보다 엄격한 타입 정의가 모델의 혼란을 줄입니다.
- 전용 API 기능 활성화: 사용 중인 모델이 `json_mode`나 `tool_use`를 지원한다면 즉시 전환하십시오. 이는 프롬프트에 “JSON으로 답해줘”라고 쓰는 것보다 수십 배 더 강력합니다.
- 검증 레이어 구축: 애플리케이션 코드 단에서 `try-except` 블록으로 파싱 에러를 잡고, 에러 발생 시 모델에게 “어떤 부분이 잘못되었는지” 구체적으로 알려주며 재시도하는 로직을 구현하십시오.
- 토큰 제한 및 정지 시퀀스 설정: JSON의 닫는 괄호(`}`)가 생성되면 즉시 생성을 중단하도록 `stop sequences`를 설정하여 불필요한 서술형 텍스트가 붙는 것을 원천 차단하십시오.
결론: 도구의 한계를 인정하는 것이 엔지니어링의 시작이다
AI 모델은 마법의 상자가 아니라 확률 기반의 계산기입니다. 모델이 완벽하게 JSON을 생성해주길 기대하는 것은, 주사위를 던져서 항상 6이 나오길 바라는 것과 같습니다. 진정한 AI 엔지니어링은 모델의 불완전함을 인정하고, 그 불완전함이 시스템 전체의 장애로 이어지지 않도록 안전장치(Guardrails)를 설계하는 과정입니다.
프롬프트에 시간을 쏟기보다, 데이터의 흐름을 제어하는 아키텍처에 집중하십시오. 구조화된 출력의 안정성은 프롬프트의 화려함이 아니라, 시스템의 견고함에서 나옵니다.
FAQ
Getting AI to Return Stable JSON: The Hard Part Isnt the Prompt의 핵심 쟁점은 무엇인가요?
핵심 문제 정의, 비용 구조, 실제 적용 방법, 리스크를 함께 봐야 합니다.
Getting AI to Return Stable JSON: The Hard Part Isnt the Prompt를 바로 도입해도 되나요?
작은 범위에서 실험하고 데이터를 확인한 뒤 단계적으로 확대하는 편이 안전합니다.
실무에서 가장 먼저 확인할 것은 무엇인가요?
목표 지표, 대상 사용자, 예산 범위, 운영 책임자를 먼저 명확히 해야 합니다.
법률이나 정책 이슈도 함께 봐야 하나요?
네. 데이터 수집 방식, 플랫폼 정책, 개인정보 관련 제한을 반드시 점검해야 합니다.
성과를 어떻게 측정하면 좋나요?
비용, 전환율, 클릭률, 운영 공수, 재사용 가능성 같은 지표를 함께 보는 것이 좋습니다.
관련 글 추천
- https://infobuza.com/2026/04/20/20260420-vdzrj4/
- https://infobuza.com/2026/04/20/%eb%a9%94%ed%83%80%ec%99%80-%ec%98%a4%ed%94%88ai-%ec%b6%9c%ec%8b%a0%eb%93%a4%ec%9d%b4-%eb%ad%89%ec%b9%9c-converge-bio%ec%9d%98-2500%eb%a7%8c-%eb%8b%ac%eb%9f%ac-%ed%88%ac%ec%9e%90-%ec%86%8c%ec%8b%9d/
지금 바로 시작할 수 있는 실무 액션
- 현재 팀의 AI 활용 범위와 검증 절차를 먼저 문서화합니다.
- 작은 파일럿 프로젝트로 KPI를 정하고 2~4주 단위로 검증합니다.
- 보안, 품질, 리뷰 기준을 자동화 도구와 함께 연결합니다.