WizardCoder 스타일로 경쟁 프로그래밍 문제를 5단계 진화(Graph 1) 한 뒤, 고도화된 문제에 대해 LLM 솔루션의 Pass@1을 측정(Graph 2)하는 LangGraph 기반 프로젝트입니다.
| 구성요소 | 진입점 | 역할 |
|---|---|---|
| Graph 1 | main_wizard.py |
원본 문제 → 5단계 진화 → TC·reference_code → 품질 게이트 |
| Graph 2 | main_pass_at_k.py |
동일 프롬프트로 N회 솔루션 생성 후 TC 채점·분석 |
| TC 검증 | verify_tc.py |
reference_code 실행 vs JSON expected_output (API 불필요) |
설계 문서: docs/GUIDE.md, docs/GRAPHS.md
원본 BOJ/CP 문제를 LLM이 표면·규칙·상태·힌트·완성 순으로 바꿉니다. 구현상 Step 2는 세부 변형 노드 5개로 나뉘며, Step 5 이후에 정답 코드 생성과 4개 게이트가 이어집니다.
노드: surface_obfuscation · 프롬프트: src/prompts/wizard/surface_obfuscation.yaml
| 목적 | 원문 문제를 “겉모습”만 완전히 다른 문제로 바꿔, 출처·유형을 패턴 매칭으로 맞추기 어렵게 함 |
|---|---|
| 도메인 변경 | 물리→화학, 게임→생물 등 테마·배경 전환 |
| 키워드 제거 | “파이어볼”, “격자” 등 원 문제를 드러내는 단어 삭제·치환 |
| 변수·서사 재작성 | 엔티티 이름·스토리를 새 도메인에 맞게 통째로 교체 |
| 보존 | 계산 구조(알고리즘 골격) 는 아직 유지 — 이후 Step 2에서 깨뜨림 |
출력: current_problem 텍스트가 한 편의 “다른 분야” 문제 설명으로 갱신됨.
개념: 기존 정해·풀이가 통째로 무효가 되도록 규칙·수식·분기를 바꿈. 코드에서는 아래 5개 노드를 순차 실행합니다.
| 순서 | 노드 | 프롬프트 | 하는 일 |
|---|---|---|---|
| 2A | mutate_formula_logic |
mutate_formula_logic.yaml |
핵심 수식·분기 조건 교체 (예: GCD→다른 집계, 비선형 임계값) |
| 2B | mutate_boundary_conditions |
mutate_boundary_conditions.yaml |
경계·주기·wrap-around, 모듈러 규칙 강화 |
| 2C | mutate_coordinate_semantics |
mutate_coordinate_semantics.yaml |
좌표계·축 의미 변경 (2D 격자→위상공간 등) |
| 2D | mutate_query_semantics |
mutate_query_semantics.yaml |
쿼리 타입·입력 형식·의미 확장 |
| 2E | mutate_interactions |
mutate_interactions.yaml |
충돌·병합·상호작용 규칙 추가·변형 |
레거시: rule_mutation.yaml은 단일 Step 2용이며, 현재 그래프는 위 5분할 버전을 사용합니다.
출력: 각 노드마다 step_history에 미리보기가 쌓이고, current_problem이 단계적으로 더 “다른 문제”가 됨.
노드: side_effect_injection · 프롬프트: side_effect_injection.yaml
| 목적 | 한 번의 시뮬레이션만 풀면 되는 정적 문제 → 쿼리 순서에 따라 답이 달라지는 상태 기계 문제 |
|---|---|
| 쿼리 체계 | 조회(무부작용) + 변경(부작용) + 구간 연산 등 최소 3종 쿼리 타입 설계 |
| 비멱등성 | 같은 입력이라도 이전 쿼리 이력에 따라 출력이 달라지도록 명세 |
| 난이도 | 구현 시 “현재 상태”를 정확히 유지·갱신해야 함 (LLM 실수 포인트) |
노드: hint_removal · 프롬프트: hint_removal.yaml
| 목적 | “이 문제는 세그먼트 트리다”처럼 유도하는 소프트 힌트 제거 |
|---|---|
| 제약 스케일 | 작은 N을 큰 N으로 바꾸되, 올바른 자료구조(희소 맵 등)로는 풀리게 |
| 힌트 삭제 | 시간복잡도·자료구조 이름·알고리즘 이름을 문장에서 제거 |
| 숨은 규칙 | 생성 조건, 빈 칸 출력 규칙, 면역 조건 등 한두 줄짜리 함정을 명세에만 명시 |
노드: problem_finalizer · 프롬프트: problem_finalizer.yaml
| 목적 | 진화된 초안을 채점 가능한 완성본으로 다듬고 테스트케이스 10개 생성 |
|---|---|
| 문장 정리 | 모순·누락 엣지 케이스 보완, 입출력 형식 고정 |
| TC 설계 | 최소→기본→변형 규칙→경계→대규모 N 등 단계적 10개 (프롬프트 템플릿 기준) |
| JSON 필드 | test_cases[]: id, input, expected_output, description, explanation |
출력: final_problem, test_cases (이 시점의 expected_output은 LLM 추정치일 수 있음).
5단계만으로 끝나지 않고, 저장 전에 아래가 이어집니다.
| 단계 | 노드 | 역할 |
|---|---|---|
| 정답 코드 | generate_reference_code |
명세에 맞는 Python reference_code 생성 |
| 일관성 | consistency_gate |
명세·TC·제약 모순 검사 |
| 난이도 | difficulty_gate |
목표 난이도(--difficulty-target) 대비 적정성 |
| TC 품질 | adversarial_tc_gate |
TC가 규칙·엣지를 실제로 검증하는지 |
| 레퍼런스 | reference_gate |
reference_code 실행 가능·TC와 정합 |
| 재튜닝 | apply_feedback_directives → mutate_formula_logic |
게이트 실패 또는 Graph 2 피드백 시 Step 2부터 재진입 (--auto-retune) |
최종 저장: outputs/evolved_problem.json (실행 시 로컬 생성).
uv run python main_wizard.py problems/example_problem.json --verbose
uv run python main_wizard.py problems/example_problem.json `
--feedback-result outputs/pass_at_k_result.json `
--auto-retune --max-retries 2옵션: --mutation-profile (baseline, hard_logic, …), --difficulty-target (medium/hard/extreme)
uv run python main_pass_at_k.py outputs/evolved_problem.json
uv run python main_pass_at_k.py problems/phase_space_qubit_wormhole.json --runs 10 --verbosevalidate_test_cases—reference_code로expected_output검증·교정generate_solutions— Flash, N회 병렬execute_solutions—python -c+ stdin, TC별 stdout 비교evaluate_pass_at_k— N회 중 1회라도 전 TC 통과 시 Pass@1report_results— Pro 분석 리포트save_pass_at_k_output→outputs/pass_at_k_result.json
콘솔에 실패 TC 번호(1-based) 표시, JSON에 failed_tc_indices 포함.
uv run python verify_tc.py problems/phase_space_qubit_wormhole.json
uv run python verify_tc.py problems/phase_space_qubit_wormhole.json --tc TC7 -swinget install astral-sh.uv # 없을 때
cd Wizard_LM_Problem
uv sync
Copy-Item .env.example .env # GEMINI_API_KEY 설정| 변수 | 설명 |
|---|---|
GEMINI_API_KEY |
API 키 |
GEMINI_PRO_MODEL |
Graph 1, Graph 2 리포트 |
GEMINI_FLASH_MODEL |
Graph 2 솔루션 N회 |
PASS_AT_K_RUNS |
기본 10 |
CODE_EXECUTION_TIMEOUT |
기본 10초 |
Graph 1 입력: problems/example_problem.json — content, input_format, constraints, …
Graph 1·2 공통(고도화): problem_statement, test_cases[], reference_code
Wizard_LM_Problem/
│
├── main_wizard.py # Graph 1 CLI: 문제 JSON 로드, 그래프 invoke, Rich 출력
├── main_pass_at_k.py # Graph 2 CLI: Pass@1 평가, TC/실패 TC 표
├── verify_tc.py # 레퍼런스만 subprocess로 TC 일괄 검증
│
├── pyproject.toml # 패키지 메타·의존성 (langgraph, rich, …)
├── uv.lock # 잠금 파일 (재현 설치용, 커밋 권장)
├── .python-version # 로컬 Python 3.12+ 힌트
├── .env.example # 환경 변수 템플릿 (커밋)
├── .gitignore # .env, outputs/*, .venv 등
│
├── problems/ # 문제 정의 (저장소에 포함)
│ ├── example_problem.json # Graph 1 원본 입력 예시 (BOJ 파이어볼 계열)
│ ├── fireball_evolved.json # 고도화 결과 예시
│ ├── microbial_colony_evolved.json
│ ├── phase_space_qubit_evolved.json
│ ├── phase_space_qubit_wormhole.json # 웜홀·TC·reference 수동 확장본
│ └── fireball_evolved_explicit_prompt.md # 명시 프롬프트 실험용 메모
│
├── outputs/ # 실행 산출물 디렉터리 (내용은 .gitignore)
│ └── .gitkeep # 빈 폴더만 Git 추적
│
├── docs/
│ ├── GUIDE.md # 사용 가이드
│ ├── GRAPHS.md # 그래프·상태 필드 설명
│ ├── GRAPH1_ENHANCEMENT_DESIGN.md # Graph 1 확장 설계
│ └── CHANGELOG.md # 변경 이력
│
└── src/
├── __init__.py
│
├── graphs/
│ ├── wizard_graph.py # Graph 1: 노드 연결·조건부 재튜닝 엣지
│ └── pass_at_k_graph.py # Graph 2: 검증→생성→실행→판정→저장
│
├── nodes/
│ ├── wizard_nodes.py # 진화·게이트·저장 LLM 호출 구현
│ └── pass_at_k_nodes.py # 솔루션 생성·채점·리포트·JSON 저장
│
├── state/
│ ├── wizard_state.py # WizardState TypedDict (current_problem, gates, …)
│ └── pass_at_k_state.py # PassAtKState (execution_results, tc_validation, …)
│
├── utils/
│ ├── llm_client.py # Gemini Pro/Flash 클라이언트
│ ├── prompt_loader.py # YAML 프롬프트 로드·치환
│ ├── code_executor.py # extract_python_code, subprocess TC 실행
│ └── pass_result_loader.py # pass_at_k_result.json → mutation_directives
│
└── prompts/
├── wizard/ # Graph 1 단계별 system/user 프롬프트
│ ├── surface_obfuscation.yaml # Step 1
│ ├── mutate_formula_logic.yaml # Step 2A
│ ├── mutate_boundary_conditions.yaml
│ ├── mutate_coordinate_semantics.yaml
│ ├── mutate_query_semantics.yaml
│ ├── mutate_interactions.yaml
│ ├── rule_mutation.yaml # (레거시 단일 Step 2)
│ ├── side_effect_injection.yaml # Step 3
│ ├── hint_removal.yaml # Step 4
│ ├── problem_finalizer.yaml # Step 5
│ ├── generate_reference_code.yaml
│ ├── consistency_gate.yaml
│ ├── difficulty_gate.yaml
│ ├── adversarial_tc_gate.yaml
│ └── reference_gate.yaml
└── pass_at_k/
├── solution_generator.yaml # Flash: 풀이 코드 생성
└── result_reporter.yaml # Pro: 실패 패턴 분석
| 파일 | 용도 |
|---|---|
example_problem.json |
Graph 1 시작용 원본 |
phase_space_qubit_wormhole.json |
쿼리형·웜홀·TC10 포함 벤치마크 |
fireball_evolved.json |
진화 파이프라인 산출 예시 |
API 비용은 Graph 1(다단 LLM) + Graph 2(N회 Flash + 1회 Pro) 호출량에 비례합니다.