신뢰도 수치가 정확성을 추적하지 못했습니다. 대신 우리가 구축한 것은 다음과 같습니다.
요약
DebugAI는 모델의 신뢰도(confidence) 수치가 실제 코드 수정의 정확도와 일치하지 않는 문제를 발견했습니다. 이를 해결하기 위해 모델의 자가 평가 대신, 실제 기계적 검증을 수행하는 결정론적 채점기(grader) 시스템을 구축했습니다.
핵심 포인트
- 모델의 높은 신뢰도 수치가 실제 코드 통과율을 보장하지 않음
- 신뢰도와 정확도 사이의 불일치 현상을 네 차례의 독립적 실험으로 확인
- 모델의 자가 채점 대신 결정론적 검증 도구(grader) 도입 필요성 강조
- 파싱 및 임포트 에러 등 기계적 검증이 가능한 영역부터 자동화 적용
신뢰도 수치가 정확성을 추적하지 못했습니다. 대신 우리가 구축한 것은 다음과 같습니다.
지난주 동일한 호출로부터 두 개의 수정 사항(fix)이 반환되었으며, 평소와 마찬가지로 신뢰도(confidence)에 따라 순위가 매겨졌습니다. 순위가 더 높았던 것은 실제 버그에 적용하자마자 실패했습니다. 반면 순위가 더 낮았던 것은 통과했습니다.
우리는 DebugAI의 응답을 읽는 누구나 그렇듯, 숫자가 클수록 모델이 더 확신한다는 의미로 그 순위를 신뢰해 왔습니다. 그래서 우리는 그 신뢰를 멈추고 확인을 시작했습니다.
2주 전, 우리는 실제 결과를 단 하나라도 채점하게 하기 전에 자체 평가 하네스(eval harness)에서 세 가지 버그를 발견했습니다. 이것은 우리가 하네스를 신뢰하게 되었을 때 발견한 내용이며, 이를 목격한 후 우리가 새롭게 구축한 것입니다.
수치가 말해준 것
우리는 모든 수정 사항을 보고된 신뢰도별로 분류한 다음, 실제 버그에 적용하여 실제로 통과했는지 여부를 기록합니다. 우리가 진행한 실행 결과의 분포는 다음과 같습니다:
| 보고된 신뢰도 (Reported confidence) | 통과한 수정 사항 (Fixes that passed) |
|---|---|
| 80% ~ 90% | 0% |
| 90% 이상 | 38% |
두 번 읽어보십시오. 모델이 가장 확신했던 수정 사항들은 동전 던지기 확률보다 더 낮은 빈도로 통과했습니다. 대부분의 사람들이 "꽤 확신함"이라고 읽을 법한 80~90% 구간의 수정 사항들은 이번 실행에서 단 한 번도 통과하지 못했습니다. 수치는 올라가고 있었지만, 그것이 맞을 확률은 올라가지 않았습니다.
여기서 "통과(Passed)"란, 소스 코드의 깨끗한 복사본에 수정 사항을 적용했을 때 실제 테스트를 통과했음을 의미합니다.
"그럴듯해 보임"이 아닙니다. "모델이 확신하는 것처럼 들림"도 아닙니다. 실제 코드에서 실행되었고, 작동했습니다.
같은 형태, 세 번의 반복
이 현상의 첫 번째 징후는 위의 표가 아니었습니다. 그것은 수동으로 확인한 단 하나의 버그였는데, 순위가 매겨진 두 개의 수정 사항이 각각 92%와 85%의 신뢰도로 반환되었으나 둘 다 실패했습니다. 그 한 가지 사례는 단순한 노이즈(noise)일 수도 있었기에, 우리는 이를 확인하기 위해 특별히 구축한 하네스를 두 번 별도로 실행하여 더 많은 사례를 찾아 나섰습니다.
세 번의 조사 모두 동일한 형태를 발견했습니다. 즉, 신뢰도(confidence)가 올라간다고 해서 정확도(correctness)가 올라가는 것은 아니었습니다. 그래서 우리는 새로운 환경에서 하네스(harness)를 처음부터 다시 구축했고, 새로운 11개 버그 코퍼스(corpus)를 대상으로 네 번째 실행을 진행하여 위 표와 같은 결과를 얻었습니다. 이전 실행에서는 전혀 다루지 않았던 코드임에도 불구하고, 다시 한번 동일한 형태가 나타났습니다.
서로 다른 시점에, 서로 다른 버그를 대상으로, 서로 다른 버전의 검증 도구를 사용하여 진행한 네 번의 별도 조사입니다. 만약 이것이 일회성 측정 오류였다면, 적어도 그 실행 중 하나는 깨끗한 결과(clean)가 나왔어야 했습니다. 하지만 단 하나도 그렇지 않았습니다.
이로 인해 우리가 구축한 것
정확도를 추적하지 못하는 신뢰도 수치는 단순히 도움이 되지 않는 수준을 넘어, 매우 유용해 보이기 때문에 적극적으로 오해를 불러일으킵니다. 따라서 우리는 모델에게 스스로 숙제를 채점하라고 요청하는 대신, 모델이 아닌 채점기(grader)를 구축했습니다.
검증 비용이 저렴하고 결정론적(deterministic)인 두 가지 버그 클래스, 즉 파싱 에러(parse errors)와 임포트 에러(import errors)의 경우, DebugAI는 신뢰도 수치를 보고하기 전에 제안된 수정 사항을 실제 기계적 검증(mechanical check)을 통해 실행합니다.
파싱 검증 (Parse Check)
수정된 코드가 실제로 파싱(parse)되는지 확인합니다.
완료되지 않은 검사(check that didn't finish)와 실패한 검사(check that failed)는 서로 다른 주장이며, 우리는 이 둘이 서로 섞이도록 내버려 두지 않습니다.
verified: null은 "검사하지 않음"을 의미합니다. 이는 해당 버그 클래스가 아직 다뤄지지 않았거나, 5초의 예산(budget)이 소진되었기 때문입니다.
verified: false는 "검사했으며, 실패함"을 의미합니다.
null을false로 올림(rounding up)하거나, 혹은 아무런 알림 없이 통과(silent pass)로 내림(rounding down)하는 것은, 기존의 신뢰도(confidence) 수치가 그랬던 것과 정확히 똑같은 방식으로 라벨을 거짓말하게 만들 것입니다.
실제로 발생하는 모습 확인하기
이것은 이론적인 이야기가 아닙니다. 실제 요청(request)에 대해 검사가 처음 실행되었을 때, 다음과 같은 결과가 반환되었습니다:
{
"rank": 1,
"confidence": 15,
...
모델은 임포트(import)해야 할 함수의 정확한 이름을 알지 못했습니다. 확신을 가지고 이름을 지어내는 대신, 플레이스홀더(placeholder)를 생성하고 더 많은 컨텍스트(context)가 필요하다는 플래그를 표시했습니다.
기존의 동작 방식이었다면, 모델이 추측에 대해 보고하고 싶어 하는 임의의 신뢰도를 보고했을 것입니다.
대신, 검사가 실행되었고, 해당 임포트가 우리가 실제로 가져온(retrieved) 그 어떤 것과도 일치하지 않음을 발견했으며, 신뢰도는 min(fix.confidence, 15)가 설정한 값인 15에 정확히 안착했습니다.
극적인 포착은 아니었습니다. 모델은 이미 여기서 정직하게 행동하고 있었으니까요. 하지만 이는 이 배선(wiring)이 고정된 테스트(fixture)가 아닌 실제 라이브 요청(live request)에서 엔드 투 엔드(end to end)로 작동한다는 첫 번째 실제 증거입니다.
아직 해결되지 않은 부분
파싱(Parse) 및 임포트(import) 검사는 정확히 두 가지 버그 클래스만을 다룹니다.
위의 버킷 테이블(신뢰도 80~90%에서 0%, 90% 이상에서 38%)은 이 두 클래스 외부에 있는 데이터 말뭉치(corpus)를 기준으로 측정된 것이며, 이 클래스들을 벗어난 영역에서는 아무것도 변하지 않았습니다.
TypeError, RuntimeError 및 단순히 파싱하는 것을 넘어 실제로 검증하기 위해 라이브 환경이나 실제 데이터가 필요한 다른 모든 항목에 대해서는 여전히 역전 현상(inversion)이 존재합니다.
남아 있는 문제들을 더 많이 잡아낼 수 있는 유형(type-class) 검사는 동일한 인터페이스 뒤에 구축되어 있으나 아직 출시되지 않았습니다. 이는 모든 응답의 느린 부분이 되지 않으면서 5초의 예산(budget) 내에서 실행될 수 있는지 여부에 따라 제한(gated)되어 있습니다.
우리는 이것이 격차를 완전히 해소한다고 주장하는 것이 아닙니다.
우리는 이것이 오늘날 정직하게 확인하기에 충분히 비용이 저렴한 두 가지 클래스(classes)에 대해서는 격차를 해소한다고 주장하는 것이며, 나머지 부분은 은밀하게 괜찮다고 가정되는 대신 눈에 띄게 검증되지 않은 상태로 남겨둔다는 것을 의미합니다.
이제 DebugAI가 반환하는 모든 수정 사항(fix)은 다음 세 가지 상태 중 하나를 가집니다:
truefalsenull
**true**는 우리가 실제 검사(check)를 수행했으며, 그 결과가 유지되었음을 의미합니다.
**false**는 우리가 검사를 수행했고 실패했음을 의미하며, 신뢰도 수치(confidence number)는 모델의 의사와 상관없이 그 사실을 반영합니다.
**null**은 우리가 검사를 수행하지 않았음을 의미하며, 우리가 답을 가지고 있지 않은 상황에서 높은 수치가 답변을 대신하게 두는 대신 그렇게 명시합니다.
FAQ
Q: 이것이 DebugAI의 수정 사항들이 보통 틀렸다는 의미인가요?
A: 아닙니다.
이는 우리가 측정한 클래스들에 대해, 수정 사항에 붙은 신뢰도 수치가 해당 특정 수정 사항이 작동할지 여부를 알려주는 신뢰할 수 있는 신호가 아니었다는 것을 의미합니다.
여기서 수정 사항 자체의 등급을 매기는 것이 아니라, "모델이 얼마나 확신에 차 있었는가"와 "그것이 맞았는가" 사이의 상관관계(correlation)를 측정하는 것입니다.
이 둘은 서로 다른 질문이며, 이 둘을 혼동하는 것이 바로 이 기능 전체가 존재함으로써 방지하고자 하는 실수입니다.
Q: 시간이 지나면서 더 많은 버그 클래스를 다루게 될까요?
A: 파싱(Parse)과 임포트(import)는 실제 지연 시간(latency)을 추가하지 않고도 기계적으로 확인하기에 충분히 저렴한 두 가지였습니다.
타입 체크(Type checking)는 이미 구축되어 있으며 지연 시간에 대한 결정만을 기다리고 있습니다.
실제 상태(real state)에 대해 실시간 실행(live execution)이 필요한 모든 것, 즉 대부분의 런타임 에러(runtime errors)는 5초간의 샌드박스 검사(sandboxed check)와는 다른 접근 방식이 필요하며, 우리는 실제로 해결하기 전까지는 그것을 해결했다고 주장하지 않을 것입니다.
DebugAI는 단순히 스택 트레이스(stack trace)뿐만 아니라 여러분의 코드베이스(codebase)를 읽고, 클릭 한 번으로 적용할 수 있는 수정 사항을 제공합니다.
이제 그 수정 사항 중 일부는 우리가 직접 확인한 수치와 함께 제공되며, 아직 확인하지 않은 것들은 확인하지 않았음을 명시합니다.
원문 게시처: debugai.io.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기