PreciseCoder가 단위 테스트 보상의 과잉 수정과 버그 환각을 줄인다

PreciseCoder: Faithful and Generalizable Debugging Beyond Unit-Test Rewards

HF Daily2610.18755

Yunkai Zhan, Miaosen Chai, Shangshang Wang2026-10-13

무엇인가

단위 테스트 기반 강화학습은 코드 모델 사후학습의 표준 레시피지만, 단위 테스트는 최종 프로그램이 통과했는지만 묻는다. 이 논문은 그 보상이 디버깅 과정에서 모델에게 무엇을 가르치는지 감사한다. 개발자가 깨진 함수를 모델에 넘길 때 원하는 것은 결함을 찾아 고치되 이미 맞는 코드는 건드리지 않는 것이다. 그런데 PDB에서 GPT-5.1-Codex는 76%의 과제를 통과하면서도 수정한 줄의 40%만이 실제로 필요했다. 리뷰어는 바뀐 모든 줄을 확인해야 하므로 수정 비용은 버그 크기가 아니라 편집 크기에 비례해 커지고, 코딩 에이전트가 만든 병합된 풀 리퀘스트도 45%는 사람 손을 거친다. 테스트를 모두 통과한 패치가 회귀를 일으킬 수도 있다.

어떻게 동작하나

진단부터 구체적이다. Qwen3.5-4B를 PDB 과제에 GRPO로 학습시키며 편집 통계를 추적한 결과, 통과율이 오르는 동안 평균 편집 줄 수가 3.94줄에서 8.28줄로 늘었고, 버그가 없는 200개 검증 프로그램에서 no-op 비율이 학습 초기 30.8%에서 마지막 세 번 평가 평균 20.5%로 떨어졌다. 즉 단위 테스트 보상은 통과율을 올리면서 더 많이 고치도록, 그리고 멀쩡한 코드에서 버그를 환각하도록 가르쳤다. 후보 보상 항의 상관관계를 재보면 편집 크기(-ℓ)와 통과 지표(unit)의 피어슨 상관은 4B에서 0.13, 9B에서 0.14에 불과해, 편집 크기를 직접 최적화하면 통과율을 깎는 거래가 된다.

무엇과 다른가

PreciseCoder는 편집을 결함 단위로 의미 검증한 정밀도와 재현율을 단위 테스트 보상에 더한다. 예측 블록 δ̂i를 참조 블록 δi*에 정렬하고, 반사실 편집 Δ = Δ* − {δi*} ∪ {δ̂i}를 적용한 프로그램이 테스트를 통과할 때만 해당 결함을 고쳤다고(fix_i=1) 인정한다. 재현율 rec = (1/m)Σfix_i는 어떤 결함을 고쳤는지를, 정밀도 prec = (1/ℓ)Σfix_i·min(|ess_i|, |δi*|+ε)는 편집한 줄 중 실제로 필요했던 비율을 묻는다. ess_i는 결함 i를 여전히 고치는 예측 블록의 최소 부분집합이고 ε은 결함당 몇 줄의 여유를 허용한다. 통과한 프로그램은 정의상 모든 결함을 해결했으므로 unit=1일 때 rec̃=1로 게이팅하고, rec̃와 prec의 조화평균 F1을 취한다. 최종 보상은 r_λ = (1−λ)·unit + λ·F1이며, 그룹 내에서 unit이 상수인 그룹에서 표준화가 F1 표준화로 붕괴하는 문제를 피하려고 GDPO로 각 항을 그룹 안에서 따로 표준화한 뒤 배치 단위로 재조정한다. λ는 그룹 크기 G=6일 때 0.37 미만이면 통과한 수정이 실패한 수정보다 큰 어드밴티지를 유지하므로 1/3을 쓴다.

어떻게 쓰나

실험은 PDB-Single-Full의 5,274개 과제(단일 파일·단일 줄 버그)로 학습하고, 겹치지 않는 1,205개 PDB-Single 과제로 평가했다. 베이스라인은 SFT, DPO, 단위 테스트만 쓰는 GRPO, RECAP, EA-GRPO다. Qwen3.5-4B에서 평균 편집 줄 수가 13.8줄에서 3.0줄로 줄면서 통과율은 GRPO와 같은 수준을 유지했다. RECAP은 편집을 3.7줄까지 줄였지만 통과율이 55.1%에서 38.1%로, EA-GRPO는 53.3%로 떨어졌다. 정밀도는 베이스 모델 대비 24~29%포인트, GRPO 대비 26~35%포인트 올랐고, 27B에서는 79.2%로 GPT-5.6 Sol보다 17.7%포인트 높았다(GPT-5.6 Sol은 통과율 86.1%지만 평균 2.6줄 대비 1.5줄 더 편집한다). 보상 항 소거 실험에서 정밀도만 주면 69.0~70.1% 정밀도·2.5~2.6줄이지만 통과율이 3~5%포인트 낮았고, 재현율만 주면 통과율 57.2%·재현율 74.1%에 정밀도 52.2%·3.8줄로 과소 제약이었다.

전제와 한계

버그 환각 억제는 학습 데이터에 정상 코드가 한 번도 나오지 않고 no-op에 보상을 주지 않았는데도 따라온다. 정상 코드 1,512개에서 no-op 비율이 GRPO는 4B 30.6%→19.3%, 9B 36.6%→30.7%, 27B 31.1%→26.9%로 떨어졌지만 PreciseCoder는 48.0%, 51.6%, 45.8%로 올랐다. 정상 프로그램을 깨뜨리는 비율도 13.5%, 11.8%, 11.1%로 베이스 모델(19.3%, 18.7%, 15.5%)보다 낮다. 정밀도와 no-op 비율은 4B~27B 전체에서 r=0.87의 거의 선형 관계를 보인다.

일반화 범위가 넓다. 단일 줄 버그만 보고 학습했는데도 PDB-Wild의 484개 다중 줄·저장소 수준 과제에서 정밀도가 4B/9B/27B에서 20.3/16.7/20.2%포인트 오르고 통과율도 10~13%포인트 올랐으며, 평균 편집이 37.8→10.8줄(4B), 33.9→12.0줄(9B), 18.4→6.8줄(27B)로 줄었다. 같은 조건에서 GRPO는 정밀도가 −2.7, +0.1, −9.0%포인트로 개선이 없었다. SWE-agent를 하네스로 쓴 SWE-Bench Verified에서 PreciseCoder-9B는 32.7%를 해결해 베이스 25.9%, GRPO 28.1%, EA-GRPO 27.1%를 앞섰고, 27B는 70.8% 대 베이스 67.9%, GRPO 69.5%였다. 해결된 인스턴스에서 골드 패치 대비 초과 변경 줄은 GRPO 58%, EA-GRPO 37%, PreciseCoder-9B 29%였고, 골드 패치를 미리 적용해 둔 저장소를 깨뜨리는 비율은 PreciseCoder-27B 8.9%로 베이스 11.0%, GRPO 13.1%보다 낮다. 5턴 에이전트로 멀티턴 RL을 하면 PreciseCoder-9B-Agent가 정밀도 67.4%·통과율 56.3%로 9B 모델 중 최고다. 가중치를 공유하지 않는 전이도 된다. PreciseCoder-9B의 사고 블록을 토큰 단위로 다른 모델의 어시스턴트 턴에 프리필하면 5개 수신 모델이 정밀도를 4.6~12.4%포인트 얻는다(통과율은 −1.5~+4.3%포인트). Qwen3.8-Max가 +12.4%, Qwen3.6-27B가 +11.1%포인트(통과율 +4.3)로 가장 컸고, API 프리필이 안 되는 GPT-5.6 Sol은 사용자 턴 텍스트로 받고도 통과율과 정밀도 모두 개선됐다. 자기 베이스 모델에 넣으면 학습이 만든 통과율 이득의 73%, 정밀도 이득의 60%를 회복하고 편집을 13.7줄에서 6.5줄로 줄인다.

사고 흔적의 언어 분석은 무엇이 전이되는지 짚는다. 두 보상 모두 모델을 더 오래 생각하게 하고 버그 줄을 인용하게 하지만, 개별 줄에 대해 추론하고 버그 가설을 세우고 각 편집이 유지할 가치가 있는지 따지는 것은 정밀도 보상만 가르친다. 버그 줄을 그대로 인용한 과제 비율은 4B에서 36%→67%, 9B에서 43%→71%로 올랐고, 인용이 1표준편차 늘 때 F1 +4.3, 정밀도 +3.2를 얻는다. PreciseCoder-9B는 GRPO보다 헤지 표현을 더 쓰고(1,000단어당 10.8 대 6.5) 지시를 그대로 되풀이하는 빈도는 절반이며(3.4 대 6.5), 프롬프트를 근거로 버그가 존재해야 한다고 주장하는 경우는 거의 없다(0.04 대 0.59). 정상 코드에서는 모든 모델이 코드가 맞아 보인다고 비슷한 비율로 말하지만, PreciseCoder-9B는 1,000단어당 27.6개의 버그 가설을 제안하고(베이스 4.7, GRPO 10.8) 가설이 가장 많은 사분위와 적은 사분위 사이에서 no-op 비율이 21%에서 68%로 오른다.

실무에서는 코드 에이전트 패치의 크기와 리뷰 비용을 줄이는 용도, 특히 저장소 수준 수정에서 이미 고쳐진 이슈를 건드리지 않는지 확인하는 용도로 쓸 수 있다. 다만 저자들은 정밀하고 최소한의 편집이 오히려 검토에서 오류를 발견하기 어렵게 만들 수 있다며 사람의 리뷰를 권고한다. 보상 설계가 참조 패치를 필요로 하므로 참조를 정의하기 어려운 장기 호라이즌 에이전트 과제로의 확장은 향후 과제로 남겨 두었고, 학습은 단일 파일·단일 줄 버그에 한정되며 학습 데이터에 정상 코드가 포함되지 않는다는 전제가 있다.