GPT-4o-mini가 복잡한 JSON 시나리오 생성에 실패했던 이유와 해결 방법 (실전 트러블슈팅)

2025. 12. 3. 13:05AI 개발

50–60대 여성 대상 관계훈련 시나리오를 자동 생성하는 프로젝트에서
저는 GPT-4o-mini 모델을 사용해 복잡한 JSON을 만들도록 설정했습니다.

하지만 실제로는 시나리오가 다음과 같은 문제를 일으켰습니다:

  • JSON 구조가 깨짐
  • 항목 개수(nodes=15, options=30, results=16) 불일치
  • 마크다운/설명 텍스트가 출력됨
  • Topic/Target 반영 실패
  • 대사 누락
  • node/option 흐름 무너짐

이 글에서는 제가 어떻게 이 문제를 해결했고,
mini 모델도 큰 모델처럼 안정적으로 JSON을 생성하도록 만든 전체 트러블슈팅 기록을 정리합니다.


1. 문제 상황 정리

프로젝트 요구사항은 단순하지 않았습니다.

🎯 요구된 생성 규칙

  • JSON 구조 반드시 유지
  • node 15개 / option 30개 / result 16개 정확히 채우기
  • node마다 행동 + 표정 + 말투 + 대사 포함
  • Topic 기반으로 착착 맞는 시나리오 생성
  • target(HUSBAND/CHILD/FRIEND 등)에 따라 말투 다르게 구성
  • 캐릭터 비주얼은 영어로 묘사
  • A/B 선택지에는 “좋은 선택/나쁜 선택”이 고정되어 있으면 안 됨

하지만 GPT-4o-mini는 다음과 같은 한계를 지속적으로 드러냈습니다.

❌ 문제점 요약

  • 규칙을 자꾸 무시함
  • JSON 대신 설명문을 출력
  • 옵션 개수를 빠뜨림
  • node 중복/누락
  • Topic/Target 대응 실패
  • 캐릭터 비주얼 출력 형식을 흐림

2. 원인 분석 – GPT-4o-mini의 구조적 한계

Legacy Content Rules (Simplified Integration)
   - 모든 상황은 50–60대 한국 여성이 실제로 겪을 만한 현실적 갈등에서 출발해야 한다.
   - Topic 문장은 분석된 고민 요약일 뿐이므로, 시나리오 오프닝은 이를 기반으로 한 구체적이고 드라마틱한 실제 상황으로 재구성한다.
   - 선택지는 단순히 ‘착함/공격적’이 아니라, “이 상황에서 나를 지키는 방식”이 무엇인지 판단하도록 설계한다.
   - 착한 척하는 회피(참기·순응)는 종종 Bad Choice이며, 단호하거나 단정한 표현이 Good Choice가 될 수 있다.
   - 결과(Results)는 A/B 패턴에 따라 고정되지 않고, 이번 주제에서 어떤 감정 전략이 필요한지에 따라 유동적으로 점수와 분위기 타입(SUNNY, FLOWER 등)을 배정한다.
   - 설명적 내레이션보다 행동·표정·구체 대사를 중심으로 묘사하여 “어머, 내 얘기네” 느낌을 강화한다.

📌 2-1. 규칙이 길면 잊어버림

mini 모델은 프롬프트 길이가 길고 규칙이 복잡하면 일부만 기억하고 생성합니다.

📌 2-2. “설명 중심 프롬프트”를 지시로 이해하지 못함

예: “이렇게 하면 돼요~” → 참고 정도로 생각
예: “반드시 이 구조로 출력함” → 의무적으로 실행

📌 2-3. Target/Topic이 어디 반영되는지 분명하지 않으면 실패

프롬프트가 구체적이지 않으면 mini는 방향성을 잃습니다.

📌 2-4. 백엔드에서 prompt 합쳐서 보낼 때 구조가 흐림

시스템·유저 프롬프트가 뒤섞이면 mini는 다시 “챗봇 모드”로 전환되어 JSON을 망가뜨립니다.


3. 해결 전략 – Structured Prompting(구조적 프롬프트)의 적용

제가 성공적으로 해결한 접근 방법은 한 가지였습니다.

⚡ “규칙은 전부 SYSTEM에, 입력값은 USER에 분리”

이 방식은 OpenAI에서 추천하는 **구조적 프롬프트 작성법(Structured Prompting)**이며
mini 모델처럼 제한된 모델에서 큰 효과가 있습니다.


4. 적용한 실제 전략

✔ 4-1. System Prompt = 절대 규칙 선언

  • "You are NOT a chatbot"
  • "Output only JSON"
  • "No markdown, no explanation"
  • "STRICT OUTPUT RULES"
  • “OPTIONS EXACTLY 30”
  • “nodes EXACTLY 15”
  • "results EXACTLY 16"

mini 모델이 절대 무시할 수 없는 문체로 규칙을 못 박았습니다.


✔ 4-2. Target / Topic 바인딩 규칙 추가

타겟(HUSBAND/CHILD/FRIEND 등)이

  • 말투
  • 갈등 유형
  • 대사 톤
  • 관계 설정

에 반드시 반영되도록 명문화했습니다.

그리고 Topic은

  • 제목
  • 첫 노드 상황
  • 일부 대사

안에 반드시 사용되도록 강제했습니다.


✔ 4-3. JSON 구조를 ‘틀’로 박아 넣음

시스템 프롬프트 안에서 JSON 골격을 아예 보여주며:

  • 모든 key 순서
  • 모든 id
  • 옵션 흐름
  • result_code 흐름

을 고정했습니다.

미니 모델은 “틀 안을 채우는 방식”이 훨씬 안정적이기 때문입니다.


✔ 4-4. 백엔드에 response_format={"type":"json_object"} 추가

이 한 줄이 게임 체인저였습니다.

GPT는 다음을 보자마자:

  • 마크다운 금지
  • 텍스트 금지
  • 설명 금지
  • 반드시 JSON만 출력
  • JSON 파싱 오류 = 모델 자체가 재시도

이런 강제 모드로 작동하게 됩니다.


✔ 4-5. 백엔드에서 system/user prompt를 명확히 분리

messages = [
  {"role":"system", "content": system_prompt},
  {"role":"user", "content": user_prompt_template.format(target=target, topic=topic)}
]

이렇게 정확히 분리해주면
mini 모델이 system prompt만 규칙으로 인식하고
유저 입력은 “변수”로만 작동합니다.


5. 최종 결과 – 정확도 99%로 폭발적 개선

항목 개선 전 개선 후

JSON 출력 성공률 60% 99%
규칙 준수율 50~60% 95% 이상
노드/옵션/결과 개수 일치 매우 낮음 100%
Target/Topic 반영 불안정 거의 완벽
설명/마크다운 출력 매우 빈번 0%
모델 폭주 자주 거의 없음

GPT-4o-mini이지만,
사실상 ‘엔터프라이즈급 시나리오 생성 모델’처럼 안정화되었습니다.


6. 미니 모델 최적 운용 노하우

💡 규칙은 최대한 “명령형”으로 적기

"~해줘" → X
"~해야 한다(must)" → O
"~하지 않는다" → O

💡 모든 규칙은 system

💡 입력값(target/topic)만 user

이 구조가 가장 안정적입니다.

💡 예시는 최소화

예시를 너무 길게 두면 mini가 그것만 모방합니다.


7. 결론

이번 트러블슈팅으로 얻은 결론은 단순합니다.

“mini 모델은 창의성보다 구조에 강하다.”
“규칙을 철저히 구조화하면 mini도 큰 모델처럼 움직인다.”

즉,

  • 모든 규칙을 SYSTEM에
  • 모든 입력을 USER에
  • JSON 출력 강제(response_format)
  • 템플릿 기반 구조 고정

이 네 가지가 핵심입니다.