AI 코딩 에이전트를 위한 명세(Specs) 준비하기
요약
AI 코딩 에이전트가 코드베이스를 직접 수정하고 명령을 실행함에 따라, 단순 프롬프트를 넘어선 명세(Spec) 준비의 중요성을 강조합니다. 명세는 에이전트에게 컨텍스트, 제약 사항, 성공 기준을 제공하여 인간의 의도와 기계의 실행을 연결하는 과업 역할을 합니다.
핵심 포인트
- 에이전트 작업 시 컨텍스트, 경계, 성공 기준을 포함한 명세가 필수적임
- 좋은 명세는 배경, 변경 동작, 제약 사항, 정확성 예시, 검증 증거를 포함해야 함
- 개인적 프롬프트는 일회성에 그치지만, 명세는 팀 단위 워크플로우를 지속시킴
- 명세 기반 개발은 인간의 의도를 기계가 실행 가능한 과업으로 변환하는 과정임
AI 코딩 에이전트(AI coding agents)는 이제 저장소(repositories)를 편집하고, 명령어를 실행하며, 브랜치(branches)를 생성합니다. 이로 인해 작업 전의 명세(spec)가 더욱 중요해졌습니다. 명세는 에이전트가 필요로 하는 컨텍스트(context), 경계(boundaries), 그리고 성공 기준(success criteria)을 담고 있기 때문입니다.
좋은 코딩 에이전트 명세에 포함되어야 할 것
AI 코딩 에이전트가 더 이상 질문에 답변만 하는 것이 아니기 때문에 명세의 중요성이 커지고 있습니다. 에이전트는 저장소를 읽고, 파일을 편집하며, 명령어를 실행하고, 브랜치를 생성하며, 인간에게 결과물에 대한 리뷰를 요청합니다. 이는 프롬프트(prompt)가 갖추어야 할 요건을 변화시킵니다.
어시스턴트(assistant)가 질문에 답변만 할 때는 개인적인 프롬프트만으로도 충분할 수 있습니다. 하지만 에이전트가 공유된 코드베이스(codebase)를 변경할 때, 프롬프트는 하나의 과업(assignment)이 됩니다. 그리고 과업에는 단순히 좋은 문구 이상의 것이 필요합니다. 적절한 컨텍스트(context), 경계(boundaries), 예시(examples), 그리고 작업이 원래 의도와 일치하는지 판단할 수 있는 방법이 필요합니다.
이것이 코딩 에이전트를 저장소에 투입하기 전에 명세를 준비해야 하는 실질적인 이유입니다. 명세가 길 필요는 없습니다. 다만 에이전트에게 어떤 문제를 해결해야 하는지, 어떤 동작이 바뀌어야 하는지, 무엇이 바뀌면 안 되는지, 그리고 결과가 어떻게 리뷰될 것인지를 알려주어야 합니다.
최소한, 좋은 코딩 에이전트 명세는 에이전트에게 다음 다섯 가지를 제공해야 합니다:
- 작업의 배경이 되는 컨텍스트 (the context behind the task)
- 변경되어야 하는 동작 (the behavior that should change)
- 에이전트가 유지해야 하는 제약 사항 (the constraints the agent should preserve)
- 정확성을 정의하는 예시 또는 시나리오 (examples or scenarios that define correctness)
- 리뷰어가 검토해야 할 검증 증거 (the validation evidence a reviewer should inspect)
이것은 명세 기반 개발(spec-driven development), 동작 시나리오(behavior scenarios), 이슈 템플릿(issue templates), 경량 설계 문서(lightweight design docs), OpenSpec, GitHub Spec Kit, 그리고 많은 내부 엔지니어링 제안 형식들의 이면에 있는 유용한 아이디어입니다. 특정 프레임워크보다는 명세의 형태가 더 중요합니다. 에이전트는 행동할 수 있을 만큼 충분한 컨텍스트(context)를 받아야 하며, 팀은 결과를 리뷰할 수 있을 만큼 충분한 구조(structure)를 받아야 합니다.
명세는 단순히 더 나은 프롬프트가 아닙니다. 그것은 인간의 의도(human intent)와 기계의 실행(machine execution) 사이에서 준비된 과업(assignment)입니다.
프롬프트는 작업을 시작하는 데 유용합니다. 명세는 작업을 지속하는 데 더 뛰어납니다.
개인적인 프롬프트(Private prompt)는 즉각적인 대응에 최적화되어 있습니다. 이는 채팅 세션 내에 존재합니다. 여기에는 작성자만 이해하고 다른 누구도 볼 수 없는 약어, 누락된 문맥, 그리고 가정이 포함될 수 있습니다.
이는 로컬 설명이나 일회성 스크립트에는 효과적일 수 있습니다. 하지만 팀 단위의 엔지니어링 작업에는 취약합니다.
문제는 프롬프트가 비형식적(informal)이라는 점이 아닙니다. 비형식성은 종종 유용합니다. 문제는 개인적인 프롬프트가 에이전트가 작업을 시작한 후 워크플로우(workflow)에서 보통 사라져 버린다는 점입니다. 프롬프트는 자연스럽게 검토 기준(review criteria)이 되지 않습니다. 풀 리퀘스트(pull request)와 비교하기도 어렵습니다. 또한 다음 작업자가 왜 이러한 변경이 존재하는지 이해하는 데 도움을 주지 못합니다.
명세(Specs)는 다른 문제를 해결합니다. 명세는 팀이 지속적으로 검사할 수 있도록 과업(assignment)에 가시적인 형태를 부여합니다.
해당 명세는 다양한 곳에 존재할 수 있습니다. 리포지토리 로컬 명세(repo-local spec), 수락 기준(acceptance criteria)이 포함된 이슈(issue), BDD 시나리오, 작은 설계 노트(design note), 변경 제안서(change proposal), 또는 변경되는 동작을 명시한 풀 리퀘스트(pull request) 설명 등이 될 수 있습니다. OpenSpec은 이 패턴의 유용한 구현체 중 하나이지만, 유일한 것은 아닙니다. GitHub Spec Kit, Gherkin 스타일의 시나리오, 팀 RFC 템플릿, 그리고 일반적인 이슈 템플릿 모두 문맥과 검토 기준을 명시적으로 만든다면 동일한 규율을 전달할 수 있습니다.
이것이 바로 팀이 주목해야 할 변화입니다. 좋은 명세는 단순히 에이전트에게 지시만 하는 것이 아닙니다. 구현 전, 구현 중, 그리고 구현 후에 인간과 에이전트가 함께 검사할 수 있는 공유된 대상을 제공합니다.
FIG 01 — 과업의 형태. 개인적인 프롬프트: 흩어진 파편들 ("이거 고쳐줘 / 더 깔끔하게 만들어줘 / 아마 인증 관련인가? / 내 말 무슨 뜻인지 알지") — 사고를 시작하는 데는 유용하지만, 공유된 검토 객체로서는 취약함. 팀에게 보이는 명세: 제안서, 명세 차이(spec delta), 설계 노트, 작업(tasks), 검토 기준 — 구현 전에 보이며, 검토 중에 유용하고, 세션이 종료된 후에도 지속됨. 개인적인 프롬프트는 빠르지만 불안정합니다. 팀에게 보이는 명세는 검토자가 나중에 검사할 수 있도록 과업에 구조를 부여합니다.
과업 계층은 의도(intent)와 실행(execution)을 분리합니다
가장 강력한 명세(specs)는 작은 행동 계약(behavior contracts)처럼 작동합니다. 요구사항(Requirements)은 시스템이 무엇을 해야 하는지를 말해줍니다. 시나리오(Scenarios)는 종종 Given/When/Then 스타일로 구체적인 예시를 제공합니다. 설계 노트(Design notes)와 작업 목록(task lists)은 기술적 접근 방식과 구현 체크리스트를 설명할 수 있지만, 이것들은 요구사항과 동일한 것이 아닙니다.
이러한 분리는 AI 지원 엔지니어링(AI-assisted engineering)에서 가장 유용한 규율 중 하나입니다.
만약 의도(intent)와 구현(implementation)이 너무 일찍 뒤섞여 버리면, 에이전트(agent)는 잘못된 것을 최적화할 수 있습니다. 팀이 실제로 필요로 했던 동작을 놓친 채, 제안된 구현 세부 사항을 충실히 따르기만 할 수도 있습니다. 또는 성공 기준(success criteria)이 명시적으로 드러나지 않아 검토하기 어려운, 그럴듯해 보이기만 하는 설계를 만들어낼 수도 있습니다.
할당 계층(assignment layer)은 세 가지 질문을 분리하여 유지합니다:
- 어떤 동작이 바뀌어야 하는가?
- 어떤 제약 조건이나 예시가 정답(correctness)을 정의하는가?
- 현재 어떤 구현 경로가 적절해 보이는가?
이 질문들은 서로 연결되어 있지만, 하나의 덩어리(blob)로 합쳐져서는 안 됩니다. 구현은 에이전트가 코드베이스(codebase)를 읽어감에 따라 진화할 수 있습니다. 하지만 요구사항은 검토자가 "이 작업이 이것을 충족했는가?"라고 물을 수 있을 만큼 충분히 안정적으로 유지되어야 합니다.
FIG 02 — 행동 계약 (Behavior contract). 에이전트를 유도하고, 네 가지 요소를 모두 수집하여, 검토 가능한 변경 사항을 전달하십시오. 명세(spec)는 에이전트가 맹목적으로 따르는 파이프라인이 아닙니다. 그것은 유효한 작업의 경계(boundary)입니다.
이것이 기존 코드베이스에 대해 차이점 중심(delta-oriented) 형식이 흥미로운 이유이기도 합니다. 대부분의 엔지니어링 작업은 그린필드(greenfield, 신규 개발)가 아닙니다. 팀은 이미 존재하는 동작을 변경하고 있습니다. 좋은 명세는 다음과 같이 말합니다: "여기에 현재의 계약이 있고, 그 계약에 대한 제안된 변경 사항이 여기 있습니다." 검토자는 제품 문서 전체를 머릿속으로 차이점 비교(diff)할 필요가 없습니다. 그들은 동작의 차이(behavior delta)만 확인하면 됩니다.
구체적인 예시
다음과 같은 비공개 프롬프트(private prompt)를 생각해 보십시오:
불안정한(flaky) 로그인 테스트를 수정하고, 변경이 필요한 부분은 무엇이든 업데이트하세요.
혼자 일하는 개발자에게는 그것으로 충분할 수도 있습니다. 하지만 팀 과제(team assignment)로서는 부족합니다. 어떤 실패가 관찰되었는지, 어떤 동작이 안정적으로 유지되어야 하는지, 어떤 검증이 중요한지, 또는 어떤 종류의 수정이 범위 외(out of scope)인지 명시되어 있지 않기 때문입니다.
더 나은 명세(spec)는 작업 범위를 더 좁게 만들어 줍니다:
- 관찰된 문제 (Observed problem): 콜백 요청(callback request)이 테스트 어설션(assertion)에서 세션 레코드를 확인할 수 있기 전에 도착할 때 로그인 테스트가 간헐적으로 실패함.
- 기대 동작 (Expected behavior): 로그인은 정확히 하나의 세션을 생성해야 하며 사용자를 원래의 목적지로 리다이렉트(redirect)해야 함.
- 제약 사항 (Constraints): 인증(auth) 검사를 약화시키지 말 것, 테스트에 sleep을 추가하지 말 것, 그리고 코드베이스에 더 넓은 문제가 나타나지 않는 한 수정을 콜백/세션 경로 내로 국한할 것.
- 검증 (Validation): 영향을 받는 인증 테스트 파일과 관련 백엔드(backend) 또는 프론트엔드(frontend) 검사를 실행할 것.
- 리뷰 대상 (Review object): 결과물인 PR(pull request)을 명시된 동작, 제약 사항 및 검증 사항과 비교할 것.
이것은 작업에서 판단(judgment)을 제거하는 것이 아닙니다. 에이전트에게는 경계(boundary)를 제공하고, 리뷰어에게는 검사할 수 있는 기준을 제공하는 것입니다. 명세가 팀에 공개되어 있으면, 리뷰어는 에이전트가 받은 것과 동일한 컨텍스트를 바탕으로 풀 리퀘스트(pull request)를 비교할 수 있습니다.
명세가 작고 수정 가능하게 유지된다면 폭포수(waterfall) 모델이 아닙니다
명세 기반 작업(Spec-driven work)은 종종 합리적인 반론을 불러일으킵니다. "이것은 그저 새로운 이름의 폭포수 모델(waterfall) 아닌가요?"라는 의문입니다.
만약 팀이 명세를 하나의 의식(ceremony)으로 만든다면 그럴 수 있습니다. 구현 몇 달 전에 작성된 거대한 문서는 AI 에이전트가 그것을 읽는다고 해서 갑자기 더 나아지지 않습니다.
유용한 대안 패턴은 더 가볍습니다. 유동적이고, 반복적이며, 수정하기 쉽고, 브라운필드 우선(brownfield-first) 방식입니다. 다양한 프레임워크가 이를 다르게 표현합니다. 어떤 곳은 제안서(proposals)와 델타 명세(delta specs)를 사용합니다. 어떤 곳은 이슈 체크리스트(issue checklists)와 수락 기준(acceptance criteria)을 사용합니다. 어떤 곳은 BDD 시나리오를 사용합니다. 중요한 점은 이것들이 변경 사항을 둘러싼 '행동'이지, 학습을 지연시키는 '고정된 단계'가 아니라는 것입니다.
이러한 구분이 중요합니다. 할당 계층(assignment layer)은 모호함을 줄여야지, 학습을 동결해서는 안 됩니다.
좋은 명세(spec)는 구현 과정에서 팀이 무언가를 배우게 될 때 변경될 수 있습니다. 탐색 과정에서 초기 접근 방식이 잘못되었다는 것이 밝혀지면, 설계(design)가 변경되어야 합니다. 요구사항이 너무 광범위했다면 범위를 좁혀야 합니다. 아무도 고려하지 않았던 엣지 케이스(edge case)가 시나리오를 통해 드러났다면, 명세에 해당 시나리오를 추가해야 합니다.
여기서 핵심적인 규율은 "코드를 작성하기 전에 완벽한 계획을 세우는 것"이 아닙니다. 핵심은 "가시적인 의도(visible intent)와 구현된 현실(implemented reality)이 함께 움직이도록 유지하는 것"입니다.
리뷰 대상의 변화
가시적인 할당(assignment)이 없다면, 리뷰어들은 주로 디프(diff)를 리뷰하게 됩니다.
할당 계층(assignment layer)이 있다면, 리뷰어는 다음 네 가지 요소 사이의 관계를 리뷰할 수 있습니다:
- 제안된 동작 변경 사항 (proposed behavior change)
- 구현 계획 또는 작업 분할 (implementation plan or task breakdown)
- 에이전트가 생성한 코드와 테스트 (code and tests produced by the agent)
- CI, 로컬 체크 또는 수동 리뷰를 통한 검증 결과 (validation result from CI, local checks, or manual review)
그 관계야말로 AI 지원 작업이 더 관리 가능해지는 지점입니다. 리뷰어는 에이전트의 확신을 믿어달라는 요청을 받는 것이 아닙니다. 그들은 명세, 구현, 그리고 증거를 비교하는 것입니다.
다양한 프레임워크는 이를 각기 다른 방식으로 명시합니다. OpenSpec은 완전성(completeness), 정확성(correctness), 일관성(coherence)에 관한 검증 개념을 가지고 있습니다. GitHub의 Spec Kit은 더 엄격한 명세 우선(specification-first) 입장을 취합니다. BDD 워크플로우는 실행 가능하거나 반실행 가능한 동작 기대치로서 예시(examples)를 사용합니다. 이슈 중심(issue-driven) 팀은 대신 수락 기준(acceptance criteria), 레이블(labels), 리뷰어, CI 요구사항을 사용할 수 있습니다.
이것들은 동일한 철학은 아닙니다. 공통된 교훈은 더 좁고 유용합니다. 코딩 에이전트가 강력해질수록, 그들이 충족해야 했던 할당(assignment)을 보존하는 것이 더욱 중요해진다는 것입니다.
팀의 입장에서 이는 리뷰 질문을 "이 디프(diff)가 괜찮아 보이나요?"에서 "이 디프가 우리가 명시한 제약 조건 하에, 우리가 합의한 동작 변경 사항을 우리가 검사할 수 있는 증거와 함께 충족합니까?"로 변화시킵니다.
이것이 더 나은 질문입니다.
올바른 명세는 팀의 컨텍스트가 된다
좋은 명세는 에이전트가 시작하는 것을 돕습니다. 공유된 명세는 팀이 정렬(aligned)된 상태를 유지하도록 돕습니다.
러너(runner)는 모호한 개인적 의도(private intent)를 전달받아 고립된 실행 환경(execution environment) 속으로 사라진 뒤, 리뷰어가 처음부터 다시 해독해야 하는 디프(diff)를 반환해서는 안 됩니다. 작업은 팀이 볼 수 있는 컨텍스트(context)에서 시작되어야 하며, 팀이 이미 이해하고 있는 증거들, 즉 브랜치(branch), 커밋(commits), 풀 리퀘스트(pull request), CI 결과, 러너 요약(runner summary), 모델 감사(model audit), 그리고 인간의 리뷰(human review)를 통해 반환되어야 합니다.
어떤 도구도 모든 팀에게 하나의 명세 프레임워크(spec framework)를 강요할 필요는 없습니다. 어떤 팀은 이슈(issues)를 사용할 것이고, 어떤 팀은 저장소 로컬 명세(repo-local specs)를 사용할 것입니다. 또 어떤 팀은 가벼운 디자인 문서(design docs)나 동작 시나리오(behavior scenarios)를 사용할 수도 있습니다. 중요한 경계선은 코딩 에이전트(coding-agent)의 작업이 반드시 가시적인 명세(spec) 및 리뷰 가능한 결과(reviewable result)와 연결되어 있어야 한다는 점입니다.
이것이 유용한 AI 러너 워크플로우(AI runner workflow)와 블랙박스 형태의 자율적 출력(black-box autonomous output)을 구분 짓는 요소입니다. Forkline도 동일한 원칙을 따르지만, 이 원칙은 특정 제품보다 더 광범위합니다. 만약 에이전트가 공유된 코드(shared code)를 바탕으로 동작한다면, 명세(spec)와 결과(result) 모두 팀이 조사(inspectable)할 수 있어야 합니다.
명세는 또한 메모리(memory)이기도 합니다
AI 코딩 세션은 일시적입니다. 저장소(repositories)는 그렇지 않습니다.
저장소 로컬 명세(repo-local specs)의 과소평가된 이점 중 하나는 그것이 코드와 함께 존재할 수 있다는 점입니다. 명세는 저장소에 체크인(checked into)될 수 있고, 기능이나 변경 사항에 따라 정리될 수 있으며, 작업이 반영됨에 따라 업데이트될 수 있습니다. 이는 나중에 사람과 에이전트 모두에게 유용하게 작용합니다.
이것이 중요한 이유는 에이전트의 컨텍스트(agent context)가 취약하기 때문입니다. 채팅 기록은 삭제됩니다. 컨텍스트 윈도우(context windows)는 가득 찹니다. 다음 작업은 다른 모델이나 도구가 처리할 수도 있습니다. 원래 프롬프트(prompt)를 작성한 사람이 자리에 없을 수도 있습니다. 만약 의도(intent)에 대한 유일한 기록이 개인적인 채팅뿐이었다면, 팀은 그 채팅이 시야에서 사라지는 즉시 컨텍스트를 잃게 됩니다.
명세(specs)는 그 컨텍스트에 내구성이 있는 집을 제공합니다. 명세는 코드, 테스트, 또는 문서(documentation)를 대체하는 것이 아니라, 이들을 연결합니다. 새로운 에이전트는 현재의 동작(behavior)을 읽을 수 있습니다. 새로운 개발자는 시스템이 무엇을 수행하도록 기대되는지 이해할 수 있습니다. 리뷰어는 보관된 변경 사항을 다시 살펴보며 무엇이 바뀌었는지뿐만 아니라, 왜 그 변경이 제안되었는지까지 확인할 수 있습니다.
이것은 일차적으로 감사(Audit)를 위한 논거가 아닙니다. 이것은 협업(Coordination)을 위한 논거입니다. 팀에는 개별 세션이 종료되어도 유지되는 메모리가 필요합니다.
제한된 작업(Bounded work)이 적절한 단위입니다
명세(Specs)가 모든 종류의 작업을 위임하기에 안전하게 만들어 주는 것은 아닙니다.
명세는 작업이 제한적(Bounded)일 때 가장 강력합니다. 즉, 동작 변경(Behavior change), 버그 수정(Bug fix), 호환성 업데이트(Compatibility update), 작은 기능(Small feature), 마이그레이션 단계(Migration step), CI 복구(CI repair), 또는 명확한 제약 조건이 있는 좁은 범위의 리팩터링(Refactor) 등이 이에 해당합니다. 이러한 경우, 팀은 원하는 변경 사항을 기술할 수 있으며 결과가 그에 부합하는지 검사할 수 있습니다.
반면, 작업이 주로 판단(Judgment)을 필요로 할 때는 명세의 힘이 약해집니다. 제품의 방향성을 선택하거나, 제1원칙(First principles)에 따라 아키텍처를 재설계하거나, 코드베이스 전체를 개선하거나, UI를 더 좋게 만들거나, 사용자가 무엇을 원하는지 결정하는 작업 등이 그러합니다.
이러한 경계는 건강한 것입니다. 명세의 목적은 인간의 판단을 없애는 것이 아닙니다. 명세의 목적은 적절한 작업을 에이전트(Agent)가 수행할 수 있고 인간이 검토할 수 있는 형태로 옮기는 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기