본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 27. 11:26

구조화된 프롬프트(Structured Prompts)를 사용하여 AI 환각(Hallucinations) 문제를 해결한 방법

요약

LLM이 예측 가능한 JSON 형식을 출력하도록 만드는 과정에서의 시행착오와 해결책을 다룹니다. 단순 지시나 온도 조절 대신, 시스템 메시지에 스키마를 임베딩하고 프로그래밍 방식으로 검증하는 전략을 제시합니다.

핵심 포인트

  • 단순 지시어만으로는 LLM의 무작위 필드 추가 및 텍스트 삽입을 막기 어려움
  • Temperature를 0으로 설정해도 환각 현상은 완전히 제거되지 않음
  • 시스템 메시지에 정확한 JSON 스키마를 직접 임베딩하는 것이 효과적임
  • 생성된 출력에 대해 프로그래밍 방식의 검증(Validation) 단계가 필수적임

저는 LLM이 깨끗하고 예측 가능한 JSON을 출력하도록 만들기 위해 2주를 보냈습니다. 성공했다고 생각할 때마다 모델은 무작위 필드를 추가하거나, 필수 필드를 누락하거나, 혹은 제가 가장 싫어하는 방식인 데이터 중간에 설명 문단을 삽입하곤 했습니다.

익숙한 상황인가요? 마침내 무엇이 효과가 있었는지 말씀드리겠습니다.

엉망진창인 현실

저는 이커머스 카탈로그를 위한 제품 설명을 자동으로 생성하는 도구를 만들고 있었습니다. 요구 사항은 간단했습니다. 제품 이름과 몇 가지 사양을 주면 title, description, keywords, category와 같은 필드를 가진 JSON 객체를 생성하는 것이었습니다. 그게 전부였습니다.

저의 첫 번째 시도는 합리적으로 보였습니다. 저는 다음과 같이 프롬프트를 작성했습니다:

"이 제품에 대한 JSON 객체를 생성하세요: [name]. title, description, keywords, category를 포함하세요."

그러자 모델은 다음과 같이 응답했습니다:

{
  "title": "Wireless Bluetooth Headphones",
  "description": "High-quality sound with noise cancellation.",
...

잠깐—저는 color를 요청한 적이 없습니다. 때로는 price를 추가하고, 때로는 rating을 추가했습니다. 그리고 가끔은 코드 블록 안에 JSON을 넣은 Markdown 형식을 반환하기도 했습니다. 그야말로 혼돈이었습니다.

제가 시도했던 것들 (그리고 실패한 이유)

1. 더 명시적인 지시 사항

"유효한 JSON만 출력하세요. 추가 텍스트는 금지합니다. 지정된 4개 이외의 필드를 추가하지 마세요."

대체로 작동했지만, 약 10%의 확률로 모델은 여전히 추가 필드를 슬쩍 끼워 넣었습니다. 더 나쁜 것은, 일부 모델은 지시 사항을 완전히 무시하고 "여기 JSON이 있습니다: ..."와 같은 대화형 노트를 추가한다는 점이었습니다.

2. 낮은 온도 (Lower temperature)

temperature=0으로 설정하는 것은 창의성을 줄이는 데 도움이 되었지만, 문제를 완전히 제거하지는 못했습니다. 결정론적인(Deterministic) 모델이라도 결정론적인 방식으로 틀릴 수 있기 때문입니다.

3. 에러 메시지와 함께 재시도

파싱 에러(Parse errors)를 잡아내어 에러를 모델에게 다시 보내는 방법을 시도했습니다. 이는 대화를 더 길게 만들었고, 종종 모델이 사과만 하고 여전히 잘못된 출력을 생성하게 만들었습니다. 또한 더 많은 토큰 비용이 발생했습니다.

4. 다른 모델 사용

GPT-4는 GPT-3.5보다 나았지만, 여전히 프로덕션(Production) 환경에서 사용하기에는 충분히 신뢰할 수 없었습니다. 저는 몇 가지 다른 API(ai.interwestinfo.com에 있는 것을 포함하여)를 테스트해 보았으나 결과는 비슷했습니다. 환각(Hallucinations)은 단순히 버그가 아니라 LLM(Large Language Models)의 특징입니다.

마침내 효과를 본 방법: 구조화된 프롬프팅(Structured Prompting) + 검증(Validation)

계속해서 시행착오를 겪은 끝에, 저는 진짜 해결책이 더 나은 프롬프트가 아니라는 것을 깨달았습니다. 그것은 바로 두 부분으로 구성된 전략이었습니다:

  1. 프롬프트를 매우 엄격하게 설계하여, 기대되는 JSON 스키마(Schema)를 시스템 메시지(System Message)에 직접 임베딩(Embedding)합니다.
  2. 생성 후 **프로그래밍 방식으로 출력을 검증(Validate)**하고, 이를 수정하거나 재시도합니다.

1단계: 스키마 인지 프롬프트(The Schema-Aware Prompt)

출력을 설명하는 대신, 이제 모델에게 채워 넣어야 할 정확한 JSON 구조를 보여줍니다. 콘텐츠를 위한 자리 표시자(Placeholder)는 남겨두되, 모든 키(Key)와 배열(Array) 위치는 고정합니다.

다음은 Python을 사용한 접근 방식입니다 (범용 AI 클라이언트를 사용 중이며, API 엔드포인트는 본인의 것으로 교체하세요):

import json
from typing import Any, Dict, List

...

이것만으로도 신뢰도가 약 90%에서 약 97%로 향상되었지만, 나머지 마지막 3%가 여전히 프로덕션 파이프라인(Pipeline)을 망가뜨릴 수 있습니다.

2단계: 프로그래밍 방식으로 검증 및 복구

저는 Python의 jsonschema 라이브러리를 사용하여 반환된 JSON을 스키마와 대조하는 작은 검증기(Validator)를 작성했습니다. 검증에 실패하면, 응답에서 JSON 파편(Fragment)을 추출하거나(마크다운으로 감싸져 있더라도), 모델에게 자신의 출력을 수정하도록 요청하여 복구를 시도합니다.

import jsonschema
import re

...
```

(?:json)?\s*([\s\S]*?)\s*

```', response)
    if match:
        try:
            data = json.loads(match.group(1))
...

이 파이프라인을 통해 성공률은 99.9%에 도달했습니다. 남아있는 소수의 실패 사례(보통 모델 장애나 터무니없는 환각으로 인한 경우)는 로그로 기록되어 수동 검토를 위해 플래그(Flag)가 지정됩니다.

교훈 / 트레이드오프(Trade-offs)

  • 프롬프트만으로는 충분하지 않습니다 (The prompt is not enough). 아무리 잘 작성하더라도 LLM(Large Language Models)은 확률적(Probabilistic)입니다. 코드 레벨에서 예상치 못한 출력에 대비한 계획을 세워야 합니다.
  • 검증 스키마(Validation schema)가 계약을 강화합니다. 허용된 구조를 명시적으로 선언함으로써, 출력을 특정 틀 안에 강제할 수 있습니다. 이는 프롬프트에만 의존하는 부담을 줄여줍니다.
  • 재시도(Retries)는 투박한 도구입니다. 모델이 단순한 형식 오류를 범했을 때는 도움이 되지만, 지시 사항이 잘못 해석된 경우 오류를 증폭시킬 수도 있습니다. 재시도보다는 복구(Repair)하는 방식을 선호하십시오.
  • 비용 대 신뢰성(Cost vs reliability)의 트레이드오프. 검증 레이어를 추가하고 가끔씩 복구 호출을 수행하면 지연 시간(Latency)과 토큰 사용량이 증가합니다. 처리량이 높은(High-throughput) 시스템의 경우, 검증된 응답을 캐싱(Caching)하거나 더 작고 저렴한 모델을 사용하는 것이 더 나은 균형점이 될 수 있습니다.
  • 모든 모델이 JSON 모드를 네이티브로 지원하는 것은 아닙. 일부 제공업체(OpenAI 등)는 JSON을 강제하는 response_format 파라미터를 가지고 있습니다. 사용 가능하다면 이를 활용하십시오. 더 쉬운 첫 번째 방어선이 됩니다.

다음에 다시 한다면 다르게 할 점

저는 단 하나의 프롬프트를 작성하기 전에 구조화된 출력 형식(Structured output formats)부터 시작할 것입니다. 또한, 가공되지 않은 JSON 스키마(Raw JSON schema) 대신 검증을 위한 간단한 Pydantic 모델에 투자할 것입니다. Pydantic은 타입 힌트(Type hints)를 제공하고 오류 처리를 더 쉽게 만들어 주기 때문입니다. 다음과 같은 방식입니다:

from pydantic import BaseModel

class Product(BaseModel):
...

그 다음 이를 사용하여 모델의 응답을 직접 파싱(Parse)하겠습니다. 파싱에 실패한다면 무언가 잘못되었다는 것을 알 수 있습니다.

결론

구조화된 프롬프트(Structured prompts)와 프로그래밍 방식의 검증(Programmatic validation)은 저의 AI 통합 과정을 취약한 장난감에서 프로덕션 준비가 된(Production-ready) 도구로 바꾸어 놓았습니다. 이 기술은 어떤 LLM API와도 작동합니다. 저는 OpenAI, Anthropic, 그리고 몇몇 더 작은 제공업체들을 통해 이를 테스트했습니다. 원칙은 보편적입니다. 모델의 출력을 절대 신뢰하지 말고, 항상 검증하십시오.

여러분의 설정은 어떤 모습인가요? 일관된 AI 출력을 강제하기 위한 더 나은 방법을 찾으셨나요? 댓글을 통해 여러분의 경험담(그리고 해결책)을 듣고 싶습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0