🤖AI/ML

Chain-of-Thought

Chain-of-Thought Prompting (CoT)

LLM이 단계별 추론을 수행하도록 유도하는 프롬프트 기법. 복잡한 문제 해결 능력 향상.

📖 상세 설명

Chain-of-Thought(CoT) Prompting은 대규모 언어 모델(LLM)이 복잡한 문제를 해결할 때 최종 답변 전에 중간 추론 단계를 명시적으로 생성하도록 유도하는 프롬프트 엔지니어링 기법입니다. Google Research가 2022년에 발표한 이 기법은 수학적 추론, 논리적 사고, 상식 추론 등에서 LLM의 성능을 획기적으로 향상시켰습니다.

CoT의 작동 원리는 인간의 사고 과정을 모방합니다. 복잡한 문제를 한 번에 풀기보다는 여러 개의 작은 단계로 나누어 순차적으로 해결합니다. 예를 들어 "Let's think step by step"이라는 간단한 문구를 추가하는 Zero-shot CoT만으로도 산술 문제 정확도가 3배 이상 향상됩니다.

Few-shot CoT는 프롬프트에 풀이 과정이 포함된 예시를 제공하는 방식입니다. 모델이 예시의 추론 패턴을 학습하여 새로운 문제에도 유사한 방식으로 단계별 풀이를 생성합니다. Self-Consistency는 여러 추론 경로를 샘플링하고 가장 일관된 답을 선택하여 정확도를 더 높입니다.

실무에서 CoT는 복잡한 분석 작업, 코드 생성 및 디버깅, 법률/의료 문서 분석 등 다단계 추론이 필요한 모든 LLM 애플리케이션에 적용됩니다. OpenAI o1 시리즈처럼 추론에 특화된 모델들은 내부적으로 CoT와 유사한 메커니즘을 사용합니다.

💻 코드 예제

# Chain-of-Thought 프롬프팅 패턴들
from openai import OpenAI
client = OpenAI()

# 1. Zero-shot CoT: 가장 간단한 방법
def zero_shot_cot(question: str) -> str:
    prompt = f"{question}\n\nLet's think step by step."
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        temperature=0
    )
    return response.choices[0].message.content

# 2. Few-shot CoT: 예시와 함께 제공
def few_shot_cot(question: str) -> str:
    prompt = """Q: Roger has 5 tennis balls. He buys 2 more cans of tennis balls.
Each can has 3 tennis balls. How many tennis balls does he have now?

A: Let me work through this step by step.
- Roger starts with 5 tennis balls
- He buys 2 cans, each containing 3 balls
- New balls: 2 cans x 3 balls = 6 balls
- Total: 5 + 6 = 11 tennis balls
The answer is 11.

Q: {question}

A: Let me work through this step by step."""

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt.format(question=question)}],
        temperature=0
    )
    return response.choices[0].message.content

# 3. Self-Consistency: 다수결로 신뢰도 향상
import re
from collections import Counter

def self_consistency_cot(question: str, n_samples: int = 5) -> dict:
    answers = []
    reasonings = []

    for _ in range(n_samples):
        response = client.chat.completions.create(
            model="gpt-4",
            messages=[{"role": "user", "content": f"{question}\nLet's think step by step."}],
            temperature=0.7  # 다양성을 위해 temperature 상향
        )
        text = response.choices[0].message.content
        reasonings.append(text)

        # 숫자 정답 추출 (마지막 숫자를 정답으로 가정)
        numbers = re.findall(r'\d+', text.split("answer")[-1] if "answer" in text.lower() else text)
        if numbers:
            answers.append(numbers[-1])

    # 다수결로 최종 답변 결정
    answer_counts = Counter(answers)
    final_answer = answer_counts.most_common(1)[0] if answer_counts else (None, 0)

    return {
        "final_answer": final_answer[0],
        "confidence": final_answer[1] / n_samples,
        "all_answers": answers
    }

# 사용 예시
question = "A store has 45 apples. If 12 are sold and 8 more are added, how many are there?"
print("Zero-shot CoT:", zero_shot_cot(question)[:200])
print("\nSelf-Consistency:", self_consistency_cot(question))

🗣️ 실무 대화 예시

기술 미팅에서

"금융 리포트 분석에서 수치 계산 오류가 많았는데, 시스템 프롬프트에 '각 수치의 출처와 계산 과정을 명시하세요'라는 CoT 지시를 추가했더니 오류율이 40% 감소했습니다."

면접 질문

"CoT와 일반 프롬프팅의 차이는 중간 추론 과정의 명시 여부입니다. 100B 파라미터 이상의 모델에서 효과가 뚜렷하며, GSM8K 벤치마크에서 정확도가 17%에서 57%로 향상된 연구 결과가 있습니다."

코드 리뷰에서

"Self-Consistency에서 temperature를 0.7로 설정한 건 좋은데, 5번 샘플링은 비용 대비 효과가 떨어질 수 있어요. 3번이면 충분하고, 불일치 시에만 추가 샘플링하는 adaptive 방식을 고려해보세요."

⚠️ 주의사항

💰
비용과 지연 시간 증가

CoT는 출력 토큰이 3-5배 증가합니다. 대량 처리 시 비용과 latency를 고려하여 정말 필요한 작업에만 적용하세요.

📐
모델 크기 의존성

CoT는 약 100B 파라미터 이상의 대형 모델에서 효과적입니다. 작은 모델에서는 오히려 잘못된 추론 경로를 생성할 수 있습니다.

🎭
추론의 신뢰성 문제

모델이 생성한 추론 과정이 항상 정확하거나 실제 내부 연산을 반영하는 것은 아닙니다. 특히 사실 관계 검증이 필요한 작업에서는 추가 검증이 필요합니다.

🔗 관련 용어

📚 더 배우기