Skip to main content

고급 프롬프팅 기법

Chain-of-Thought가 모델의 “생각”을 유도한다면, 고급 기법들은 모델이 외부 도구를 사용하고, 여러 경로를 탐색하며, 스스로 결과를 개선하도록 만듭니다. 이 기법들은 LLM을 단순한 텍스트 생성기에서 **자율적 에이전트(Agent)**로 진화시키는 핵심 패턴입니다.

핵심 아이디어

1. ReAct (Reasoning + Acting)

동작 방식

ReAct는 모델이 **추론(Thought)**과 **행동(Action)**을 번갈아 수행하는 패턴입니다. 모델이 스스로 “지금 무엇을 알아야 하는지” 추론하고, 외부 도구를 호출하여 정보를 수집한 후, 그 결과를 바탕으로 다시 추론합니다.

구현 예시

from openai import OpenAI
client = OpenAI()

REACT_SYSTEM_PROMPT = """당신은 도구를 사용할 수 있는 AI 어시스턴트입니다.

사용 가능한 도구:
- search(query): 위키피디아에서 정보를 검색합니다
- calculate(expression): 수학 계산을 수행합니다
- lookup(term): 특정 용어의 정의를 찾습니다

다음 형식을 반드시 따르세요:

Thought: [지금 무엇을 알아야 하는지 추론]
Action: [도구_이름(인자)]
Observation: [도구 실행 결과 — 시스템이 채워줌]

이 과정을 필요한 만큼 반복한 후:
Thought: [최종 추론]
Answer: [최종 답변]"""

def simulate_react(question):
    """ReAct 패턴 시뮬레이션"""
    messages = [
        {"role": "system", "content": REACT_SYSTEM_PROMPT},
        {"role": "user", "content": question},
    ]

    # 시뮬레이션을 위한 도구 응답
    tool_responses = {
        "search": lambda q: f"검색 결과: {q}에 대한 정보...",
        "calculate": lambda expr: f"계산 결과: {eval(expr)}",
    }

    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        temperature=0,
    )

    print(response.choices[0].message.content)

simulate_react("테슬라의 2024년 매출은 전년 대비 얼마나 변화했나요?")
# Thought: 테슬라의 2024년과 2023년 매출을 각각 확인해야 합니다.
# Action: search("테슬라 2024년 연간 매출")
# Observation: 테슬라의 2024년 매출은 약 967억 달러입니다.
# Thought: 2023년 매출도 확인해야 비교할 수 있습니다.
# Action: search("테슬라 2023년 연간 매출")
# Observation: 테슬라의 2023년 매출은 약 967억 달러입니다.
# Thought: 두 해의 매출을 비교하여 변화율을 계산합니다.
# Action: calculate("(967 - 967) / 967 * 100")
# Answer: ...
Agent 탭과의 연결: ReAct는 Agent 탭에서 다루는 LLM 에이전트의 핵심 패턴입니다. LangChain과 LangGraph에서 ReAct 에이전트를 프레임워크 수준으로 구현하는 방법은 Agent 탭에서 상세히 다룹니다.

2. Tree-of-Thought (ToT)

동작 방식

Tree-of-Thought는 Chain-of-Thought의 확장으로, **여러 가지 사고 경로를 분기(Branch)**하여 탐색하고, 각 경로를 평가하여 가장 유망한 경로를 선택합니다.

구현 예시

def tree_of_thought(problem, n_thoughts=3):
    """Tree-of-Thought: 분기 탐색 기반 문제 해결"""

    # 1단계: 여러 초기 접근법 생성
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{
            "role": "user",
            "content": f"""다음 문제에 대해 {n_thoughts}가지 서로 다른 접근 방법을 제안하세요.
각 접근법을 2~3문장으로 설명하세요.

문제: {problem}

형식:
접근법 1: [설명]
접근법 2: [설명]
접근법 3: [설명]""",
        }],
        temperature=0.7,
    )
    approaches = response.choices[0].message.content
    print("=== 생성된 접근법 ===")
    print(approaches)

    # 2단계: 각 접근법 평가
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{
            "role": "user",
            "content": f"""다음 접근법들을 평가하고 가장 유망한 것을 선택하세요.

문제: {problem}

{approaches}

각 접근법에 대해:
- 실현 가능성 (1~10)
- 예상 효과 (1~10)
- 리스크 (1~10, 높을수록 위험)

가장 유망한 접근법 번호와 이유를 설명하세요.""",
        }],
        temperature=0,
    )
    evaluation = response.choices[0].message.content
    print("\n=== 평가 결과 ===")
    print(evaluation)

    # 3단계: 선택된 접근법으로 상세 해결
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{
            "role": "user",
            "content": f"""위 평가에서 선택된 최적 접근법으로 문제를 상세히 해결하세요.

문제: {problem}
선택된 접근법과 평가:
{evaluation}

단계별로 구체적인 실행 계획을 수립하세요.""",
        }],
        temperature=0,
    )

    print("\n=== 최종 해결책 ===")
    print(response.choices[0].message.content)

tree_of_thought("기술 스타트업의 B2B SaaS 제품 출시 후 첫 100명의 유료 고객을 확보하는 전략")

3. Structured Output (구조화 출력)

LLM의 출력을 프로그래밍에서 파싱 가능한 형식으로 제한합니다. JSON, XML, YAML 등 구조화된 형식으로 출력하면 후속 처리가 용이해집니다.
# OpenAI JSON 모드
response = client.chat.completions.create(
    model="gpt-4o-mini",
    response_format={"type": "json_object"},  # JSON 모드 활성화
    messages=[
        {"role": "system",
         "content": "반드시 JSON 형식으로 응답하세요."},
        {"role": "user",
         "content": """다음 텍스트에서 정보를 추출하세요.

텍스트: "삼성전자가 2024년 3분기 매출 79조원을 기록했다.
         영업이익은 9조원으로 전년 대비 200% 증가했다."

스키마:
{
  "company": "회사명",
  "period": "기간",
  "revenue": "매출 (조원)",
  "operating_profit": "영업이익 (조원)",
  "yoy_change": "전년 대비 변화율"
}"""},
    ],
)

import json
result = json.loads(response.choices[0].message.content)
print(json.dumps(result, ensure_ascii=False, indent=2))
# {
#   "company": "삼성전자",
#   "period": "2024년 3분기",
#   "revenue": "79조원",
#   "operating_profit": "9조원",
#   "yoy_change": "200% 증가"
# }

4. Self-Refine (자기 개선)

모델이 자신의 출력을 **비평(Critique)**하고 **개선(Refine)**하는 반복 과정입니다.
def self_refine(task, max_iterations=3):
    """Self-Refine: 자기 비평과 개선 반복"""

    # 초기 답변 생성
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": task}],
        temperature=0.7,
    )
    current_output = response.choices[0].message.content
    print(f"[초기 답변]\n{current_output}\n")

    for i in range(max_iterations):
        # 비평 단계
        critique_response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": f"""다음 답변을 비판적으로 평가하세요.

원래 태스크: {task}

답변:
{current_output}

평가 기준:
1. 정확성: 사실 오류가 없는가?
2. 완전성: 빠진 내용이 없는가?
3. 명확성: 이해하기 쉬운가?
4. 실용성: 실제로 도움이 되는가?

각 기준에 대해 점수(1~5)와 구체적 개선점을 제시하세요.
개선이 필요 없으면 "개선 불필요"라고 답하세요."""}],
            temperature=0,
        )
        critique = critique_response.choices[0].message.content
        print(f"[비평 {i+1}]\n{critique}\n")

        if "개선 불필요" in critique:
            print("비평에서 개선이 불필요하다고 판단. 종료.")
            break

        # 개선 단계
        refine_response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": f"""아래 비평을 반영하여 답변을 개선하세요.

원래 태스크: {task}

현재 답변:
{current_output}

비평:
{critique}

비평에서 지적된 모든 점을 반영하여 개선된 답변을 작성하세요."""}],
            temperature=0.7,
        )
        current_output = refine_response.choices[0].message.content
        print(f"[개선 {i+1}]\n{current_output}\n")

    return current_output

result = self_refine("Python 초보자를 위한 에러 핸들링 가이드를 작성하세요.")

5. Prompt Chaining (프롬프트 연결)

복잡한 태스크를 여러 단계의 프롬프트로 분할하여 순차적으로 실행합니다. 각 단계의 출력이 다음 단계의 입력이 됩니다.
def prompt_chain(document):
    """프롬프트 체이닝: 문서 분석 파이프라인"""

    # 1단계: 핵심 정보 추출
    step1 = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user",
                   "content": f"다음 문서에서 핵심 사실 5가지를 추출하세요:\n\n{document}"}],
    ).choices[0].message.content

    # 2단계: 추출된 정보 분석
    step2 = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user",
                   "content": f"다음 사실들의 인사이트를 분석하세요:\n\n{step1}"}],
    ).choices[0].message.content

    # 3단계: 실행 가능한 제안 생성
    step3 = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user",
                   "content": f"다음 분석을 바탕으로 실행 가능한 제안 3가지를 작성하세요:\n\n{step2}"}],
    ).choices[0].message.content

    return {"facts": step1, "analysis": step2, "recommendations": step3}

기법 비교 및 선택 가이드

기법복잡도API 호출 수적합한 상황
ReAct높음다수 (루프)외부 정보 필요, Agent 구축
Tree-of-Thought높음3~5회창의적 문제 해결, 전략 수립
Structured Output낮음1회데이터 추출, API 연동
Self-Refine중간3~7회글쓰기, 코드 품질 개선
Prompt Chaining중간단계 수복잡한 파이프라인

관련 기술 비교

기법기원 논문핵심 혁신한계
CoTWei et al. (2022)추론 과정 명시화단일 경로 추론
Self-ConsistencyWang et al. (2022)다수결 투표비용 증가
ToTYao et al. (2023)분기 탐색구현 복잡도 높음
ReActYao et al. (2023)추론 + 도구 사용도구 설계 필요
Self-RefineMadaan et al. (2023)자기 비평 루프수렴 보장 없음

참고 논문

논문연도핵심 기여
Chain-of-Thought Prompting Elicits Reasoning in LLMs2022CoT 프롬프팅 제안
Self-Consistency Improves CoT Reasoning in LLMs2022다수결 기반 일관성 향상
Tree of Thoughts: Deliberate Problem Solving with LLMs2023분기 탐색 추론
ReAct: Synergizing Reasoning and Acting in LLMs2023추론 + 행동 통합
Self-Refine: Iterative Refinement with Self-Feedback2023자기 비평 개선 루프
ReAct는 프롬프트 수준에서 추론과 행동을 구조화하는 패턴이고, Function Calling은 API 수준에서 모델이 도구를 선택하고 호출하는 메커니즘입니다. ReAct는 개념적 프레임워크이고, Function Calling은 그것을 구현하는 기술입니다. 실무에서는 Function Calling API를 사용하여 ReAct 패턴을 구현합니다.
아닙니다. ToT는 각 분기를 명시적으로 평가하므로 비용이 더 높습니다. 단순 추론 문제에서는 Self-Consistency가 더 비용 효율적입니다. ToT는 창의적 문제 해결, 계획 수립, 게임 전략 같은 탐색이 필요한 문제에서 강점을 보입니다.
max_iterations을 설정하여 방지합니다. 또한 비평 단계에서 “개선 불필요” 판단을 포함하면 자연스럽게 종료됩니다. 실무에서는 3~5회 반복이 일반적이며, 이후에는 개선 폭이 미미해집니다.

다음 문서