코드를 실행하여 버그를 수정하는 에이전트
요약
단순히 코드를 추론하는 모델을 넘어, 런타임에서 로그를 확인하고 가설을 검증하는 '하네스 엔지니어링(harness engineering)'의 중요성을 설명합니다. 모델 자체의 성능보다 도구, 피드백 루프, 에러 핸들링 등 모델을 둘러싼 구조적 설계가 에이전트의 성능을 결정합니다.
핵심 포인트
- 모델의 추론 능력보다 모델을 둘러싼 루프와 도구가 핵심임
- 하네스 엔지니어링: 도구, 프롬프트, 피드백 루프를 포함한 시스템 설계
- 단순 코드 추론과 런타임 증거 기반 디버깅의 차이 강조
- 성공적인 코딩 에이전트는 실행 환경과 상호작용해야 함
코딩 에이전트가 단 한 번의 시도로 버그를 정확하게 수정하는 것을 처음 목격했을 때의 이야기를 하고 싶습니다.
그것은 모델의 차이가 아니었습니다. 모델은 제가 몇 달 동안 사용해 온 것과 동일한 모델이었습니다. 변화가 있었던 것은 모델을 둘러싼 루프 (loop)였습니다.
이 에이전트는 파일 세 개를 열어 훑어보고, 머릿속으로 자신만만한 이론을 세운 뒤, 원인처럼 "보이는" 무언가를 수정하지 않았습니다. 그것은 과거의 루프였습니다. 코드를 실행하고, 똑같은 버그를 확인하며, 에이전트가 어깨를 으쓱하며 다른 파일을 시도하는 것을 지켜봐야 했던 방식 말입니다.
이번에 에이전트는 다른 행동을 했습니다. 다섯 가지 가설을 나열했습니다. 그중 하나를 선택했습니다. 로그 (logging)를 추가했습니다. 그러고 나서 멈추더니 저에게 실패 상황을 재현 (reproduce)해 달라고 요청했습니다. 제가 버튼을 클릭했습니다. 버그가 발생했습니다. 에이전트는 로그를 읽고, 가설을 확인한 뒤, 두 줄짜리 수정 코드를 작성하고, 추가했던 로그를 다시 제거했습니다.
이 모든 과정은 아마 4분 정도 걸렸을 것입니다.
이것이 소스 코드 (source code)를 보고 추측하는 에이전트와 런타임 (runtime)에서 증거를 확보하는 에이전트의 차이입니다. 그리고 이것은 오늘날 대부분의 사람들이 하고 있는 AI 보조 코딩 (AI-assisted coding)과 실제로 제품을 출시 (ships)할 수 있는 코딩 사이의 차이입니다.
이 분야를 일컫는 명칭이 형성되고 있습니다. Martin Fowler의 사이트에 게재된 올해 초 Birgitta Böckeler의 기사에서는 지난 몇 달 동안 에이전트 커뮤니티에서 조용히 퍼지고 있는 용어를 사용합니다: 하네스 엔지니어링 (harness engineering).
전제는 간단합니다. 에이전트는 모델 (model)에 하네스 (harness)를 더한 것입니다. 모델은 언어 모델 (language model) 그 자체입니다. 하네스는 그 외의 모든 것입니다. 도구 (tools), 프롬프트 (prompts), 피드백 루프 (feedback loops), 에러 핸들링 (error handling), 재시도 (retries), 그리고 모델이 무엇을 보고 언제 행동할지를 결정하는 코드의 스캐폴드 (scaffold) 등이 포함됩니다.
오랫동안 AI 코딩에 관한 대화는 모델에 집중되어 왔습니다. 더 큰 모델, 더 똑똑한 모델, 더 새로운 모델, 다른 제공자, 다른 프롬프트, 다른 시스템 메시지 (system message) 같은 것들 말입니다. 사람들은 상자 내부를 튜닝해 왔습니다.
하네스는 상자 그 자체입니다. 그리고 알고 보니 그 상자가 사람들이 인정하고 싶어 했던 것보다 훨씬 더 많은 일을 하고 있었습니다.
어떤 에이전트든 디버깅하는 것을 지켜보세요
가장 인기 있는 도구들을 포함하여 어떤 AI 코딩 도구라도 사용해 보셨다면, 아마 다음과 같은 루프를 목격했을 것입니다.
당신은 에이전트 (Agent)에게 버그를 줍니다. 에이전트는 몇 개의 파일을 엽니다. 그것들을 읽습니다. 무엇이 잘못되었는지에 대해 머릿속으로 가설을 세웁니다. 이러한 종류의 버그를 유발할 법한 코드와 유사한 라인을 수정합니다. 당신에게 수정이 완료되었다고 말합니다. 당신은 실패하는 시나리오를 실행합니다. 버그가 다시 발생합니다. 에이전트는 "다른 파일을 살펴보겠습니다"라고 말하고 이 사이클은 반복됩니다.
때로는 성공하기도 합니다. 하지만 자주 실패합니다. 그리고 그 실패에는 특유의 양상이 있습니다. 에이전트가 혼란스러워하는 것이 아닙니다. 에이전트가 확신에 차 있는 것입니다.
그 이유는 구조적입니다. 모델은 코드 (Code)에 대해 추론하고 있습니다. 프로그램 (Program)에 대해 추론하고 있는 것이 아닙니다. 모델은 코드가 무엇을 한다고 명시되어 있는지는 읽었지만, 당신의 특정 입력값, 특정 부하, 특정 경쟁 상태 (Race condition) 하에서 코드가 실제로 무엇을 하는지는 보지 못했습니다.
코드는 가설입니다. 프로그램은 진실입니다. 그리고 모델은 오직 가설만을 보아왔을 뿐입니다.
작동하지 않는 모든 "명백한 수정 사항"은 현실과 마주하지 못한 가설입니다.
아무도 충분히 크게 말하지 않는 변화
Cursor에서 근무하는 David Gomes는 몇 주 전 그들이 디버그 모드 (Debug Mode)라고 부르는 것에 대해 글을 썼습니다. 그가 주장하는 바는 흥미로운데, 왜냐하면 그것이 단순히 기능에 관한 것이 아니라, 그 기능 밑에 깔린 원칙에 관한 것이기 때문입니다.
Cursor의 디버그 모드는 한 가지 일을 합니다. 에이전트가 수정 사항을 작성하려고 시도하기 전에 로깅 (Logging)을 추가하고, 코드를 실행하며, 로그를 읽도록 가르치는 것입니다. 여기에는 가설 설정, 계측 (Instrument), 재현, 읽기, 수정, 정리라는 깔끔하고 작은 루프가 있습니다. 에이전트는 로깅을 추가하는 단계와 구현 (Implementation)을 수정하는 단계를 동일한 패스 (Pass)에서 처리하지 않습니다. 에이전트는 로깅을 탐침 (Probe)으로 취급하고 코드 변경을 개입 (Intervention)으로 취급합니다. 이 둘을 분리하여 유지합니다.
Gomes는 이 기능을 계측 모드 (Instrumentation Mode)라고 불렀어야 했다고 주장하며, 제 생각에 그의 주장은 옳습니다. 참신함은 에이전트가 디버깅을 한다는 점에 있는 것이 아닙니다. 참신함은 에이전트가 런타임 컨텍스트 (Runtime context)를 갖게 되었다는 점에 있습니다.
그리고 이 패턴을 한 번 이해하고 나면, 어디에서나 이를 발견하게 될 것입니다. 조용히 작동하는 코드를 배포하는 에이전트들은 그들의 하네스 (Harness)가 런타임 정보 (Runtime information)를 제공하는 에이전트들입니다. 반면, 동일한 버그에 대해 무한 루프를 도는 에이전트들은 그들의 하네스가 소스 코드 (Source code)만을 제공하는 에이전트들입니다.
이것은 Cursor만의 이야기가 아닙니다. 하네스에 관한 Tejas Kumar의 IBM 강연, OpenAI에서의 Ryan Lopopolo의 연구, 프롬프트 (Prompt)에서 컨텍스트 (Context)를 거쳐 하네스 (Harness)로의 진화에 관한 Manjeet의 글, 그리고 플레이그라운드 (Playground)를 벗어나는 순간 모델 주변의 장치 (Apparatus)가 핵심적인 역할 (Heavy lifting)을 수행한다는 Karpathy의 반복적인 지적에서 볼 수 있는 것과 동일한 개념입니다.
모델 단독으로는 닫힌 책과 같습니다. 하네스는 모델에게 실행 중인 세상(Running world)을 들여다볼 수 있는 창을 제공하는 것입니다.
런타임 증거가 실제로 포착하는 것들
하네스 엔지니어링 (Harness engineering)이 단순히 멋진 아이디어에 그치지 않고, 에이전트가 작동하는 방식에 즉각적이고 측정 가능한 개선을 가져다주는 지점이 바로 여기입니다.
아무리 코드를 많이 읽어도 드러나지 않는 버그 카테고리들이 통째로 존재합니다. 이들은 소스 (Source)가 아니라 프로그램 (Program) 안에 존재합니다. 프로그램이 실행될 때만 모습을 드러냅니다.
동시성 (Concurrency) 상황에서 상태 (State)를 손상시키는 20번 중 1번 꼴로 발생하는 레이스 컨디션 (Race condition). 어떤 파일도 이에 대해 알려주지 않습니다. 두 개의 로그 라인 (Log lines)이 잘못된 순서로 도착하는 것을 직접 확인해야 합니다.
30분간의 트래픽이 발생해야 나타나는 메모리 누수 (Memory leak). 객체의 생명 주기 (Object lifetimes)를 응시하는 것만으로는 절대 발견할 수 없습니다. 힙 스냅샷 (Heap snapshot)을 통해 확인해야 합니다.
컴파일된 의존성 (Compiled dependency) 내부의 네이티브 크래시 (Native crash). 에이전트가 하루 종일 당신의 Python 코드를 읽을 수도 있습니다. 하지만 크래시는 C 언어에서 발생합니다.
팀의 모든 시니어 개발자가 포기했기 때문에 티켓 큐 (Ticket queue)에 6개월 동안 머물러 있는 렌더링 버그 (Rendering bug). 부하가 걸린 상태의 DOM은 소스 코드 상의 DOM과 다르게 보입니다.
중단점 (Breakpoint)을 근처에 설정하는 순간 사라져 버리는 하이젠버그 (Heisenbug). 이를 찾는 유일한 방법은 프로그램을 그대로 두고 관찰하는 것뿐입니다.
이제 저는 이러한 버그를 잡아내는 에이전트 루프 (agent loop)를 가지고 있습니다. 이는 제가 모델을 바꿨기 때문이 아닙니다. 모델 주변에 기본적으로 런타임 증거 (runtime evidence)를 제공할 수 있는 하네스 (harness)를 구축했기 때문입니다. 가설이 순위가 매겨지고, 로깅 (logging)이 추가되며, 시나리오가 재현되고, 로그가 읽히며, 수정 사항이 작성되고, 계측 (instrumentation)이 정리됩니다.
동일한 모델. 다른 하네스. 다른 결과.
이를 작동하게 만드는 규율
이 글에서 단 한 가지만 얻어 가신다면, 바로 이것입니다.
에이전트가 단 한 번의 패스 (pass) 내에서 로깅과 편집을 동시에 하게 두지 마십시오.
로깅과 편집을 섞는 순간 증거 루프 (evidence loop) 전체가 무너집니다. 만약 에이전트가 로깅을 추가하는 동시에 구현 (implementation)을 변경하고, 그 후 버그의 동작이 달라진다면, 어떤 변경 사항이 결과를 변화시켰는지 알 수 없습니다. 새로운 로직 때문이었을까요? 아니면 계측 (instrumentation)의 부작용 때문이었을까요? 당신은 알 수 없습니다. 다시 추측하게 될 뿐입니다. 그것도 더 복잡한 단계를 거치면서 말이죠.
로깅은 탐침 (probe)입니다. 코드 변경은 개입 (intervention)입니다. 이들을 서로 다른 작업으로 취급하십시오. 서로 다른 패스 (pass)로 실행하십시오. 에이전트는 먼저 관찰합니다. 에이전트는 그다음에 개입합니다. 한 번의 휘두름에 두 가지를 절대 동시에 하지 마십시오.
이것은 당연하게 들릴 수 있습니다. 하지만 대부분의 에이전트가 기본적으로 수행하는 방식은 아닙니다. 대부분의 에이전트는
이는 Gomes가 디버그 모드 (Debug Mode) 채택에 대해 언급한 것과 같은 맥락입니다. 이 기능은 진정으로 유용합니다. 하지만 대부분의 사용자는 이를 사용하지 않습니다. 재현 (reproduction) 단계를 수행할 만큼 충분히 몰입한 사람이 필요하기 때문입니다. 그리고 앞으로 작성될 대부분의 코드는 특별히 몰입하지 않은 인간들에 의해 작성될 것입니다.
저는 이 점으로 계속 되돌아오게 됩니다. AI 코딩의 미래는 "버튼을 누르면 에이전트가 배포한다"가 아닙니다. 에이전트가 지루한 계측 (instrumentation) 및 추론 (inference) 작업을 수행하고, 당신은 화면 앞에 몸을 두고 버튼 위에 손가락을 올리는 작업, 즉 인간의 개입이 필요한 부분을 수행하는 긴밀하고 빠른 루프 (loop)입니다.
이것은 퇴보가 아닙니다. 업그레이드입니다. 당신은 코드 타이퍼 (code-typer)에서 디버거의 디버거 (debugger-of-debuggers)로 거듭나는 것입니다. 당신의 판단력은 줄어드는 것이 아니라 더욱 중요해집니다.
사고 모델의 전환 (The mental model shift)
모델을 더 똑똑하게 만들려고 애쓰는 것을 멈추십시오. 세상에서 가장 똑똑한 모델이라 할지라도 여전히 볼 수 없는 것은 볼 수 없습니다.
당신이 진지한 에이전트 시스템을 구축할 때 실제로 만들고 있는 것은 모델 주변의 장치 (apparatus)입니다. 도구 (Tools). 로그 (Logs). 재시도 (Retries). 상태 유지 (State persistence). 검증 단계 (Verification steps). 에이전트가 당신에게 확인을 요청하는 대신, 자신의 가설을 현실과 대조하여 테스트할 수 있는 방법들 말입니다.
Fowler의 기사는 이를 피드포워드 제어 (feedforward controls, 에이전트가 행동하기 전에 무엇을 할지 형성하는 가이드)와 피드백 제어 (feedback controls, 에이전트가 행동한 후 실수를 포착하는 센서)로 정의합니다. 둘 다 중요합니다. 피드포워드가 없다면 에이전트는 감독되지 않은 상태가 됩니다. 피드백이 없다면 에이전트는 똑같은 실수를 영원히 반복하게 됩니다.
위에서 설명한 버그 수정 루프 (bug-fixing loop)는 이것의 한 가지 구체적인 사례입니다. 가설은 당신의 코드베이스와 버그 설명에 의해 형성되는 피드포워드이며, 로그는 어떤 가설이 실행 중인 프로그램과의 접촉에서 살아남았는지 에이전트에게 알려주는 피드백입니다.
코드 리뷰, 리팩터링 (refactoring), 마이그레이션 (migrations), 성능 작업 등 모델이 소스 코드로부터 현실을 발명하는 대신 현실이 어떤 모습인지 전달받아야 하는 모든 작업에 대해 동일한 패턴을 구축할 수 있습니다.
그것이 바로 작업입니다. 그것이 바로 하네스 엔지니어링 (harness engineering)입니다.
모델이 더 똑똑해진 것이 아닙니다. 하네스 (harness)가 더 똑똑해진 것입니다.
이번 주에 해야 할 일
벤더가 이를 배포해 줄 때까지 기다리지 마세요. 만약 내장된 증거 루프 (evidence loop)가 없는 에이전트 (agent)를 사용하고 있다면, 직접 만드세요. 구성 요소들은 결코 생소한 것들이 아닙니다.
다음 세 가지부터 시작하세요:
에이전트가 읽을 수 있는 로깅 컨벤션 (logging convention). 형식을 선택하고, 로그가 어디로 가는지와 어떻게 읽는지 설명하는 한 줄짜리 스킬 (skill) 또는 AGENTS.md 노트를 작성하세요. 그리고 에이전트가 계측 (instrumenting)할 때 항상 해당 형식으로 출력하도록 만드세요.
분리 규칙 (separation rule). 에이전트가 읽는 어떤 지침 파일 (instruction file)이든, 로깅 (logging)과 구현 변경 (implementation changes)은 서로 다른 패스 (passes)에서 이루어져야 한다고 에이전트에게 말하세요. 필요하다면 작업 템플릿 (task templates)에 체크박스로 추가하세요.
실제로 실행 가능한 재현 도구 (reproducer). 재현 루프 (reproduction loop)가 빠를수록 증거 루프 (evidence loop)도 빨라집니다. 만약 테스트 사이클이 90초나 걸린다면, 당신의 에이전트도 그만큼 기다려야 할 것입니다. 이를 10초로 단축하면, 어떤 모델을 사용하든 상관없이 버그를 5배 더 빠르게 수정할 수 있습니다.
이 세 가지 변화는 기능 출시 (feature release)가 아닙니다. 그것은 태도 (attitude)입니다. 하네스 (harness)를 모델만큼 진지하게 다루는 것이 어떤 모습인지를 보여주는 것입니다.
그렇게 한다면, 에이전트가 수정했다고 주장하는 다음 버그는 실제로 수정될 것이라고 약속합니다.
이 글을 쓰는 동안 유용하다고 생각한 출처들:
- Martin Fowler / Birgitta Böckeler, Harness engineering for coding agent users (2026년 4월)
- David Gomes, Cursor's Debug Mode Is Arguably Its Best Feature
- Cursor 팀, Introducing Debug Mode: Agents with runtime logs
- Eric Zakariasson (Cursor), original announcement thread on X
- Manjeet, Context → Harness Engineering: The Evolution of Building AI Agents
이 내용이 공감이 가셨다면, 여러분의 재현 사례(reproducer)는 어떤 모습인지, 그리고 증거 루프(evidence loop)가 어디에서 끊어지는지 꼭 듣고 싶습니다. Substack으로 답장을 보내주시거나 여기에 댓글을 남겨주세요.
원문은 저의 Substack에 게시되었습니다.
— Shrey
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기