일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- #include
- 중복인클루드
- sk네트웍스familyai캠프12기
- Docker
- 어셈블
- few-shot
- openai
- 전처리
- ai캠프
- 12기
- 주간회고
- sk네트웍스ai캠프
- 소스코드
- 배포
- 21주차
- 임베딩
- 회고록
- Rag
- 헤더가드
- sk네트웍스familyai캠프
- Fine-tuning
- 컴파일
- AWS
- Langchain
- zero-shot
- 최종프로젝트
- one-shot
- sk네트웍스family
- C++
- FastAPI
- Today
- Total
ansir 님의 블로그
[ SK 네트웍스 Family AI 캠프 수업 내용 복습 ] 프롬프트 엔지니어링 응용 - CoT( Chan of Thought ) 2025-05-16 본문
[ SK 네트웍스 Family AI 캠프 수업 내용 복습 ] 프롬프트 엔지니어링 응용 - CoT( Chan of Thought ) 2025-05-16
ansir 2025. 5. 19. 13:44CoT의 진화 (Chain of Thought Prompting)
1. 개요
- CoT( Chain of Thought )는 LLM( Large Language Model )이 복잡한 문제를 단계적으로 논리적으로 해결할 수 있도록 유도하는 프롬프트 기법입니다.
핵심 개념
- 일반적인 LLM은 문제의 최종 답을 바로 예측하려 하지만, CoT는 문제 해결 과정을 명시적으로 서술하도록 유도합니다.
- 대표적인 문구:이는 모델이 추론 과정을 서술하도록 유도하여 정답률을 높이는 효과가 있습니다.
- "Let's think step by step."
예시
질문: 2 + 2 × 3 = ?
- 일반 모델 출력 (CoT 없음): 12 또는 8 (랜덤하게 오류 가능)
- CoT 사용:
- Let's think step by step. 먼저 곱셈을 합니다: 2 × 3 = 6 그런 다음 덧셈을 합니다: 2 + 6 = 8 따라서 정답은 8입니다.
효과
- CoT는 수학, 논리, 지식 기반 문제, 추론 문제 등 단계적 사고가 필요한 작업에서 특히 효과적입니다.
- CoT가 없을 경우 GPT-4 같은 모델도 연산 순서 오류, 개념적 오해 등을 일으킬 수 있음
2. CoT의 진화 방향 ( 보충 설명 )
Chain of Thought 기법은 최근 다양한 형태로 확장되고 있으며, 주요 진화 방향은 다음과 같습니다:
기법 | 특징 |
Standard CoT | 단순한 단계별 사고 유도 (Let's think step by step.) |
Few-shot CoT | 여러 개의 예시를 함께 제시하여 학습 효과 강화 |
Auto-CoT | LLM이 스스로 CoT 예시를 생성하고, 그 예시를 활용하여 문제 해결 |
Self-consistency | 다양한 CoT 경로를 생성하고, 그 중 가장 자주 등장하는 답을 선택 |
Tree of Thought (ToT) | 하나의 해답 경로가 아닌 여러 사고 경로를 분기시켜 탐색, 더 정교한 의사결정 |
Program-Aided CoT (PACT) | 모델이 논리적 추론 중 실제 프로그램 코드(예: 파이썬)를 이용하여 계산 수행 |
3. 결론
CoT는 단순히 출력 양식을 바꾸는 것이 아니라, 모델의 사고 방식 자체를 유도하는 강력한 기법입니다.
이를 통해 LLM의 잠재력을 더 깊이 끌어낼 수 있으며, 특히 추론, 계산, 다중 선택 문제 등 복잡한 작업에서 큰 성능 향상을 가져올 수 있습니다.
import openai # OpenAI API 라이브러리 임포트
import os # 환경 변수 관리를 위한 os 모듈 임포트
# OpenAI API 키를 환경 변수로 설정 (실제 코드에서는 보안을 위해 노출되면 안 됨)
os.environ["OPENAI_API_KEY"] = "private-api-key"
# OpenAI API 클라이언트 생성
client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
# CoT 방식의 프롬프트를 구성하고 응답을 받아오는 함수
def cot_prompt(query):
# 입력된 질의를 기반으로 단계별 풀이를 요구하는 프롬프트 작성
prompt = f'''다음 문제를 단계별로 풀어주세요. 각 단계를 번호로 구분하고 최종 답변을 명확하게 제시하세요
{query}
1. 문제 분석
2. 계산
3. 답변 확인
'''
# OpenAI GPT 모델에 요청
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 사용할 모델 지정
messages=[
{"role": "system", "content": "당신은 단계별로 문제를 해결하는 논리적인 시스템입니다."},
{"role": "user", "content": prompt}
],
max_tokens=200, # 응답의 최대 길이 제한
temperature=0.7 # 창의성 정도 (0에 가까울수록 보수적, 1에 가까울수록 다양성 높음)
)
# 모델의 응답 텍스트 반환
return response.choices[0].message.content
# 테스트 질의 실행
query = "2 + 2 x 3 = ?"
print(cot_prompt(query))
1. 문제 분석
- 주어진 수식은 "2 + 2 x 3"으로, 곱셈과 덧셈이 혼합되어 있습니다. 이때 연산 순서를 고려하여 정확한 답을 도출해야 합니다.
2. 계산
- 주어진 수식에 따라 우선 곱셈을 먼저 계산합니다.
- 2 x 3 = 6
- 따라서, 2 + 2 x 3 = 2 + 6 = 8
3. 답변 확인
- 따라서, 2 + 2 x 3 = 8 입니다.
코드 설명
1. 목적
- 이 코드는 Chain of Thought (CoT) 방식으로 수학 문제를 단계적으로 해결하도록 LLM(GPT-3.5-turbo)에 요청하는 예제입니다.
2. 주요 구성
- cot_prompt(query) 함수: 주어진 문제(query)를 문제 분석 → 계산 → 답 확인의 단계로 유도하는 프롬프트를 생성하고, 그 결과를 반환합니다.
- openai.OpenAI(...): 최신 OpenAI SDK에서 사용하는 방식으로, 이전의 openai.ChatCompletion.create 방식과 달리 클라이언트를 생성해 사용합니다.
- temperature: 0.7로 설정되어 있어 너무 획일적인 응답이 아닌, 적절한 다양성을 가진 응답을 기대할 수 있습니다.
Tree-of-Thoughts (ToT)
개념 요약
- CoT(Chain-of-Thought) 방식의 확장으로, 단일한 추론 경로가 아닌 트리 형태의 다중 추론 경로를 따라 문제를 해결함.
- 각 단계에서 가능한 여러 사고 분기점(branch) 를 고려하고, 그 결과를 탐색하여 최적의 해결 경로를 찾음.
- 대표 사례: 체스 수 예측처럼 한 선택이 이후 선택에 영향을 주는 문제에 적합.
- 다중 시나리오 분석 및 비결정적/불확실한 문제 탐색에 효과적.
- 단일한 논리 흐름만 따르는 CoT보다 훨씬 더 탐색적이고 유연한 문제 해결이 가능함.
주요 특징
요소 | 설명 |
구조 | 사고 과정이 트리 형태로 확장됨 (여러 경로 탐색) |
적용 예시 | 체스, 법률 시뮬레이션, 전략적 선택 문제 |
CoT와의 차이점 | CoT는 선형 사고, ToT는 비선형(분기적 사고) |
장점 | 다양한 경로의 결과를 비교해 최적의 해결안 도출 가능 |
단점 | 계산량 증가, 경로 선택 기준이 명확하지 않으면 탐색 효율이 낮을 수 있음 |
예시 문제: 몬티홀 문제
"3개의 상자 중 하나에만 상품이 있다. 한 상자를 선택한 후, 나머지 두 상자 중 하나가 열리고 빈 상자가 공개된다. 이때 선택을 바꾸면 정답일 확률은?"
CoT 방식:
- 처음에 상자를 하나 선택할 확률은 1/3
- 진행자가 빈 상자를 공개
- 선택을 바꾸면 남은 두 상자 중 처음 고르지 않은 것 → 확률 2/3로 당첨 가능
ToT 방식:
- 트리 구조로 시나리오를 전개:
- 루트 노드: 초기 선택
- 자식 노드: 진행자가 빈 상자 공개
- 다음 노드들: 선택 유지 vs. 변경
- 각 경로의 성공 확률을 비교하여 전략 도출
활용 사례
- 게임 전략: 체스, 바둑 등에서 수를 여러 수 앞까지 전개하여 판단
- 법률 시뮬레이션: 여러 시나리오별 결과를 예측하여 변호 전략 수립
- 계획 수립: 여행 계획, 프로젝트 분기 등에서 조건 따라 다양한 결과 분석
보충 설명: ToT가 왜 중요한가?
기존 LLM은 추론 시 하나의 답을 선택하고 그 흐름을 따라가며 응답합니다. 이는 많은 문제에서 효과적이지만, 복잡하고 불확실성이 높은 문제(예: 심리 전략, 정책 결정, 법률 등)에서는 여러 가능성을 고려한 탐색적 사고가 더 유용합니다.
ToT는 이런 상황에서 다양한 사고 시나리오를 병렬적으로 생성하고, 비교/선택하는 방식으로 인간의 고차 사고와 유사한 문제 해결 전략을 구현할 수 있게 합니다.
Graph-of-Thoughts (GoT)
개념 요약
- Graph-of-Thoughts(GoT) 는 사고 과정을 그래프 구조로 확장한 프롬프트 방식입니다.
- 노드(node) 는 개별 개념(예: 조항, 조건, 사건 등), 엣지(edge) 는 개념 간의 논리적, 인과적, 시간적 관계를 표현합니다.
- CoT가 선형 추론, ToT가 트리형 다중 추론이라면, GoT는 비선형 연결망 기반의 추론 체계입니다.
- 복잡한 도메인(법률, 의료, 정책, 학술 분석 등)에서 사용 시, 서로 얽힌 개념들을 시맨틱 그래프 형태로 명시적으로 모델링할 수 있어 유리합니다.
주요 특징
요소 | 설명 |
구조 | 개념 간 관계를 그래프로 구성 (비순차적 사고) |
노드(Node) | 주요 개념, 조항, 사건, 명제 등 |
엣지(Edge) | 의존 관계, 인과 관계, 상호작용 등 |
활용 분야 | 법률 조항 간 해석, 의료 진단 인과 구조, 학술 논문 간 개념 연결 |
장점 | 복잡한 시스템 내 개념들의 상호작용을 분석 가능 |
단점 | 그래프 구성 기준이 주관적일 수 있고, 시각화 필요성이 큼 |
예시
질문
임대차 계약에서 임차인의 계약 해지 통지 의무와 임대인의 보증금 반환 의무는 어떻게 연결되나요?
GoT 방식 프롬프트
다음 문제를 Graph-of-Thoughts 방식으로 풀어주세요. 관련 개념(예: 조항, 의무)을 노드로, 그 관계를 엣지로 구성하여 단계별로 분석하세요.
1. 개념 노드 식별
2. 관계 엣지 분석
3. 최종 연결 설명
응답 예시
1. 개념 노드 식별
- N1: 임차인의 계약 해지 통지 의무
- N2: 계약 해지 효력 발생
- N3: 임대인의 보증금 반환 의무
- N4: 임대인의 확인 의무
- N5: 반환 시기 조건
2. 관계 엣지 분석
- E1: N1 → N2 : 통지가 있어야 해지 효력이 발생함
- E2: N2 → N3 : 계약이 해지되어야 반환 의무가 발생함
- E3: N3 ↔ N5 : 반환 시기는 조건(계약 만료 후 일정 기간 등)에 따라 다름
- E4: N3 ← N4 : 임대인은 임차인으로부터의 통지 내용 확인 후 의무가 발생함
3. 최종 연결 설명
- 임차인이 계약 해지 의사를 통지(N1) 해야만 해지 효력이 발생(N2)하고,반환 의무는 특정 조건(N5) 하에 이행되며, 이 의무는 임대인의 확인(N4)을 통해 활성화됩니다.
- 해지 효력이 발생해야 임대인은 보증금 반환 의무(N3) 를 가지며,
왜 GoT가 필요한가?
- CoT/ToT는 순차 또는 분기 사고에 적합하지만, 실세계 문제는 선형이 아닌 다중 관계 기반으로 작동하는 경우가 많습니다.
- GoT는 개념들 간의 구조적 관계와 의존성을 추론에 포함시킴으로써 더 정밀하고 깊이 있는 reasoning을 가능하게 합니다.
- 특히 법률, 의료, 정책, 금융 계약 등 고차원적 복합 reasoning이 요구되는 분야에서 LLM의 reasoning 능력을 질적으로 향상시킵니다.
비교 요약
프롬프트 방식 | 구조 | 적용 예시 |
CoT | 선형 (단일 경로) | 단순 수학, 논리 문제 |
ToT | 트리 (분기 경로) | 전략 게임, 다중 시나리오 |
GoT | 그래프 (비선형 관계망) | 법률 해석, 의료 진단, 정책 시뮬레이션 |
Tool-augmented Chain of Thought (Tool-augmented CoT)
개요
- Tool-augmented CoT는 기존의 Chain of Thought 방식에 **외부 도구(external tools)**를 연동하여 LLM의 계산 능력, 정보 검색 능력 등의 한계를 보완하는 방식입니다.
- 인간이 문제를 풀 때 계산기나 사전, 웹검색을 활용하듯, LLM도 필요한 작업을 적절한 도구에게 위임하여 보다 정확한 reasoning을 수행할 수 있게 합니다.
핵심 요소
구성 요소 | 설명 |
LLM | 추론 과정을 구성하고, 도구 사용의 시점과 목적을 결정 |
도구 | 계산기, 웹 검색, API, 데이터베이스, 코드 실행기 등 |
연결 방식 | 내장 함수 호출, 플러그인, API 연동, Toolformer 방식 |
예시 문제
√(16) + 3² = ?
일반 CoT 방식 (LLM만 사용)
1. 루트 16은 4
2. 3의 제곱은 9
3. 4 + 9 = 13
→ 답: 13
→ 간단한 문제는 가능하나, 복잡한 계산 또는 최신 정보 검색이 필요한 경우 한계 존재
Tool-augmented CoT 방식
1. 루트 16 계산 → 계산기 호출: sqrt(16) = 4
2. 3의 제곱 계산 → 계산기 호출: 3^2 = 9
3. 덧셈 수행: 4 + 9 = 13
→ 정확한 계산 기반으로 답 도출
활용 예시
도구 종류 | 활용 예시 |
계산기 | 수학 문제, 재무 계산 등 |
웹 검색 | 시사 문제, 최신 데이터, 트렌드 정보 |
API | 날씨, 번역, 환율, 주식 정보 등 |
코드 실행기 | 코드 분석, 시뮬레이션, 수치 계산 |
DB 질의 도구 | 고객 정보 조회, 대규모 테이블 분석 등 |
대표 기술
- Toolformer
- Meta AI에서 개발한 LLM + 도구 조합 모델
- 모델이 도구가 필요한 지점을 스스로 인식하고, API 호출을 삽입하는 방식으로 fine-tuning함
- 학습 시 도구 사용 여부와 타이밍을 스스로 결정할 수 있게 함
- ReAct (Reasoning + Acting)
- 추론을 하면서 중간에 필요한 도구를 호출함 (예: 검색→추론→계산 반복)
- OpenAI의 Plugin 기반 프롬프트 등에도 활용됨
장점
- LLM의 내재적 한계(계산, 최신 정보 부족 등)를 보완
- 보다 정확하고 신뢰도 높은 reasoning 가능
- 추론 과정이 도구 호출과 결합되어 명확하게 드러남
단점
- 도구 호출의 정확성에 의존 → 오작동, 오류 처리 필요
- 도구 호출 비용 발생
- 복잡한 구성: API 인증, 호출 시점 판단, 에러 처리 등 설계 필요
관련 기술 비교
방식 | 설명 |
CoT | 내부 추론만으로 문제 해결 |
Tool-augmented CoT | 추론 중 도구를 호출하여 보완 |
ReAct | 추론과 행동(도구 사용)을 번갈아 반복 |
Toolformer | 도구 사용이 포함된 데이터로 사전 학습된 모델 |
def tool_augmented_cot(query):
# 계산기 함수: 제한된 eval 환경에서 sqrt() 함수만 허용하여 계산 수행
def calculator(expression):
try:
return eval(expression, {'__builtins__': None}, {'sqrt': lambda x: x**0.5})
except Exception as e:
return None
# 수식 정규화 함수:
# - ^ 연산자는 Python의 거듭제곱 연산자 **로 변경
# - √(x)는 sqrt(x)로 변경하여 eval에서 계산 가능하게 함
def normalize_expr(expr):
expr = expr.replace('^', '**')
expr = re.sub(r'√\\((.*?)\\)', r'sqrt(\\1)', expr)
return expr
# OpenAI LLM 호출: CoT 방식으로 문제를 해결하되, 계산식은 [CALC: ...] 형태로 출력 요청
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "당신은 단계별로 문제를 해결하는 논리적인 시스템입니다."},
{"role": "user", "content": f"""
문제를 단계별로 풀어주세요. 계산이 필요하면 '[CALC: 식]'으로 표기하고, 계산기 도구를 사용하세요.
{query}
1. 문제 분석
2. 계산
3. 답변 확인
"""}
],
max_tokens=200,
temperature=0.7
)
# LLM 응답 메시지 가져오기
result = response.choices[0].message.content
# 응답 내에서 [CALC: ...] 패턴의 수식을 모두 추출
calc_pattern = r'\\[CALC: (.*?)\\]'
for calc in re.findall(calc_pattern, result):
# 수식을 eval에서 계산 가능한 형태로 정규화
normalized = normalize_expr(calc)
# 계산 수행
calc_result = calculator(normalized)
if calc_result is not None:
# 계산 결과를 응답 메시지에 덧붙이기
result += f"\\n계산 결과: {calc} = {calc_result}"
return result
# 테스트할 질의 입력
query = "√(16) + 3^2 = ?"
# 실행
print(tool_augmented_cot(query))
함수 설명
함수 목적
- Tool-augmented Chain-of-Thought (CoT) 기법을 구현합니다.
- LLM이 문제 해결 흐름을 단계별로 출력하고, 계산이 필요한 부분은 [CALC: ...]로 명시하게 합니다.
- 그런 후 외부 도구(여기선 eval)를 사용해 계산 결과를 보완합니다.
작동 흐름 요약
- 질문 입력: query = "√(16) + 3^2 = ?"
- LLM 응답 생성: 문제를 Chain-of-Thought 형식으로 해결하고, 계산이 필요한 부분에 [CALC: ...] 형식으로 표시.
- 정규식 추출: [CALC: ...] 수식들을 모두 추출.
- 정규화: ^ → *, √(x) → sqrt(x) 형태로 변경.
- 계산: eval()을 사용해 실제 계산 수행.
- 결과 덧붙이기: 계산 결과를 원래 LLM 응답에 추가.
query = "√(16) + 3^2 = ?"
print(tool_augumented_coat(query))
1. 문제 분석:
주어진 수식을 계산해야 합니다. 수식은 다음과 같습니다.
√(16) + 3^2
2. 계산:
√(16) = 4
3^2 = 9
따라서, 수식을 계산하면 다음과 같습니다.
4 + 9
[CALC: 4 + 9]
3. 답변 확인:
4 + 9 = 13
따라서, 주어진 수식을 계산하면 13이 됩니다.
계산 결과: 4 + 9 = 13
1. Self-Refinement
- 정의: LLM이 자신의 초기 응답을 스스로 점검하고 개선하는 능력
- 핵심 아이디어:② 자기 검토(Self-critique)
- ③ 수정 및 개선된 응답 생성
- ① 초기 응답 생성
- 적용 예:
- 요약 결과를 다시 보고 부족한 점(정보 누락, 논리 불일치 등)을 수정
- 수학 풀이에서 계산 오류를 스스로 찾아 재계산
- 예시 흐름:
- Q: AI는 인간을 대체할 수 있는가? A1: AI는 많은 직무에서 인간을 대체할 수 있다. 특히 반복적인 업무에서 그렇다. Self-Check: 윤리적 문제와 창의성에 대한 고려가 빠졌다. A2 (Refined): AI는 반복 업무를 대체할 수 있으나, 윤리적 고려 및 창의적 판단 영역에서는 인간의 역할이 여전히 중요하다.
2. CoT + Toolformer
- 정의: CoT(Chain-of-Thought)에 도구 자동 삽입 훈련을 결합한 방식
- Toolformer는 LLM이 어떤 도구를 어느 시점에 호출할지 스스로 학습하게 하여, 계산기/검색/API 등 외부 도구를 자동 호출함
- 기능 요약:
- LLM이 프롬프트 내에 [TOOL: ...]을 자동 생성
- 훈련 없이 기존 LLM만으로 도구 호출 시점 예측 가능
- 예시:
- 입력: √(121) + 5^2 = ? 출력: 1. √(121)을 계산해야 함 → [TOOL: sqrt(121)] 2. 5^2는 → [TOOL: pow(5, 2)] 3. 두 값을 더함 최종 결과: 11 + 25 = 36
3. ReAct 2.0 (Reasoning + Acting)
- 정의: **추론(Reasoning)**과 **행동(Acting)**을 교차하며 문제 해결을 수행하는 프레임워크의 발전된 버전
- ReAct 1.0에서 발전:
- 더 강력한 메모리 구조
- 불확실성 추적, 자기 피드백 루프 포함
- 핵심 흐름:
- Thought: 우편번호를 찾기 위해 검색이 필요해요. Action: [SEARCH: "서울시 강남구 우편번호"] Observation: "06000" Thought: 우편번호는 06000입니다. Final Answer: 06000
- 활용:
- 웹 검색 기반 Q&A
- 계산, 문서 요약, 웹탐색 등을 순차적으로 처리
세 방식 비교 요약
방법 | 목적 | 핵심 구성 | 장점 |
Self-Refinement | 스스로 검토 및 개선 | 응답 → 자기평가 → 재작성 | 정확도와 논리성 향상 |
CoT + Toolformer | 추론 도중 도구 자동 호출 | CoT + 도구 삽입 학습 | 계산기, 검색기 등 유연한 활용 가능 |
ReAct 2.0 | 행동과 추론의 결합 | Thought-Action-Obs 순환 | 복잡한 문제 해결, 외부 정보 조합 |
import os
import openai
# OpenAI API 클라이언트 초기화 (환경변수에서 API 키를 불러옴)
client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
# Self-Refinement 기반 Chain-of-Thought 실행 함수
def self_refinement_cot(query):
# GPT 모델에 요청 보내기
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 사용할 OpenAI 모델
messages=[
# 시스템 역할: 자기개선 시스템이라고 정의
{"role": "system", "content": "당신은 자기개선을 통해 문제를 해결하는 시스템입니다."},
# 사용자 질문과 단계별 지시 포함
{"role": "user", "content": f"""
다음 문제를 단계별로 풀어주세요, 답변 후 스스로 검토해 오류를 수정하세요,
최종 답변에 오류가 있다면 2번 순서부터 다시 실행하세요.
{query}
1. 문제 분석
2. 계산
3. 검토 및 수정
4. 최종 답변
"""}
],
max_tokens=400, # 출력 최대 토큰 수
temperature=0.7 # 창의성 조절 (0.7은 중간 정도의 무작위성)
)
# 생성된 응답 중 첫 번째 메시지의 content(본문) 반환
return response.choices[0].message.content
query = "한 농부가 닭과 소를 합쳐서 20마리를 기르고 있습니다. 농부가 기르는 동물의 다리 수는 총 50개일 때, 닭과 소의 수는 각각 몇 마리인가요?"
print(self_refinement_cot(query))
1. 문제 분석
- 닭과 소의 수를 각각 x와 y라고 가정합니다.
- 문제에서 주어진 조건에 따라 방정식을 세워야 합니다.
- 닭과 소를 합쳐서 20마리를 기르고 있으므로 x + y = 20
- 농부가 기르는 동물의 다리 수는 총 50개이므로 2x + 4y = 50
2. 계산
- 위의 두 방정식을 풀어 x와 y 값을 구합니다.
- x + y = 20 → x = 20 - y
- 2(20 - y) + 4y = 50
- 40 - 2y + 4y = 50
- 2y = 10
- y = 5
- x = 20 - 5 = 15
3. 검토 및 수정
- 닭과 소의 수를 각각 15마리와 5마리로 계산하였습니다.
- 다리 수를 확인해보겠습니다. 닭은 2개의 다리, 소는 4개의 다리를 가지므로 전체 다리 수는 15*2 + 5*4 = 50으로 맞는 것을 확인할 수 있습니다.
4. 최종 답변
- 농부가 기르는 닭은 15마리, 소는 5마리입니다.
동작 구조 설명 (Self-Refinement CoT)
- 입력
- query: 예를 들어 "√(16) + 3^2 = ?" 같은 질문을 받음
- 단계별 출력 요청
- 모델에게 아래 4단계로 작업을 수행하도록 프롬프트를 구성함:
- 문제 분석: 질문의 구조 및 요소 파악
- 계산: 필요한 수식이나 논리 수행
- 검토 및 수정: 계산 또는 논리 오류 여부 판단
- 최종 답변: 오류가 있다면 2번부터 다시 반복하여 재계산 후 최종 답변
- 모델에게 아래 4단계로 작업을 수행하도록 프롬프트를 구성함:
- 자기검토
- GPT는 자체적으로 응답 결과를 분석하여, 오류 여부를 판단하고 자동으로 수정 루프를 수행함
- 예: √(16) + 3^2 → 처음에 계산을 잘못하면 검토 후 다시 계산해서 바르게 고침
- 출력
- 최종적으로 검토/수정이 완료된 정답을 반환함
CoT Prompt Template 고도화
개념 정리
고도화된 Chain-of-Thought(CoT) Prompt Template이란, 단순히 “step-by-step”이라는 지시어만 사용하는 것이 아니라 문제 해결 단계, 출력 형식, reasoning 방식을 더 구체적이고 체계적으로 명시하는 프롬프트 설계 방식입니다. 이를 통해 LLM의 일관된 추론 경로 유도 및 오류 감소를 도모할 수 있습니다.
핵심 요소
- 단계 수 명시예: 수학 문제 → "변수 정의 → 계산 → 검증"
- 문제 유형에 따라 해결 단계의 수와 흐름을 명확히 지정
- 명시적 지시어 사용예: "모든 숫자를 변수로 치환한 후 연산 순서를 설명하세요."
- 각 단계에서 LLM이 해야 할 사고 절차 또는 판단 기준을 구체적으로 지시
- 출력 형식 정의예:
- 1. 변수 정의: ... 2. 계산: ... 3. 검증: ... 4. 최종 답변: ...
- 응답이 일관되게 구성되도록 결과 형식(template)을 명확히 요구
예시 (수학 문제에 대한 고도화된 CoT Prompt)
프롬프트
다음 수학 문제를 아래 단계에 따라 체계적으로 해결하세요. 각 단계를 번호로 구분하고, 명확한 출력 형식을 따르세요.
문제: (4 + 2) × (10 ÷ 2) = ?
1. 변수 정의: 수식에 포함된 주요 수치와 연산자의 의미를 정의하세요.
2. 계산: 연산 순서에 따라 각 단계를 계산하세요.
3. 검증: 계산 결과가 논리적으로 타당한지 검토하세요.
4. 최종 답변: 최종 정답을 한 문장으로 요약하여 제시하세요.
효과
- LLM이 혼동 없이 일관된 논리 전개 가능
- 문제에 특화된 reasoning 전략 적용 가능 (예: 수학, 법률, 코딩 등)
- 평가와 디버깅이 쉬운 구조적 응답 확보
보충 설명
이러한 방식은 특히 다음 상황에서 효과를 발휘합니다:
- 고난도 문제: 단순한 “step-by-step” 프롬프트로는 reasoning depth가 부족할 수 있음
- 문제별 편차가 큰 응답 방지: 구조화된 형식이 정답의 신뢰도를 높여 줌
- 툴 결합 방식 (Tool-augmented CoT) 또는 Self-Refinement와의 병행에 적합
# utils.py
import math # 수학 관련 함수 및 상수 사용을 위한 모듈
import re # 정규 표현식 처리를 위한 모듈
# 고도화된 Chain-of-Thought(CoT) 템플릿을 사용하여 문제를 단계적으로 해결하는 함수
def advanced_cot_template(client, query):
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 사용하는 언어 모델
messages=[
# 시스템 역할: 자기개선을 수행하는 문제 해결 시스템
{"role": "system", "content": "당신은 자기개선을 통해 문제를 해결하는 시스템입니다."},
# 사용자 입력: 문제를 단계적으로 풀고 검토 및 수정 절차까지 거칠 것
{"role": "user", "content": f"""
다음 문제를 단계별로 풀어주세요, 답변 후 스스로 검토해 오류를 수정하세요.
{query}
1. 문제 분석
2. 계산
3. 검토 및 수정
4. 최종 답변
"""}
],
max_tokens=800, # 출력 토큰 수 제한
temperature=0.7 # 출력의 창의성(무작위성) 조절
)
# 최종 응답 텍스트 반환
return response.choices[0].message.content
# Few-shot 예제를 포함한 Chain-of-Thought 방식으로 문제를 해결하는 함수
def few_shot_cot(client, query):
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "당신은 자기개선을 통해 문제를 해결하는 시스템입니다."},
{"role": "user", "content": f"""
다음 문제를 few shot으로 단계별로 풀어주세요. 아래 예제를 참고하여 단계별로 답변하세요. 답변 후 스스로 검토해 오류를 수정하세요.
예제 1:
1. 문제 분석
- 닭과 소의 수를 각각 x와 y라고 가정합니다.
- 문제에서 주어진 조건에 따라 방정식을 세워야 합니다.
- 닭과 소를 합쳐서 20마리를 기르고 있으므로 x + y = 20
- 농부가 기르는 동물의 다리 수는 총 50개이므로 2x + 4y = 50
2. 계산
- 위의 두 방정식을 풀어 x와 y 값을 구합니다.
- x + y = 20 → x = 20 - y
- 2(20 - y) + 4y = 50
- 40 - 2y + 4y = 50
- 2y = 10
- y = 5
- x = 20 - 5 = 15
3. 검토 및 수정
- 닭과 소의 수를 각각 15마리와 5마리로 계산하였습니다.
- 다리 수를 확인해보겠습니다. 닭은 2개의 다리, 소는 4개의 다리를 가지므로 전체 다리 수는 15*2 + 5*4 = 50으로 맞는 것을 확인할 수 있습니다.
4. 최종 답변
- 농부가 기르는 닭은 15마리, 소는 5마리입니다.
예제 2:
1. 문제 분석:
- 사과를 A원, 오렌지를 O원이라고 가정하겠습니다.
- 첫 번째 방정식: 3A + 2O = 13000
- 두 번째 방정식: 2A + 3O = 12000
2. 계산:
- 두 방정식을 활용하여 연립방정식을 풀어보겠습니다.
- 먼저 두 번째 방정식에 2를 곱하여 새로운 방정식을 만듭니다.
4A + 6O = 24000
- 이제 첫 번째 방정식에서 두 번째 방정식을 빼줍니다.
(3A + 2O) - (4A + 6O) = 13000 - 24000
-A - 4O = -11000
A = 11000 - 4O
- A = 11000 - 4O를 첫 번째 방정식에 대입하여 O를 구합니다.
3(11000 - 4O) + 2O = 13000
33000 - 12O + 2O = 13000
-10O = -20000
O = 2000
- O = 2000을 A = 11000 - 4O에 대입하여 A를 구합니다.
A = 11000 - 4(2000)
A = 11000 - 8000
A = 3000
...
- 계산 결과, 사과의 가격은 3,000원, 오렌지의 가격은 2,000원으로 계산되었습니다.
4. 최종 답변:
- 사과는 3,000원, 오렌지는 2,000원입니다.
문제:
{query}
1. 변수 정의.
2. 방정식 설정.
3. 계산 과정.
4. 검토.
5. 최종 답변.
"""}
],
max_tokens=1000,
temperature=0.7
)
return response.choices[0].message.content
코드 설명
- 이 코드는 LLM 기반 문제 해결 파이프라인 중 CoT 방식으로 구성된 템플릿 2종을 제공합니다.
- 두 함수 모두 OpenAI의 Chat API를 사용하며, 각각의 방식은 다음과 같습니다:
함수명 | 주요 목적 | 특징 |
advanced_cot_template | 일반 CoT + Self-Refinement | 4단계 구조(문제 분석 ~ 최종 답변)로 구성 |
few_shot_cot | 예시 기반 Few-shot CoT | 2개의 수학 예시 제공 후 5단계 구조(변수 정의 ~ 최종 답변)로 유도 |
- 이들은 주로 수학/논리 문제 해결 시 유용하며, 다음과 같은 방식으로 사용할 수 있습니다:
result = advanced_cot_template(client, "어떤 수에 5를 더했더니 12가 되었다. 그 수는?")
print(result)
result = few_shot_cot(client, "3개의 펜과 2개의 연필이 8000원, 2개의 펜과 3개의 연필이 7000원일 때 각각의 가격은?")
print(result)
# 사과 3개와 오렌지 2개는 13,000원이고, 사과 2개와 오렌지 3개는 12,000원입니다. 사과와 오렌지는 각각 얼마인가요?
import openai
import os
from dotenv import load_dotenv
load_dotenv()
query = "사과 3개와 오렌지 2개는 13,000원이고, 사과 2개와 오렌지 3개는 12,000원입니다. 사과와 오렌지는 각각 얼마인가요?"
# advanced_cot_template은 utils.py에 정의된 함수입니다.
from utils import advanced_cot_template
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
print(advanced_cot_template(client, query))
1. 문제 분석:
- 사과를 A원, 오렌지를 O원이라고 가정하겠습니다.
- 첫 번째 방정식: 3A + 2O = 13000
- 두 번째 방정식: 2A + 3O = 12000
2. 계산:
- 두 방정식을 활용하여 연립방정식을 풀어보겠습니다.
- 먼저 두 번째 방정식에 2를 곱하여 새로운 방정식을 만듭니다.
4A + 6O = 24000
- 이제 첫 번째 방정식에서 두 번째 방정식을 빼줍니다.
(3A + 2O) - (4A + 6O) = 13000 - 24000
-A - 4O = -11000
A = 11000 - 4O
- A = 11000 - 4O를 첫 번째 방정식에 대입하여 O를 구합니다.
3(11000 - 4O) + 2O = 13000
33000 - 12O + 2O = 13000
-10O = -20000
O = 2000
- O = 2000을 A = 11000 - 4O에 대입하여 A를 구합니다.
A = 11000 - 4(2000)
A = 11000 - 8000
A = 3000
...
- 계산 결과, 사과의 가격은 3,000원, 오렌지의 가격은 2,000원으로 계산되었습니다.
4. 최종 답변:
- 사과는 3,000원, 오렌지는 2,000원입니다.
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
암호화
# XOR 연산자를 이용한 암호화 샘플
original = "이건 비밀인데 너만 알고 있어야 해."
key = 64
encoded = [ord(c) ^ key for c in original]
print(f"Encoded: {encoded}")
decoded = "".join([chr(c ^ key) for c in encoded])
print(f"Decoded: {decoded}")
Encoded: [50996, 44084, 96, 48644, 48192, 51000, 45872, 96, 45384, 47500, 96, 50444, 44192, 96, 51144, 50676, 50492, 96, 54580, 110]
Decoded: 이건 비밀인데 너만 알고 있어야 해.
cryptography
!pip install cryptography
from cryptography.fernet import Fernet
# 키 생성( 한 번만 )
public_key = Fernet.generate_key()
print(f"public_key: {public_key.decode()}")
# 암호화
original = "이건 비밀인데 너만 알고 있어야 해."
fernet = Fernet(public_key) # 객체 생성
encrypted = fernet.encrypt(original.encode())
print(f"Encrypted: {encrypted.decode()}")
# 복호화
decrypted = fernet.decrypt(encrypted).decode()
print(f"Decrypted: {decrypted}")
public_key: efCH-8oSrcGKOeyofamWroXxAxyoM74f6gXinAw4-Es=
Encrypted: gAAAAABoJtwu97kdcfdniW4IrLvssE252VuFHojq5e7z6o4e57dqP9jsfztcdG3b8StzAESRFCL1FRvwYa-_RnoY9S-ftWu4shgjg6d93bLyU_nVqPWHfYwvZvDiMFMpzL4Dnr-R1x9f2SfqozoOizXZFv4CqdBR1A==
Decrypted: 이건 비밀인데 너만 알고 있어야 해.
Few_Shot
# 사과 3개와 오렌지 2개는 13,000원이고, 사과 2개와 오렌지 3개는 12,000원입니다. 사과와 오렌지는 각각 얼마인가요?
import openai
import os
from dotenv import load_dotenv
load_dotenv()
query = "닭과 소를 합쳐서 20마리를 기르고 있습니다. 농부가 기르는 동물의 다리 수는 총 56개일 때, 닭과 소의 수는 각각 몇 마리인가요?"
# advanced_cot_template은 utils.py에 정의된 함수입니다.
from utils import few_shot_cot
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
print(few_shot_cot(client, query))
1. 변수 정의:
- 닭의 수를 x, 소의 수를 y로 정의합니다.
2. 방정식 설정:
- 닭과 소를 합쳐서 20마리를 기르고 있으므로 x + y = 20
- 농부가 기르는 동물의 다리 수는 총 56개이므로 2x + 4y = 56
3. 계산 과정:
- 위의 두 방정식을 활용하여 x와 y 값을 구합니다.
- x + y = 20 → x = 20 - y
- 2(20 - y) + 4y = 56
- 40 - 2y + 4y = 56
- 2y = 16
- y = 8
- x = 20 - 8 = 12
4. 검토:
- 닭과 소의 수를 각각 12마리와 8마리로 계산하였습니다.
- 다리 수를 확인해보겠습니다. 닭은 2개의 다리, 소는 4개의 다리를 가지므로 전체 다리 수는 12*2 + 8*4 = 56으로 맞는 것을 확인할 수 있습니다.
5. 최종 답변:
- 농부가 기르는 닭은 12마리, 소는 8마리입니다.