DSPy 치트시트
DSPy 치트시트 (DSPy Cheatsheet)
자주 쓰는 DSPy 사용 패턴을 코드 스니펫으로 모아 둔 페이지예요. 프로그램 작성, 지표, 평가, 옵티마이저, 도구·유틸리티까지 한눈에 훑어볼 수 있어요.
출처: 문서
본문
이 페이지에는 자주 쓰는 사용 패턴의 스니펫이 들어 있어요.
DSPy 프로그램 (DSPy Programs)
새 LM 출력 강제 (Forcing fresh LM outputs)
DSPy는 LM 호출을 캐시해요. 고유한 rollout_id를 제공하고 0이 아닌 temperature(예: 1.0)를 설정하면 기존 캐시 항목을 우회하면서 새 결과는 캐시할 수 있어요.
predict = dspy.Predict("question -> answer")
predict(question="1+1", config={"rollout_id": 1, "temperature": 1.0})
dspy.Signature
class BasicQA(dspy.Signature):
"""Answer questions with short factoid answers."""
question: str = dspy.InputField()
answer: str = dspy.OutputField(desc="often between 1 and 5 words")
dspy.ChainOfThought
generate_answer = dspy.ChainOfThought(BasicQA)
# Call the predictor on a particular input alongside a hint.
question='What is the color of the sky?'
pred = generate_answer(question=question)
dspy.ProgramOfThought
pot = dspy.ProgramOfThought(BasicQA)
question = 'Sarah has 5 apples. She buys 7 more apples from the store. How many apples does Sarah have now?'
result = pot(question=question)
print(f"Question: {question}")
print(f"Final Predicted Answer (after ProgramOfThought process): {result.answer}")
dspy.ReAct
react_module = dspy.ReAct(BasicQA)
question = 'Sarah has 5 apples. She buys 7 more apples from the store. How many apples does Sarah have now?'
result = react_module(question=question)
print(f"Question: {question}")
print(f"Final Predicted Answer (after ReAct process): {result.answer}")
dspy.Retrieve
colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')
dspy.configure(rm=colbertv2_wiki17_abstracts)
#Define Retrieve Module
retriever = dspy.Retrieve(k=3)
query='When was the first FIFA World Cup held?'
# Call the retriever on a particular query.
topK_passages = retriever(query).passages
for idx, passage in enumerate(topK_passages):
print(f'{idx+1}]', passage, '\n')
dspy.CodeAct
from dspy import CodeAct
def factorial(n):
"""Calculate factorial of n"""
if n == 1:
return 1
return n * factorial(n-1)
act = CodeAct("n->factorial", tools=[factorial])
result = act(n=5)
result # Returns 120
dspy.Parallel
import dspy
parallel = dspy.Parallel(num_threads=2)
predict = dspy.Predict("question -> answer")
result = parallel(
[
(predict, dspy.Example(question="1+1").with_inputs("question")),
(predict, dspy.Example(question="2+2").with_inputs("question"))
]
)
result
DSPy 지표 (DSPy Metrics)
함수를 지표로 (Function as Metric)
커스텀 지표를 만들려면 숫자나 boolean 값을 반환하는 함수를 만들면 돼요.
def parse_integer_answer(answer, only_first_line=True):
try:
if only_first_line:
answer = answer.strip().split('\n')[0]
# find the last token that has a number in it
answer = [token for token in answer.split() if any(c.isdigit() for c in token)][-1]
answer = answer.split('.')[0]
answer = ''.join([c for c in answer if c.isdigit()])
answer = int(answer)
except (ValueError, IndexError):
# print(answer)
answer = 0
return answer
# Metric Function
def gsm8k_metric(gold, pred, trace=None) -> int:
return int(parse_integer_answer(str(gold.answer))) == int(parse_integer_answer(str(pred.answer)))
LLM as Judge
class FactJudge(dspy.Signature):
"""Judge if the answer is factually correct based on the context."""
context = dspy.InputField(desc="Context for the prediction")
question = dspy.InputField(desc="Question to be answered")
answer = dspy.InputField(desc="Answer for the question")
factually_correct: bool = dspy.OutputField(desc="Is the answer factually correct based on the context?")
judge = dspy.ChainOfThought(FactJudge)
def factuality_metric(example, pred):
factual = judge(context=example.context, question=example.question, answer=pred.answer)
return factual.factually_correct
DSPy 평가 (DSPy Evaluation)
from dspy.evaluate import Evaluate
evaluate_program = Evaluate(devset=devset, metric=your_defined_metric, num_threads=NUM_THREADS, display_progress=True, display_table=num_rows_to_display)
evaluate_program(your_dspy_program)
DSPy 옵티마이저 (DSPy Optimizers)
LabeledFewShot
from dspy.teleprompt import LabeledFewShot
labeled_fewshot_optimizer = LabeledFewShot(k=8)
your_dspy_program_compiled = labeled_fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
BootstrapFewShot
from dspy.teleprompt import BootstrapFewShot
fewshot_optimizer = BootstrapFewShot(metric=your_defined_metric, max_bootstrapped_demos=4, max_labeled_demos=16, max_rounds=1, max_errors=10)
your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
컴파일에 다른 LM 사용 (teacher_settings 지정)
from dspy.teleprompt import BootstrapFewShot
fewshot_optimizer = BootstrapFewShot(metric=your_defined_metric, max_bootstrapped_demos=4, max_labeled_demos=16, max_rounds=1, max_errors=10, teacher_settings=dict(lm=gpt4))
your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
컴파일된 프로그램 재컴파일 - 부트스트랩된 프로그램 부트스트랩
your_dspy_program_compiledx2 = teleprompter.compile(
your_dspy_program,
teacher=your_dspy_program_compiled,
trainset=trainset,
)
컴파일된 프로그램 저장/로딩
save_path = './v1.json'
your_dspy_program_compiledx2.save(save_path)
loaded_program = YourProgramClass()
loaded_program.load(path=save_path)
BootstrapFewShotWithRandomSearch
BootstrapFewShotWithRandomSearch의 상세 문서는 여기에서 볼 수 있어요.
from dspy.teleprompt import BootstrapFewShotWithRandomSearch
fewshot_optimizer = BootstrapFewShotWithRandomSearch(metric=your_defined_metric, max_bootstrapped_demos=2, num_candidate_programs=8, num_threads=NUM_THREADS)
your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset, valset=devset)
기타 커스텀 구성은 BootstrapFewShot 옵티마이저 커스터마이즈와 비슷해요.
Ensemble
from dspy.teleprompt import BootstrapFewShotWithRandomSearch
from dspy.teleprompt.ensemble import Ensemble
fewshot_optimizer = BootstrapFewShotWithRandomSearch(metric=your_defined_metric, max_bootstrapped_demos=2, num_candidate_programs=8, num_threads=NUM_THREADS)
your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset, valset=devset)
ensemble_optimizer = Ensemble(reduce_fn=dspy.majority)
programs = [x[-1] for x in your_dspy_program_compiled.candidate_programs]
your_dspy_program_compiled_ensemble = ensemble_optimizer.compile(programs[:3])
BootstrapFinetune
from dspy.teleprompt import BootstrapFewShotWithRandomSearch, BootstrapFinetune
#Compile program on current dspy.settings.lm
fewshot_optimizer = BootstrapFewShotWithRandomSearch(metric=your_defined_metric, max_bootstrapped_demos=2, num_threads=NUM_THREADS)
your_dspy_program_compiled = tp.compile(your_dspy_program, trainset=trainset[:some_num], valset=trainset[some_num:])
#Configure model to finetune
config = dict(target=model_to_finetune, epochs=2, bf16=True, bsize=6, accumsteps=2, lr=5e-5)
#Compile program on BootstrapFinetune
finetune_optimizer = BootstrapFinetune(metric=your_defined_metric)
finetune_program = finetune_optimizer.compile(your_dspy_program, trainset=some_new_dataset_for_finetuning_model, **config)
finetune_program = your_dspy_program
#Load program and activate model's parameters in program before evaluation
ckpt_path = "saved_checkpoint_path_from_finetuning"
LM = dspy.HFModel(checkpoint=ckpt_path, model=model_to_finetune)
for p in finetune_program.predictors():
p.lm = LM
p.activated = False
COPRO
COPRO의 상세 문서는 여기에서 볼 수 있어요.
from dspy.teleprompt import COPRO
eval_kwargs = dict(num_threads=16, display_progress=True, display_table=0)
copro_teleprompter = COPRO(prompt_model=model_to_generate_prompts, metric=your_defined_metric, breadth=num_new_prompts_generated, depth=times_to_generate_prompts, init_temperature=prompt_generation_temperature, verbose=False)
compiled_program_optimized_signature = copro_teleprompter.compile(your_dspy_program, trainset=trainset, eval_kwargs=eval_kwargs)
MIPROv2
참고: 상세 문서는 여기에서 볼 수 있어요. MIPROv2는 MIPRO의 최신 확장으로 (1) 지침 제안 개선, (2) 미니배칭으로 더 효율적인 검색 같은 업데이트를 포함해요.
MIPROv2로 최적화
auto=light로 손쉽게 바로 실행하는 방법을 보여드려요. 이는 많은 하이퍼파라미터를 자동 구성하고 가벼운 최적화 실행을 수행해요. 더 긴 최적화 실행은 auto=medium 또는 auto=heavy로 설정할 수 있어요. 더 상세한 MIPROv2 문서 여기에서 하이퍼파라미터를 수동으로 설정하는 방법도 볼 수 있어요.
# Import the optimizer
from dspy.teleprompt import MIPROv2
# Initialize optimizer
teleprompter = MIPROv2(
metric=gsm8k_metric,
auto="light", # Can choose between light, medium, and heavy optimization runs
)
# Optimize program
print(f"Optimizing program with MIPRO...")
optimized_program = teleprompter.compile(
program.deepcopy(),
trainset=trainset,
max_bootstrapped_demos=3,
max_labeled_demos=4,
)
# Save optimize program for future use
optimized_program.save(f"mipro_optimized")
# Evaluate optimized program
print(f"Evaluate optimized program...")
evaluate(optimized_program, devset=devset[:])
MIPROv2로 지침만 최적화 (0-Shot)
# Import the optimizer
from dspy.teleprompt import MIPROv2
# Initialize optimizer
teleprompter = MIPROv2(
metric=gsm8k_metric,
auto="light", # Can choose between light, medium, and heavy optimization runs
)
# Optimize program
print(f"Optimizing program with MIPRO...")
optimized_program = teleprompter.compile(
program.deepcopy(),
trainset=trainset,
max_bootstrapped_demos=0,
max_labeled_demos=0,
)
# Save optimize program for future use
optimized_program.save(f"mipro_optimized")
# Evaluate optimized program
print(f"Evaluate optimized program...")
evaluate(optimized_program, devset=devset[:])
KNNFewShot
from sentence_transformers import SentenceTransformer
from dspy import Embedder
from dspy.teleprompt import KNNFewShot
from dspy import ChainOfThought
knn_optimizer = KNNFewShot(k=3, trainset=trainset, vectorizer=Embedder(SentenceTransformer("all-MiniLM-L6-v2").encode))
qa_compiled = knn_optimizer.compile(student=ChainOfThought("question -> answer"))
BootstrapFewShotWithOptuna
from dspy.teleprompt import BootstrapFewShotWithOptuna
fewshot_optuna_optimizer = BootstrapFewShotWithOptuna(metric=your_defined_metric, max_bootstrapped_demos=2, num_candidate_programs=8, num_threads=NUM_THREADS)
your_dspy_program_compiled = fewshot_optuna_optimizer.compile(student=your_dspy_program, trainset=trainset, valset=devset)
기타 커스텀 구성은 dspy.BootstrapFewShot 옵티마이저 커스터마이즈와 비슷해요.
SIMBA
SIMBA(Stochastic Introspective Mini-Batch Ascent)는 임의의 DSPy 프로그램을 받아 일련의 미니배치로 진행하며 프롬프트 지침이나 few-shot 예시를 점진적으로 개선하려는 프롬프트 옵티마이저예요.
from dspy.teleprompt import SIMBA
simba = SIMBA(metric=your_defined_metric, max_steps=12, max_demos=10)
optimized_program = simba.compile(student=your_dspy_program, trainset=trainset)
DSPy 도구와 유틸리티 (DSPy Tools and Utilities)
dspy.Tool
import dspy
def search_web(query: str) -> str:
"""Search the web for information"""
return f"Search results for: {query}"
tool = dspy.Tool(search_web)
result = tool(query="Python programming")
dspy.streamify
import dspy
import asyncio
predict = dspy.Predict("question->answer")
stream_predict = dspy.streamify(
predict,
stream_listeners=[dspy.streaming.StreamListener(signature_field_name="answer")],
)
async def read_output_stream():
output_stream = stream_predict(question="Why did a chicken cross the kitchen?")
async for chunk in output_stream:
print(chunk)
asyncio.run(read_output_stream())
dspy.asyncify
import dspy
dspy_program = dspy.ChainOfThought("question -> answer")
dspy_program = dspy.asyncify(dspy_program)
asyncio.run(dspy_program(question="What is DSPy"))
사용량 추적 (Track Usage)
import dspy
dspy.configure(track_usage=True)
result = dspy.ChainOfThought(BasicQA)(question="What is 2+2?")
print(f"Token usage: {result.get_lm_usage()}")
dspy.configure_cache
import dspy
# Configure cache settings
dspy.configure_cache(
enable_disk_cache=False,
enable_memory_cache=False,
)
DSPy Refine와 BestofN
dspy.Suggest와dspy.Assert는 DSPy 2.6에서dspy.Refine와dspy.BestofN으로 대체됐어요.
BestofN
모듈을 서로 다른 rollout ID로 최대 N번 실행(캐시 우회)하고, reward_fn이 정의한 최고 예측 또는 threshold를 통과한 첫 번째 예측을 반환해요.
import dspy
qa = dspy.ChainOfThought("question -> answer")
def one_word_answer(args, pred):
return 1.0 if len(pred.answer) == 1 else 0.0
best_of_3 = dspy.BestOfN(module=qa, N=3, reward_fn=one_word_answer, threshold=1.0)
best_of_3(question="What is the capital of Belgium?").answer
# Brussels
Refine
모듈을 서로 다른 rollout ID로 최대 N번 실행(캐시 우회)하고, reward_fn이 정의한 최고 예측 또는 threshold를 통과한 첫 번째 예측을 반환해요. 각 시도(마지막 제외) 후 Refine는 모듈 성능에 대한 상세 피드백을 자동 생성하고 이를 이후 실행의 힌트로 사용해 반복적 개선 과정을 만들어요.
import dspy
qa = dspy.ChainOfThought("question -> answer")
def one_word_answer(args, pred):
return 1.0 if len(pred.answer) == 1 else 0.0
best_of_3 = dspy.Refine(module=qa, N=3, reward_fn=one_word_answer, threshold=1.0)
best_of_3(question="What is the capital of Belgium?").answer
# Brussels
오류 처리 (Error Handling)
기본적으로 Refine는 임계값이 충족될 때까지 최대 N번 모듈을 실행하려 해요. 모듈이 오류를 만나면 실패한 시도가 N번까지 계속돼요. fail_count를 N보다 작은 값으로 설정해 이 동작을 바꿀 수 있어요.
refine = dspy.Refine(module=qa, N=3, reward_fn=one_word_answer, threshold=1.0, fail_count=1)
...
refine(question="What is the capital of Belgium?")
# If we encounter just one failed attempt, the module will raise an error.
오류 처리 없이 최대 N번 실행하고 싶다면 fail_count를 N으로 설정하면 돼요. 이것이 기본 동작이에요.
refine = dspy.Refine(module=qa, N=3, reward_fn=one_word_answer, threshold=1.0, fail_count=3)
...
refine(question="What is the capital of Belgium?")
더 알아보기 (Learn more)
- FAQs — 자주 묻는 질문
- Signatures in depth — 시그니처 심화
- Optimizers: choosing one — 옵티마이저 선택 가이드