AI가 실제로 버그의 근본 원인을 찾을 수 있을까, 아니면 그저 확신에 찬 것처럼 들릴 뿐일까?
요약
AI 기반 근본 원인 분석(RCA) 도구인 Pinaka의 성능을 실제 오픈소스 프로젝트인 BullMQ를 통해 검증한 실험 결과입니다. AI가 코드베이스 검색을 통해 버그의 위치와 논리적 흐름을 정확히 짚어낼 수 있는지, 아니면 그저 그럴듯한 답변만 내놓는지 분석합니다.
핵심 포인트
- AI는 코드베이스 시맨틱 검색을 통해 버그가 발생하는 파일과 메서드를 정확히 식별할 수 있음
- 단순 코드 기반 분석은 버그의 논리적 흐름은 잘 파악하나, 정확한 라인 단위 수정안 제시에는 한계가 있음
- 런타임 컨텍스트(실행 데이터)를 함께 제공할 때 분석의 정확도가 향상될 가능성이 높음
- AI의 '그럴듯함(Plausible)'과 '정확함(Correct)' 사이의 간극을 줄이는 것이 신뢰 구축의 핵심임
우리는 Jira 티켓을 읽고, 코드베이스를 검색하며, 실패를 추적하고, RCA(Root Cause Analysis, 근본 원인 분석)를 댓글로 게시하는 방식으로 근본 원인 분석을 자동으로 수행하는 Pinaka를 구축했습니다. 이를 실제 팀들에게 선보이기 전에, 우리는 한 가지 질문에 대한 정직한 답변이 필요했습니다. AI가 실제로 올바른 버그를 찾는 것일까, 아니면 그저 맞는 것처럼 들리는 것일까?
무엇인가가 왜 고장 났는지 설명하는 모든 AI 도구에는 "맞는 것처럼 들리는(Sound right)" 함정이 있습니다. LLM(Large Language Models, 대규모 언어 모델)은 그럴듯하게 들리는 근본 원인을 생성하는 데 매우 능숙합니다. 그럴듯함(Plausible)과 정확함(Correct)은 같은 것이 아니며, 그 사이의 간극이야말로 팀이 도구에 대한 신뢰를 잃게 되는 바로 그 지점입니다. 보통 누군가가 잘못된 파일을 한 시간 동안 붙잡고 있게 만든 첫 번째 사례 이후에 신뢰는 무너집니다.
그래서 우리는 실제 운영 중인 코드베이스에서 실제 버그를 선택했고, 이미 기록된 실제 사람이 작성한 근본 원인이 있는 상태에서 Pinaka의 두 가지 버전을 테스트했습니다.
테스트 설정
우리는 수천 개의 GitHub 별(star)을 보유하고 있으며 실제 운영 환경에서 활발히 사용되는 Node.js용 Redis 기반 작업 큐 라이브러리인 BullMQ(github.com/taskforcesh/bullmq)를 사용했습니다. 이는 우리 자신의 기술 스택의 일부이기도 했기에, AI의 확신 점수(confidence score)를 단순히 믿는 것이 아니라 우리가 직접 RCA 품질을 판단할 수 있었습니다.
버그: 이슈 #2487 — 작업(job)에 stackTraceLimit이 설정되어 있고 재시도(retry) 시 여러 번 실패할 경우, 표시되는 스택 트레이스(stack trace)가 업데이트되지 않는 문제입니다. 세 번째 또는 네 번째 재시도 시에도 항상 첫 번째 실패 내용만 보여줍니다. 실제 BullMQ 유지 관리자가 이를 실제 버그로 확인했으며, v5.4.6에서 수정되었습니다.
우리는 BullMQ 리포지토리를 Pinaka에 인덱싱한 후, 두 가지 별도의 RCA 패스를 실행했습니다:
Run A — 코드만 사용. 엔지니어가 실제로 티켓을 생성하는 방식처럼 현실적으로 모호한 Jira 티켓을 제공했습니다. 파일 이름도 없고, 가설도 없이 그저 "재시도 후 스택 트레이스가 업데이트되지 않음"이라고만 적혀 있습니다. Pinaka는 코드베이스에 대한 시맨틱 검색(semantic search)만을 사용하여 버그를 찾아내야 했습니다.
실행 B — 코드와 런타임 컨텍스트(runtime context). 동일한 인덱싱된 저장소(repo)를 사용하지만, 이번에는 Pinaka가 우리 SDK가 자동으로 캡처하도록 설계된 실행 시점(execution-time) 데이터, 즉 실제 옵션 값, 작업 상태(job state), 그리고 라이브 Redis 인스턴스에서 발생하는 실제 이벤트 시퀀스를 전달받았습니다.
우리는 두 출력 모두를 BullMQ 팀이 실제로 배포한 실제 수정 사항(fix)과 비교하여 평가했습니다.
코드 전용 RCA(근본 원인 분석)가 찾아낸 것
Pinaka는 정확한 파일(job.ts)과 정확한 메서드(moveToFailed())를 올바르게 식별했으며, 재시도(retries) 과정에서 버그가 어떻게 나타나는지에 대해 일관된 단계별 추적(trace)을 제공했습니다. 심지어 세 가지 그럴듯한 대안적 설명을 검토하고 테스트 스위트(test suite)의 구체적인 증거를 바탕으로 각 설명을 배제했는데, 이는 시니어 엔지니어가 수동으로 작업할 때 기대하는 수준의 추론입니다.
찾아내지 못한 것: 정확한 라인 단위(line-level)의 원인입니다. 버그의 동작을 정확하게 설명했지만, 제안된 수정안은 기능적으로는 유효했으나 BullMQ 유지 관리자들이 실제로 배포한 것보다 더 복잡했습니다. 또한, 버그가 TypeScript 코드 자체가 아니라 BullMQ가 원자적 작업 업데이트(atomic job updates)를 위해 사용하는 Redis Lua 스크립트 내부의 한 단계 아래에 존재하는 더 깊고 밀접하게 관련된 버그가 있다는 사실을 파악할 방법이 없었습니다.
인간의 정답(ground truth)과 비교했을 때, 이 실행의 점수는 10점 만점에 약 6.5점으로 평가됩니다. 정답 근처에 도달했으나 정확한 수정안은 아니었습니다.
런타임 컨텍스트가 찾아낸 것
실제 실행 시점 데이터가 포함된 두 번째 실행은 단순히 기존 답변을 개선하는 데 그치지 않고, 완전히 다른 더 깊은 버그를 드러냈습니다. 바로 stackTraceLimit이 명시적으로 0으로 설정될 때 발생하는 문제였습니다. 이는 첫 번째 수정 사항이 배포된 후 BullMQ의 유지 관리자들이 직접 제기한 실제 후속 이슈로 밝혀졌습니다.
근본 원인은 Lua 스크립트의 trim 조건에 있었습니다. 이 조건은 제한(limit)이 0보다 클 때만 실행되었기 때문에, 제한이 정확히 0인 경우 trim 단계를 조용히 건너뛰고 오래된 스택 트레이스(stack traces)가 Redis로 유출되도록 방치했습니다. Pinaka는 정확한 조건(ARGV[4] > 0)을 지목했으며, 유지 관리자들이 실제로 병합(merge)한 것과 일치하는 구조의 수정안을 제안했습니다.
동일한 Ground Truth (정답)를 기준으로 했을 때, 이번 실행은 10점 만점에 9.2점에 더 가까운 점수를 기록했습니다.
이 점수가 단순한 점수보다 더 중요한 이유
흥미로운 점은 단순히 "9.2점이 6.5점보다 높다"는 사실이 아닙니다. 런타임 컨텍스트 (Runtime context)가 어떤 종류의 실수를 해결했는가 하는 점입니다. 정적 코드 분석 (Static code reading)은 코드가 무엇을 해야 한다고 명시되어 있는지는 알려줄 수 있습니다. 하지만 장애가 발생한 순간 Redis에 실제로 무엇이 들어 있었는지, 혹은 값이 0일 때 불리언 (Boolean) 조건이 조용히 단락 평가 (Short-circuit)되는지, 또는 실제 버그가 애플리케이션 코드와 데이터베이스 내부에서 원자적 (Atomically)으로 실행되는 Lua 스크립트라는 두 개의 서로 다른 시스템 계층에 걸쳐 있는지까지는 알려줄 수 없습니다. 이것은 LLM (Large Language Model)이 읽기만 해서 해결할 수 있는 지식의 격차가 아닙니다. 이것은 가시성 격차 (Visibility gap)이며, 가시성 격차를 해결하는 유일한 방법은 실제로 런타임에서 무슨 일이 일어났는지를 포착하는 것뿐입니다.
이것이 바로 단순히 GitHub 리포지토리를 읽기만 하는 도구를 만드는 대신 @getpinaka/sdk를 출시한 핵심적인 도박입니다. 수많은 실제 운영 환경의 버그는 눈에 보이는 코드 안에 존재하지 않습니다. 그것들은 코드가 말하는 것과 실제로 일어난 일 사이의 간극 속에 존재합니다.
우리 스스로의 결과에 대해 반론을 제기한다면
작은 글씨 속에 숨기고 싶지 않은 몇 가지 사항이 있습니다:
실행 A (Run A)의 입력값은 실제 운영 로그보다 더 많은 정보를 담고 있었습니다. 우리는 엔지니어가 실제 상황에서 직접 파헤쳐야 할 사실들을 명시적으로 기술하도록 시뮬레이션된 로그를 작성했습니다. 만약 어떤 의미가 있다면, 이는 6.5점이라는 점수가 코드 전용 (Code-only) 조건에 관대한 편임을 의미합니다. 즉, 코드 전용 방식과 SDK가 계측된 (Instrumented) RCA (Root Cause Analysis, 근본 원인 분석) 사이의 실제 세계에서의 격차는 우리가 여기서 측정한 것보다 아마 더 클 것입니다.
실행 A와 실행 B는 엄밀히 말하면 하나의 버그에 대해 컨텍스트 유무를 비교하는 완전한 일대일 비교 (Apples-to-apples test)가 아니라, 서로 관련은 있지만 다른 두 개의 버그를 대상으로 했습니다. 두 실행 모두 동일한 GitHub 이슈 스레드의 일부이며, 두 번째 이슈는 첫 번째 이슈의 직접적인 후속 조치로 접수되었습니다. 하지만 이 테스트를 더 엄격하게 수행하려면 버그는 고정하고 컨텍스트만 변화시켜야 합니다.
이것은 하나의 버그, 하나의 리포지토리(repo)에서 각 조건당 한 번씩 실행된 결과입니다. 이는 통계적 유의성을 가진 벤치마크(benchmark)가 아니라, 실제 질적 사례 연구(qualitative case study)입니다. 우리는 다음으로 TypeORM과 Prisma의 이슈(issue)들을 대상으로 동일한 방법론을 적용할 예정이며, 이번 사례처럼 결과가 깔끔하게 나오지 않더라도 발견한 모든 내용을 공개할 것입니다.
실행 B의 런타임 컨텍스트(runtime context)는 SDK에 의해 실시간으로 캡처된 것이 아니라 구성된 것입니다. 이 테스트의 다음 버전은 실제 계측된 서비스(instrumented service)와 실제 크래시(crash)를 사용하여 엔드 투 엔드(end-to-end)로 진행됩니다.
우리는 여러분이 GitHub 이슈 스레드에서 직접 이 벤치마크의 취약점을 발견하게 하기보다, 차라리 우리가 먼저 어디가 부족한지 말씀드리는 편을 택하겠습니다. 만약 여러분이 근본 원인 분석(root cause analysis)을 직업으로 삼는 엔지니어라면, 어차피 직접 찾아내시겠지만 말입니다.
직접 시도해 보세요
Pinaka가 여러분의 코드베이스에서 어떻게 작동하는지 직접 확인하고 싶다면 getpinaka.com에서 대기 명단(waitlist)에 등록하세요. 우리는 이 제품을 공개적으로 구축하고 있는 작은 팀이며, 이와 같은 벤치마크는 단순히 출시 게시물에 올릴 내용을 정하기 위한 것이 아니라, 우리가 다음에 무엇을 만들지 결정하는 기준이 됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기