포스트

추론 모델(Reasoning Model) 프롬프트 엔지니어링 가이드

추론 모델(Reasoning Model) 프롬프트 엔지니어링 가이드

1. 서론

1.1 추론 모델이란

추론 모델(Reasoning Model)은 최종 답변을 생성하기 전에 내부적으로 사고 과정(chain-of-thought)을 수행하는 LLM을 지칭한다. 일반 모델이 입력을 받으면 곧바로 출력을 생성하는 반면, 추론 모델은 “생각하는 단계”를 거친 뒤 답변을 제출한다.

RummiArena에서 사용하는 추론 모델 3종:

모델추론 방식특성
GPT-5-mini (OpenAI)내장 추론 (reasoning_tokens)completion 내부에 reasoning과 답변이 합산
DeepSeek Reasoner (DeepSeek)Chain-of-Thought (reasoning_content)reasoning과 content가 별도 필드로 분리
Claude Sonnet 4 (Anthropic)Extended Thinking (thinking 블록)thinking과 text가 별도 블록으로 분리, budget_tokens로 사고량 제어

1.2 비추론 vs 추론 모델의 핵심 차이

flowchart LR
    subgraph NON_REASON["비추론 모델\n(일반 LLM)"]
        direction TB
        NR_IN["입력 프롬프트"] --> NR_OUT["즉시 응답 생성"]
    end

    subgraph REASON["추론 모델\n(Reasoning LLM)"]
        direction TB
        R_IN["입력 프롬프트"] --> R_THINK["내부 사고 과정\n(reasoning_tokens)\n수백~수천 토큰"]
        R_THINK --> R_OUT["최종 응답 생성"]
    end

    NON_REASON -.->|"루미큐브 결과"| NR_RESULT["Claude Opus (비추론)\nPlace Rate: 5% (F등급)"]
    REASON -.->|"루미큐브 결과"| R_RESULT["Claude Sonnet + Thinking\nPlace Rate: 33.3% (A+등급)"]

    style NON_REASON fill:#f8d7da,stroke:#c0392b
    style REASON fill:#d4edda,stroke:#28a745
    style NR_RESULT fill:#e74c3c,color:#fff,stroke:#333
    style R_RESULT fill:#27ae60,color:#fff,stroke:#333

RummiArena에서 이 차이가 극명하게 드러났다. Claude Opus(비추론)는 5% Place Rate에 그쳤으나, Claude Sonnet + Extended Thinking(추론)은 동일한 게임 규칙과 프롬프트로 33.3%를 달성했다. 루미큐브처럼 4색 x 13숫자 x 2세트 = 106타일에서 유효한 그룹/런 조합을 탐색하는 조합론적 문제에서는 추론 능력이 필수이다.

1.3 왜 프롬프트 엔지니어링이 추론 모델에서 더 중요한가

추론 모델의 성능은 “무엇을 생각하게 하느냐”에 크게 좌우된다. 비추론 모델에서는 프롬프트가 주로 “출력 형식”을 제어하지만, 추론 모델에서는 프롬프트가 사고의 방향과 깊이 자체를 결정한다.

요소비추론 모델에서의 영향추론 모델에서의 영향
프롬프트 언어출력 언어에 영향reasoning chain 깊이에 직접 영향
예시 개수출력 형식 학습사고 패턴 학습 + reasoning 예산 소비
검증 지시무시하거나 형식적 수행reasoning chain에 검증 단계 편입
max_tokens출력 길이 제한reasoning + 출력 합산 제한 (절단 위험)

RummiArena 실험 데이터가 이를 증명한다. 동일한 DeepSeek Reasoner 모델에서 프롬프트 변경만으로 5%(R2) -> 12.5%(R3) -> 23.1%(R4) -> 30.8%(R4 토너먼트)까지 개선되었다.


2. 핵심 원칙 (6 Principles)

2.1 성과 추이: 원칙 적용의 누적 효과

본 문서의 6가지 원칙은 RummiArena의 5라운드에 걸친 실험에서 단계적으로 적용되었다.

---
config:
  theme: default
---
xychart-beta
    title "프롬프트 최적화에 따른 Place Rate 추이"
    x-axis ["R2 (v0)<br\>한국어 공통", "R3 (v1)<br\>영문 전용", "R4 (v2)<br\>few-shot+검증", "R4 토너먼트<br\>(v2)", "v2 Cross<br\>전 모델 통일"]
    y-axis "Place Rate (%)" 0 --> 40
    bar [5, 12.5, 23.1, 30.8, 33.3]
    line [15, 15, 15, 15, 15]

bar: 각 라운드 최고 성적 (R2~R4: DeepSeek, v2 Cross: Claude). line: 목표선(15%).


원칙 1: 언어는 영문으로 통일하라

추론 모델의 chain-of-thought는 영문 학습 데이터에 최적화되어 있다. 한국어 프롬프트를 영문으로 전환하면 동일한 토큰 예산 내에서 더 깊은 추론이 가능하다.

RummiArena 근거: 한국어 공통 프롬프트(~3,000 토큰)를 영문 전용(~1,200 토큰)으로 전환하자 DeepSeek의 Place Rate가 5% -> 12.5%로 개선되었다(+7.5%p). 토큰이 60% 절감되면서 모델이 규칙 해석이 아닌 실제 타일 조합 탐색에 reasoning 예산을 집중할 수 있게 되었다.

flowchart LR
    subgraph BEFORE["변경 전 (한국어 혼합)"]
        direction TB
        B1["시스템 프롬프트: ~3,000 토큰"]
        B2["한국어 게임 규칙\n+ 한국어 캐릭터 설명\n+ 한국어 JSON 안내"]
        B3["DeepSeek Place Rate: 5%"]
    end

    subgraph AFTER["변경 후 (영문 전용)"]
        direction TB
        A1["시스템 프롬프트: ~1,200 토큰"]
        A2["영문 규칙 (간결)\n+ 구조화된 포맷\n+ VALID/INVALID 예시"]
        A3["DeepSeek Place Rate: 12.5%"]
    end

    BEFORE -->|"60% 토큰 절감\n+7.5%p 개선"| AFTER

    style BEFORE fill:#f8d7da,stroke:#c0392b
    style AFTER fill:#d4edda,stroke:#28a745

적용 방법:

  • 시스템 프롬프트의 모든 지시를 영문으로 작성
  • 게임 규칙, 응답 형식, 예시 모두 영문 통일
  • 타일 코드(R7a, B13b)는 원래 영문이므로 자연스럽게 맞물림
  • 한국어가 필요한 영역(캐릭터 대사 등)만 별도 분리

추정 기여도: ~+5%p


원칙 2: 자기 검증 단계를 명시하라 (Self-Verification)

추론 모델에게 “답변을 제출하기 전에 검증하라”고 지시하면, 모델은 reasoning chain에 검증 단계를 자연스럽게 편입한다. 이 원칙은 Claude Extended Thinking에서 가장 극적인 효과를 보였다.

RummiArena 근거: v2 프롬프트의 “Pre-Submission Validation Checklist” 7항목 도입 후:

  • Claude Sonnet 4: 20.0% -> 33.3% (+13.3%p, 최대 개선폭)
  • DeepSeek Reasoner: 12.5% -> 23.1% (+10.6%p)
  • GPT-5-mini: 28.0% -> 30.8% (+2.8%p)

Claude에서 효과가 가장 큰 이유는 extended thinking이 검증 지시를 “thinking 블록 안에서 각 항목을 하나씩 점검”하는 형태로 처리하기 때문이다. thinking의 깊이가 검증 항목 수만큼 구조적으로 늘어난다.

v2 프롬프트의 실제 검증 체크리스트 (v2-reasoning-prompt.ts 110~118행):

1
2
3
4
5
6
7
8
9
# Pre-Submission Validation Checklist (MUST verify before answering)
Before you output your JSON, verify ALL of these:
1. Each set in tableGroups has >= 3 tiles (NEVER 2 or 1)
2. Each run has the SAME color and CONSECUTIVE numbers (no gaps, no wraparound)
3. Each group has the SAME number and ALL DIFFERENT colors (no duplicate colors)
4. tilesFromRack contains ONLY tiles from "My Rack Tiles" (not table tiles)
5. ALL existing table groups are preserved in tableGroups (none omitted)
6. If initialMeldDone=false: sum of placed tile numbers >= 30, and no table tiles used
7. Every tile code in your response matches the {Color}{Number}{Set} format exactly

핵심: “자유롭게 검증하라”가 아니라 구체적인 항목을 나열해야 한다. 추론 모델은 나열된 항목을 reasoning에서 하나씩 체크하는 경향이 있다.

추정 기여도: ~+8%p (Claude에서는 +13.3%p까지)


원칙 3: 부정 예시를 반드시 포함하라 (Negative Examples)

“이것은 유효하다”만으로는 부족하다. “이것은 왜 무효인지”를 쌍으로 제시해야 추론 모델이 reasoning 중 자체 반례를 생성하는 패턴을 학습한다.

RummiArena 근거: Round 3에서 DeepSeek의 무효 배치 비율이 55%(11회 시도 중 4회 거부)였다. 주요 실패 유형은 “동일 색상 중복 그룹”과 “비연속 숫자 런”이었는데, 이는 부정 예시 부재로 모델이 경계 케이스를 학습하지 못한 결과였다. v2에서 VALID/INVALID 쌍을 도입한 후 무효 배치가 크게 감소했다.

v2 프롬프트의 실제 부정 예시 (v2-reasoning-prompt.ts 36~60행):

1
2
3
4
5
6
7
8
VALID GROUP examples:
  [R7a, B7a, K7a]           -> number=7 for all, colors=R,B,K (3 different) OK
  [R5a, B5b, Y5a, K5a]      -> number=5 for all, colors=R,B,Y,K (4 different) OK

INVALID GROUP examples:
  [R7a, R7b, B7a]  -> REJECTED: color R appears TWICE (ERR_GROUP_COLOR_DUP)
  [R7a, B5a, K7a]  -> REJECTED: numbers differ 7,5,7 (ERR_GROUP_NUMBER)
  [R7a, B7a]        -> REJECTED: only 2 tiles, need >= 3 (ERR_SET_SIZE)

설계 원칙:

  1. 모든 VALID 예시에 대응하는 INVALID 예시를 함께 배치
  2. INVALID의 이유를 명시 (에러 코드까지 포함하면 더 효과적)
  3. 실제 실험에서 관찰된 실패 유형을 우선적으로 부정 예시화
  4. a/b 세트 구분자 혼동 사례를 반드시 포함 (루미큐브 특수)

추정 기여도: ~+5%p


원칙 4: Step-by-Step 사고 절차를 구조화하라

추론 모델에게 “생각하라”가 아니라 “이 순서로 생각하라” 고 지시해야 한다. 구조화된 사고 절차는 reasoning chain을 안정화시키고, 빠뜨리는 단계 없이 체계적으로 탐색하게 만든다.

RummiArena 근거: v2 프롬프트의 9단계 사고 절차 도입 후 GPT-5-mini가 최초로 80턴 완주에 성공했다(이전 Round 4에서는 서버 이슈로 14턴 종료). 구조화된 절차가 매 턴 일관된 품질의 reasoning을 유도하여 80턴 장기전에서 안정성을 확보한 것으로 분석된다.

v2 프롬프트의 실제 9단계 절차 (v2-reasoning-prompt.ts 120~129행):

1
2
3
4
5
6
7
8
9
10
# Step-by-Step Thinking Procedure
1. List ALL tiles in my rack, grouped by color
2. Find ALL possible groups: for each number, check if 3+ different colors exist
3. Find ALL possible runs: for each color, find consecutive sequences of 3+
4. If initialMeldDone=false: calculate point sum for each combination, keep only sum >= 30
5. If initialMeldDone=true: also check if I can extend existing table groups/runs
6. Compare all valid combinations: pick the one that places the MOST tiles
7. If no valid combination exists: choose "draw"
8. Build JSON response: include ALL existing table groups + your new groups
9. Run the validation checklist above before outputting

설계 원칙:

  • 탐색 단계(1 ~ 3) -> 필터링 단계(4 ~ 5) -> 결정 단계(6 ~ 7) -> 출력 단계(8 ~ 9)의 자연스러운 흐름
  • 6번의 “MOST tiles” 기준이 모델의 의사결정에 명확한 방향을 제공
  • 마지막 단계(9번)에서 검증 체크리스트와 연결하여 원칙 2와 시너지

추정 기여도: ~+3%p (GPT에서 안정성 향상에 특히 효과적)


원칙 5: max_tokens를 충분히 확보하라

추론 모델의 output은 reasoning_tokens + completion_tokens의 합산이다. 프롬프트가 복잡해질수록 내부 추론이 길어지며, max_tokens가 부족하면 reasoning만 소비하고 실제 응답(completion)이 잘리는 치명적 문제가 발생한다.

RummiArena 근거: DeepSeek Reasoner에서 v2 프롬프트(few-shot 5개 + 자기 검증 7항목)를 적용했을 때, max_tokens 8192 설정으로는 Place Rate가 4.0% (F등급) 까지 추락했다. reasoning이 ~5,000 토큰을 소비하여 content(실제 JSON 응답)가 잘렸기 때문이다. 16384로 확대 후 23.1% (A등급) 으로 회복되었다.

flowchart LR
    subgraph TRUNCATED["max_tokens: 8192\n(부족한 경우)"]
        direction TB
        T1["reasoning: ~5,000 토큰\n(few-shot 학습 + 검증)"]
        T2["completion: ~3,192 토큰\n(JSON 잘림!)"]
        T3["finish_reason: length\nPlace Rate: 4.0% (F)"]
    end

    subgraph SUFFICIENT["max_tokens: 16384\n(충분한 경우)"]
        direction TB
        S1["reasoning: ~5,000 토큰\n(동일한 사고 과정)"]
        S2["completion: ~100 토큰\n(JSON 정상 출력)"]
        S3["finish_reason: stop\nPlace Rate: 23.1% (A)"]
    end

    TRUNCATED -.->|"max_tokens 확대"| SUFFICIENT

    style TRUNCATED fill:#e74c3c,color:#fff,stroke:#333
    style SUFFICIENT fill:#27ae60,color:#fff,stroke:#333

모델별 max_tokens 설정 가이드:

모델max_tokens 의미권장값파라미터명
GPT-5-minireasoning + completion 합산8192max_completion_tokens
DeepSeek Reasonerreasoning + completion 합산16384max_tokens
Claude Sonnet 4thinking + text 합산16000max_tokens + budget_tokens: 10000
Ollama qwen2.5:3bcompletion만4096num_predict

핵심: 프롬프트를 복잡하게 만들수록(few-shot, 검증 체크리스트 추가 등) reasoning이 길어진다. 자기 검증 체크리스트는 반드시 충분한 max_tokens와 함께 사용해야 한다.

추정 기여도: ~+10%p (DeepSeek에서 4.0% -> 23.1%의 핵심 원인)


원칙 6: 토큰 예산을 reasoning에 집중시켜라

시스템 프롬프트가 짧을수록 모델의 reasoning 예산이 늘어난다. few-shot 예시는 “패턴 시연”에 필요한 최소한(3~5개)만 포함하고, 나머지는 모델이 추론하게 맡겨야 한다.

RummiArena 근거: v2 프롬프트의 시스템 토큰은 ~1,200으로, 한국어 혼합 프롬프트(~3,000)의 40% 수준이다. 절감된 ~1,800 토큰이 그대로 reasoning 예산으로 전환된다. few-shot은 5개(draw, run, group, extend, multi)로 핵심 패턴만 커버하고, “2개 세트 동시 배치”나 “조커 활용” 같은 고급 전략은 모델이 규칙으로부터 스스로 추론하도록 했다.

시스템 프롬프트 토큰 예산 구성 (v2 기준):

구성 요소토큰비율
Tile Encoding + a/b 구분~1008%
규칙 (Group/Run/Size/InitialMeld/tableGroups)~45038%
Few-shot 예시 5개~30025%
Self-Verification 체크리스트 7항목~1008%
Step-by-Step 9단계~1008%
Response Format + JSON 강제~15013%
합계~1,200100%

안티패턴: few-shot을 10개 이상 넣으면 reasoning budget을 잠식한다. DeepSeek Reasoner처럼 reasoning이 길어지는 모델에서는 시스템 프롬프트 비대가 직접적으로 content 절단 위험으로 이어진다.

추정 기여도: 단독 측정 어려움 (원칙 1의 영문 전환과 시너지)


3. 안티패턴 (Anti-Patterns)

3.1 안티패턴 목록

flowchart TB
    subgraph ANTI["프롬프트 안티패턴 5가지"]
        AP1["AP1: 한국어 장문 프롬프트\n(~3,000+ 토큰)"]
        AP2["AP2: 비구조적 사고 지시\n('자유롭게 생각하세요')"]
        AP3["AP3: Few-shot 과다\n(10개 이상)"]
        AP4["AP4: max_tokens 부족\n(8192 이하)"]
        AP5["AP5: 비추론 모델에\n추론 전략 적용"]
    end

    AP1 -->|"결과"| R1["토큰 낭비, 추론 깊이 감소\nDeepSeek R2: 5% (F)"]
    AP2 -->|"결과"| R2["무방향 reasoning\n무효 배치 55%"]
    AP3 -->|"결과"| R3["reasoning budget 잠식\ncontent 절단 위험"]
    AP4 -->|"결과"| R4["reasoning만 소비, 응답 잘림\nDeepSeek R4 Run1: 4% (F)"]
    AP5 -->|"결과"| R5["추론 없이 패턴 매칭만\nClaude Opus: 5% (F)"]

    style ANTI fill:#fff3cd,stroke:#ffc107
    style R1 fill:#e74c3c,color:#fff,stroke:#333
    style R2 fill:#e74c3c,color:#fff,stroke:#333
    style R3 fill:#e74c3c,color:#fff,stroke:#333
    style R4 fill:#e74c3c,color:#fff,stroke:#333
    style R5 fill:#e74c3c,color:#fff,stroke:#333

3.2 안티패턴 상세

AP1: 한국어 장문 프롬프트

문제: 한국어는 동일한 의미를 전달하는 데 영문 대비 ~2.5배의 토큰을 소비한다. 추론 모델에서는 이 추가 토큰이 직접적으로 reasoning 예산을 압축한다.

실험 근거: Round 2에서 한국어 혼합 공통 프롬프트(~3,000 토큰)를 사용한 DeepSeek는 5%(F)를 기록했다. 동일한 게임 규칙을 영문 전용(~1,200 토큰)으로 재작성한 Round 3에서 12.5%(C)로 개선되었다.

AP2: “자유롭게 생각하세요” 지시

문제: 구조 없는 reasoning은 탐색 방향이 산만해진다. 추론 모델이 “무엇부터 확인해야 하는지” 모르면 불필요한 가설을 세우거나 핵심 규칙을 빠뜨린다.

실험 근거: Round 3 이전에는 Step-by-Step 절차 없이 “가능한 조합을 찾아 배치하라”는 포괄적 지시만 있었다. DeepSeek는 런과 그룹 탐색 순서를 혼동하거나, initial meld 조건을 늦게 확인하여 T24까지 첫 배치가 지연되었다. 9단계 절차 도입 후 체계적 탐색이 이루어져 R4에서는 T2에서 첫 배치에 성공했다.

AP3: Few-shot 과다 (10개 이상)

문제: few-shot 1개당 약 60~80 토큰이 소비된다. 10개면 ~700 토큰으로, v2 시스템 프롬프트(~1,200)의 58%를 차지하게 된다. 남은 예산으로는 규칙 명시와 검증 체크리스트를 담을 수 없다.

설계 결정: v2에서는 5개 예시로 핵심 패턴만 커버한다 – (1) draw, (2) run, (3) group, (4) extend, (5) multi-set. 이 5가지가 루미큐브의 모든 행동 유형을 대표한다.

AP4: max_tokens 부족

문제: 추론 모델에서 max_tokens는 “reasoning + completion”의 합산 상한이다. 프롬프트가 복잡하면 reasoning이 길어지고, completion(실제 JSON 응답)이 잘린다.

실험 근거: DeepSeek R4 Run 1에서 max_tokens 8192로 v2 프롬프트를 실행했을 때 finish_reason: "length"가 빈번히 발생하며 Place Rate가 4.0%(F)까지 추락했다. 16384로 확대 후 23.1%(A)로 회복. 이 차이만으로 +19.1%p가 발생했다.

AP5: 비추론 모델에 추론 전략 적용

문제: Step-by-Step 절차나 자기 검증 체크리스트는 추론 모델이 reasoning chain에서 활용할 때만 효과적이다. 비추론 모델(Ollama qwen2.5:3b 등)에서는 이런 지시가 출력 토큰만 늘리고 실제 사고 개선에 기여하지 않는다.

설계 결정: RummiArena에서 Ollama(qwen2.5:3b)는 v2 프롬프트를 적용하지 않고 기존 v1 공통 프롬프트를 유지한다. USE_V2_PROMPT 환경 변수가 true여도 Ollama 어댑터는 v1을 사용한다.


4. 모델별 특화 가이드

4.1 GPT-5-mini (OpenAI, 내장 추론)

flowchart TB
    subgraph GPT["GPT-5-mini 특성"]
        direction TB
        G1["내장 추론: reasoning_tokens가\ncompletion 내부에 합산"]
        G2["JSON mode: response_format으로\n출력 형식 강제 가능"]
        G3["Temperature: 고정 1\n(추론 모델에서 변경 불가)"]
        G4["비용: ~$0.025/턴\n(균형잡힌 가격대)"]
    end

    subgraph GPT_RESULT["RummiArena 성과"]
        direction TB
        GR1["R2 (v1): 28.0%\n80턴 완주"]
        GR2["v2 Cross: 30.8%\n80턴 완주, Fallback 0%"]
    end

    GPT --> GPT_RESULT

    style GPT fill:#10a37f,color:#fff,stroke:#333
    style GPT_RESULT fill:#d4edda,stroke:#28a745

핵심 설정:

파라미터근거
max_completion_tokens8192GPT는 자체 최적화로 reasoning 절단이 드물다
response_format{ type: "json_object" }API 수준 JSON 강제로 파싱 실패 0%
temperature1 (고정)추론 모델에서 변경 불가
timeout120,000ms평균 응답 20.9 ~ 64.6s

GPT 특화 포인트:

  • response_format: json_object가 있으므로 프롬프트에서의 JSON 강제 지시는 보조적 역할
  • max_completion_tokens(max_tokens가 아님)를 사용해야 함 – OpenAI 추론 모델 고유 파라미터
  • v2 프롬프트의 Step-by-Step 절차가 80턴 장기전 안정성에 핵심적 기여

4.2 Claude Sonnet 4 (Anthropic, Extended Thinking)

flowchart TB
    subgraph CLAUDE["Claude Sonnet 4 특성"]
        direction TB
        C1["Extended Thinking: thinking 블록이\ntext와 분리되어 출력"]
        C2["budget_tokens: thinking 예산을\n별도 제어 (10,000)"]
        C3["Temperature: thinking 모드에서\n설정 불가 (비활성)"]
        C4["비용: ~$0.074/턴\n(가장 고비용)"]
    end

    subgraph CLAUDE_RESULT["RummiArena 성과"]
        direction TB
        CR1["R2 (v1): 23.0%\n80턴 완주"]
        CR2["R4 (v1): 20.0%\nWS_TIMEOUT 32턴"]
        CR3["v2 Cross: 33.3%\n역대 최고, Fallback 0%"]
    end

    CLAUDE --> CLAUDE_RESULT

    style CLAUDE fill:#d97706,color:#fff,stroke:#333
    style CLAUDE_RESULT fill:#d4edda,stroke:#28a745

핵심 설정:

파라미터근거
max_tokens16000thinking + text 합산
budget_tokens10000thinking 예산 별도 제어
temperature비활성thinking 모드에서 설정 불가
timeout120,000ms평균 응답 52.3 ~ 63.8s (변동 16.8 ~ 170.5s)

Claude 특화 포인트:

  • v2 프롬프트의 자기 검증 체크리스트와 extended thinking의 시너지가 최대 – thinking 블록 안에서 7항목을 하나씩 검증하는 패턴이 관찰됨
  • thinking과 text 블록이 별도 파싱 필요: response.content에서 type === "thinking" / type === "text" 분리
  • 응답 시간 변동이 큼(16.8s ~ 170.5s) – WS_TIMEOUT에 유의해야 함
  • “slow start, strong finish” 패턴: 전반에는 보수적으로 draw, 후반에 thinking 심층 분석으로 연속 배치

4.3 DeepSeek Reasoner (DeepSeek, Chain-of-Thought)

flowchart TB
    subgraph DEEPSEEK["DeepSeek Reasoner 특성"]
        direction TB
        D1["CoT: reasoning_content 필드가\ncontent와 별도 반환"]
        D2["JSON mode 미지원:\n프롬프트 수준에서만 강제"]
        D3["Temperature: 0 고정\n(추론 모델에서 변경 불가)"]
        D4["비용: ~$0.001/턴\n(압도적 저비용)"]
    end

    subgraph DEEPSEEK_RESULT["RummiArena 성과"]
        direction TB
        DR1["R2 (v0): 5.0% (F)"]
        DR2["R3 (v1): 12.5% (C)"]
        DR3["R4 (v2): 23.1% (A)"]
        DR4["R4 토너먼트: 30.8% (A+)"]
    end

    DEEPSEEK --> DEEPSEEK_RESULT

    style DEEPSEEK fill:#4f46e5,color:#fff,stroke:#333
    style DEEPSEEK_RESULT fill:#d4edda,stroke:#28a745

핵심 설정:

파라미터근거
max_tokens16384reasoning 절단 방지 (8192에서 content 잘림 발생)
temperature0 (고정)추론 모델에서 변경 불가
timeout150,000ms평균 응답 131.5~147.8s (최대 200.3s)
maxRetries3JSON 파싱 실패 시 재시도

DeepSeek 특화 포인트:

  • JSON mode 미지원이므로 4단계 JSON 추출 파이프라인이 필수:
    1. content 필드에서 직접 JSON.parse 시도
    2. 실패 시 정규식으로 JSON 블록 추출 (/\{[\s\S]*\}/)
    3. 실패 시 reasoning_content에서 JSON 탐색
    4. 모든 단계 실패 시 fallback draw
  • reasoning이 길어서(avg 131~148s) 타임아웃 여유를 충분히 확보해야 함
  • 비용 대비 성과(Place per Dollar)가 압도적: GPT의 14.6배, Claude의 39.9배
  • “저빈도 대량 배치” 패턴: place 횟수는 적지만 단회 배치 타일 수가 평균 4.1개로 최고

5. 실전 적용 가이드

5.1 프롬프트 설계 체크리스트

새로운 도메인에 추론 모델 프롬프트를 설계할 때 아래 체크리스트를 따른다.

#항목원칙확인
1프롬프트가 영문으로 작성되었는가?원칙 1 
2자기 검증 체크리스트(3항목 이상)가 포함되었는가?원칙 2 
3VALID/INVALID 쌍의 부정 예시가 포함되었는가?원칙 3 
4번호가 매겨진 Step-by-Step 사고 절차가 있는가?원칙 4 
5max_tokens가 예상 reasoning 길이의 2배 이상인가?원칙 5 
6시스템 프롬프트가 2,000 토큰 이하인가?원칙 6 
7few-shot 예시가 3~5개 범위인가?원칙 6 
8모델별 JSON 강제 방식이 적용되었는가?모델 가이드 
9타임아웃이 모델 평균 응답 시간의 3배 이상인가?모델 가이드 

5.2 A/B 테스트 방법론

프롬프트 최적화는 반드시 단일 변수 변경 원칙을 따라야 한다.

flowchart TB
    subgraph METHOD["A/B 테스트 방법론"]
        direction TB
        M1["1. Control 설정\n(현재 프롬프트)"]
        M2["2. Treatment 설정\n(변경 1가지만)"]
        M3["3. 동일 조건 실행\n(모델, 난이도, 턴 수)"]
        M4["4. 결과 비교\n(Place Rate, Fallback, 비용)"]
        M5["5. 유의성 확인\n(n >= 3 반복)"]
    end

    M1 --> M2 --> M3 --> M4 --> M5

    subgraph EXAMPLE["RummiArena 실례"]
        E1["Control: max_tokens=8192"]
        E2["Treatment: max_tokens=16384"]
        E3["결과: 4.0% -> 23.1%\n(단일 변수 변경으로 확인)"]
    end

    style METHOD fill:#3498db,color:#fff,stroke:#333
    style EXAMPLE fill:#d4edda,stroke:#28a745

RummiArena에서의 A/B 테스트 실제 사례:

테스트ControlTreatment변경 변수결과
R2 -> R3한국어 ~3000 토큰영문 ~1200 토큰프롬프트 언어5% -> 12.5%
R3 -> R4 Run 1v1 (few-shot 0, 검증 0)v2 (few-shot 5, 검증 7)프롬프트 내용12.5% -> 4.0% (max_tokens 부족 발견)
R4 Run 1 -> R4 Run 2max_tokens 8192max_tokens 16384max_tokens4.0% -> 23.1%
R4 개별 -> v2 CrossDeepSeek 전용 v23모델 공통 v2프롬프트 공유 범위GPT +2.8%p, Claude +13.3%p

5.3 비용 최적화 전략

추론 모델은 비용 차이가 극심하다. 효율적인 최적화 파이프라인은 저비용 모델로 프롬프트를 튜닝한 뒤, 검증된 프롬프트를 고비용 모델에 적용하는 것이다.

flowchart LR
    subgraph STAGE1["Stage 1: 프롬프트 개발\n(DeepSeek, $0.001/턴)"]
        S1_1["프롬프트 v1 작성"]
        S1_2["A/B 테스트 반복\n(10~20게임, ~$0.20)"]
        S1_3["최적 프롬프트 확정"]
        S1_1 --> S1_2 --> S1_3
    end

    subgraph STAGE2["Stage 2: 크로스 모델 검증\n(GPT, $0.025/턴)"]
        S2_1["확정 프롬프트 적용"]
        S2_2["3게임 검증\n(~$3.00)"]
        S2_1 --> S2_2
    end

    subgraph STAGE3["Stage 3: 프로덕션 배포\n(목적에 따라 선택)"]
        S3_1["대량 실행: DeepSeek"]
        S3_2["최고 품질: Claude"]
        S3_3["균형: GPT"]
    end

    STAGE1 -->|"검증된 프롬프트"| STAGE2
    STAGE2 -->|"배포"| STAGE3

    style STAGE1 fill:#4f46e5,color:#fff,stroke:#333
    style STAGE2 fill:#10a37f,color:#fff,stroke:#333
    style STAGE3 fill:#d97706,color:#fff,stroke:#333

RummiArena 비용 데이터:

모델비용/턴80턴 게임 비용Place/Dollar비고
DeepSeek Reasoner$0.001$0.039179.5프롬프트 개발에 최적
GPT-5-mini$0.025$0.97512.3균형잡힌 비용/성능
Claude Sonnet 4$0.074$2.2204.5최고 성능, 고비용

DeepSeek로 프롬프트를 20게임 튜닝하는 비용($0.80)은 Claude 1게임($2.22)보다 저렴하다.

5.4 분산 관리

단일 게임(n=1)의 결과는 타일풀 랜덤성에 크게 좌우된다. RummiArena v2 Cross 실험에서 DeepSeek는 동일한 프롬프트로 17.9%(n=1)와 30.8%(n=1)라는 큰 분산을 보였다.

분산 감소 전략:

  1. 다회 실행 평균: 최소 n=3, 이상적으로 n=5 이상
  2. 타일풀 시드 고정: 동일한 초기 배분으로 프롬프트 변수만 격리
  3. 구간별 분석: 전반(T1 ~ T26)/중반(T27 ~ T54)/후반(T55 ~ T80) 분리 평가
  4. 신뢰 구간 보고: 단일 수치가 아닌 범위로 보고
모델관측 횟수Rate 범위추정 실력 범위
GPT-5-mini2회28.0~30.8%25~35%
Claude Sonnet 43회20.0~33.3%20~35%
DeepSeek Reasoner4회 (v2 이후 2회)17.9~30.8%15~30%

6. 결론

6.1 핵심 메시지

  1. 추론 모델은 프롬프트 품질에 비추론 모델보다 더 민감하다. 동일한 DeepSeek Reasoner에서 프롬프트 변경만으로 5% -> 30.8%(6.2배)까지 개선되었다.

  2. 6가지 원칙은 상호 보완적이다. 영문 전환(원칙 1)으로 확보된 토큰 예산이 자기 검증(원칙 2)과 부정 예시(원칙 3)에 활용되고, max_tokens 확보(원칙 5)가 이 모든 것을 뒷받침한다.

  3. 한 번의 프롬프트 최적화가 다모델에 공통 적용된다. v2 프롬프트를 DeepSeek 전용에서 3모델 공통으로 확장했을 때, GPT(+2.8%p)와 Claude(+13.3%p) 모두 개선되었다. 프롬프트 유지보수가 2종에서 1종으로 단순화되었다.

  4. 비용과 성능의 트레이드오프는 목적으로 결정한다. DeepSeek는 Place/Dollar 179.5로 개발/대량 실행에, Claude는 최고 Rate 33.3%로 품질 우선 시나리오에, GPT는 30.8% + 0% Fallback으로 균형 시나리오에 적합하다.

6.2 6가지 원칙 요약

원칙핵심최대 효과 모델추정 기여도
1. 영문 통일토큰 60% 절감 -> reasoning 깊이 증가전 모델 공통~+5%p
2. 자기 검증검증 항목을 reasoning에 편입Claude (+13.3%p)~+8%p
3. 부정 예시VALID/INVALID 쌍으로 경계 학습DeepSeek~+5%p
4. Step-by-Step구조화된 사고로 안정성 확보GPT (80턴 완주)~+3%p
5. max_tokens 확보reasoning 절단 방지DeepSeek (+19.1%p)~+10%p
6. 토큰 집중few-shot 최소화, 규칙 우선전 모델 공통원칙 1과 시너지

6.3 프롬프트 최적화 여정 전체 타임라인

gantt
    title 프롬프트 최적화 여정 (v0 -> v2 Cross, 5% -> 33.3%)
    dateFormat YYYY-MM-DD
    axisFormat %m/%d

    section Round 2 (v0)
    한국어 공유 프롬프트       :done, r2, 2026-03-31, 1d
    DeepSeek 5% (F)            :milestone, m2, 2026-03-31, 0d

    section Round 3 (v1, 원칙1 적용)
    영문 전용 전환 (원칙 1)     :done, r3a, 2026-04-01, 2d
    4단계 JSON 추출 구현        :done, r3b, 2026-04-01, 2d
    DeepSeek 12.5% (C)         :milestone, m3, 2026-04-03, 0d

    section Round 4 (v2, 원칙2~4 적용)
    자기 검증 7항목 (원칙 2)    :done, r4b, 2026-04-04, 1d
    부정 예시 추가 (원칙 3)     :done, r4c, 2026-04-04, 1d
    Step-by-Step 9단계 (원칙 4) :done, r4d, 2026-04-04, 1d
    max_tokens 16384 (원칙 5)   :done, r4e, 2026-04-05, 1d
    DeepSeek 23.1% (A)         :milestone, m4, 2026-04-05, 0d

    section R4 토너먼트 + v2 Cross (원칙6 확인)
    3모델 토너먼트 (원칙 6)     :done, r5a, 2026-04-06, 1d
    DeepSeek 30.8% (A+)       :milestone, m5d, 2026-04-06, 0d
    v2 크로스 모델 실험         :done, r5b, 2026-04-06, 1d
    Claude 33.3% (A+, 역대최고) :milestone, m5c, 2026-04-06, 0d
    GPT 30.8% (A+, 80턴 첫 완주) :milestone, m5g, 2026-04-06, 0d

부록 A: v2 프롬프트 전문

아래는 src/ai-adapter/src/prompt/v2-reasoning-prompt.tsV2_REASONING_SYSTEM_PROMPT 전문이다. 3모델(GPT-5-mini, Claude Sonnet 4, DeepSeek Reasoner)이 공유하는 단일 시스템 프롬프트이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
export const V2_REASONING_SYSTEM_PROMPT = `You are a Rummikub game AI. Respond with ONLY a valid JSON object.

# Tile Encoding (CRITICAL - understand this perfectly)
Each tile code follows the pattern: {Color}{Number}{Set}

| Component | Values                          | Meaning                            |
|-----------|----------------------------------|-------------------------------------|
| Color     | R, B, Y, K                       | Red, Blue, Yellow, Black            |
| Number    | 1, 2, 3, ..., 13                 | Face value (also = point value)     |
| Set       | a, b                             | Distinguishes duplicate tiles       |
| Jokers    | JK1, JK2                         | Wild cards (2 total)                |

Examples: R7a = Red 7 (set a), B13b = Blue 13 (set b), K1a = Black 1 (set a)
Total tiles: 4 colors x 13 numbers x 2 sets + 2 jokers = 106 tiles

# Rules (STRICT - Game Engine rejects ALL violations)

## GROUP Rules: Same number, DIFFERENT colors, 3-4 tiles
- Every tile in a group MUST have the SAME number
- Every tile in a group MUST have a DIFFERENT color (R, B, Y, K)
- No color can appear twice in a group

VALID GROUP examples:
  [R7a, B7a, K7a]           -> number=7 for all, colors=R,B,K (3 different) OK
  [R5a, B5b, Y5a, K5a]      -> number=5 for all, colors=R,B,Y,K (4 different) OK

INVALID GROUP examples:
  [R7a, R7b, B7a]  -> REJECTED: color R appears TWICE (ERR_GROUP_COLOR_DUP)
  [R7a, B5a, K7a]  -> REJECTED: numbers differ 7,5,7 (ERR_GROUP_NUMBER)
  [R7a, B7a]        -> REJECTED: only 2 tiles, need >= 3 (ERR_SET_SIZE)

## RUN Rules: Same color, CONSECUTIVE numbers, 3+ tiles
- Every tile in a run MUST have the SAME color
- Numbers must be strictly consecutive (no gaps)
- No wraparound: 13-1 is NOT allowed
- Minimum 3 tiles, maximum 13 tiles

VALID RUN examples:
  [R7a, R8a, R9a]              -> color=R for all, numbers=7,8,9 consecutive OK
  [B10a, B11a, B12a, B13a]     -> color=B for all, numbers=10,11,12,13 OK
  [K1a, K2a, K3a, K4a, K5a]   -> color=K for all, numbers=1,2,3,4,5 OK

INVALID RUN examples:
  [R7a, B8a, K9a]  -> REJECTED: different colors R,B,K (run needs SAME color)
  [R7a, R9a, R10a] -> REJECTED: gap at 8 (numbers must be consecutive)
  [R12a, R13a, R1a] -> REJECTED: wraparound 13->1 is forbidden
  [R7a, R8a]        -> REJECTED: only 2 tiles, need >= 3 (ERR_SET_SIZE)

## Size Rule: EVERY group and run must have >= 3 tiles. 2 tiles = ALWAYS INVALID.

## Initial Meld Rule (when initialMeldDone=false):
- Sum of tile numbers in your placed sets must be >= 30 points
- Use ONLY your rack tiles (you CANNOT touch or use table tiles)
- Each tile's number IS its point value: R10a = 10 pts, B3a = 3 pts
- Example: R10a + R11a + R12a = 10+11+12 = 33 pts >= 30 -> VALID
- Example: R1a + R2a + R3a = 1+2+3 = 6 pts < 30 -> REJECTED

## tableGroups = COMPLETE final state of the ENTIRE table after your move
- You MUST include ALL existing table groups (even unchanged ones)
- Then add your new groups
- If you omit any existing group -> "tile loss" -> REJECTED

## tilesFromRack = ONLY tiles YOU placed from YOUR hand (not table tiles)

# Few-Shot Examples (study these carefully)

## Example 1: Draw (no valid combination)
My rack: [R5a, B7b, K3a, Y11a]
Table: (empty), initialMeldDone=false
Analysis: R5+B7+K3=15 (not a valid set anyway), no 3+ same-number or same-color consecutive
-> {"action":"draw","reasoning":"no valid group or run with sum >= 30"}

## Example 2: Place single run (initial meld)
My rack: [R10a, R11a, R12a, B5b, K3a]
Table: (empty), initialMeldDone=false
Analysis: R10a,R11a,R12a = Red run 10-11-12, sum=33 >= 30
-> {"action":"place","tableGroups":[{"tiles":["R10a","R11a","R12a"]}],
    "tilesFromRack":["R10a","R11a","R12a"],
    "reasoning":"Red run 10-11-12, sum=33 for initial meld"}

## Example 3: Place group (initial meld)
My rack: [R10a, B10b, K10a, Y2a, R3b]
Table: (empty), initialMeldDone=false
Analysis: R10a,B10b,K10a = Group of 10s (R,B,K), sum=30 >= 30
-> {"action":"place","tableGroups":[{"tiles":["R10a","B10b","K10a"]}],
    "tilesFromRack":["R10a","B10b","K10a"],
    "reasoning":"Group of 10s (R,B,K), sum=30 for initial meld"}

## Example 4: Extend existing table group (after initial meld)
My rack: [R6a, B2a]
Table: Group1=[R3a,R4a,R5a], Group2=[B7a,Y7a,K7a], initialMeldDone=true
Analysis: R6a can extend Group1 (R3a,R4a,R5a,R6a = Red run 3-4-5-6)
-> {"action":"place","tableGroups":[{"tiles":["R3a","R4a","R5a","R6a"]},
    {"tiles":["B7a","Y7a","K7a"]}],
    "tilesFromRack":["R6a"],
    "reasoning":"extend existing Red run with R6a, keep Group2 unchanged"}

## Example 5: Multiple sets placed at once
My rack: [R10a, R11a, R12a, B7a, Y7b, K7a, R1a]
Table: (empty), initialMeldDone=false
Analysis: Run R10-11-12 (33pts) + Group 7s B,Y,K (21pts) = 54pts total, 6 tiles placed
-> {"action":"place","tableGroups":[{"tiles":["R10a","R11a","R12a"]},
    {"tiles":["B7a","Y7b","K7a"]}],
    "tilesFromRack":["R10a","R11a","R12a","B7a","Y7b","K7a"],
    "reasoning":"Red run 33pts + Group of 7s 21pts = 54pts, 6 tiles placed"}

# Pre-Submission Validation Checklist (MUST verify before answering)
Before you output your JSON, verify ALL of these:
1. Each set in tableGroups has >= 3 tiles (NEVER 2 or 1)
2. Each run has the SAME color and CONSECUTIVE numbers (no gaps, no wraparound)
3. Each group has the SAME number and ALL DIFFERENT colors (no duplicate colors)
4. tilesFromRack contains ONLY tiles from "My Rack Tiles" (not table tiles)
5. ALL existing table groups are preserved in tableGroups (none omitted)
6. If initialMeldDone=false: sum of placed tile numbers >= 30, and no table tiles used
7. Every tile code in your response matches the {Color}{Number}{Set} format exactly

# Step-by-Step Thinking Procedure
1. List ALL tiles in my rack, grouped by color
2. Find ALL possible groups: for each number, check if 3+ different colors exist
3. Find ALL possible runs: for each color, find consecutive sequences of 3+
4. If initialMeldDone=false: calculate point sum for each combination, keep only sum >= 30
5. If initialMeldDone=true: also check if I can extend existing table groups/runs
6. Compare all valid combinations: pick the one that places the MOST tiles
7. If no valid combination exists: choose "draw"
8. Build JSON response: include ALL existing table groups + your new groups
9. Run the validation checklist above before outputting

# Response Format (output ONLY this JSON, nothing else)

Draw:
{"action":"draw","reasoning":"reason"}

Place:
{"action":"place","tableGroups":[{"tiles":["R10a","R11a","R12a"]}],
 "tilesFromRack":["R10a","R11a","R12a"],"reasoning":"reason"}

IMPORTANT: Output raw JSON only. No markdown, no code blocks, no explanation text.`;

부록 B: 라운드별 전체 성과 데이터

B.1 전 모델 성과 추이

라운드일자프롬프트모델Place Rate등급비용비고
R22026-03-31v0 한국어 공통GPT-5-mini28.0%A80$1.00 
R22026-03-31v0 한국어 공통Claude Sonnet 423.0%A80$2.96 
R22026-03-31v0 한국어 공통DeepSeek Reasoner5.0%F80$0.04 
R32026-04-03v1 영문 전용DeepSeek Reasoner12.5%C80$0.066영문 전환 효과
R42026-04-05v2 전용DeepSeek Reasoner23.1%A28$0.013max_tokens 16384
R4 토너먼트2026-04-06v2 (DeepSeek만)GPT-5-mini33.3%(N/A)14$0.15WS_CLOSED (불완전)
R4 토너먼트2026-04-06v1 공통Claude Sonnet 420.0%A32$1.11WS_TIMEOUT
R4 토너먼트2026-04-06v2 전용DeepSeek Reasoner30.8%A+80$0.0480턴 완주
v2 Cross2026-04-06v2 공유GPT-5-mini30.8%A+80$0.97580턴 첫 완주
v2 Cross2026-04-06v2 공유Claude Sonnet 433.3%A+62$2.220역대 최고
v2 Cross2026-04-06v2 공유DeepSeek Reasoner17.9%B80$0.039타일풀 분산

B.2 DeepSeek Place Rate 진화 차트

---
config:
  theme: default
---
xychart-beta
    title "DeepSeek Reasoner Place Rate 진화 (프롬프트 최적화별)"
    x-axis ["R2 (v0)<br\>5%", "R3 (v1)<br\>12.5%", "R4 Run2<br\>23.1%", "R4 Tourn<br\>30.8%", "v2 Cross<br\>17.9%"]
    y-axis "Place Rate (%)" 0 --> 35
    bar [5.0, 12.5, 23.1, 30.8, 17.9]
    line [15, 15, 15, 15, 15]

B.3 v2 크로스 모델 비교 차트

---
config:
  theme: default
---
xychart-beta
    title "v2 프롬프트 크로스 모델 결과 (2026-04-06)"
    x-axis ["GPT-5-mini", "Claude Sonnet 4", "DeepSeek Reasoner"]
    y-axis "Place Rate (%)" 0 --> 40
    bar [30.8, 33.3, 17.9]
    line [15, 15, 15]

B.4 비용 효율 비교 차트 (Place per Dollar)

---
config:
  theme: default
---
xychart-beta
    title "비용 대비 성과: Place per Dollar (v2 Cross)"
    x-axis ["GPT-5-mini<br\>(12.3)", "Claude Sonnet 4<br\>(4.5)", "DeepSeek<br\>(179.5)"]
    y-axis "Place per Dollar" 0 --> 200
    bar [12.3, 4.5, 179.5]

부록 C: 참조 문서 목록

문서경로내용
AI Adapter 설계docs/02-design/04-ai-adapter-design.md모델 무관 공통 인터페이스 설계
AI 프롬프트 템플릿docs/02-design/08-ai-prompt-templates.mdv0 프롬프트 원본
DeepSeek 프롬프트 최적화docs/02-design/15-deepseek-prompt-optimization.mdv1 -> v2 최적화 설계
모델별 프롬프트 정책docs/02-design/18-model-prompt-policy.md4종 모델 프롬프트 전략 비교
Round 4 토너먼트 보고서docs/04-testing/37-3model-round4-tournament-report.md3모델 대전 결과
v2 크로스 모델 실험docs/04-testing/38-v2-prompt-crossmodel-experiment.mdv2 프롬프트 전이 효과 검증
v2 프롬프트 코드src/ai-adapter/src/prompt/v2-reasoning-prompt.tsv2 프롬프트 구현체
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.