프롬프트를 '구조화'하면 성능이 오르는 진짜 이유

모델/상황마다 프롬프트가 달라지는 이유를 정리하고, 시스템 프롬프트·few/one-shot·XML 태그·Markdown 헤더를 “구조”로 설계해 재사용 가능한 템플릿으로 만드는 법을 소개합니다.
Arqia's avatar
Dec 31, 2025
프롬프트를 '구조화'하면 성능이 오르는 진짜 이유

프롬프트를 손으로 관리하다 보면 비슷한 장면을 반복해서 보게 됩니다.

  • 어제는 잘 나오던 결과가 오늘은 흔들립니다.

  • 같은 일을 시켜도 출력 포맷이 매번 달라집니다.

  • 모델을 바꾸거나, 컨텍스트가 길어지면 성능이 급격히 떨어집니다.

처음에는 “프롬프트 문장을 더 잘 써야 하나?”로 접근했는데, 문제의 대부분은 문장이 아니라 경계(boundary)였습니다. 모델이 무엇을 규칙으로 읽어야 하고, 무엇을 데이터로 읽어야 하는지 명확하지 않을 때 성능이 흔들립니다.

이 글은 one-shot/few-shot, XML 태그, Markdown 헤더를 ‘기법 모음집’으로 소개하지 않습니다. 실무에서 프롬프트가 깨지는 지점을 기준으로, 프롬프트를 문서처럼 구조화해 재현성을 높이는 방법을 정리합니다.

참고로 OpenAI는 공식 문서에서 Markdown/XML로 메시지 경계를 명확히 하는 방법을 소개합니다. OpenAI
Claude 문서는 복합 프롬프트일수록 XML 태그로 섹션을 분리하면 파싱이 좋아진다고 설명합니다. Claude Docs
Gemini 문서는 XML-style tags 또는 Markdown headings를 일관되게 사용하라고 안내합니다. Google Gemini


"같은 프롬프트인데 실행할 때마다 품질 차이가 심해요"

실무에서 프롬프트를 ‘문서’로 만들려고 하면 흔히 이런 식으로 시작합니다.

  • 규칙을 문장으로 붙입니다.

  • 입력 데이터를 뒤에 이어 붙입니다.

  • 출력 포맷은 “표로” 정도로만 적습니다.

그리고 얼마 지나지 않아 문제가 생깁니다.

  1. 규칙과 데이터가 섞입니다

  2. 출력 형식이 느슨해 모델이 매번 다르게 선택합니다

  3. 의도를 모델이 추측합니다(모델·스냅샷마다 추측이 달라집니다)

가장 흔한 실패 프롬프트는 아래 형태입니다.

아래 회의록 요약해줘. 그리고 액션아이템 뽑아줘. 참고로 액션아이템은 담당자/기한 포함해. 회의록: …(긴 텍스트)…

사람은 “앞부분은 규칙, 뒷부분은 데이터”라고 자연스럽게 해석하지만, 모델은 그 경계를 더 자주 놓칩니다.


구조화의 목표: 지시·데이터·출력의 경계를 분리한다

구조화는 거창한 기술이 아닙니다. 다음 세 가지를 분리하는 작업입니다.

  • Instructions: 해야 할 일, 규칙, 금지, 우선순위

  • Input: 처리할 데이터(텍스트/로그/문서)

  • Output format: 결과의 모양(헤더/필드/개수)

OpenAI 문서에서도 Markdown 헤더와 XML 태그가 “논리적 경계”를 만들기 위해 유용하다고 설명합니다. OpenAI


선택지 비교: Markdown과 XML 중 무엇을 쓰는 게 낫나

아래 표는 ‘취향’이 아니라, 깨지는 지점을 기준으로 정리한 선택 기준입니다.

방식

언제 쓰나

장점

단점

Markdown 헤더/리스트

팀에서 사람이 읽고 고치는 프롬프트

유지보수·공유·diff가 쉬움

입력 블록이 많아지면 경계가 다시 흐려질 수 있음

Delimiter(구분자)

입력이 길거나, 입력 안에 명령 같은 문장이 섞일 때

사고 방지턱(규칙/데이터 혼선 감소)

구분자만 넣고 구조를 안 잡으면 효과가 제한적

XML 태그

문서 A/B, RAG 컨텍스트, 예시 다수, 파싱 목적 출력

블록 경계가 가장 강함, 후처리/추출에 유리

사람이 ‘처음’ 읽을 때는 Markdown보다 덜 친숙할 수 있음

(Claude 문서의 요지도 동일합니다: 복합 프롬프트에서는 XML 태그로 context/instructions/examples를 분리하라고 안내합니다. Claude Docs)


패턴 1. Markdown 헤더로 “프롬프트 문서” 만들기

가장 먼저 추천하는 형태는 아래입니다. 설명이 아니라 형태를 먼저 고정합니다.

# Role
너는 (역할)이다.

## Task
(해야 할 일 1문장)

## Rules
- (규칙/우선순위)

## Input
"""
(처리할 데이터)
"""

## Output format
(헤더/필드/개수까지 명시)

이 레이아웃의 핵심은 “문장이 예쁘다”가 아니라, 섹션이 고정된 순서로 존재한다는 점입니다.


패턴 2. Delimiter는 ‘보안’보다 ‘운영’에서 더 자주 필요하다

실무에서 구분자를 쓰는 이유는 보안만이 아닙니다.

  • 입력 데이터 안에 “지시처럼 보이는 문장”이 섞일 때

  • 출력 예시가 “지시처럼” 해석될 위험이 있을 때

이때 구분자는 모델의 오해를 줄이는 저비용 장치입니다. OpenAI도 구분자로 섹션을 분리하라고 안내합니다. OpenAI

권장 관례는 단순합니다.

  • 일반 텍스트: """ ... """

  • 코드/JSON:


패턴 3. 입력이 복잡해지면 XML로 넘어간다

다음 조건이 하나라도 해당되면, Markdown만으로는 유지가 어렵습니다.

  • 문서 A와 B를 비교해야 한다

  • 컨텍스트 블록이 여러 개다(RAG)

  • 예시가 여러 개다(few-shot)

  • 출력에서 특정 블록만 추출해야 한다

이때는 XML이 가장 덜 깨집니다.

<instructions>
1) <input>을 읽고 TL;DR 1줄
2) 실행 가능한 액션 3개
3) 불확실하면 "확인 필요"로 표기
</instructions>

<input>
"""
(원문 텍스트)
"""
</input>

<output_format>
- TL;DR: ...
- Actions:
  - ...
  - ...
  - ...
</output_format>

Claude 문서도 태그 이름이 정답인 것은 아니고, 일관성(consistency)중첩(nesting)이 중요하다고 설명합니다. Claude Docs


패턴 4. one-shot/few-shot은 “정확도 비법”이 아니라 “의도 고정 장치”다

예시는 모델에게 ‘학습’이라기보다, 작업의 정의를 전달합니다.

  • one-shot: 출력 포맷과 말투를 고정

  • few-shot: 분류/엣지케이스에서 경계를 고정

OpenAI 문서에서도 few-shot은 fine-tuning 없이 예시로 패턴을 보여주는 방식으로 설명합니다. OpenAI

아래는 라벨링 작업에서 자주 쓰는 최소 구성입니다.

You are a classifier.
Return JSON only.

Labels: [billing, bug, feature, other]

Example 1
Input: "결제 취소하고 싶어요"
Output: {"label":"billing"}

Example 2
Input: "업데이트 이후 로그인 버튼이 안 눌려요"
Output: {"label":"bug"}

Example 3
Input: "그냥 문의드려요"
Output: {"label":"other"}

Now classify:
Input: "{{TEXT}}"

패턴 5. 첫 줄을 깔아두는 방식(Completion strategy)

출력 포맷을 “설명”하기보다, 출력의 시작을 제공하는 방식이 더 안정적인 경우가 있습니다. Gemini 문서에서도 동일한 전략을 소개합니다. Google Gemini

Create an outline for an essay about hummingbirds.
I. Introduction
  *

실무 레시피 3종(복붙용)

1) 요약/정리형(메일/회의록/리서치 노트)

# Task
아래 텍스트를 요약하고, 실행 가능한 액션을 뽑아라.

## Rules
- 원문에 없는 사실은 추측하지 말 것
- 불확실하면 "확인 필요"로 표시

## Input
"""
{{TEXT}}
"""

## Output format
- TL;DR: (1문장)
- Key points: (3개)
- Actions: (3개)
- Open questions: (있으면)

2) 비교/평가형(문서 A vs B)

<instructions>
- 각 문서를 5줄로 요약
- 공통점 3개 / 차이점 3개
- 상황별 추천(A가 좋은 경우 / B가 좋은 경우)
</instructions>

<doc_a>
"""
{{DOC_A}}
"""
</doc_a>

<doc_b>
"""
{{DOC_B}}
"""
</doc_b>

3) 추출/구조화형(표로 뽑기)

## Task
아래 텍스트에서 엔티티를 추출해 표로 정리하라.

## Input
"""
{{TEXT}}
"""

## Output format
| entity | type | evidence |
|---|---|---|
| | | |

디버깅 체크리스트

프롬프트가 흔들릴 때는 문장을 수정하기 전에 아래를 먼저 확인합니다.

  1. 지시와 입력이 섞였는가 → Input 블록 분리 + 구분자 추가

  2. 출력 포맷이 느슨한가 → 헤더/필드/개수까지 고정

  3. 의도를 모델이 추측하는가 → one-shot 예시 1개 추가

  4. 우선순위가 충돌하는가 → Rules 우선순위 명시

  5. 입력이 긴가 → 컨텍스트를 먼저 주고 지시/질문을 뒤에 배치 Google Gemini


마치며

프롬프트가 깨지는 문제는 대개 ‘모델이 멍청해서’가 아니라, 사람이 경계를 명시하지 않았기 때문에 발생합니다. Markdown 헤더로 문서 구조를 먼저 고정하고, 입력이 복잡해지면 XML로 경계를 강화하는 것만으로도 재현성이 크게 올라갑니다.


참고 링크

Share article

아키아