Qwen Validation Debugger 합성 데이터 E2E 계약
작성일: 2026년 7월 15일
문서 목적
Qwen Validation Debugger는 운영용 Retriever와 검증기가 완성되기 전에 합성 데이터로 전체 흐름을 시험하는 도구다.
하나의 테스트 주제에 대해 Godot 3 코드와 Godot 4 코드를 만들고, 그 코드에 맞는 JSONL과 맞지 않는 JSONL을 생성한다. 이후 같은 JSONL을 각 버전 코드에 대입해 최종 판정이 예 또는 아니오로 맞게 나오는지 확인한다.
기존 응답 스키마와 판정 종류는 바꾸지 않았다.
- 문법 범위:
common,separate - JSONL 테이블:
docs_chunks,api_mapping,label_prototypes - 슬롯:
positive,negative - 최종 판정:
예,아니오
제3의 판정값, 점수, 추가 이유 필드는 만들지 않았다.
전체 흐름
TEST_ITEM
-> common / separate 분류
-> 분류 결과 저장
-> 대상 버전 코드 생성
-> 실제 Godot 엔진 파서 검사
-> Qwen 예/아니오 코드 검사
-> 통과한 코드로만 JSONL 생성
-> 기존 JSON Schema 검사
-> 현재 코드와 직접 증거 검사
-> JSONL과 코드 교차 검증separate 항목은 Godot 3 코드를 먼저 만든다. Godot 4 코드는 그 Godot 3 코드를 REFERENCE_GODOT3_CODE로 받아 같은 기능과 실행 흐름을 유지한 대응 코드로 생성한다.
분류와 코드 생성 입력 분리
분류 응답은 기존 다섯 필드를 유지한다.
{
"syntax_scope": "common 또는 separate",
"label": "짧은 한국어 라벨",
"reason": "분류 근거",
"godot3_focus": "Godot 3 코드 생성 포인트",
"godot4_focus": "Godot 4 코드 생성 포인트"
}reason, godot3_focus, godot4_focus는 화면 표시와 기록에는 남기지만 코드 생성 프롬프트에는 전달하지 않는다. 분류 단계가 잘못된 버전 문법을 설명하더라도 그 문장이 다음 코드 생성의 사실 근거가 되지 않게 하기 위해서다.
코드 생성에는 다음 입력만 사용한다.
- 테스트 항목
common또는separate- 생성 대상 버전
separateGodot 4 생성 시 먼저 통과한 Godot 3 코드- 재시도 시 직전 거부 코드와 실제 검사 진단
합성 코드 계약
생성 코드는 코드 조각처럼 보이는 문자열이 아니라 엔진이 파싱할 수 있는 하나의 GDScript 파일이어야 한다.
- 첫 실행 문장은
extends선언이다. - 테스트 API를 실제로 소유한 클래스를 사용한다.
- 일반 함수는 다른 함수 안에 중첩하지 않는다.
- 테스트 항목의 실제 동작 API를 사용한다.
pass, 주석, 로컬call로 대상 동작을 흉내 내지 않는다.- 반대 버전 전용 문법을 주석이나 코드에 섞지 않는다.
- Godot 4 코드는 먼저 통과한 Godot 3 코드와 기능, 입력, 대상, 결과를 유지한다.
RPC처럼 버전별 문법이 명확히 다른 항목은 공식 문법 계약을 프롬프트에 제공한다. 이것은 생성 결과의 단어를 사후 치환하는 로직이 아니다. 생성된 소스 문자열을 임의 수정하지 않고, 그대로 엔진 파서에 넣는다.
실제 Godot 엔진 검사
Qwen이 자기 코드를 다시 판정하는 것만으로는 잘못된 문법을 통과시킬 수 있었다. 실제 시험에서는 Godot 3 코드에 Godot 4의 @rpc가 들어갔는데도 Qwen 검사기가 예라고 답한 사례가 있었다.
현재는 코드 생성 직후 실제 엔진을 실행한다.
Godot 3: --no-window --check-only --script
Godot 4: --headless --check-only --script
common: Godot 3과 Godot 4 양쪽 검사실행 파일은 GODOT3_BIN, GODOT4_BIN으로 지정할 수 있다. 로컬 기본 설치본은 저장소 밖의 사용자 데이터 디렉터리에 둔다. 검사할 코드는 임시 파일로만 만들고 검사 후 삭제한다. 진단 로그에서는 임시 경로와 사용자 홈 경로를 제거한다.
코드 생성과 검사는 최대 세 번 수행한다. 실패하면 같은 응답을 반복하지 않도록 seed를 바꾸고, 직전 코드와 실제 엔진 진단을 다음 생성 프롬프트에 넣는다.
JSONL 스키마 유지
top-level 필드는 기존 세 테이블 정의와 동일하다.
docs_chunks
chunk_id, doc_version, source_url, source_file, source_sha256,
doc_type, symbol, section_path, heading, content, code_blocks,
language_tags, godot_version_tags, api_symbols, token_count, metadataapi_mapping
mapping_id, source_api, target_api, change_type, godot_from,
godot_to, confidence, evidence_chunk_ids, match_terms, notes,
negative_patternslabel_prototypes
prototype_id, label, task_type, input_pattern, expected_finding,
recommended_action, evidence_mapping_ids, evidence_chunk_ids,
severity, validator_rulesvalidator_rules도 기존 네 필드만 사용한다.
{
"required_when_seen_in_code": [],
"before_code": "",
"after_code": "",
"reject_when_seen_in_code": []
}응답을 받은 뒤 기존 JSON Schema로 필수 필드, 타입, enum, 추가 필드 여부를 검사한다. 모델이 confidence를 숫자로 쓰거나 section_path를 문자열로 쓰면 거부하고 최대 세 번 다시 생성한다.
positive와 negative 생성
positive JSONL은 현재 합성 코드의 직접 증거를 사용한다.
docs_chunks: 코드의 목적, 대상, 입력 흐름, 결과를 직접 설명한다.api_mapping: Godot 3의source_api와 Godot 4의target_api가 각각 실제 코드에 있어야 한다.label_prototypes: before 근거는 Godot 3 코드에, after 근거는 Godot 4 코드에 있어야 한다.- positive의
negative_patterns와reject_when_seen_in_code는 빈 배열이다.
negative JSONL 생성에는 현재 코드와 현재 항목을 제공하지 않는다. 현재 항목 다음의 샘플 항목을 동적으로 NEGATIVE_TEST_ITEM으로 선택하고, 그 다른 항목만으로 JSONL을 만든다. 생성 후 서버가 현재 코드와 직접 비교해 source/before 증거가 겹치면 거부한다.
이 과정은 특정 API 이름이나 문장을 일대일 치환하지 않는다. 샘플 순서 선택과 실제 생성 결과의 문자열 비교만 사용한다.
검증 순서
검증은 다음 순서로 처리한다.
- 버전 슬롯 구조로 결과가 확정되면 모델을 호출하지 않고
아니오로 판정한다. - 마이그레이션 변경 전 직접 근거가 현재 코드에 하나도 없으면
아니오로 판정한다. - 위 두 조건으로 확정되지 않은 경우에만 Qwen이 의미와 사용 방식을 비교한다.
결정론적 게이트는 새 상태를 만들지 않는다. 반환값은 기존과 같이 예 또는 아니오다.
| JSONL | 검증 대상 | 기대 응답 |
|---|---|---|
같은 버전 docs_chunks positive |
생성 기준 코드 | 예 |
다른 버전 docs_chunks positive |
교차 버전 코드 | 아니오 |
docs_chunks negative |
어느 코드든 | 아니오 |
3 -> 4 migration positive |
Godot 3 코드 | 예 |
3 -> 4 migration positive |
Godot 4 코드 | 아니오 |
3 -> 4 migration negative |
어느 코드든 | 아니오 |
API 요청 안정성
- thinking 출력을 비활성화한다.
- 분류, 코드, JSONL은 기존 필드만 가진 JSON Schema 응답을 요청한다.
- 최종 판정은 grammar로
예또는아니오만 허용한다. - 코드와 JSONL 재생성은 seed를 바꾼다.
- HTTP 429, 502, 503, 504, 연결 종료, 요청 시간 초과는 최대 세 번 제한 재시도한다.
API key는 브라우저 메모리의 현재 입력값으로만 요청에 포함한다. 저장소, 문서, 로그, 커밋에는 기록하지 않는다.
2026년 7월 15일 시험 결과
단위 계약 테스트는 27개가 통과했다.
실제 Godot 엔진 검사에서는 다음을 확인했다.
- Godot 3의
remote func코드는 Godot 3 파서를 통과했다. - Godot 3 코드에
@rpc를 넣으면Unexpected '@'로 거부됐다. - Godot 4의
@rpc코드는 Godot 4 파서를 통과했다.
실제 RunPod Qwen 시험의 진행 결과는 다음과 같다.
- 초기 전체 E2E: 5/12 통과. 잘못된 Godot 3 합성 코드와 넓은 관련성 판정이 확인됐다.
- 엔진 검사와 생성 계약 적용 후 전체 E2E: 10/12 통과.
- 동적 negative 항목과 직접 문자열 게이트 적용 후 migration negative: 4/4 통과.
- 남은 2건은 migration positive를 Godot 4에 다시 적용할 수 없다는 슬롯 계약을 모델이 무시한 사례였다. 해당 조건은 결정론적 버전 게이트로 옮겼고 단위 테스트가 통과했다.
- 최종 전체 재시험을 시작했으나 RunPod 서비스가
/v1/models와 생성 요청에 HTTP 502를 반환해 중단됐다. 코드 또는 JSONL 거부가 아니라 원격 서비스 미응답이다.
원격 서비스가 다시 응답하면 같은 12칸 E2E를 처음부터 재실행해야 한다.