이제 에이전트를 여러 개 동시에 실행하는 건 어렵지 않다. 하지만 에이전트가 많이 돌아간다고 해서 당신의 가용 여력까지 늘어나는 건 아니다. 인지 대역폭(cognitive bandwidth)은 병렬화되지 않기 때문이다. 에이전트들의 방향을 잡아주고, 그들이 작성한 코드를 코드베이스에 병합하는 모든 판단은 결국 단 하나의 직렬 프로세서, 바로 당신을 통해야 한다. 오케스트레이션 세금이란 이 사실을 잊었을 때 치르는 대가다. 진짜 해결책은 하나뿐이다. 동시성 시스템을 설계하듯, 자신의 주의(attention)를 구조적으로 관리하는 것이다.
이번 주 Google I/O에서 Richard Seroter, Aja Hammerly, Ciera Jaspan과 함께 패널 토론에 참여했다. 지금 소프트웨어 엔지니어링이 어떤 모습인지, 앞으로 어떻게 변해갈지에 대한 이야기를 나눴다. 토론 말미에 Richard가 물었다. 개발자들이 오늘 여기서 뭔가 하나를 가져간다면 무엇이어야 하는가. 나는 몇 달째 맴돌고 있던 생각을 꺼냈다. 바쁘다는 느낌이 곧 생산성을 의미하지는 않는다는 것이다. 에이전트 20개를 돌리면 완전히 바쁜 것 같은 기분이 든다. 하지만 그게 에이전트 20개 분량의 결과물로 이어지지는 않는다.
토론 앞부분에서 Richard는 이 문제에 이름을 붙였다. "오케스트레이션 세금이라고 하셨죠." 그가 말했다. "혼자 머릿속으로 에이전트 스무 개를 제대로 관리할 수는 없으니까요." 완전히 옳은 말이다. 이 개념을 제대로 풀어보고 싶다. 이건 의지나 규율의 문제가 아니다. 설계의 문제다.
패널에서 내가 거의 즉흥적으로 내뱉은 말인데, 계속 머릿속에 맴돈다. 에이전트를 여러 개 돌린다고 해서 당신이 여러 명이 되는 건 아니다.
에이전트 기반 워크플로에는 숨겨진 비대칭이 있다. 에이전트를 시작하는 건 매우 싸다. 키 하나, 문장 하나면 된다. 하지만 에이전트가 한 일을 마무리하는 건 전혀 싸지 않다. 결과물이 올바른지 확인하고, 다른 에이전트가 건드린 부분과 조율하는 건 누군가의 몫이다. 그 누군가는 당신이다. 그리고 당신은 딱 한 명이다.
지난달 병렬 에이전트 한계에서 이 주제의 일부를 다뤘다. 주로 어떤 병렬 스레드가 조용히 실패하고 있는지 모를 때 느끼는 막연한 불안감에 대한 이야기였다. 이번 글은 그 비용의 실제 구조에 관한 것이다. 에이전트 개발을 동시성 시스템으로 바라보기 시작하면, 인간이 그 시스템 안에 있는 하나의 컴포넌트라는 사실이 보인다. 느리고, 직렬로만 동작하는 컴포넌트.
동시성 코드를 짜본 적 있다면 이미 올바른 직관을 갖고 있다. 다만 그 직관을 시스템의 잘못된 부분에 겨누고 있었을 뿐이다.
Python에는 전역 인터프리터 잠금(GIL, Global Interpreter Lock)이 있다. 스레드를 아무리 많이 만들어도, 실제로 Python 바이트코드를 실행하는 건 한 번에 하나뿐이다. 잠금을 획득해야 하기 때문이다. AI 에이전트에서 GIL은 바로 당신이다. 에이전트들은 동시에 실행될 수 있다. 하지만 그 결과물이 아키텍처에 대한 진짜 이해를 요구하거나 병합 충돌을 해결해야 할 때, 그 작업은 반드시 잠금을 획득해야 한다. 잠금은 하나다. 그걸 쥐고 있는 건 당신이다.
암달의 법칙은 이를 정확하게 설명한다. 병렬화로 얻을 수 있는 속도 향상은 직렬로 남아 있는 작업의 비율에 의해 상한이 정해진다. 파이프라인의 상당 부분을 병렬화할 수 없다면, 코어를 아무리 늘려도 결국 한계에 부딪힌다. 에이전트 개발에서 직렬 구간은 바로 판단이다. 에이전트를 8개로 늘린다고 판단하는 시간이 빨라지지 않는다. 판단을 기다리는 대기열만 더 깊어질 뿐이다.
성능 엔지니어링에서 오래된 사실이지만 여전히 많은 사람을 놀라게 한다. 병목이 아닌 부분을 최적화해도 처리량은 늘지 않는다. 병목 앞에 쌓이는 미완성 작업 더미만 커질 뿐이다. 에이전트를 추가하는 건 처음부터 병목이 아니었던 부분을 최적화하는 것이다. 진짜 병목은 검토 단계이고, 시스템 전체의 처리량은 바로 그 단계의 처리량과 정확히 같다. 오케스트레이션 세금은 에이전트의 생산 속도와 실제로 병합할 수 있는 속도 사이의 구조적 간극이다. 단일 스레드 자원에게 동시성 자원을 관리하게 했을 때 필연적으로 생기는 결과다.
패널에서 나는 이렇게 말했다. 도구 덕분에 그 어느 때보다 생산적이라고 느끼지만, 동시에 그 어느 때보다 피곤하다고. 두 가지 모두 완전히 사실이고, 원인도 같다.
피로감의 원인은 구체적이다. 여유 없이 100%로 가동되는 직렬 프로세서의 상태가 바로 그것이다. 한동안 신경 쓰지 못했던 에이전트를 확인할 때마다 컨텍스트 전환 비용이 발생한다. 머릿속을 비우고, 다른 컨텍스트를 처음부터 다시 불러와야 한다. CPU도 이 작업을 마이크로초 단위로 수행하면서, 아키텍트들은 이를 피하기 위해 공을 들인다. 사람은 이걸 분 단위로 하고, 컨텍스트를 완벽하게 복원하지도 못한다. 에이전트 다섯 개는 동일한 작업을 다섯 번 하는 것이 아니다. 다섯 번의 콜드 리로드에, 어떤 에이전트를 지금 확인해야 하는지 끊임없이 걱정하는 백그라운드 프로세스까지 더해진 것이다.
구조적 한계는 더 노력한다고 극복되지 않는다. 세금은 어떻게든 납부된다. 억지로 밀어붙이면, 한계는 얕은 코드 리뷰나 인지적 항복의 형태로 나타난다. 인지적 항복이란 스스로 판단을 내릴 주의력이 더 이상 남아 있지 않아서, 그냥 에이전트의 코드를 받아들여 버리는 상태다. 세금을 의식적으로 지불하거나, 아니면 그것이 조용히 자신의 시스템 이해를 갉아먹도록 내버려 두거나, 둘 중 하나다.
따라서 자신의 주의를 희소한 직렬 자원으로 대우해야 한다. 분산 시스템을 설계할 때 병목에 대해 진지하게 고민하듯, 자신의 뇌에도 같은 존중을 보여야 한다.
실제로 효과가 있었던 방법들이다.
에이전트 수는 UI가 아닌 검토 속도에 맞춰 조정하라. 잘 설계된 동시성 시스템은 역압(backpressure)을 사용해 대기열이 무한히 쌓이는 것을 막는다. 생산자가 소비자의 속도에 맞춰 늦추는 것이다. 에이전트 수가 생산자이고, 검토 속도가 소비자다. 적정 에이전트 수란 자신이 실제로 제대로 코드 리뷰할 수 있는 만큼이다. 대부분의 경우 한 자릿수 초반이다. AI 도구는 20개도 기꺼이 실행시켜 주겠지만, 그건 그냥 UI 기능일 뿐이다.
작업을 분류하라. Richard가 어떻게 헤쳐나가는지 물었을 때 이 방법을 이야기했다. 나는 작업을 두 가지로 나눈다. 하나는 독립적인 작업으로, 클라우드에서 백그라운드 에이전트에게 기꺼이 맡길 수 있는 것들이다. 이런 작업은 비동기로 실행되고, 대부분 최종 단계에서만 내가 개입하면 된다. 나머지는 판단 자체가 작업의 본질인 복잡한 과제들이다. 이상한 버그나 아키텍처 설계 같은 것들이다. 가장 큰 실수는 두 번째 더미를 병렬화하려는 것이다. 복잡한 작업을 동시에 여러 개 처리한다고 아웃풋이 늘어나지 않는다. 잠금 경합만 심해지고 모든 결과물이 나빠질 뿐이다.
검토는 묶어서 처리하라. 컨텍스트 전환은 할 때마다 무거운 비용을 치른다. 에이전트 4개를 한 번에 앉아서 검토하는 것은, 하나씩 확인하고 다른 일을 하다 돌아오는 것보다 훨씬 저렴하다. 에이전트에게 긴 줄을 줘라. 작업이 어느 정도 쌓이게 두고, 한꺼번에 처리하라.
잠금은 판단에만 써라. 기계가 스스로 검증할 수 있는 것에 뇌를 낭비하지 마라. 에이전트에게 통과하는 테스트를 작성하게 하거나 스크린샷을 생성하게 하라. 지루한 80%는 에이전트가 스스로 증명할 수 있다. 희소한 주의는 진짜 사람이 필요한 20%에만 써야 한다.
직렬 시간을 보호하라. 병목에는 에이전트 확인 사이사이 남은 자투리 시간이 아닌, 하루 중 가장 좋은 시간이 필요하다. 때로는 오케스트레이션을 완전히 멈추는 것이 가장 레버리지가 높은 선택이다. 에이전트로 가득한 노트북을 닫고, 잠금을 온전히 쥔 채 하나의 문제만 깊이 생각하는 것이다. 오케스트레이션은 진짜 작업이 아니다. 작업을 감싸는 오버헤드다.
Aja는 아키텍처가 지금 당장 필요한 핵심 역량이라고 짚었다. 어떤 것이 에이전트 하나에 들어가야 하고, 어떤 것이 너무 많은지 아는 것. 나는 여기에 덧붙이고 싶다. 당신도 그 시스템의 컴포넌트다. 당신의 주의에는 낮고, 이미 알려진 직렬 처리량이 있다. 시스템이 그 수치를 존중하거나, 아니면 조용히 당신의 기준을 낮추는 방식으로 그것을 우회하거나 둘 중 하나다.
이 부분이 정말 중요한 이유는, 실패 방식이 본인에게는 보이지 않기 때문이다. 에이전트 스무 개가 돌아가면 엄청난 생산성이 느껴진다. 대시보드는 가득 차 있고 모든 것이 움직인다. 하지만 그 느낌은 실제로 좋은 코드를 main에 배포하는 것과 전혀 별개다. 최대한 바쁘면서 거의 아무것도 만들어내지 못할 수 있다. 안에서는 구분이 되지 않는다.
Ciera는 Margaret-Anne Storey의 부채 연구를 언급했다. 우리는 기술 부채와 인지 부채에 대해 이야기했다. 갚지 않은 오케스트레이션 세금은 두 가지를 동시에 쌓는 방법이다. 제대로 읽지 않은 코드를 병합한다. 코드베이스에 대한 정신적 모델이 완전히 낡아버린다. 이 중 어느 것도 오늘의 대시보드에는 나타나지 않는다. 프로덕션이 터지고, 시스템을 들여다봤을 때 이게 어떻게 동작하는지 더 이상 모르겠다는 사실을 깨달을 때 나타난다.
결론은 이것이다. 에이전트를 띄우는 건 기술이 아니다. 20개는 누구나 실행할 수 있다. 진짜 기술은 복제도, 병렬화도 불가능한 단 하나의 직렬 자원을 중심으로 시스템을 설계하는 것이다. 그 자원은 당신의 주의다. 프로덕션에서 의존하는 다른 모든 것을 설계하듯, 그것을 설계하라.