포스트

Chain-of-Thought(CoT) 프롬프트, 2026년식으로 다시 쓰기: “생각을 시키는” 대신 “생각이 잘 나오게” 설계하는 고급 프롬프트 최적화

Chain-of-Thought(CoT) 프롬프트, 2026년식으로 다시 쓰기: “생각을 시키는” 대신 “생각이 잘 나오게” 설계하는 고급 프롬프트 최적화

들어가며

2022~2023년의 CoT 유행은 “Let’s think step by step” 한 줄로 요약됐습니다. 그런데 2026년 4월 시점의 현장은 다릅니다. 이유는 두 가지입니다.

1) Reasoning model의 CoT가 항상 ‘신뢰 가능한 설명’이 아니다. 모델이 보여주는 reasoning trace가 실제 의사결정의 원인과 완전히 일치하지 않을 수 있다는 연구가 공개적으로 강조됐습니다. 즉, “과정을 길게 출력”시키는 것만으로 품질/안전/디버깅이 해결되지 않습니다. (anthropic.com)
2) 상용 모델은 CoT를 그대로 노출하지 않거나, 요약만 제공하는 방향으로 설계되고 있습니다. OpenAI는 reasoning 모델에서 “원문 CoT”가 아니라 모델이 만든 summary를 제공하는 접근을 설명합니다. (openai.com)

그래서 지금 필요한 건 “CoT를 출력하라”가 아니라,

  • (a) 문제를 잘게 쪼개고
  • (b) 후보 해법을 생성/검증하고
  • (c) 관측 가능한 산출물(JSON, 테스트, 로그)로 품질을 고정 하는 프롬프트 최적화 관점의 CoT 고급 기법입니다.

🔧 핵심 개념

1) CoT의 재정의: “출력 형식”이 아니라 “추론 파이프라인”

현대 CoT는 보통 다음 3계층으로 나뉩니다.

  • Hidden reasoning (모델 내부/비노출): 상용 reasoning 모델은 내부 추론을 안전/정렬 관점에서 그대로 보여주지 않을 수 있음 (openai.com)
  • Reasoning summary (요약된 근거/하이레벨 단계): 사용자에게는 핵심 근거만 간결히 노출
  • Verifiable artifacts (검증 가능한 결과물): 계산/코드/테스트/스키마 출력 등

실무적으로는 “CoT를 길게”보다 검증 가능한 artifacts를 늘리는 것이 더 강력합니다. 이 관점에서 대표 기법이 Self-ConsistencyProgram-of-Thought(PoT) 입니다.

2) Self-Consistency: “한 번 잘 풀기” 대신 “여러 번 풀고 다수결”

CoT는 샘플링에 따라 경로가 달라집니다. Self-Consistency는 여러 해법을 생성한 뒤 최종 답을 집계해 정확도를 올립니다. 단순 greedy decoding 대비 성능이 크게 오른다는 고전 결과가 있고, 여전히 실전에서 강력합니다. (arxiv.org)

핵심은 “생각을 잘하게 지시”가 아니라,

  • N개 후보 생성
  • 정답/근거를 스코어링
  • 합의(majority vote, best-of-n)

3) Plan-and-Solve: CoT를 “계획(Plan) → 실행(Solve)”로 분리

Zero-shot CoT가 흔히 놓치는 건 “처음부터 풀기 시작해서 길을 잃는 것”입니다. Plan-and-Solve는 먼저 계획을 고정하고, 그 계획대로만 풉니다. (arxiv.org)
이건 프롬프트 최적화에서 매우 중요합니다. 계획은 짧고 안정적이라 캐시/재사용도 쉽습니다.

4) Program-of-Thought(PoT): 계산은 코드로, 추론은 텍스트로

수치/로직 문제에서 LLM이 자주 틀리는 이유는 “추론+계산”을 같은 채널에서 하기 때문입니다. PoT는 계산을 코드로 분리해 외부 인터프리터로 실행합니다. (arxiv.org)
결과적으로 “그럴듯한 계산 실수”가 크게 줄고, 디버깅도 쉬워집니다.

5) CoT 모니터링/가시성의 함정: “보이는 CoT = 진짜 원인”이 아닐 수 있다

Anthropic은 reasoning trace의 faithfulness(충실성) 문제를 지적합니다. 즉, 모델이 힌트를 사용해 답을 맞추고도, reasoning에는 다른 이유를 적을 수 있습니다. “설명”을 그대로 신뢰하면 프롬프트 튜닝 방향이 틀어질 수 있습니다. (anthropic.com)
따라서 CoT 자체를 KPI로 두지 말고, 정답률/제약준수율/테스트통과율 같은 외부 지표로 최적화해야 합니다.


💻 실전 코드

아래는 (1) Plan-and-Solve + (2) Self-Consistency + (3) PoT 스타일(계산은 실행)을 한 파이프라인으로 묶는 예시입니다.
“CoT를 출력하라”가 아니라 검증 가능한 결과(JSON + 실행 결과)를 얻는 쪽에 집중합니다.

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
# 언어: Python 3.11+
# pip install openai
import os, json, re
from collections import Counter
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

MODEL = "gpt-4.1-mini"  # 예시: 실제 사용 모델로 교체

SYSTEM = """You are a senior engineer.
Return outputs that are verifiable and follow the requested JSON schema.
Do NOT include hidden chain-of-thought. Provide only a brief reasoning summary when asked.
"""

PLAN_PROMPT = """
You will receive a problem. First produce a short plan (3-6 steps max).
Constraints:
- The plan must be generic and reusable (no final numeric answer in the plan).
- Output JSON only with key: plan (array of strings).
Problem:
{problem}
"""

SOLVE_PROMPT = """
Follow the given plan. Produce:
1) a short reasoning_summary (high-level, no detailed chain-of-thought)
2) executable python_code that computes the final answer
3) final_answer (number or string)

Output JSON only with keys: reasoning_summary, python_code, final_answer.
Plan:
{plan_json}

Problem:
{problem}
"""

def chat_json(prompt: str) -> dict:
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[
            {"role": "system", "content": SYSTEM},
            {"role": "user", "content": prompt},
        ],
        temperature=0.7,
    )
    txt = resp.choices[0].message.content
    return json.loads(txt)

def exec_python(code: str):
    # 매우 단순한 샌드박스(데모용). 실제는 제한 실행/컨테이너 권장.
    loc = {}
    exec(code, {"__builtins__": {"print": print, "range": range, "len": len}}, loc)
    return loc.get("result", None)

def solve_with_self_consistency(problem: str, n: int = 5):
    # 1) Plan 고정
    plan = chat_json(PLAN_PROMPT.format(problem=problem))["plan"]
    plan_json = json.dumps(plan, ensure_ascii=False)

    candidates = []
    for _ in range(n):
        out = chat_json(SOLVE_PROMPT.format(plan_json=plan_json, problem=problem))
        # 2) PoT: python_code 실행 결과로 검증
        code = out["python_code"]
        # 코드가 result 변수에 최종값을 넣게 유도(프롬프트에서 요구 가능)
        try:
            computed = exec_python(code)
        except Exception:
            computed = None

        candidates.append({
            "final_answer": out["final_answer"],
            "computed": computed,
            "reasoning_summary": out["reasoning_summary"],
            "python_code": code
        })

    # 3) Self-Consistency: computed가 있으면 computed 기준, 없으면 final_answer 기준 다수결
    key = "computed" if any(c["computed"] is not None for c in candidates) else "final_answer"
    votes = [c[key] for c in candidates]
    winner, _ = Counter(votes).most_common(1)[0]

    best = next(c for c in candidates if c[key] == winner)
    return {
        "plan": plan,
        "winner_key": key,
        "winner": winner,
        "best_candidate": best,
        "all_candidates": candidates
    }

if __name__ == "__main__":
    problem = "어떤 상점에서 15% 할인 후 8% 세금을 붙인다. 정가 120달러의 최종 지불 금액은?"
    result = solve_with_self_consistency(problem, n=5)
    print(json.dumps(result, ensure_ascii=False, indent=2))

포인트는 3가지입니다.

  • Plan을 먼저 고정해 변동성을 줄이고(Plan-and-Solve)
  • N번 생성 후 합의로 안정화(Self-Consistency) (arxiv.org)
  • 계산은 코드 실행으로 검증해 “그럴듯한 오답”을 제거(PoT) (arxiv.org)

⚡ 실전 팁

1) “Think step by step”를 KPI로 삼지 마세요 상용 reasoning 모델은 CoT를 숨기거나 요약만 제공하기도 하고, 무엇보다 보이는 CoT가 실제 원인을 충실히 반영하지 않을 수 있습니다. (openai.com)
대신 KPI를 이렇게 두세요:

  • 정답률 / 제약 준수율(JSON schema, 금칙어, 길이)
  • 테스트 통과율(코딩)
  • 재현성(temperature 고정 + self-consistency)
  • 비용(토큰) 대비 성능

2) CoT는 “출력”이 아니라 “분리”로 최적화

  • Plan과 Solve를 분리(Plan-and-Solve) (arxiv.org)
  • 추론과 계산을 분리(PoT) (arxiv.org)
  • 후보 생성과 선택을 분리(Self-Consistency) (arxiv.org)

이 분리는 곧바로 프롬프트 실험 설계(A/B)를 가능하게 합니다. 예: Plan 프롬프트만 바꿔도 Solve 품질이 어떻게 변하는지 측정 가능.

3) “가시성(모니터링)”은 CoT 노출이 아니라 평가 설계로 확보 OpenAI는 CoT의 monitorability를 연구/평가하는 흐름을 공개적으로 다룹니다. (openai.com)
하지만 실무에서 중요한 건 “사람이 CoT를 읽고 납득”이 아니라,

  • 모델이 정해진 체크리스트를 통과했는지
  • tool 호출/코드 실행/스키마 생성이 정확히 되었는지 입니다. 즉, 테스트/검증을 프롬프트의 일부로 만들기가 더 확실합니다.

4) 프롬프트 최적화는 수작업이 아니라 ‘탐색 문제’로 보세요 요즘은 “장인 프롬프트”보다, 데이터(라벨 10~50개)와 metric을 두고 자동으로 변형/평가하는 방향(DSPy류)이 대세입니다(프레임워크/운영 관점). (proceedings.iclr.cc)
핵심은 프롬프트를 문장 예술이 아니라 최적화 대상(파라미터)로 취급하는 마인드 전환입니다.


🚀 마무리

2026년의 CoT 고급 기법은 “길게 생각해봐”가 아니라 생각이 성능으로 연결되도록 파이프라인을 설계하는 쪽으로 이동했습니다.

  • CoT는 항상 믿을 수 있는 설명이 아닐 수 있다 → 외부 metric으로 최적화 (anthropic.com)
  • Plan-and-Solve로 변동성을 줄이고 (arxiv.org)
  • Self-Consistency로 안정성을 올리며 (arxiv.org)
  • PoT로 계산을 검증 가능하게 만들면 (arxiv.org)
    프롬프트 최적화가 “감”이 아니라 “엔지니어링”이 됩니다.

다음 학습으로는: 1) Self-Consistency를 실제 업무 데이터셋에 적용해 N, temperature, vote 전략을 튜닝해보고 (arxiv.org)
2) PoT를 도입해 코드 실행 기반 검증 루프를 붙여본 뒤 (arxiv.org)
3) Plan/Solve/Verify를 모듈화해서 프롬프트를 실험 가능한 컴포넌트로 쪼개보는 걸 추천합니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.