속도는 공짜가 되었지만, 책임은 그렇지 않습니다

seonest

어느 날 제 노트북에는 에이전트가 여덟 개 돌아가고 있었고, 밤사이 도착한 PR이 다섯 개 쌓여 있었습니다. 대시보드는 쉴 새 없이 움직였고, 그날 저는 한 주 중 가장 바빴습니다. 그런데 퇴근할 무렵 main에 실제로 머지된 변경은 거의 없었습니다. 가장 생산적이라고 느낀 날과, 가장 적게 만들어 낸 날이 같은 날이었습니다.

이 역설이 어디서 오는지 알면, 요즘 에이전트 기반 개발을 둘러싼 과한 기대와 막연한 불안 사이에서 중심을 잡을 수 있습니다. 코드를 만드는 비용은 거의 0으로 떨어졌지만, 그 코드를 책임지는 비용은 한 푼도 싸지지 않았습니다.

도구가 좋아진 것은 사실입니다

먼저 분명히 해 둘 것이 있습니다. 저는 AI 도구를 매일 쓰고, 이 도구들 덕분에 예전보다 훨씬 과감하고 재미있는 일을 합니다. Addy Osmani도 같은 이야기를 합니다. 지난 1년 동안 이 도구들로 그 전 5년보다 더 많은 것을 실제로 만들었다고 합니다. 생산성이 2배, 5배로 뛰었다는 경험담은 과장이 아닙니다. 그래서 "에이전트가 다 해준다"는 목소리가 어디서나 들립니다.

데모만 보면 이 코드를 계속 써도 될 것 같습니다. 하지만 코드를 수정하거나 기능을 확장하고 보안을 점검하려는 순간, 아무도 이 코드가 실제로 무엇을 하는지 이해하지 못했다는 사실이 드러납니다.

1년 전 Andrej Karpathy가 만든 vibe coding 이라는 말은 원래 이 방식을 정확히 가리켰습니다. 프롬프트를 던지고, diff는 읽지 않고, 에러가 나면 다시 붙여 넣는 식으로 감에 맡기는 프로그래밍 말입니다. 주말 프로토타입이나 한 번 쓰고 버릴 스크립트라면 더없이 좋은 방식입니다. 망가지면 다시 생성하면 그만입니다.

그런데 이 말이 어느새 결제 시스템을 만드는 일까지 전부 뭉뚱그려 부르는 단어가 되어 버렸습니다. Karpathy는 이번에 agentic engineering이라는 더 정확한 표현을 제안했고, Simon Willison을 비롯한 여러 사람이 비슷한 구분을 시도해 왔습니다. 두 표현을 구분하는 이유는 사람이 맡는 역할이 다르기 때문입니다. vibe coding에서는 코드를 읽지 않지만, agentic engineering에서는 구현을 AI에게 맡기더라도 아키텍처와 품질, 정확성은 사람이 책임집니다.

그러니 기대 자체가 문제는 아닙니다. 도구를 잘 다루는 사람은 분명히 앞서갑니다. 위험한 것은 그 기대가 책임을 건너뛰는 핑계가 될 때입니다. "에이전트가 했으니까"라는 말은 디버깅에도, 사고 보고서에도 아무 도움이 되지 않습니다.

리뷰어가 병목이 됩니다

기대와 현실이 가장 먼저, 가장 아프게 부딪히는 곳이 코드 리뷰입니다.

코드 리뷰는 늘 병목이었습니다. 하지만 생산적이고 교육적인 병목이었습니다. PR을 읽다 보면 이해하지 않고는 넘어갈 수 없습니다. 숨은 가정이 드러나고, 반년 전 내린 설계 결정과 부딪히는 부분이 잡히고, 시스템이 실제로 무엇을 하는지가 유지보수를 책임질 사람들에게 전해집니다.

AI는 사람이 검토할 수 있는 속도보다 훨씬 빠르게 코드를 생성합니다. 코드를 작성하는 데 시간이 많이 들던 시절에는 시니어가 주니어의 작성 속도보다 빠르게 리뷰할 수 있었습니다. 이제는 주니어 한 명이 에이전트로 만든 코드도 시니어가 꼼꼼히 검토하기에는 너무 많습니다. 코드가 만들어지는 동안 앞선 변경을 검토할 여유가 사라진 것입니다.

결과를 충분히 확인하지 않고 올린 커밋과 PR이 리뷰어에게 계속 쌓입니다. 작성자가 시니어든 주니어든 최종적으로 검토할 사람의 부담은 늘어납니다. 1,800줄짜리 PR 앞에서 무슨 일이 벌어지는지는 이미 살펴본 적이 있습니다. 처음 100줄은 꼼꼼히 읽다가, 500줄을 넘으면 함수 시그니처만 훑고, 1,000줄을 넘으면 "테스트는 통과했네"로 끝내 버립니다.

Addy Osmani는 이런 상태를 인지적 항복(cognitive surrender)이라고 부릅니다. 변경량이 한 번에 이해할 수 있는 범위를 넘으면, 내용을 이해하려는 대신 승인 절차만 밟게 됩니다. "Approve" 버튼을 눌러도 실제 검토를 마쳤다고 보기 어렵습니다.

조직은 오랫동안 "리뷰된 코드는 이해된 코드다"라고 여겨 왔습니다. 하지만 엔지니어가 충분히 이해하지 못한 코드도 일단 승인하면 조직은 검토가 끝난 것으로 받아들입니다. 검토자가 놓친 문제를 조직 전체가 떠안게 되는 것입니다.

당신은 단일 스레드입니다

여기서 한 단계 더 들어가면, 이것이 의지나 규율의 문제가 아니라 구조의 문제라는 사실이 보입니다.

파이썬에는 GIL(Global Interpreter Lock)이 있습니다. 스레드를 몇 개 만들든, 한 순간에 실제로 파이썬 바이트코드를 실행하는 것은 잠금을 쥔 스레드 하나뿐입니다. 에이전트 입장에서 보면, 당신이 곧 GIL입니다. 에이전트는 얼마든지 동시에 돌릴 수 있지만, 아키텍처를 진짜로 이해해야 하는 판단이나 머지 충돌을 푸는 일은 결국 잠금을 잡아야만 처리됩니다. 잠금은 하나뿐이고, 그것을 쥔 사람은 당신입니다.

Amdahl의 법칙이 이 한계를 수식으로 보여 줍니다. 병렬화로 얻는 속도 향상은 끝까지 직렬로 남는 작업의 비율이 좌우합니다. 에이전트 개발에서 그 직렬 구간은 판단 입니다. 에이전트를 여덟 개 띄운다고 당신의 판단 시간이 8분의 1로 줄지 않습니다. 당신에게 들어오는 작업 큐만 여덟 배 깊어질 뿐입니다.

이것을 다른 각도에서 보면 이렇습니다. 코드를 생성 하는 비용은 빠르게 O(1)에 수렴하고 있습니다. 변경의 크기와 거의 무관하게, 사실상 공짜에 가까운 시간이면 됩니다. 하지만 그 코드를 이해하고 책임지는 비용은 여전히 O(n)입니다. 변경량에 비례해 사람의 주의력을 꼬박꼬박 잡아먹습니다. 생성 곡선은 바닥으로 내려앉는데 검토 곡선은 그대로이니, 그렇게 벌어지는 틈이 곧 오케스트레이션 세금(orchestration tax)입니다. 에이전트가 만들어 내는 양과 당신이 실제로 머지할 수 있는 양이 구조적으로 벌어진 결과입니다.

CPU는 마이크로초 단위로 작업을 전환하고 저장해 둔 상태를 복원하지만, 사람은 그렇지 않습니다. 한동안 보지 않던 에이전트의 작업으로 돌아가면 몇 분씩 맥락을 다시 파악해야 하고, 이전에 알던 내용을 빠뜨리기도 합니다. 사람에게 검토가 몰리는 문제에 작업을 오가는 부담까지 더해지는 셈입니다.

그래서 에이전트 스무 개가 돌아가는 화면은 위험할 만큼 생산적으로 느껴집니다. 하지만 바쁜 것과 만들어 내는 것은 전혀 다릅니다. 좋은 동시성 시스템이 큐가 무한정 길어지지 않도록 생산자에게 백프레셔(backpressure)를 걸듯이, 띄우는 에이전트 수는 당신이 실제로 리뷰를 끝낼 수 있는 속도에 맞춰야 합니다. 그 숫자는 대부분 낮은 한 자릿수입니다. UI가 스무 개를 띄우게 해 준다는 것은, 그저 UI가 그렇게 만들어졌다는 뜻일 뿐입니다.

코드를 이해하지 못하거나 설계 의도를 남기지 않아도 부채가 쌓입니다

사람이 판단할 수 있는 속도를 무시하고 작업량만 늘리면, 나중에 해결해야 할 문제가 쌓입니다. Margaret-Anne Storey의 3중 부채 모델은 이런 부채를 세 가지로 나눕니다.

기술 부채 는 코드에 쌓입니다. 얽힌 모듈이나 마감에 쫓겨 임시로 처리한 코드처럼, 나중에 시스템을 바꾸기 어렵게 만드는 선택입니다. 수십 년 된 개념이고, 빌드가 느려지거나 테스트가 깨지는 형태로 체감됩니다.

인지 부채(이해 부채)는 시스템의 코드는 계속 늘어나는데 사람이 이해하는 범위는 그만큼 넓어지지 않을 때 쌓입니다. 코드가 깔끔해 보여도 아무도 동작을 설명할 수 없다면 안심할 수 없습니다. Storey가 관찰한 어느 학생 팀은 7주 차에 개발을 이어 가기 어려워졌습니다. 코드가 지저분해서가 아니었습니다. 왜 그런 설계 결정을 내렸는지 아무도 설명하지 못했고, 사소한 변경에도 예상치 못한 문제가 생겼기 때문입니다.

인텐트 부채는 시스템을 왜 이렇게 만들었는지 기록하지 않았을 때 쌓입니다. 목표와 제약, 결정의 근거가 머릿속에만 남아 있는 상태입니다. 이런 설계 의도를 문서로 남겨야 다음 사람이나 에이전트도 참고할 수 있습니다.

기술 부채와 이해 부채는 에이전트의 도움을 받아 줄일 수 있습니다. 얽힌 모듈의 리팩터링을 맡기거나 코드를 설명해 달라고 요청할 수 있습니다. 코드가 남아 있기 때문입니다. 하지만 기록하지 않은 설계 의도는 코드만으로 알아낼 수 없습니다. 모델은 300ms라는 디바운스 값이 의도된 UX 결정인지, 벤치마크 결과인지, 누군가 한 번 적고 잊은 숫자인지 알지 못합니다. 그럴듯한 이유를 지어내고도 확신하는 듯 설명한다면, 모른다고 말하는 것보다 오히려 해롭습니다.

이 부채들은 서로를 키웁니다. 이해하지 못한 코드를 머지하면 코드와 설계 의도를 설명하기가 더 어려워집니다. 그러다 작은 변경조차 두려워지면, 다시 에이전트에게 "그냥 고쳐 줘"라고 맡기게 됩니다. 결과를 이해하지 않은 채 머지하는 일이 반복되고, 코드베이스는 갈수록 고치기 어려워집니다. 코드 생성이 빨라질수록 이런 문제도 빠르게 쌓입니다.

하네스를 조이는 것만으로는 부족합니다

여기까지 오면 자연스럽게 떠오르는 해법이 있습니다. "그럼 하네스를 잘 설계하면 되는 것 아닌가?"

하네스(harness)는 모델이 작업할 수 있도록 구성한 주변 도구와 실행 환경입니다. 시스템 프롬프트와 CLAUDE.md, 도구와 MCP 서버, 훅, 샌드박스, 서브에이전트, 규칙과 스킬, 외부 프레임워크와 플랫폼까지 포함합니다. 하네스 엔지니어링에서는 이 구성도 개발하고 관리해야 할 산출물로 다룹니다. 에이전트가 실수하면 같은 문제가 반복되지 않도록 보완합니다.

에이전트가 한 번 저지른 실수를 다음 작업에서도 막을 수 있도록 규칙과 검증 절차를 보완합니다. 이를 래칫(ratchet)이라고 부릅니다. 에이전트가 테스트를 주석 처리한 채 PR을 올렸다면, 규칙 파일에 "테스트를 주석 처리하지 말 것"을 추가합니다. pre-commit 훅으로 해당 패턴을 검사하고, 리뷰어 서브에이전트도 확인하도록 합니다. 규칙마다 어떤 실패를 막기 위해 추가했는지 설명할 수 있어야 합니다.

그런데 하네스를 강화하면 모든 것이 해결된다는 식의 접근은 두 가지 지점에서 어긋납니다.

모델이 좋아지면 이전의 한계를 보완하던 코드는 필요 없어질 수 있습니다. 동시에 예전에는 시도하지 못했던 작업이 가능해지고, 새로운 종류의 실패도 생깁니다. 며칠 동안 작업 맥락을 유지할 메모리 정책이나 여러 전문 에이전트를 조율할 방법이 필요해지는 것입니다. 더 똑똑한 모델을 기다리거나 하네스를 계속 추가하는 것만으로 끝나지 않습니다. 모델에 맡기는 일이 달라지면 하네스도 그에 맞게 바꿔야 합니다.

도구를 많이 추가한다고 결과가 좋아지는 것도 아닙니다. 플러그인과 의존성을 무작정 붙이면 컨텍스트에 불필요한 정보가 늘어납니다. 행맨 게임 하나를 만드는 데 71세션 전의 메모까지 포함하면 성능은 오히려 떨어집니다. 외부 도구로 검증된 기능은 모델의 기본 기능에 포함되기도 합니다. 스킬과 메모리, 작업 계획 기능이 그런 예입니다. 최신 하네스가 나올 때마다 구성을 바꾸기보다 필요한 것부터 시작하고, 실제로 문제가 생기면 보완하는 편이 낫습니다.

어떤 실패를 규칙으로 막을지, 결과를 받아들여도 될지, 언제 작업을 완료했다고 볼지는 사람이 판단해야 합니다. 하네스가 많아져도 이 판단을 동시에 여러 개 처리할 수는 없습니다. 하네스는 사람이 정한 기준을 에이전트에게 전달하고 따르게 하는 수단입니다. 그 기준을 정하는 일까지 대신해 주지는 못합니다.

결국 책임은 사람이 집니다

그래서 모든 길은 한 곳으로 모입니다. 오늘 나와 있는 어떤 에이전트도 완벽하지 않고, 설계와 구현의 상당 부분을 넘길 수는 있어도 결과에 대한 책임은 머지 버튼을 누른 사람의 몫으로 남습니다.

결과를 확인하고 책임지는 사람이 없다면 에이전트 이전에도 겪던 문제가 반복됩니다. 아무도 이해하지 못하는 시스템, 알 수 없는 설계 의도, 손대기 두려운 모듈이 다시 생깁니다. 코드를 더 빨리 만드는 만큼 이런 문제도 더 빠르게, 더 큰 규모로 쌓입니다. 생성 속도에 맞춰 검토할 준비가 되어 있지 않으면, 잘못된 결정도 그만큼 빠르게 코드에 반영됩니다.

Addy Osmani는 코딩 세션을 마칠 때마다 이렇게 묻는다고 합니다. "오늘 나는 뭔가를 배웠는가, 아니면 그냥 티켓만 닫았는가?" 결과물을 내는 것(Ship)과 배우는 것(Learn)은 별개입니다. 매니저와 고객은 주로 결과물을 묻기 때문에, 그 과정에서 무엇을 배웠는지는 스스로 챙겨야 합니다.

시스템을 깊이 이해해야 어떤 변경이 핵심 동작에 영향을 주는지 알아볼 수 있습니다. 리팩터링이 안전한지, 사용자가 의존하던 동작을 의도치 않게 바꾸는지도 판단할 수 있습니다. 코드 작성 비용이 줄어들수록 이런 판단을 할 수 있는 사람의 역할은 더 중요해집니다.

함께 이해하는 데서 시작합니다

팀에서 이런 문제를 함께 이해하고 이야기하는 데서 시작할 수 있습니다.

인지적 항복, 이해 부채, 인텐트 부채, 오케스트레이션 세금이라는 이름이 있으면 막연한 불안을 구체적으로 설명할 수 있습니다. "이 PR은 내 인지 용량을 넘었어"라거나 "이 결정은 인텐트를 남겨 두자"고 말할 수 있는 것입니다. 하네스의 역할도 함께 이해하면 어디까지 도구로 해결하고 어떤 판단은 사람이 맡아야 할지 논의할 수 있습니다.

이런 논의를 실제 작업에 반영하는 데 거창한 도구가 필요한 것은 아닙니다. 이미 쓰는 도구로 다음을 실천할 수 있습니다.

조직에서는 이 방식을 에이전트 개발 생애주기에 적용할 수 있습니다. 빌드와 테스트를 거쳐 배포하고, 운영 중의 동작을 관찰해 다음 개선에 반영하는 과정을 반복합니다. 각 단계의 결과를 확인할 수 있어야 빠르게 반복해도 문제를 발견할 수 있습니다. 여기에 비용과 도구 접근 권한을 관리하고, 필요한 도구와 자료를 쉽게 찾을 수 있게 하는 절차를 마련합니다. 그래야 반년 뒤 다른 사람이 이어받아 고칠 수 있는 시스템을 만들 수 있습니다.

내일, 다음 에이전트를 띄우기 전에

다음 에이전트를 실행하기 전에 이번 변경에서 잘못 판단하면 비용이 큰 결정 하나를 골라 이유를 적어 둡니다. 오늘 결과물만 냈는지, 시스템에 관해 새로 배운 것도 있는지 돌아봅니다. 그리고 실제로 리뷰를 끝낼 수 있는 에이전트 수를 정합니다.

에이전트와 함께 이전에는 엄두를 내지 못했던 일을 해내는 것은 즐거운 경험입니다. 그 경험을 오래 이어 가려면 코드가 늘어나는 만큼 이해와 검토에도 시간을 써야 합니다. 에이전트가 빠르게 만든 코드 중 무엇을 받아들이고 어떻게 운영할지는 끝까지 사람이 결정해야 합니다.