
x3.16 개발자 | 파트 1
요약
AI를 활용해 생산성을 10배 높이는 'x3.16 개발자' 방법론을 소개합니다. 단순히 모델의 속도에 의존하는 대신, TDD와 정적 분석 등 구조적 제약을 통해 작업 품질을 높이고 동시에 여러 작업을 수행하는 스케일 아웃 전략을 강조합니다.
핵심 포인트
- AI 모델 자체의 성능보다 모델 주변의 개발 환경 최적화가 중요함
- TDD, 인수 테스트, 정적 분석을 통한 구조적 제약 설정 필요
- 작업 속도(Scale up)와 동시 작업량(Scale out)의 균형을 통한 생산성 극대화
- 반복적인 피드백 루프를 통한 워크플로의 자동화 및 일반화
요약 (TL;DR)
이 특정 작업 이상의 가치를 지닌 것이 무엇인지 파악하고, 이를 자신의 환경(setup)에 다시 피드백하는 데 시간을 투자하는 것이 당신이 할 수 있는 가장 레버리지가 높은(highest-leverage) 단 한 가지 일입니다.
1. 약속과 격차
요즘 모두가 x10 개발자를 쫓고 있습니다. AI가 당신을 10배 더 생산적으로 만들어 줄 수 있다고들 말합니다. 10배 더 빠르게 결과물을 내놓고(Ship), 한 팀의 업무량을 혼자 해내라고 말이죠.
제가 코딩에 AI를 사용하기 시작했을 때, 당연한 선택은 더 빨라지는 것이었습니다. 가장 좋은 LLM(대규모 언어 모델)을 코드베이스(codebase)에 연결하고, 크기와 복잡도가 적절한 작업을 부여한 뒤, 제가 따라잡을 수 없을 정도로 빠르게 코드를 변경하는 모습을 지켜보는 것이었죠. 하지만 그것은 효과가 없었습니다. 모델은 맞는 것처럼 보이는 결과물을 만들어냈지만, 저는 직접 만드는 것보다 수정하고 다시 추적하는 데 더 많은 시간을 소비하게 되었습니다. 6개월마다 상황을 개선해 주는 새로운 모델이나 도구가 출시되었지만, 그 격차를 진정으로 메워주는 것은 없었습니다. 제 생각에 저는 아마 x1.25 정도에 도달했을 것입니다.
천천히, 저는 다시 예전의 원칙들로 돌아갔습니다. TDD(테스트 주도 개발), 인수 테스트(acceptance tests), 정적 분석(static analysis): 위험한 영역 주변에 구조적 제약(structural constraints)을 두는 것이었습니다. 작업이 반복될 때마다 저는 모델의 코딩을 지원하는 요소들을 회고(retrospect)하고, 수정하고, 일반화하고, 자동화했습니다. 그리고 효과가 나타나기 시작했습니다. 모델이 좋아졌기 때문이 아니라, 모델 주변의 모든 것이 좋아졌기 때문입니다. 작업 품질이 올라갔고, 제가 직접 속도를 최적화하지 않았음에도 속도가 뒤따라왔습니다. 어느 시점에 이르자 작업당 요구되는 주의력이 충분히 낮아져서 두 개의 작업을 동시에 수행할 수 있게 되었습니다. 그다음은 세 개였습니다. 현재 저의 정점은 세 개의 코딩 작업을 동시에 실행하면서 디자인 브레인스토밍(design brainstorm)을 함께 진행하는 것입니다.
제가 생각하는 방식은 이렇습니다. x10은 두 개의 축으로 나뉩니다: 각 작업이 더 빠르게 완료되는 '스케일 업(scale up)', 그리고 더 많은 작업을 동시에 실행할 수 있는 '스케일 아웃(scale out)'입니다. 만약 각 축에서 x√10에 도달할 수 있다면, 총 x10을 얻게 됩니다. √10 = 3.16입니다. 이것이 제목의 유래입니다.
다음에 이어질 내용은 방법론입니다. 제가 시스템을 어떻게 생각하는지, 어떻게 최적화하는지, 그리고 피드백 루프 (feedback loops)가 어떤 모습인지에 대해 다룹니다. 구체적인 도구와 워크플로 (workflows)는 별도의 글로 다룰 예정입니다.
2. 엔진 (The Engine)
LLM (대규모 언어 모델)에 대해 가장 먼저 이해해야 할 점은, 이들이 기본적으로 문장에서 다음에 올 내용을 예측하도록 훈련된 후, 도움이 되도록 미세 조정 (fine-tuned)되었다는 것입니다. 이는 모델이 사용자에게 '좋은 답변처럼 보이는' 무언가를 제공하려는 강력한 경향성을 가지고 있음을 의미합니다. 반드시 '좋은 답변인' 것이 아니라, '좋은 답변처럼 보이는' 것에 가깝습니다. 저는 이를 방향 감각이 없는 매우 강력한 엔진이라고 생각합니다.
사람과 함께 일할 때는 그들이 도메인 지식 (domain knowledge)을 가지고 있고, 결과에 대한 이해관계가 있으며, 문제를 이해하고 있습니다. LLM은 이 중 어느 것도 가지고 있지 않습니다. LLM은 그저 메시지 하나하나마다 지금 당장 가장 도움이 될 것 같은 방향으로 끌리는 경향성만을 가질 뿐입니다. 그리고 많은 경우 그것이 실질적인 내용처럼 보이지만, 항상 실제로 내용이 알찬 것은 아닙니다.
이것이 대략 환각 (hallucinations)이 발생하는 방식입니다. 환각을 일으킨 답변은 해박하고, 자신감 있으며, 관련성이 있어 보입니다. 모델이 그렇게 설계되었기 때문에 사용자의 즉각적인 품질 검사를 통과해 버립니다. 모델이 당신을 속이려고 노력하는 것이 아니라, 단지 시스템이 작동하는 방식이 그러한 것입니다.
단순히 채팅을 하거나, 질문을 던지거나, 브레인스토밍 (brainstorming)을 하는 경우에는 대부분 잘 작동합니다. 왜냐하면 '맞게 들리는 것'과 '실제로 맞는 것'이 대부분 일치하기 때문입니다. 문제는 상황이 복잡해질 때 발생하며, '맞게 들리는 것'과 '실제로 맞는 것' 사이의 괴리가 더 커지기 시작합니다. 도메인이 복잡해질수록, 도움이 되는 것처럼 보이려는 이러한 경향성은 오히려 역효과를 낳게 됩니다.
제가 이를 내면화하는 데는 시간이 좀 걸렸습니다. 모델은 그 모든 지능을 갖추고 있음에도 불구하고, 시스템 내에서 가장 신뢰할 수 없는 부분이라는 사실 말입니다. 엔지니어들은 본능적으로 LLM (Large Language Model)을 핵심으로 취급하고 그 주변을 불확실성으로 감싸려 합니다. 하지만 LLM은 사실 무작위성 (Randomness)이 더해진 통계적 추측 상자일 뿐입니다. 본질적으로 합리적이지 않습니다. 그 주변의 모든 것들은 바로 그 점을 보완해야만 합니다.
3. 하네스 (The Harness)
따라서 LLM이 엔진이라면, 이를 실제로 사용 가능하게 만드는 것은 그 주변을 둘러싼 모든 것들입니다. 시스템 프롬프트 (System prompts), 도구 (Tools), 검증 단계 (Verification steps), 컨텍스트 관리 (Context management), 가드레일 (Guardrails) 등이 그것입니다. 에이전트 엔지니어링 (Agent engineering)에서는 이를 하네스 (Harness)라고 부릅니다. 기본적으로 모델과 현실 사이의 모든 것을 의미합니다.
에이전트가 실패할 때, 반사적으로 프롬프트를 다시 작성하려 합니다. 더 많은 세부 사항을 추가하고, 더 구체적으로 작성하는 식이죠. 하지만 에이전트의 행동은 프롬프트만이 아니라 전체 시스템에서 비롯됩니다. 하네스 수준에서의 구조적 수정은 프롬프트 수정보다 흔히 한 자릿수(an order of magnitude) 더 뛰어난 성능을 보여줍니다.
Tejas Kumar는 최근 2023년 시대의 모델인 GPT-3.5 Turbo를 사용하여, 오직 하네스 엔지니어링 (Harness engineering)만으로 다단계 브라우저 작업을 성공적으로 완료했습니다 (그의 훌륭한 강연을 여기서 시청하세요). 그는 이어 하네스에는 다음과 같은 가동 부품들이 있다고 설명했습니다.
- 도구 레지스트리 (Tool registry): 모델이 실제로 무엇을 할 수 있는지, 그리고 이러한 능력을 어떻게 인지하는지에 대한 것.
- 컨텍스트 관리 (Context management): 지금까지 진행된 대화의 작업 기억 (Working memory). 이는 긴 세션 동안 성능이 저하되는 부분입니다.
- 가드레일 (Guardrails): 실패를 빠르게 감지하는 메커니즘 (Fail-fast mechanisms). 최대 재시도 횟수 (Max retries), 권한 (Permissions), 리소스 제한 (Resource caps) 등.
- 에이전트 루프 (The agent loop): 생각하고 (Think), 행동하고 (Act), 결과를 관찰하고 (Observe the result), 다음 단계를 결정하는 (Decide what's next) 과정.
- 검증 (Verification): 모델이 주장하는 내용과는 독립적으로, 모델이 수행한 작업이 실제로 작동했는지 확인하는 것.
마지막 단계는 "성공한 것처럼 보이는 것"과 "실제로 성공한 것" 사이의 간극을 메워줍니다. 이 단계가 없다면, 여러분은 모델이 자신의 출력을 스스로 판단하도록 신뢰하게 됩니다. 그리고 모델은 모든 것이 아주 잘 되었다고 말하려는 편향 (Bias)을 가지고 있습니다.
Tejas Kumar가 완전히 자율적인 에이전트 (Autonomous Agents)의 맥락에서 이야기할 수도 있겠지만, 이것은 자율 주행 자동차가 아닙니다. 여러분은 운영의 중심에 있습니다. 엔진이 힘든 일을 대신 수행하지만, 어디로 갈지, 언제 멈출지, 그리고 생성된 결과물이 실제로 필요한 것인지 결정하는 것은 여러분입니다. 하네스 (Harness)는 그 주변에 설정됩니다. 하네스가 모든 것을 스스로 처리할 필요는 없습니다. 하네스는 여러분의 개입 (Intervention) 비용을 낮추고 감독 (Oversight)을 쉽게 만들어 줄 필요가 있습니다. 모든 자동화는 작업을 수동으로 수행하며 프로세스를 학습하는 것에서 시작하여, 부분적으로 자동화해 나가는 과정을 거칩니다.
4. 드라이버-메카닉 (The Driver-Mechanic)
이제 엔진과 자동차가 있습니다. 하지만 어딘가로 이동하려면 드라이버 (Driver)가 필요합니다.
드라이버는 엔진이나 자동차와 마찬가지로 시스템의 대등한 구성 요소입니다. 무엇을 확인할지, 어디에 에너지를 아낄지, 모델의 출력을 어떻게 검토할지, 언제 개입하기로 결정할지, 작업을 어떻게 정의할지 — 이것들은 개인마다 다르며 시간이 흐름에 따라 변하는 기술이자 직관입니다. 그것이 바로 드라이버의 역할입니다.
현재 범용 AI 코딩 (General-purpose AI-coding)은 자동차의 초기 시절과 매우 흡사합니다. 기술은 작동하지만, 아무 생각 없이 그냥 사용할 수 있는 단계는 아닙니다. 만약 여러분이 1905년에 자동차를 소유했다면, 도구 상자를 들고 다녔을 것이며 엔진에 대해 잘 알고 있었을 것입니다. 운전과 유지보수 (Maintenance)가 아직 분리되지 않았기 때문입니다.
코딩 하네스 (Coding harnesses)의 현재 상황이 대략 이와 같습니다. 여러분은 단순히 도구를 사용하는 것이 아니라, 그 도구를 미세 조정하고 유지보수하는 사람이기도 합니다. 그리고 정말 좋은 결과물은 아직 범용화 (Commoditized)되지 않았습니다. 여러분은 스스로, 그리고 여러분을 중심으로 그 결과물을 직접 만들어내야 합니다.
따라서 이것이 우리가 최적화해야 할 대상입니다. 엔진(Engine)은 고정되어 있습니다. 하네스(Harness)는 엔지니어링이 가능합니다. 드라이버(Driver)는 연습과 피드백을 통해 개선되며, 동시에 하네스도 개선합니다. 그리고 계층 간의 인터페이스(Interfaces), 바로 그곳에 대부분의 가치가 존재하며 대부분의 문제가 발생하는 지점입니다.
5. 최적화 프로세스 (The Optimization Process)
제조업에서 유래하여 매우 대중화된 아이디어가 하나 있습니다. 1950년대 Toyota는 생산량이나 자본 측면에서 미국 제조업체들과 경쟁할 수 없었습니다. 그래서 그들은 대신 프로세스(Process)에 집중했습니다. 그들은 품질과 낭비 감소에 관한 Deming과 같은 인물들의 아이디어를 가져와서, 모든 수준에서 지속적으로 자신들의 작업 방식에 내재화했습니다. 이 접근 방식을 카이젠(Kaizen)이라고 부릅니다. 그 핵심은 프로세스에서 낭비를 계속해서 찾아내고 제거하는 과정을 반복함으로써, 개선 사항들이 복리로 쌓이게(Compound) 만드는 것입니다.
직접적으로 적용 가능한 몇 가지 원칙은 다음과 같습니다:
- 처리량(Throughput)을 최적화하라, 용량(Capacity)이 아니라. 중간 어디에선가 전력의 절반을 잃고 있다면 강력한 엔진은 아무런 의미가 없습니다.
- 낭비를 제거하라. 도구와 싸우는 시간을 포함하여, 출력(Output)에 기여하지 않는 모든 것을 제거하십시오.
- 피드백 루프(Feedback loop)를 단축하라. 사이클당 학습 속도가 빠를수록 개선 속도도 빨라집니다.
- 작은 배치(Small batches). 더 작은 반복(Iteration)이 문제를 더 빨리 드러냅니다.
- 라인을 멈춰라(Stop the line). 결함이 전파되도록 두지 마십시오. 나중이 아니라 지금 수정하십시오.
또한 제가 알고 있는 '완료의 숭배 (Cult of Done, Bre Pettis와 Kio Stark 저)'라는 개념이 있는데, 이는 대략적으로 "완료는 더 많은 것을 만드는 엔진이다. 불완전한 것을 출시하고, 그것으로부터 배우며, 다음 것을 더 나은 상태로 출시하라"라고 말합니다. AI 도구를 사용할 때 빠지기 쉬운 유혹은 매 반복마다 더 많은 영역을 점유하고, 더 많은 일을 하며, 더 멀리 확장하려는 것입니다. 이는 표류(Drift)를 초래합니다. 작은 단위의 완결(Small completions)을 강제하는 것이 이에 대응하는 방법입니다.
이제 다시 하네스(Harness)를 개선하는 문제로 돌아와 봅시다:
이 특정 작업 너머로 무엇이 가치가 있는지 파악하는 데 시간을 할애하고, 그것을 여러분의 설정(Setup)에 다시 반영하는 것이 여러분이 할 수 있는 단일 항목 중 가장 레버리지가 높은(Highest-leverage) 일입니다. 이것은 화려하지 않습니다. 그것은 자동차를 정비하는 정비사로서의 여러분의 모습입니다. 그것은 배우고 있는 드라이버로서의 여러분의 모습입니다. 그리고 이것은 LLM과는 아무런 관련이 없습니다.
이것이 바로 복리로 쌓이는 것입니다.
6. 인터럽트 루프 (Interrupt Loop, 안돈 코드 (Andon Cord))
작업 수행 중, 드라이버 (Driver)에서 하네스 (Harness)로 전달되는 즉각적인 피드백.
잘못된 작업에 대한 저의 기본 해결책은 보통 작업을 재시작하는 것입니다. 하지만 저는 가능한 한 전역적 재시작 (Global restart)보다는 국소적 수리 (Local repair)를 사용하는 것을 선호하며, 이를 위해서는 실행 가능한 시점에서의 조기 탐지가 필요합니다. 재시작은 컨텍스트 (Context), 진행 상황, 웜업 (Warmup) 등 모든 것을 잃게 만듭니다. 반면 국소적 수리는 조기에 발견하기만 한다면 비용이 거의 들지 않습니다.
Toyota의 공장에서는 결함을 발견하면 어떤 작업자라도 안돈 코드 (Andon cord)를 당겨 생산 라인을 멈출 수 있었습니다. 이것은 시스템의 실패가 아니라, 시스템이 의도한 대로 작동하고 있는 것입니다. 결함이 하류 (Downstream)로 전파되는 대신 발생 지점에서 수정됩니다.
여러분이 작업을 수행할 때도 마찬가지입니다. 에이전트 (Agent)가 코드를 생성하다가 경로를 이탈하여 불필요한 추상화 (Abstraction)를 추가하거나, 나중에 비용을 치르게 될 방식으로 무언가에 접근하기 시작합니다. 이때 여러분은 인터럽트 (Interrupt)를 겁니다. 처음부터 다시 시작하기 위해서가 아니라, 국소적 수리를 하기 위해서입니다.
때로는 프롬프트 조정 (Prompt adjustment)일 수도 있습니다. 때로는 에이전트에게 필요한 컨텍스트가 없다는 것을 깨닫거나, 도구 (Tool)가 에이전트를 잘못된 길로 인도하고 있다는 것을 알게 될 수도 있습니다. 때로는 무언가를 추가하는 것이 아니라 제거하는 것이 해결책이 되기도 합니다.
본능적으로는 작업이 끝날 때까지 내버려 두게 됩니다. 하지만 그것이 바로 결함이 전파되는 방식입니다. 나중에는 항상 더 많은 비용이 듭니다. 무언가 잘못되었다고 처음 느껴질 때, 설령 확신이 없더라도 코드를 당기십시오. 단지 여러분이 잘못되었다고 생각하는 이유를 설명해 달라고 요청하거나, 문제가 될 것 같은 특정 과제를 어떻게 처리할 계획인지 물어보기 위해서라도 말입니다. 이 습관에는 두 가지 훌륭한 부수 효과 (Side-effect)가 있으며, 상황이 잘 진행되고 있다고 판단되면 언제든
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기

