dspy.GEPA - 고급 기능

dspy.GEPA - 고급 기능

GEPA 옵티마이저의 고급 기능들, 즉 커스텀 지시문 제안기(instruction proposer), 커스텀 코드 제안기(code proposer), 커스텀 컴포넌트 선택(component selection)에 대해 다룹니다.

출처: 문서

본문

커스텀 지시문 제안기 (Custom Instruction Proposers)

instruction_proposer란?

instruction_proposer는 GEPA 최적화 중 reflection_lm을 호출해 새 프롬프트를 제안하는 컴포넌트입니다. GEPA가 프로그램에서 성능이 낮은 컴포넌트를 식별하면, 지시문 제안기가 실행 trace, 피드백, 실패를 분석해 관찰된 문제에 맞는 개선된 지시문을 생성합니다.

기본 구현

기본적으로 GEPA는 GEPA 라이브러리의 내장 지시문 제안기를 사용합니다. 이는 ProposalFn 프로토콜을 구현합니다. 기본 제안기는 다음 프롬프트 템플릿을 사용합니다:

I provided an assistant with the following instructions to perform a task for me:

<curr_param>


The following are examples of different task inputs provided to the assistant along with the assistant's response for each of them, and some feedback on how the assistant's response could be better:

<side_info>


Your task is to write a new instruction for the assistant.

Read the inputs carefully and identify the input format and infer detailed task description about the task I wish to solve with the assistant.

Read all the assistant responses and the corresponding feedback. Identify all niche and domain specific factual information about the task and include it in the instruction, as a lot of it may not be available to the assistant in the future. The assistant may have utilized a generalizable strategy to solve the task, if so, include that in the instruction as well.

Provide the new instructions within ``` blocks.

이 템플릿은 자동으로 채워집니다:

  • <curr_param>: 최적화 중인 현재 지시문
  • <side_info>: predictor 입력, 생성된 출력, 평가 피드백을 담은 구조화된 마크다운

기본 동작 예시:

# Default instruction proposer is used automatically
gepa = dspy.GEPA(
    metric=my_metric,
    reflection_lm=dspy.LM(model="gpt-5", temperature=1.0, max_tokens=32000, api_key=api_key),
    auto="medium"
)
optimized_program = gepa.compile(student, trainset=examples)

커스텀 instruction_proposer를 언제 쓰나

참고: 커스텀 지시문 제안기는 고급 기능입니다. 대부분의 사용자는 대부분의 텍스트 기반 최적화 작업에 잘 동작하는 기본 제안기부터 시작해야 합니다.

다음이 필요할 때 커스텀 지시문 제안기 구현을 고려하세요:

  • 멀티모달 처리: 입력의 텍스트 정보와 함께 이미지(dspy.Image)를 처리해야 할 때
  • 길이 제한에 대한 정밀한 제어: 지시문 길이, 형식, 구조 요구사항을 더 세밀하게 제어해야 할 때
  • 도메인 특화 정보: 기본 제안기가 가지지 못하고 feedback_func로도 제공할 수 없는 전문 지식·용어·맥락을 주입해야 할 때. 이는 고급 기능이며 대부분의 사용자에게 필요하지 않습니다.
  • 프로바이더별 프롬프팅 가이드: OpenAI, Anthropic 등 특정 LLM 프로바이더의 고유한 포맷팅 선호에 맞춰 지시문을 최적화해야 할 때
  • 결합 컴포넌트 업데이트: 각 컴포넌트를 독립적으로 최적화하는 대신 2개 이상의 컴포넌트를 함께 조정된 방식으로 업데이트해야 할 때 (관련 기능은 Custom Component Selection 섹션의 component_selector 파라미터 참고)
  • 외부 지식 통합: 지시문 생성 중 데이터베이스, API, 지식 베이스에 연결해야 할 때

사용 가능한 옵션

  • 기본 제안기(Default Proposer): 표준 GEPA 지시문 제안기(instruction_proposer=None일 때 사용). 기본 제안기도 하나의 지시문 제안기이며, GEPA 논문과 튜토리얼에 보고된 다양한 실험에 사용된 가장 일반적인 제안기입니다.
  • MultiModalInstructionProposer: dspy.Image 입력과 구조화된 멀티모달 콘텐츠를 처리합니다.
from dspy.teleprompt.gepa.instruction_proposal import MultiModalInstructionProposer

# For tasks involving images or multimodal inputs
gepa = dspy.GEPA(
    metric=my_metric,
    reflection_lm=dspy.LM(model="gpt-5", temperature=1.0, max_tokens=32000, api_key=api_key),
    instruction_proposer=MultiModalInstructionProposer(),
    auto="medium"
)

GEPA 라이브러리가 성장함에 따라 특화 도메인을 위한 새 지시문 제안기 커뮤니티 기여를 환영합니다.

커스텀 지시문 제안기 구현 방법

커스텀 지시문 제안기는 콜러블 클래스나 함수로 ProposalFn 프로토콜을 구현해야 합니다. GEPA는 최적화 중에 제안기를 호출합니다:

from dspy.teleprompt.gepa.gepa_utils import ReflectiveExample

class CustomInstructionProposer:
    def __call__(
        self,
        candidate: dict[str, str],                          # Candidate component name -> instruction mapping to be updated in this round
        reflective_dataset: dict[str, list[ReflectiveExample]],  # Component -> examples with structure: {"Inputs": ..., "Generated Outputs": ..., "Feedback": ...}
        components_to_update: list[str]                     # Which components to improve
    ) -> dict[str, str]:                                    # Return new instruction mapping only for components being updated
        # Your custom instruction generation logic here
        return updated_instructions

# Or as a function:
def custom_instruction_proposer(candidate, reflective_dataset, components_to_update):
    # Your custom instruction generation logic here
    return updated_instructions

반성적 데이터셋 구조(Reflective Dataset Structure):

  • dict[str, list[ReflectiveExample]]: 컴포넌트 이름을 예시 리스트에 매핑
  • ReflectiveExample TypedDict에는 다음이 포함됩니다:
    • Inputs: dict[str, Any]: predictor 입력 (dspy.Image 객체 포함 가능)
    • Generated_Outputs: dict[str, Any] | str: 성공 시 출력 필드 dict, 실패 시 에러 메시지
    • Feedback: str: metric 함수에서 오거나 GEPA가 자동 생성한 문자열

기본 예시: 단어 수 제한 제안기(Word Limit Proposer)

import dspy
from gepa.core.adapter import ProposalFn
from dspy.teleprompt.gepa.gepa_utils import ReflectiveExample

class GenerateWordLimitedInstruction(dspy.Signature):
    """Given a current instruction and feedback examples, generate an improved instruction with word limit constraints."""

    current_instruction = dspy.InputField(desc="The current instruction that needs improvement")
    feedback_summary = dspy.InputField(desc="Feedback from examples that might include both positive and negative cases")
    max_words = dspy.InputField(desc="Maximum number of words allowed in the new instruction")

    improved_instruction = dspy.OutputField(desc="A new instruction that fixes the issues while staying under the max_words limit")

class WordLimitProposer(ProposalFn):
    def __init__(self, max_words: int = 1000):
        self.max_words = max_words
        self.instruction_improver = dspy.ChainOfThought(GenerateWordLimitedInstruction)

    def __call__(self, candidate: dict[str, str], reflective_dataset: dict[str, list[ReflectiveExample]], components_to_update: list[str]) -> dict[str, str]:
        updated_components = {}

        for component_name in components_to_update:
            if component_name not in candidate or component_name not in reflective_dataset:
                continue

            current_instruction = candidate[component_name]
            component_examples = reflective_dataset[component_name]

            # Create feedback summary
            feedback_text = "\n".join([
                f"Example {i+1}: {ex.get('Feedback', 'No feedback')}"
                for i, ex in enumerate(component_examples)  # Limit examples to prevent context overflow
            ])

            # Use the module to improve the instruction
            result = self.instruction_improver(
                current_instruction=current_instruction,
                feedback_summary=feedback_text,
                max_words=self.max_words
            )

            updated_components[component_name] = result.improved_instruction

        return updated_components

# Usage
gepa = dspy.GEPA(
    metric=my_metric,
    reflection_lm=dspy.LM(model="gpt-5", temperature=1.0, max_tokens=32000, api_key=api_key),
    instruction_proposer=WordLimitProposer(max_words=700),
    auto="medium"
)

커스텀 코드 제안기 (Custom Code Proposers)

code_proposer란?

code_proposer는 GEPA 최적화 중에 코드 컴포넌트(예: dspy.Code 필드나 프로그램의 코드 조각)를 진화시키는 역할을 담당합니다. 지시문 제안기와 유사하지만, 텍스트 지시문 대신 코드를 생성·수정합니다.

계약 (The contract)

커스텀 코드 제안기는 코드 제안 계약(CodeProposalFn)을 따라야 합니다. GEPA는 최적화 대상 컴포넌트 후보와 반성적 데이터셋, 갱신할 컴포넌트 목록을 전달하고, 제안기는 갱신된 코드 매핑을 반환합니다.

예시

지시문 제안기와 유사한 패턴으로 구현하며, dspy.Code 타입을 사용해 코드를 생성합니다. 예시 코드는 원문 문서를 참고하세요.

커스텀 컴포넌트 선택 (Custom Component Selection)

component_selector란?

component_selector는 GEPA가 각 반성적 반복에서 어느 컴포넌트(predictor)를 갱신할지 결정하는 컴포넌트입니다.

기본 동작

기본값은 'round_robin'입니다. 각 반복에서 최적화 대상을 라운드로빈 방식으로 돌아가며 선택합니다.

내장 선택 전략

  • 'round_robin': 컴포넌트들을 차례로 선택.

커스텀 컴포넌트 선택을 언제 쓰나

특정 컴포넌트를 우선하거나, 함께 갱신해야 하거나, 실행 trace·점수 정보를 바탕으로 선택을 결정해야 할 때 사용합니다.

커스텀 컴포넌트 선택기 프로토콜

ReflectionComponentSelector 프로토콜을 구현하는 콜러블로, 반성적 데이터와 갱신 후보 정보를 받아 갱신할 컴포넌트 목록을 반환합니다.

커스텀 구현 예시

전용 프로토콜과 예시 코드는 원문 문서를 참고하세요.

커스텀 지시문 제안기와의 통합

컴포넌트 선택과 지시문 제안기는 함께 동작합니다. 선택기가 고른 컴포넌트가 제안기의 components_to_update 인자로 전달됩니다.

더 알아보기 (Learn more)