포스트

2026-03-26 강의 정리

프롬프트 엔지니어링 - Chain-of-Thought (CoT)

2026-03-26 강의 정리

목차

  1. 오늘 강의 개요
  2. 환경 설정 & 라이브러리 import
  3. Few-Shot 프롬프팅 - 기본 개념 복습
  4. FewShotPromptTemplate - LangChain 구현
  5. FewShotChatMessagePromptTemplate - 채팅 기반 구현
  6. 동적 예시 선택 (SemanticSimilarityExampleSelector)
  7. Few-Shot 성능 평가 (Zero-Shot vs Few-Shot)
  8. 평가 지표 개요 (Metrics)
  9. LLM의 추론 한계 - 문제 사례
  10. Chain-of-Thought (CoT) 프롬프팅
  11. Few-Shot CoT 심화 기법
  12. 자주 나오는 실수 / 주의사항
  13. [보충] 프롬프트 설계 전략 정리

1. 오늘 강의 개요

오늘 강의는 어제 배운 Few-Shot 프롬프팅을 LangChain 컴포넌트로 구현하고, 예시를 동적으로 선택하는 방법, 그리고 LLM의 추론 능력을 끌어올리는 Chain-of-Thought(CoT) 기법까지 심화 학습한다.

핵심 키워드: FewShotPromptTemplate, SemanticSimilarityExampleSelector, CoT

전체 학습 흐름

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Few-Shot 기본 (고정 예시)
        ↓
FewShotPromptTemplate (LangChain 컴포넌트화)
        ↓
FewShotChatMessagePromptTemplate (채팅 형식)
        ↓
SemanticSimilarityExampleSelector (동적 예시 선택)
        ↓
Zero-Shot vs Few-Shot 성능 평가
        ↓
LLM 추론 한계 확인 (논리 퍼즐, 글자 세기)
        ↓
Chain-of-Thought (CoT) → 추론 능력 향상
        ↓
Few-Shot CoT (예시 + 단계별 사고)

핵심 원칙: 예시를 “잘 선택”하는 것이 Few-Shot 성능을 결정한다. 무조건 많은 예시보다, 관련성 높은 예시가 더 효과적이다.


2. 환경 설정 & 라이브러리 import

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from langchain_core.prompts import (
    FewShotPromptTemplate,
    PromptTemplate,
    ChatPromptTemplate,
    FewShotChatMessagePromptTemplate
)
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_core.vectorstores import InMemoryVectorStore

load_dotenv()
llm = ChatOpenAI(model="gpt-4o-mini")
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
컴포넌트역할
ChatOpenAIgpt-4o-mini LLM 인스턴스
OpenAIEmbeddings텍스트 → 벡터 변환 (예시 선택에 사용)
FewShotPromptTemplate고정 예시 기반 프롬프트 생성
FewShotChatMessagePromptTemplate채팅 형식의 Few-Shot 프롬프트
SemanticSimilarityExampleSelector의미 유사도 기반 동적 예시 선택
InMemoryVectorStore예시를 메모리 내 벡터 DB에 저장

3. Few-Shot 프롬프팅 - 기본 개념 복습

예시(examples) 정의

1
2
3
4
5
6
examples = [
    {"input": "이 제품 정말 최고입니다!", "output": "긍정"},
    {"input": "품질이 너무 안좋아요",      "output": "부정"},
    {"input": "보통이에요, 무난합니다.",    "output": "중립"},
    {"input": "디자인은 좋은데 성능이 아쉬워요", "output": "혼합"}
]

왜 이 구조인가? input/output 키-값 쌍으로 예시를 딕셔너리로 정의하면, LangChain의 FewShotPromptTemplate이 자동으로 포맷해준다.

예시 선택의 3원칙 (주석에서 언급됨)

  • 다양성: 카테고리별로 골고루 예시 제공
  • 관련성: 입력과 유사한 예시가 더 효과적
  • 균형: 특정 레이블에 편향되지 않게 배분

4. FewShotPromptTemplate - LangChain 구현

4-1. 예시 포맷 템플릿 정의

1
2
3
4
example_template = PromptTemplate(
    input_variables=["input", "output"],
    template="리뷰: {input}\n감정: {output}"
)
  • PromptTemplate: 예시 하나를 어떻게 텍스트로 표현할지 정의
  • {input}, {output}: 예시 딕셔너리의 키와 매핑됨

4-2. FewShotPromptTemplate 구성

1
2
3
4
5
6
7
8
fewshot_prompt = FewShotPromptTemplate(
    examples=examples,           # 예시 리스트
    example_prompt=example_template,  # 예시 포맷
    prefix='다음 예시를 참고해서 리뷰의 감정을 분류해주세요.\n',
    suffix='\n리뷰: {input}\n감정:',  # 실제 입력 포맷
    input_variables=['input'],
    example_separator='\n\n'     # 예시 사이 구분자
)

4-3. 프롬프트 구조 시각화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[prefix]
다음 예시를 참고해서 리뷰의 감정을 분류해주세요.

[example 1]
리뷰: 이 제품 정말 최고입니다!
감정: 긍정

[example 2]
리뷰: 품질이 너무 안좋아요
감정: 부정

... (example_separator='\n\n' 로 구분)

[suffix]
리뷰: {실제 입력}
감정:
1
2
3
# 포맷 확인
formatted = fewshot_prompt.format(input='가격은 비싸지만 품질이 뛰어나요')
print(formatted)

5. FewShotChatMessagePromptTemplate - 채팅 기반 구현

5-1. 채팅용 예시 템플릿

1
2
3
4
example_prompt_chat = ChatPromptTemplate.from_messages([
    ('human', '리뷰 : {input}'),
    ('ai',    '감정: {output}')
])

왜 채팅 형식인가? ChatGPT 계열 모델은 messages 리스트로 대화를 받는다. Human/AI 턴으로 예시를 구성하면 모델이 더 자연스럽게 패턴을 인식한다.

5-2. FewShotChatMessagePromptTemplate

1
2
3
4
fewshot_chat_prompt = FewShotChatMessagePromptTemplate(
    examples=examples,
    example_prompt=example_prompt_chat
)

5-3. 최종 프롬프트 + 체인 구성

1
2
3
4
5
6
7
8
9
10
final_prompt = ChatPromptTemplate.from_messages([
    ('system', '당신은 감정 분석 전문가입니다. 리뷰의 감정을 긍정/부정/중립/혼합 중 하나로 분류해주세요'),
    fewshot_chat_prompt,   # Few-Shot 예시 삽입
    ('human', '리뷰 : {input}')
])

chain = final_prompt | llm
result = chain.invoke({'input': '가격은 비싸지만 품질이 뛰어나요'})
print(result.content)
# 출력: 감정: 혼합

프롬프트 메시지 구조

1
2
3
4
5
6
7
[system]   당신은 감정 분석 전문가입니다...
[human]    리뷰 : 이 제품 정말 최고입니다!
[ai]       감정: 긍정
[human]    리뷰 : 품질이 너무 안좋아요
[ai]       감정: 부정
...
[human]    리뷰 : {실제 입력}   ← 실제 질문

6. 동적 예시 선택 (SemanticSimilarityExampleSelector)

6-1. 왜 동적 선택이 필요한가?

고정 예시 방식의 문제:

  • 예시가 많으면 → 토큰 비용 증가, 컨텍스트 초과
  • 관련 없는 예시 포함 → 오히려 성능 저하
  • 새로운 도메인 입력에 대응 어려움

해결책: 입력과 의미적으로 유사한 예시만 자동 선택

6-2. 확장 예시 데이터셋

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
large_examples = [
    # 긍정
    {"input": "정말 만족합니다. 강력 추천!",    "output": "긍정"},
    {"input": "배송이 빠르고 포장이 꼼꼼해요.", "output": "긍정"},
    {"input": "가격 대비 훌륭합니다.",          "output": "긍정"},
    # 부정
    {"input": "품질이 최악입니다. 환불 요청했어요.", "output": "부정"},
    {"input": "고객센터 응대가 너무 불친절합니다.", "output": "부정"},
    {"input": "택배가 분실되었어요.",               "output": "부정"},
    # 중립
    {"input": "보통이에요. 특별한 점은 없습니다.", "output": "중립"},
    {"input": "사진과 동일한 제품입니다.",         "output": "중립"},
    # 혼합
    {"input": "디자인은 예쁜데 내구성이 약해요.", "output": "혼합"},
    {"input": "기능은 많은데 사용법이 복잡합니다.", "output": "혼합"},
]

6-3. SemanticSimilarityExampleSelector 생성

1
2
3
4
5
6
example_selector = SemanticSimilarityExampleSelector.from_examples(
    large_examples,
    OpenAIEmbeddings(model="text-embedding-3-small"),  # 임베딩 모델
    InMemoryVectorStore,   # 벡터 저장소
    k=3                    # 상위 k개 예시 선택
)

동작 원리:

1
2
3
4
5
6
7
입력 텍스트
    ↓  (임베딩)
입력 벡터
    ↓  (코사인 유사도 계산)
large_examples 벡터들과 비교
    ↓
유사도 높은 k=3개 예시 반환

6-4. 동적 선택 결과 확인

1
2
3
4
5
6
7
8
9
10
11
queries = [
    '배송이 너무 느려요',         # → 배송 관련 부정 예시 선택
    '값은 좀 나가지만 성능은 훌륭해요',  # → 혼합 관련 예시 선택
    '무난한 제품이에요'           # → 중립 관련 예시 선택
]

for q in queries:
    selected = example_selector.select_examples({'input': q})
    print(f"query : {q}")
    for s in selected:
        print(f"  selected : {s['output']}, {s['input']}")

쿼리에 따라 자동으로 관련성 높은 예시가 선택된다.

6-5. 동적 Few-Shot 체인 구성

1
2
3
4
5
6
7
8
9
10
11
12
dynamic_few_shot_prompt = FewShotChatMessagePromptTemplate(
    example_selector=example_selector,   # 고정 examples 대신 selector 사용
    example_prompt=example_prompt_chat
)

dynamic_final_prompt = ChatPromptTemplate.from_messages([
    ('system', '당신은 감정 분석 전문가입니다. 리뷰의 감정을 긍정/부정/중립/혼합 중 하나로 분류하세요'),
    dynamic_few_shot_prompt,
    ('human', '리뷰 : {input}')
])

dynamic_chain = dynamic_final_prompt | llm
1
2
3
4
5
6
7
8
9
# 실행 결과
test_inputs = ['택배 상자가 찌그러져왔어요', '화면은 선명한데 스피커 소리가 작아요']
for t in test_inputs:
    result = dynamic_chain.invoke({'input': t})
    print(f'{t} : {result.content}')

# 출력:
# 택배 상자가 찌그러져왔어요 : 감정: 부정
# 화면은 선명한데 스피커 소리가 작아요 : 감정: 혼합

7. Few-Shot 성능 평가 (Zero-Shot vs Few-Shot)

7-1. 평가 데이터셋 정의

1
2
3
4
5
6
7
8
9
10
eval_dataset = [
    {"text": "완벽한 제품입니다! 강력 추천합니다.",       "expected": "긍정"},
    {"text": "두 번 다시 구매하지 않겠습니다.",           "expected": "부정"},
    {"text": "평범합니다. 특별히 좋지도 나쁘지도 않아요.", "expected": "중립"},
    {"text": "기능은 좋은데 AS가 아쉬워요.",              "expected": "혼합"},
    {"text": "가격도 착하고 품질도 좋아요.",              "expected": "긍정"},
    {"text": "사진과 너무 달라서 실망했습니다.",           "expected": "부정"},
    {"text": "그냥 쓸만 합니다.",                        "expected": "중립"},
    {"text": "배송은 빠른데 제품이 기대 이하에요.",        "expected": "혼합"},
]

7-2. Zero-Shot 평가 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def evaluate_zero_shot(dataset):
    results = []
    for item in dataset:
        response = llm.invoke([
            SystemMessage(content="리뷰의 감정을 분류하세요. 반드시 '긍정', '부정', '중립', '혼합' 중 하나만 출력하세요"),
            HumanMessage(content=item['text'])
        ]).content

        predicted = response.strip()
        results.append({
            'text':      item['text'],
            'expected':  item['expected'],
            'predicted': predicted,
            'correct':   predicted == item['expected'],
        })
    return results

7-3. Few-Shot 평가 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def evaluate_few_shot(dataset, examples):
    results = []
    # 시스템 메시지 + 예시를 기본 메시지로 구성
    base_messages = [SystemMessage(content="리뷰의 감정을 분류하세요. 반드시 '긍정', '부정', '중립', '혼합' 중 하나만 출력하세요")]
    for ex in examples:
        base_messages.append(HumanMessage(content=ex['input']))
        base_messages.append(AIMessage(content=ex['output']))   # AI 응답으로 예시 주입

    for item in dataset:
        messages = base_messages + [HumanMessage(content=item['text'])]
        response = llm.invoke(messages).content

        predicted = response.strip()
        results.append({
            'text':      item['text'],
            'expected':  item['expected'],
            'predicted': predicted,
            'correct':   predicted == item['expected'],
        })
    return results

핵심 패턴: AIMessage를 직접 삽입해서 모델에게 “이전 대화에서 이렇게 대답했다”는 형태로 예시를 주입한다.

7-4. 평가 실행 & 결과

1
2
3
4
5
6
7
8
9
few_shot_examples = [
    {"input": "정말 만족합니다. 강력 추천!",        "output": "긍정"},
    {"input": "배송이 빠르고 포장이 꼼꼼해요.",     "output": "긍정"},
    {"input": "가격 대비 훌륭합니다.",              "output": "긍정"},
    {"input": "품질이 최악입니다. 환불 요청했어요.", "output": "부정"},
]

zero_results   = evaluate_zero_shot(eval_dataset)
fewshot_results = evaluate_few_shot(eval_dataset, few_shot_examples)
방식정확도
Zero-Shot8/8 (100%)
Few-Shot8/8 (100%)

이 태스크는 비교적 쉬운 감정 분류라 둘 다 100%가 나왔지만, 어려운 태스크일수록 Few-Shot의 이점이 극명하게 드러난다.


8. 평가 지표 개요 (Metrics)

LLM 출력을 평가하는 지표는 태스크 유형에 따라 달라진다.

태스크별 주요 지표

태스크 유형지표설명
분류 (classification)Accuracy, F1, Precision, Recall맞은/틀린 개수 기반
회귀 (regression)RMSE, MAE, MSE예측값과 실제값 차이
번역/요약/생성BLEU, ROUGE참조 텍스트와 겹치는 정도

RMSE 예시

1
2
3
4
5
6
7
실제값:   0.8,   0.9,   0.0
예측값:   0.5,   0.1,   0.2

오차:     0.3,   0.8,   0.2
제곱:     0.09,  0.64,  0.04
평균:     0.257
RMSE:     √0.257 ≈ 0.507

BLEU 예시

1
2
3
4
정답:   "I go to school"
예측:   "I go school"

겹치는 단어: "I", "go", "school" → 3/4 = 0.75

BLEU는 n-gram 겹침을 측정한다. 1에 가까울수록 좋다.


9. LLM의 추론 한계 - 문제 사례

9-1. 경마 문제 (논리 퍼즐)

1
2
말이 25마리, 한 번에 5마리만 경주 가능
가장 빠른 3마리를 찾으려면 몇 번 경주?
1
result = llm.invoke('말이 25마리 있습니다. 한 번에 5마리만 경주를 할 수 있습니다. 가장 빠른 3마리 말을 찾으려면 몇 번의 경주를 해야할까요?')

정답: 7번 (5그룹 예선 + 1번 결선 + 1번 최종) LLM은 대부분 정답을 맞추지만, 단순화된 변형 문제에서 틀리는 경향이 있다.

9-2. 변형 경마 문제 (6마리 → 최빠른 1마리)

1
result = llm.invoke('말이 6마리가 있고, 가장 빠른 말을 찾고 싶습니다. 한 번에 최대 6마리가 동시에 뛸 수 있습니다. 최소 몇 번의 경주가 필요할까요?')

정답: 1번 (6마리를 한 번에 경주시키면 됨) LLM의 오답: 7번 → 유명 문제의 답을 그대로 적용하는 패턴 오류

9-3. 글자 세기 문제

1
2
print(llm.invoke('LOLLAPALOOZA 라는 단어에서 L이 몇 번 나타나나요?').content)
# 오답: 3개 (실제로는 4개: LoLLapaLooza)

LLM이 글자를 못 세는 이유: LLM은 텍스트를 토큰 단위로 처리한다. “LOLLAPALOOZA”가 단일 토큰으로 묶일 수 있어 글자를 하나씩 세지 못한다.

9-4. 몬티 홀 문제

1
llm.invoke('3개 문 중 하나에 황금이 있고, 나머지는 야채입니다. 당신이 1번 문을 고르고, 사회자가 2번 문으로 바꾸시겠습니까? 라고 묻습니다. 사회자는 아직 어떤 문도 열지 않았습니다. 바꾸는 것이 유리할까요?')

정답: 이 경우 확률이 동일하므로 유불리 없음 (사회자가 문을 열지 않음!) 그러나 LLM은 고전 몬티 홀 문제의 답(바꾸면 2/3)을 그대로 적용하는 경향이 있다. → 유명 문제 변형에 특히 취약

9-5. Sally 형제 문제

1
2
3
Sally(여자)한테 남자 형제가 3명 있어요
각 남자형제한테는 여자 형제가 2명 있어요
Sally의 여자 형제는 몇 명?

정답: 1명 (Sally 자신을 포함해 각 오빠/남동생에게 여자형제가 Sally+1명 = 2명) → 조건을 꼼꼼히 읽지 않으면 오답


10. Chain-of-Thought (CoT) 프롬프팅

10-1. CoT란?

모델에게 “단계별로 생각하라”고 지시해서 추론 과정을 유도하는 기법

1
2
일반 프롬프트:  "답이 뭔가요?"         → 결과만 출력
CoT 프롬프트:   "단계별로 생각해보세요" → 추론 과정 + 결과 출력

10-2. CoT 적용 예시 - 글자 세기

1
2
3
4
5
6
7
8
9
10
# CoT 없이 → 오답
print(llm.invoke('LOLLAPALOOZA 라는 단어에서 L이 몇 번 나타나나요?').content)
# 출력: 3개 (틀림)

# CoT 적용 → 정답
print(llm.invoke('LOLLAPALOOZA 라는 단어에서 L이 몇 번 나타나나요? 단계별로 생각해보세요').content)
# 출력 예시:
# 1. L-O-L-L-A-P-A-L-O-O-Z-A 로 각 글자를 분리하면
# 2. L이 등장하는 위치: 1번째, 3번째, 4번째, 8번째
# 3. 총 4개입니다.

10-3. CoT 효과 비교

문제CoT 없이CoT 적용
경마 6마리 문제오답 (7번)정답 (1번)
글자 세기 (L 개수)오답 (3개)정답 (4개)
Sally 형제 문제불안정정답

10-4. CoT 트리거 문구 예시

1
2
3
4
5
# 이런 문구들이 CoT를 유발한다
"단계별로 생각해보세요"
"단계적으로 추론해주세요"
"지문의 조건을 전부 나열한 후 각 조건을 검토하면서 풀어줘"
"이 문제가 기존 유명한 문제와 어떻게 다른지 분석하고 답해줘"

11. Few-Shot CoT 심화 기법

11-1. 시스템 프롬프트로 변형 문제 경계 설정

1
2
3
4
5
6
7
8
9
10
system_prompt = """당신은 퍼즐 전문가입니다. 아래 문제들은 유명한 문제의 **변형**입니다.
원래 문제의 답을 그대로 적용하지 마세요. 이 문제의 조건을 정확히 읽고 답하세요.

예시:
문제: 셔츠 1장을 말리는데 4시간이 걸립니다. 셔츠 5장을 말리면 몇 시간?
[흔한 실수] 4 x 5 = 20시간
[올바른 생각] 동시에 널면 됩니다. 답: 4시간

이처럼 문제의 조건을 주의 깊게 읽고 단계별로 생각하세요
"""

Few-Shot CoT의 핵심: 예시에서 잘못된 사고방식(흔한 실수)올바른 사고방식을 함께 보여준다. 이렇게 하면 모델이 같은 패턴의 실수를 피할 수 있다.

11-2. 구조화된 단계별 프롬프트 - 평균 속도 문제

문제: 갈 때 시속 3마일, 왕복 평균 6마일을 만들려면 돌아올 때 얼마?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
prompt = """
당신은 물리 문제를 푸는 전문가입니다. 절대 직감이나 추측으로 답하지 말고, 정의에 따라 단계적으로 계산하세요.

문제:
한 사람이 친구 집까지 평균 시속 3마일로 걸어갔습니다.
왕복 전체 평균 속도를 시속 6마일로 만들려면, 돌아올 때 얼마나 빨리 달려야 할까요?

다음 순서를 반드시 따르세요:
1. 편도 거리를 D마일이라고 두세요
2. 갈 때 걸린 시간을 계산하세요
3. 왕복 전체 평균 속도가 6mph가 되기 위한 총 시간을 계산하세요
4. 이미 사용한 시간과 필요한 총 시간을 비교하세요
5. 남은 시간으로 돌아오는 것이 가능한지 판단하세요
6. 가능하다면 필요한 속도를 계산하고, 불가능하면 왜 불가능한지 논리적으로 설명하세요
"""

print(llm.invoke(prompt).content)

LLM의 풀이 과정:

1
2
3
4
5
6
7
1. 편도 거리: D마일
2. 갈 때 걸린 시간: D/3 시간
3. 왕복 총 거리: 2D마일
   왕복 평균 속도 6mph → 총 시간 = 2D/6 = D/3 시간
4. 이미 갈 때 D/3 시간을 다 써버렸다
5. 남은 시간 = D/3 - D/3 = 0
6. 결론: 불가능! 돌아오는 데 0초가 필요하다 = 무한대 속도 필요

핵심 인사이트: 평균 속도는 총 거리 / 총 시간이다. 단순 산술 평균(3+9)/2=6이 아니다. 이처럼 단계 강제를 통해 LLM이 직관적 오류를 피하게 만든다.

11-3. Few-Shot CoT 전략 정리

1
2
3
4
5
6
7
8
9
10
11
12
13
[전략 1] "단계별로 생각해보세요" 한 줄 추가
  → 간단하지만 효과적. 대부분의 추론 문제에 적용 가능

[전략 2] 풀이 단계를 번호로 명시 강제
  → "1. X를 구하세요, 2. Y를 구하세요..." 형식
  → 복잡한 계산/논리 문제에 효과적

[전략 3] 흔한 실수를 예시로 보여주기
  → "흔한 실수: ..., 올바른 생각: ..."
  → 모델이 같은 패턴의 함정에 빠지지 않도록 방지

[전략 4] 이 문제가 기존 유명 문제와 어떻게 다른지 분석 요구
  → 변형 문제 특화. 패턴 매칭 오류 방지

12. 자주 나오는 실수 / 주의사항

❌ example_selector 와 examples를 동시에 지정하면 안 된다

1
2
3
4
5
6
# 잘못된 사용
FewShotChatMessagePromptTemplate(
    examples=examples,           # ❌ 둘 중 하나만!
    example_selector=selector,   # ❌
    example_prompt=example_prompt_chat
)

examplesexample_selector 중 하나만 사용해야 한다.


❌ suffix의 input_variables와 FewShotPromptTemplate의 input_variables를 일치시켜야 한다

1
2
3
4
5
fewshot_prompt = FewShotPromptTemplate(
    ...
    suffix='\n리뷰: {input}\n감정:',
    input_variables=['input'],  # suffix의 변수와 반드시 일치!
)

❌ CoT 없이 복잡한 추론 문제를 LLM에게 바로 던지면 안 된다

1
2
3
4
5
# 위험한 방식
result = llm.invoke('복잡한 논리 문제...')

# 안전한 방식
result = llm.invoke('복잡한 논리 문제... 단계별로 생각해보세요')

❌ LLM의 글자 세기를 신뢰하면 안 된다

LLM은 토큰 단위 처리 특성상 글자 수, 문자 위치 계산을 정확히 못할 수 있다. 글자 세기가 중요한 로직은 반드시 코드(Python)로 검증하라.


❌ 평균 속도를 산술 평균으로 계산하면 안 된다

1
2
평균 속도 = 총 이동 거리 / 총 소요 시간  (조화 평균 개념)
         ≠ (속도1 + 속도2) / 2            (산술 평균 - 틀림!)

❌ 유명 문제의 변형을 원본과 동일하게 취급하면 안 된다

  • 몬티 홀 문제: 사회자가 문을 열지 않으면 확률이 달라짐
  • 경마 문제: 찾는 대상(3마리 vs 1마리)에 따라 답이 완전히 달라짐
  • 이런 변형 문제에 대응하려면 CoT + 조건 분석 요구 필수

13. [보충] 프롬프트 설계 전략 정리

Few-Shot 예시 선택 기준

기준설명적용 방법
다양성다양한 케이스를 커버긍정/부정/중립/혼합 골고루
관련성입력과 유사한 예시SemanticSimilarityExampleSelector
균형레이블 편향 방지클래스별 균등 수량

Zero-Shot vs Few-Shot vs CoT 선택 기준

1
2
3
4
5
6
7
8
9
10
11
간단한 분류/생성 태스크
    → Zero-Shot 충분

패턴 학습이 필요한 태스크 (감정 분류, 문체 변환)
    → Few-Shot

추론/계산이 필요한 태스크 (수학, 논리, 퍼즐)
    → CoT

복잡한 추론 + 패턴 모두 필요
    → Few-Shot + CoT (가장 강력)

LangChain Few-Shot 컴포넌트 선택 기준

상황사용할 컴포넌트
일반 텍스트 프롬프트, 예시 고정FewShotPromptTemplate
채팅 모델, 예시 고정FewShotChatMessagePromptTemplate
채팅 모델, 예시를 자동 선택FewShotChatMessagePromptTemplate + SemanticSimilarityExampleSelector
예시 풀이 크고 입력 다양SemanticSimilarityExampleSelector (k=3~5)

전체 오늘 학습 개념 연결도

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Few-Shot
  ├── 고정 예시
  │     ├── FewShotPromptTemplate (텍스트 기반)
  │     └── FewShotChatMessagePromptTemplate (채팅 기반)
  │
  └── 동적 예시
        └── SemanticSimilarityExampleSelector
              ├── OpenAIEmbeddings (입력 → 벡터)
              └── InMemoryVectorStore (예시 벡터 저장)

CoT (Chain-of-Thought)
  ├── Zero-Shot CoT: "단계별로 생각해보세요"
  ├── 단계 강제 프롬프트: "1. X를 구하고, 2. Y를 구하고..."
  └── Few-Shot CoT: 예시에서 추론 과정도 함께 제시

평가 (Evaluation)
  ├── 분류: Accuracy, F1
  ├── 회귀: RMSE, MAE
  └── 생성: BLEU, ROUGE

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

인기 태그