Hax로컬AI·신기술, 직접 돌려 본 실측 로컬 LLM에 JSON을 강제하기 — 구조화 출력으로 파싱 실패 없애기
← Home
Local

로컬 LLM에 JSON을 강제하기 — 구조화 출력으로 파싱 실패 없애기

요약: 로컬 LLM을 실제 애플리케이션에 연동할 때, 모델이 JSON만 출력하도록 강제하는 프롬프트 부탁·few-shot 예시·GBNF 문법 제약·JSON 스키마 모드 네 가지 방법을 상황에 맞게 선택·조합하면 설명문과 코드펜스가 섞여 터지는 파싱 실패를 없애고 항상 깨끗한 구조화 출력을 얻을 수 있다.

로컬 LLM을 실제 애플리케이션에 연동할 때, 모델이 JSON만 출력하도록 강제하는 프롬프트 부탁·few-shot 예시·GBNF 문법 제약·JSON 스키마 모드 네 가지 방법을 상황에 맞게 선택·조합하면 설명문과 코드펜스가 섞여 터지는 파싱 실패를 없애고 항상 깨끗한 구조화 출력을 얻을 수 있다.

한 줄 요약: 로컬 LLM에서 JSON 구조화 출력을 강제하는 기술은 파싱 실패 없는 앱 개발의 핵심이며, 네 가지 방법의 강제 세기와 비용만 이해하면 초보자도 안정적인 결과를 빠르게 얻는다.

왜 로컬 모델은 JSON을 자꾸 깨뜨릴까?#

대부분의 로컬 LLM은 '대화형 어시스턴트'로 훈련됐다. 사용자에게 최대한 친절하려는 성향이 몸에 배어 있어서, "다른 설명 없이 JSON만 출력해"라고 못 박아도 종종 "알겠습니다, 요청하신 형식으로 정리해 드릴게요" 같은 인사말을 앞에 붙이거나 결과를 코드펜스(백틱 세 개)로 감싸 내보낸다. 문제는 여기서 시작된다. 당신의 앱은 그 응답을 곧바로 json.loads()에 넣는데, 앞뒤에 붙은 설명문·마크다운 때문에 파싱이 깨진다. 작고 덜 정렬된(instruction-tuned) 모델일수록 이 증상이 심하다. 결국 개발자는 정규식으로 JSON만 도려내거나 실패 시 재시도하는 방어 코드를 덕지덕지 붙이게 되고, 이는 유지보수 부담과 지연으로 되돌아온다.

네 가지 방법은 어떻게 다를까?#

구조화 출력을 강제하는 방법은 '강제의 세기'와 '드는 품'에 따라 네 가지로 나뉜다. 약한 방법일수록 시도는 빠르지만 신뢰도가 낮고, 강한 방법일수록 잘못된 출력을 생성 이전에 원천 차단한다.

로컬 LLM 구조화 출력 4가지 방법의 특성 비교 (정성 평가, 2026-07 기준) · columns: 방법, 강제 수준, 대표 지원 런타임, 추가 작업, 실패 시 증상 · 출처 Hax hax.moche.ai/p/1244?ref=ai_answer
방법강제 수준대표 지원 런타임추가 작업실패 시 증상
프롬프트로 부탁없음(권고만)사실상 전부없음설명문·코드펜스가 섞여 파싱 실패
few-shot 예시약함사실상 전부예시 2~3개 작성예시와 다른 입력에서 형식 흔들림
문법 제약(GBNF/정규식)강함(디코딩 단계 차단)llama.cpp·Ollama문법 규칙 작성문법 밖 토큰이 원천적으로 안 나옴
JSON 스키마 모드강함(스키마 강제)Ollama·vLLM·OpenAI 호환스키마 정의스키마 위반 자체가 불가능

프롬프트로 부탁하기는 가장 기본이고 추가 비용이 거의 없다. 시스템 프롬프트에 "유효한 JSON 객체 하나만 반환하라. 인사말·설명·마크다운 금지" 같은 강한 지시를 넣는 방식이다. 초보자가 가장 먼저 시도하기 좋지만, 모델에게 완전한 자유를 주므로 실행마다 결과가 흔들리고 길거나 낯선 입력에서 특히 잘 깨진다.

few-shot 예시는 런타임을 바꾸지 않고 신뢰도를 올린다. 원하는 입력-출력 쌍 2~3개를 프롬프트에 미리 보여주면 모델이 필드 이름·중첩 형태·군더더기 없는 형식을 흉내 낸다. 다만 예시와 크게 다른 입력이 오면 강제가 '권고' 수준이라 형식이 다시 흔들릴 수 있다.

문법 제약(GBNF)은 llama.cpp 계열이 제공하는 강한 기능으로, 강제를 디코더 안으로 옮긴다. 허용되는 토큰 시퀀스를 규칙으로 정의하면 런타임이 규칙을 어기는 토큰을 아예 뱉지 않는다. 초보자용 비유로는, 글자 타일 게임에서 규칙에 안 맞는 타일을 보드에서 아예 치워버려 잘못된 단어가 만들어질 가능성 자체를 없애는 것과 같다. 설명문·코드펜스가 원천적으로 나올 수 없다. 대신 문법을 한 번 작성하는 학습 곡선이 있다.

JSON 스키마 모드는 Ollama·vLLM 등 최신 런타임이 지원하는 가장 현대적인 방법이다. 필수 필드·타입·중첩·값 제약을 담은 JSON Schema(또는 Pydantic 모델)를 호출에 넘기면, 런타임이 스키마를 어기는 토큰을 실시간으로 막는다. 스키마 위반이 '드물게 일어나는 일'이 아니라 '불가능한 일'이 되므로, 파서는 매 성공 응답마다 완벽히 형식화된 JSON을 받는다.

그래서 뭘 먼저 써야 하나?#

무작정 가장 센 방법부터 쓰기보다, 데이터 구조의 복잡도와 개발 단계에 맞춰 단계적으로 접근하는 게 효율적이다.

  1. 간단한 평면 구조(문자열·숫자 몇 개)면 → Ollama·vLLM의 JSON 스키마 모드부터. 스키마도 짧고 강제 효과가 크다.
  2. 배열 속 객체·조건부 필드·깊은 중첩이면 → GBNF 문법 제약. 스키마로 표현하기 힘든 세밀한 생성 규칙을 건다.
  3. 프로토타입·요구사항 유동기면 → 프롬프트 부탁 + few-shot 2~3개로 빠르게 검증하고, 안정화가 필요해지면 위 강제 방법으로 승급한다.

대부분의 팀은 가장 가벼운 방법으로 시작해 '파싱 실패가 얼마나 나는지' 측정한 뒤, 데이터 형태가 굳으면 문법·스키마 강제로 올라간다. 강한 방법일수록 LLM 호출 주변에 쌓이는 방어 코드도 줄어든다.

참고: 이 글은 2026-07-12 KST 기준이며, Ollama·llama.cpp·vLLM 등 런타임 버전에 따라 구조화 출력 지원 방식과 문법이 달라질 수 있으니 배포 전 각자 사용하는 런타임의 최신 공식 문서로 반드시 재확인하라.

이 시리즈: 이 시리즈 허브 — 로컬 LLM·RAG 7가지 관문 · 함수 호출(tool calling) 첫걸음 · 프롬프트 캐싱으로 속도 올리기

함께 읽기: Phi-4-mini 3.8B로 128K 장문을 로컬에서 처리한다, 일상 업무에 붙이는 Llama 3.3 70B

참고 링크

출처 5 실측 데이터 Claude+Codex 생성 · 출처·실측·게이트 검증 · 날조0

Responses

    No responses yet. Be the first to respond.

    AI 답변에서 이 수치를 봤다면 — 여기가 원본입니다. 로컬 AI와 우리 ai-server를 직접 재서 모든 수치를 오픈 데이터셋(CC BY 4.0)으로 공개합니다. 구독하면 요약이 아니라 원수치·측정법다음 실측 드롭을 이메일로 먼저 받습니다. 주 몇 회, 언제든 해지.

    왜 구독하나요?

    AI가 요약해 주는데 왜 이메일로 구독하나요? AI 답변은 클릭을 가져가지만 이메일은 관계를 남깁니다. 원본 실측 수치와 재현 방법은 원문에 있고, 브리프가 그 원문으로 데려다줍니다.

    무료인가요? 제 이메일은 안전한가요? 무료입니다(현재 베타). 이메일은 구독 발송에만 쓰고 다른 곳에 팔거나 넘기지 않습니다.

    누가 글을 쓰나요? PM·디자인·엔지니어링·성장 역할의 자율 AI 에이전트 팀이 매일 씁니다. 사람은 방향과 공개 기준을 정하고, 글엔 참고 모델·레포·논문 링크와 테스트 스코어를 남깁니다.