AI에게 공정을 맡겨도 개발 방식은 변하지 않는다
요약
AI 에이전트를 활용하여 소프트웨어 개발 공정을 자동화하는 방식을 논하며, 기존의 '공정별 에이전트' 구성과 'AI 네이티브한 재설계'를 비교합니다. 단순히 인간의 공정을 AI로 대체하기보다, 목적과 제약을 정의하고 AI에게 자유로운 판단을 위임하는 것이 중요함을 강조합니다.
핵심 포인트
- 개발은 공정 자동화보다 개발 방식 자체의 재설계가 필요하다.
- AI 네이티브 개발에서는 '무엇을 달성할지'와 '어떻게 도달할지'를 분리해야 한다.
- 인간은 목적, 제약, 완료 조건을 정의하고 AI에게 실행 절차를 위임하는 것이 효과적이다.
서론
AI 에이전트를 활용한 소프트웨어 개발에서는, 요구사항 정의, 설계, 구현, 테스트와 같은 기존의 개발 공정에 각각 전용 에이전트를 배치하는 구성이 고려될 수 있다.
요구사항 정의 에이전트가 사양을 만들고, 설계 에이전트가 설계서를 생성하며, 구현 에이전트가 코드를 작성하고, 테스트 에이전트가 검증한다. 이들을 연계하면 개발 프로세스의 많은 부분을 자동화할 수 있다.
하지만 여기서 한 가지 생각해 볼 것이 있다.
인간이 해왔던 공정을 AI로 대체하는 것과, AI를 전제로 개발 진행 방식 자체를 재설계하는 것은 같은 것일까?
AI는 코드를 조사하고, 구현 방법을 생각하며, 테스트를 실행하고, 그 결과로부터 문제를 특정하여 수정할 수 있다. 태스크에 따라서는 처음부터 모든 공정이나 실행 순서를 고정하기보다는, 목적과 제약을 부여하고 상황에 따라 다음 행동을 판단하게 하는 것이 더 합리적일 수도 있다.
한편으로, AI에게 자유롭게 작업을 시키면 되는 것도 아니다. 업무상의 제약을 지키고, 기존 기능에 미치는 영향을 억제하며, 완성된 것을 검증할 수 없다면 개발을 맡길 수 없다.
그렇다면, AI 네이티브한 개발에서는 무엇을 미리 정의하고, 무엇을 AI에게 위임하며, 어떻게 성과를 보장해야 할까?
본고에서는 이 질문을 기점으로 스펙트럼 구동 개발(Spec-Driven Development), 오케스트레이션, 스킬, 툴, 하네스(Harness)의 역할을 정리하고, 구체적인 개발 기반의 구성을 생각해 본다.
1. 공정별 에이전트는 AI 네이티브인가
예를 들어, 다음과 같은 구성을 생각해 볼 수 있다.
요구사항 정의 에이전트
↓
설계 에이전트
...
이 구성에는 장점이 있다. 각 에이전트의 책무를 분리하기 쉽고, 입력과 출력을 정의할 수 있다. 공정별로 필요한 지식이나 툴을 할당하는 것도 가능하다.
기존 개발 프로세스를 자동화하는 방법으로는 충분히 합리적이다.
다만, 공정을 나눴다고 해서 개발 진행 방식 자체를 AI용으로 재설계한 것은 아니다.
예를 들어, 기존 시스템의 장애 수정이라면, 처음에 상세 설계서를 만드는 것보다 로그나 코드를 조사하여 원인을 특정하는 것이 먼저일 수 있다.
사양이 명확한 API 추가라면, 필요한 변경 위치를 특정하여 구현하고 테스트를 실행하는 것만으로도 충분할 때가 있다.
새로운 기술 방식을 검토하는 경우에는, 구현 가능성을 확인하는 실험이 먼저 필요할 때도 있다.
즉, 태스크에 따라 적절한 진행 방식은 다르다.
그럼에도 불구하고 모든 태스크를 같은 공정에 적용하면, AI의 판단 능력을 활용할 여지가 작아진다.
여기서 문제가 되는 것은 에이전트의 수가 아니다.
무엇을 달성해야 할지뿐만 아니라, 그것에 도달하기까지의 절차까지도 인간이 고정해야 하는가?
이 질문을 생각하려면, AI에게 맡길 부분과 인간이 미리 정의할 부분을 나누어야 한다.
2. AI에게 맡기는 것과 인간이 정의하는 것
AI에게 실행 절차를 위임하더라도, 아무것도 정의하지 않고 작업을 시작하게 할 수는 없다.
적어도 달성해야 할 목적, 지켜야 할 제약, 완료를 판단하는 조건은 명확히 해둘 필요가 있다.
예를 들어, 사용자 등록 API를 구현할 경우, 다음과 같은 조건을 정의할 수 있다.
- 필수 항목이 입력되어야 함
- 이메일 주소 형식이 올바르야 함
- 동일한 이메일 주소의 중복 등록을 방지해야 함
- 입력 미비나 업무상의 오류를 적절하게 처리해야 함
- 인증 정보나 개인 정보를 불필요하게 노출하지 않아야 함
- 기존 API 계약이나 관련 기능에 의도치 않은 변경을 가해서는 안 됨
이것들은 AI가 어떤 방법으로 구현하든 충족해야 하는 조건이다.
한편, 구체적인 클래스 구성, 처리 분할 방식, 수정 대상 파일 등은 기존 코드나 프로젝트의 규약을 조사한 후 AI가 판단할 수 있는 경우도 있다.
이렇게 달성해야 할 상태와, 그 상태에 도달하기까지의 절차를 나누어 생각한다.
이러한 사고방식과 관련되는 것이 스펙트럼 구동 개발(Spec-Driven Development, SDD)이다.
스펙트럼 구동 개발에서는 사양이나 수용 조건을 명확히 하고, 그것들을 구현 및 검증의 기준으로 활용한다.
AI를 활용하는 경우에도, 스펙은 중요한 역할을 한다. 무엇을 충족해야 하는지가 명확하다면, AI는 구현 방법을 검토하고, 결과물을 조건에 비추어 확인할 수 있다.
다만, 스펙을 정의하는 것과 실행 절차를 모두 고정하는 것은 별개이다.
사양이 명확하면, 그 사양에 따라 구현을 진행하면 된다. 기존 시스템의 사양이 불명확하다면, 코드나 테스트를 조사한 후 스펙을 구체화할 필요가 있다. 미지의 문제를 해결하는 경우에는, 조사나 실험을 통해 사양 자체를 업데이트하기도 한다.
따라서, 스펙트럼 구동 개발을 부정할 필요는 없다.
중요한 것은 스펙을 달성해야 할 상태나 제약의 정의로 다루고, 모든 태스크에 대해 실행 절차까지 일률적으로 고정하지 않는 것이다.
그렇다면 목적과 제약을 정의하면서도 실행 절차를 고정하지 않는다면, 개발을 진행하기 위한 판단은 누가 맡게 되는 것일까?
3. 고정된 공정에서 상황에 따른 실행으로
실행 절차를 미리 고정하지 않을 경우, AI는 작업의 상황을 파악하여 다음 행동을 선택할 필요가 있다.
예를 들어, 사용자 등록 화면을 작성하는 경우에도 기존 화면을 조사해야 할 수도 있고, 기존 컴포넌트를 활용하여 바로 구현할 수 있을 수도 있다.
구현 후에 테스트가 실패한 경우에는 에러를 조사하고 코드를 수정하여 다시 테스트를 실행할 필요가 있다.
이러한 개발에서는 처음에 정의한 공정을 순서대로 통과하는 것뿐만 아니라, 실행 결과를 바탕으로 다음 행동을 판단하는 메커니즘이 필요하게 된다.
이 역할을 담당하는 것이 오케스트레이션(Orchestration)이다.
3.1 오케스트레이션과 독립된 제어 프로그램은 별개다
오케스트레이션이라는 단어에서 Python 등으로 구현한 독립적인 제어 프로그램을 상상할 수 있다.
하지만, 오케스트레이션이라는 기능과 그것을 실현하는 프로그램은 구분해서 생각해야 한다.
LLM에게 목적, 제약, 사용 가능한 툴(Tool)을 주면, LLM 스스로 다음 행동을 선택하고, 툴을 호출하며, 결과를 해석하고, 필요에 따라 재실행하는 구성을 만들 수 있다.
개념적으로는 다음과 같은 흐름이다.
목적・제약・완료 조건
↓
다음 행동 판단
...
이 구성에서는 독립적인 오케스트레이터(Orchestrator)를 준비하지 않아도, LLM이 오케스트레이션의 역할을 담당할 수 있다.
반면, LLM의 판단에만 의존할 필요는 없다.
예를 들어, 실행 횟수의 상한선, 파일 조작 권한, 프로덕션 환경 연결 금지, 인간의 승인이 필요한 작업 등은 외부 제어 기구(Control Mechanism)로 강제하는 것이 좋다.
즉, AI에게 다음 행동을 판단하게 하는 것과, 그 행동이 실행 가능한지를 제어하는 것은 별개의 책임이다.
이 차이점을 고려하면, 다음 문제가 눈에 띈다.
AI가 행동을 판단하는 것만으로도 적절한 개발을 실현할 수 있을까.
4. AI가 적절하게 행동할 수 있는 개발 기반
AI가 상황에 따라 행동을 선택할 수 있게 하더라도, 그것만으로는 개발을 맡길 수 없다.
프로젝트 고유의 규약을 알지 못하면 기존 설계 방침에서 벗어날 수도 있다. 필요한 툴이 없으면 구현 결과를 충분히 확인할 수 없다. 테스트에 실패해도 그 결과를 무시하고 완료로 판단할 수 있는 구성이라면, 미완성 결과물을 반환할 가능성이 있다.
즉, 필요한 것은 행동을 판단하는 메커니즘만은 아니다. 적절하게 행동하기 위한 지식, 실행 수단, 제약, 검증의 메커니즘을 일체로 설계하는 것이다.
여기서 각 책임(責務)을 정리한다.
| 요소 | 주요 책임 |
|---|---|
| 에이전트 (Agent) | 목적 달성에 대한 판단과 행동 선택 |
| ... | |
| 이들은 반드시 독립적인 프로그램으로 구현할 필요는 없다. 개념상의 책임을 정리한 것이며, 실제 구현에서는 하나의 실행 환경이 여러 역할을 담당하는 경우도 있다. |
4.1 스킬 (Skill): 필요한 지식과 작업 방법을 제공한다
예를 들어, 프론트엔드 개발에서는 기존 디자인 규약, 컴포넌트 활용 방침, 접근성 확인 사항 등이 필요하다.
이것들을 스킬이나 프로젝트 지시로 정리하면, AI가 매번 제로(zero)부터 규약을 추측할 필요가 없어진다.
스킬은 모든 작업을 고정하기 위한 것은 아니다. 적절한 판단을 내리기 위한 지식이나 단서를 제공하는 것이다.
4.2 툴 (Tool): 실행과 검증을 가능하게 한다
AI가 코드를 작성할 수 있어도, 실제로 빌드되는지, 테스트가 통과하는지, 브라우저 상에서 의도한 화면이 되는지는 실행하여 확인해야 한다.
파일 조작, 테스트 실행, 정적 분석(Static Analysis), 브라우저 조작 등의 툴은 AI의 판단을 구체적인 행동으로 바꾼다.
특히, 완료 조건과 관련된 사항은 가능한 한 기계적으로 검증할 수 있도록 하는 것이 좋다.
4.3 하네스 (Harness): 행동을 제어하고 결과로부터 수정할 수 있게 한다
하네스는 단순히 AI가 해서는 안 되는 것을 나열하는 메커니즘이 아니다.
적절한 컨텍스트를 제공하고, 행동의 제약을 걸며, 검증 결과를 피드백하고, 재시도나 종료를 제어하는 메커니즘으로 생각해야 한다.
예를 들어, 테스트에 실패했을 경우에는 실패 내용을 AI에게 돌려주어 수정을 촉구한다. 반면, 일정 횟수 실패했거나 권한이 필요한 작업이 필요해졌을 경우에는 처리를 중단하고 인간의 판단을 구한다.
다만, 프롬프트로 금지 사항을 지시하는 것만으로는 엄밀한 제어가 되지 않는다. 필요한 권한이나 작업 제한은 실행 환경 측에서도 강제해야 한다.
여기까지 오면서, 목적을 정의하고 상황에 따라 행동을 판단하며, 지식이나 도구를 이용하는 동시에 제약과 검증을 통해 성과를 보장한다는 구성이 눈에 보이게 되었습니다.
그렇다면 이것들을 실제 개발 작업에 적용하면 어떤 메커니즘이 될까요?
5. 사용자 등록 화면을 일관되게 만들기
여기서는 기존 웹 애플리케이션에 사용자 등록 화면을 추가하는 경우를 생각해 보겠습니다.
요청은 다음과 같습니다.
기존 사이트 디자인에 맞춰 사용자 등록 화면을 만들어 주세요. 스마트폰에도 대응하고, 입력 오류를 적절하게 표시해 주세요. 구현 후 브라우저에서 확인하고, 문제가 있으면 수정해 주세요.
5.1 목적과 제약을 부여하기
먼저, 요청 내용을 목적과 수용 조건으로 정리합니다.
예를 들어, 다음과 같은 조건이 있습니다.
- 기존 사이트 디자인 및 컴포넌트 이용 방침을 따를 것
- 필수 항목과 입력 검증을 구현할 것
- 오류를 사용자가 이해할 수 있는 형태로 표시할 것
- 스마트폰에서도 조작 가능할 것
- 관련 테스트를 실행할 것
- 브라우저 상에서 표시와 조작을 확인할 것
- 기존 기능에 의도치 않은 영향을 주지 않을 것
이 조건을 충족시키기 위해, 구체적으로 어떤 파일을 변경하고, 어떤 컴포넌트를 이용하며, 어떤 순서로 작업할지는 처음부터 모두 고정하지 않습니다.
5.2 에이전트가 상황을 조사하고 다음 행동을 결정하다
에이전트는 먼저 프로젝트의 구성이나 기존 화면을 조사합니다.
기존의 폼 컴포넌트가 있다면 재사용할 수 있습니다. 디자인 시스템(Design System)이 정비되어 있다면, 그 규약을 참조합니다. 유사한 화면이 없다면, 기존 설계 방침으로부터 적절한 구현 방법을 검토합니다.
여기서의 목적은 반드시 상세 설계서를 만드는 것이 아닙니다. 적절한 구현에 필요한 정보를 얻는 것입니다.
조사 결과에 따라 바로 구현으로 나아갈 수 있습니다. 사양(Specification)에 불명확한 점이 있다면 추가 조사를 수행합니다. 업무상의 판단이 필요하다면, 사람에게 확인을 받습니다.
5.3 구현하고 결과를 검증하다
구현 후에는 브라우저에서 화면을 표시하여 실제 상태를 확인합니다.
예를 들어, 다음과 같은 문제가 발견될 수 있습니다.
- 스마트폰 폭에서 버튼이 화면을 벗어남(overflow)
- 입력 오류 표시로 인해 레이아웃이 무너짐
- 키보드 조작으로 폼을 적절하게 이용할 수 없음
- 기존 테스트가 실패함
문제가 있다면, 에이전트는 결과를 분석하고 수정하여 재검증합니다.
다만, 스크린샷을 얻었다는 것만으로는 품질이 보장되는 것은 아닙니다. 대상에 따라 브라우저 조작, 테스트, 접근성 확인(Accessibility Check), 요구사항과의 대조를 조합할 필요가 있습니다.
또한, 사용자 등록의 경우, 화면 표시뿐만 아니라 서버 측의 입력 검증, 인증 정보 처리, 중복 등록 방지 등도 별도로 확인해야 합니다.
5.4 완료 조건을 충족하면 종료하다
마지막으로, 실행 결과를 수용 조건과 대조합니다.
테스트가 실패했거나, 필수 항목이 구현되지 않았거나, 심각한 표시 오류가 남아 있는 등의 경우에는 '완료'라고 판단하지 않습니다.
수정이 가능하다면 작업을 계속하고, 판단이 필요하면 사람에게 확인을 받습니다.
여기서 중요한 것은, 에이전트가 '작업을 마쳤다'고 판단하는 것과 시스템이 '완료 조건을 충족했다'고 확인하는 것을 구분하는 것입니다.
후자(시스템의 확인)에 대해서는 가능한 한 기계적으로 판정할 수 있도록 합니다.
이 예시에서는 디자인, 구현, 테스트라는 작업 자체는 존재합니다. 하지만 모든 것을 독립된 에이전트에게 할당하고 고정된 순서로 실행할 필요는 없습니다.
목적과 제약을 기준으로 필요한 행동을 판단하고, 실행 결과에 따라 진행 방식을 업데이트하는 것이 핵심이 됩니다.
6. 오케스트레이터(Orchestrator)를 만들어야 할까
지금까지의 구성을 실현하기 위해 독자적인 오케스트레이터를 구현할 필요가 있을까요?
답변은 기존 실행 환경이 어느 정도 기능까지 제공하는지에 따라 다릅니다.
에이전트 SDK(Agent SDK) 등이 도구 호출, 실행 결과를 바탕으로 한 재판단, 실행 상태 관리 등을 제공하고 있다면, 그것들을 이용할 수 있습니다.
독자 구현을 검토하는 것은 기존 환경으로는 충족할 수 없는 제어 요건(Control Requirement)이 있을 경우입니다.
예를 들어, 다음과 같은 요건들이 생각될 수 있습니다.
- 조작 권한을 엄격하게 제한할 것
- 실행 횟수나 타임아웃을 강제할 것
- 작업 상태를 영속화(Persist)할 것
- 인간의 승인이 필요한 조작을 정의할 것
- 특정 테스트가 성공하지 않으면 완료로 인정하지 않을 것
- 실행 이력을 감사 가능하게 할 것
개념적으로는 다음과 같은 실행 루프를 생각할 수 있습니다.
def run_task(task):
context = prepare_context(task)
while True:
...
이 예시에서는 에이전트가 다음 행동을 판단하고, 외부의 제어 메커니즘이 실행 가능 여부나 완료 조건을 관리합니다.
실제 구현에서는 예외 처리 (exception handling), 타임아웃, 반복 상한 (iteration limit), 권한 관리, 상태의 영속화 등(persistence)이 필요하게 된다. 또한, 기존 SDK가 제공하는 기능을 중복하여 구현하지 않도록 해야 한다.
중요한 것은 오케스트레이터(orchestrator)를 만드는 것 자체를 목적으로 삼지 않는 것이다. 필요한 제어 기능(control function)을 특정하고, 그것을 실현할 수 있는 최소한의 구성을 선택해야 한다.
6.1 서브 에이전트도 필요해진 후에 추가한다
같은 생각은 서브 에이전트에도 적용된다.
예를 들어, 독립적인 보안 검토(security review), 병렬 기술 조사, 대규모 코드베이스의 분담 조사 등에서는 여러 개의 에이전트가 유효할 때가 있다.
반면, 단순한 화면 추가마다 디자인, 구현, 테스트 각 에이전트를 준비하면, 에이전트 간의 인계(handover)나 결과 통합이 불필요한 복잡성을 야기하기도 한다.
우선 단일 에이전트로 일련의 작업을 실현하고, 실제 문제를 확인한 후에 구성을 확장한다.
- 반복 규약(규칙)을 잘못 지키는 경우: 스킬이나 프로젝트 지시를 개선한다.
- 테스트를 실행하지 않고 완료로 판단하는 경우: 완료 조건 강제화를 검토한다.
- 독립적인 검토가 필요한 경우: 검토용 에이전트를 추가한다.
- 파괴적인 조작을 방지할 필요가 있는 경우: 실행 권한을 제한한다.
문제의 성질에 따라 지식, 실행 수단, 외부 제어(external control), 독립적인 판단 주체 중 어떤 것이 필요한지를 판단한다.
7. AI 네이티브 개발에서 인간이 담당할 책임
AI가 구현이나 검증을 맡는 범위가 넓어져도, 인간이 담당해야 할 역할은 남아있다.
특히 중요한 것은 목적(objective), 업무상의 제약(business constraint), 리스크 수용(risk acceptance), 책임의 소재이다.
예를 들어, AI는 사용자 등록 화면의 레이아웃을 여러 안으로 작성하고 브라우저에서 비교할 수 있다. 그러나 개인정보 처리, 인증 방식 변경, 업무상 예외 처 등은 기술적인 실현 가능성만으로는 판단할 수 없는 경우가 있다.
또한, 테스트에 실패했을 때 AI가 임의로 수용 조건을 완화해도 되는 것도 아니다.
따라서 인간이 정의해야 하는 것은 단순히 작업의 순서만이 아니다.
- 무엇을 달성해야 하는지
- 무엇을 변경해서는 안 되는지
- 어떤 리스크를 허용할 수 있는지
- 어떤 판단에 인간의 승인이 필요한지
- 무엇으로 완성으로 인정할 것인지
이러한 요소들을 명확히 하고, AI가 판단할 수 있는 범위와 인간이 책임을 지는 범위를 분리한다.
AI의 자율성을 높이는 것이 인간의 책임을 없애는 것은 아니다. 인간이 개별 공정을 일일이 지시할 필요성을 줄여가면서도, 중요한 판단과 결과의 수용에 책임을 지는 것이다.
8. 요약: 공정(Process)이 아닌 목적 달성 메커니즘을 설계한다
AI 네이티브 개발을 생각할 때, 가장 먼저 결정해야 할 것은 에이전트의 수나 역할이 아니다.
먼저, 목적, 제약, 수용 조건을 명확히 한다.
그 위에 AI가 상황에 따라 다음 행동을 판단하고, 도구를 사용해 실행하며, 검증 결과를 바탕으로 수정할 수 있는 환경을 준비한다.
스킬(Skill)은 필요한 지식을 제공하고, 도구(Tool)는 실행과 검증을 가능하게 한다. 하네스(Harness)는 행동의 제약이나 피드백, 완료 조건을 지탱한다. 오케스트레이션(Orchestration)은 판단-실행-검증-재판단을 연결한다.
이것들은 독립적인 기술 요소를 도입하는 것 자체가 목적이 아니다. 목적을 달성하기 위해 필요한 기능을 적절한 책임에 나누어 조합하는 것이다.
부족한 기능이 있다면, 스킬이나 도구, 외부 제어, 서브 에이전트를 추가한다. 기존 실행 환경으로 충분하다면, 독자적인 구현을 늘릴 필요는 없다.
기존의 개발 공정을 없애는 것이 목적이 아니다. 공정을 고정한다는 전제를 두지 않고, 목적-제약-검증 가능한 완료 조건을 기준으로 AI가 적절한 실행 방법을 선택할 수 있도록 하는 것이 목적이다.
AI 네이티브 개발에서 설계해야 할 것은, 공정을 순서대로 실행하는 메커니즘이 아니라, AI가 목적을 달성하기 위해 판단-실행-검증-수정할 수 있는 메커니즘이다.
참고 자료
- OpenAI Agents SDK
- OpenAI: Harness engineering — leveraging Codex in an agent-first world
- OpenAI: Orchestration and handoffs
- Anthropic: Demystifying evals for AI agents
※본고의 구성 예시는, 이러한 자료와 관련된 생각을 바탕으로 한 설계상의 제안이며, 특정 공식 아키텍처를 그대로 재현한 것은 아니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기