아카이브사이트맵
© 2026 Rayon. All rights reserved.
DevDay
아티클랭킹스페이스채용
데브투 favicon데브투

벤치마크 버그 9가지, 어떻게 잡았을까?

by DD
2026-07-16
1일 전
조회수 0

과거 작성된 벤치마크 스크립트(`run_benchmark_1_22.py`)가 N=22까지만 실행되어 근본 원인 파악 필요성 대두

Python 에이전트에서 4,300자리 정수 변환 제한으로 인한 크래시 발생, 이를 회피하기 위해 벤치마크 범위를 축소함

LLM 응답 파싱 오류, 잘못된 시간 단위 표기, 아키텍처 혼동 등 다양한 문제로 인해 벤치마크 결과의 신뢰도 저하 발생

최종적으로 9가지 버그 수정 및 4개의 PR을 통해 96/96 데이터 완전성 확보 및 신뢰할 수 있는 결과 도출

CPython 3.11 정수-문자열 변환 제한의 영향

CPython 3.11부터 도입된 int→str 변환 시 4,300자리 제한은 잠재적인 서비스 거부(Denial-of-Service) 공격을 방지하기 위한 조치다. 그러나 이 제한은 예상치 못한 방식으로 벤치마크 실행을 중단시켰다. 24번째 메르센 소수(Mersenne Prime)는 6,002자리로, 이 제한을 초과하여 문자열 변환 시 예외가 발생했다. 흥미로운 점은 해당 문자열이 실제로 반환되지 않았음에도 불구하고, 이로 인해 발생한 오류가 벤치마크를 N=22에서 중단시킨 원인이었다는 것이다. Go 에이전트에서도 유사한 `val.String()` 호출이 있었으나, 크래시를 유발하지는 않았다. 불필요한 문자열 변환 로직 제거만으로도 이 문제를 해결할 수 있었다.

LLM 기반 파싱의 취약점과 대안

벤치마크 파이프라인이 Python 에이전트의 경과 시간을 파싱하기 위해 사용한 정규 표현식(`r"It took ([\d\.\-e]+) seconds"`)은 LLM의 응답 형식 변화에 매우 취약했다. LLM은 종종 예상치 못한 문구를 사용하며, 이 경우 파이프라인은 데이터를 전혀 얻지 못할 수 있었다. 다행히 구조화된 도구 아티팩트(Structured Tool Artifacts)가 존재했으나, 이를 활용하지 않고 LLM 텍스트에 의존한 것은 구현상의 중대한 오류였다. 구조화된 데이터 형식(JSON, Protocol Buffers 등)을 사용하는 것이 LLM 응답의 가변성에 대한 의존도를 낮추는 근본적인 해결책이다.

시간 단위 표기 오류와 로그 스케일 차트의 함정

Rust와 Node.js 에이전트에서 발생한 0.00ms 단위 표기 오류는 로그 스케일 차트에서 해당 데이터 포인트를 완전히 누락시키는 결과를 초래했다. 이는 실제로는 매우 짧은 시간이지만, 0으로 해석되어 시각화에서 사라지는 문제였다. 또한, 두 에이전트가 실제로는 LLM을 통하지 않고 직접 HTTP 핸들러로 동작함에도 불구하고, 벤치마크 차트에서는 Gemini를 통과하는 다른 에이전트와 동일한 축에 비교되었다. 이는 아키텍처적 차이(Architectural Differences)를 무시한 잘못된 비교이며, 약 400배의 RTT(Round-Trip Time) 격차가 단순 언어 비교로 오해될 소지가 있었다.

Go 에이전트의 나노초(Nanosecond) 처리 실패

벤치마크 수정 과정에서 Go 에이전트의 실행 속도가 극도로 빨라지자, `time.Duration`이 마이크로초(µs) 단위를 넘어 나노초(ns) 단위로 출력되었다. 기존 파서에는 나노초 단위를 처리하는 로직이 부재하여 해당 데이터 포인트가 누락되었다. 이는 성능 최적화가 오히려 벤치마크 시스템 자체의 한계를 드러낸 사례다. 다양한 시간 단위(Time Units)를 처리할 수 있도록 파서 로직을 확장하는 패치가 필요했다.

언어 모델의 상태 저장 및 반복 거부 문제

Gemini API가 이전 대화 기록을 재사용하는 문제로 인해, 동일한 컨텍스트 ID로 벤치마크를 재실행했을 때 LLM이 작업을 반복하는 것을 거부하는 현상이 발생했다. 이는 언어 모델의 상태 저장(Stateful Behavior) 및 결정론적이지 않은 응답(Non-deterministic Responses)이 벤치마크의 재현성(Reproducibility)을 저해할 수 있음을 보여준다. 실행마다 고유한 컨텍스트 ID를 부여하는 방식으로 이 문제를 해결했으며, 벤치마크의 완전한 성공을 위해서는 외부 서비스의 동작 방식까지 고려해야 함을 시사한다.

벤치마크 코드의 프로덕션 수준 관리 필요성

이 이야기는 벤치마크 코드가 단순한 테스트 스크립트가 아니라 프로덕션 코드(Production Code)와 동일한 수준의 관리가 필요함을 강조한다. 스택 트레이스(Stack Trace)를 조사하지 않고 단순히 파일 이름을 변경하는 임시방편은 근본적인 버그를 숨기는 결과를 낳는다. 본문의 벤치마크는 크래시, 잘못된 데이터 수, 부정확한 측정, 아키텍처 혼동 등 네 가지 측면에서 오류를 포함하고 있었다. 자동화된 파이프라인에서 LLM 응답을 직접 파싱하는 방식은 극도로 취약하며, 구조화된 데이터 사용이 필수적이다.

Why did my benchmark stop at N=22? A debugging story in nine bugs
원문 읽기
원문 읽기
고급
리뷰
Python
Go
Node.js
Rust
gRPC
HTTP
Gemini API
JavaScript
Backend
AI/ML

댓글 0

첫 번째 댓글을 남겨보세요!

관련 추천 글

Python 정수 변환 제한부터 LLM 응답 오류까지, 9가지 버그 해결기

데브투 로고

AI 모델에 독립적인 취약점 탐지 하네스 구축

클라우드플레어 로고

GitHub Copilot SDK, 이제 프로덕션에서 직접 사용하세요!

깃헙 로고

Claude Code가 뽑은 최고의 기술 스택!

테오 로고

Go와 Rust, 과연 보일러플레이트(Boilerplate)는?

레딧 로고

API 캐싱 혁신: HTTP QUERY 메서드 등장!

랍스타즈 로고
데브투 favicon데브투
고급
리뷰
Python
Go
Node.js
Rust
gRPC
HTTP
Gemini API
JavaScript
Backend
AI/ML

관련 추천 글

Python 정수 변환 제한부터 LLM 응답 오류까지, 9가지 버그 해결기

데브투 로고

AI 모델에 독립적인 취약점 탐지 하네스 구축

클라우드플레어 로고

GitHub Copilot SDK, 이제 프로덕션에서 직접 사용하세요!

깃헙 로고