코드 작성 이후의 다섯 가지 AI 에이전트: 실제 파이프라인에서 GitLab Duo가 수행한 작업
요약
본 글은 코드 작성 이후의 복잡한 개발 파이프라인 관리 과정을 AI 에이전트가 얼마나 자동화할 수 있는지 탐구한다. GitLab Duo 에이전트를 활용하여 계획, 검토, 보안 강화, 배포 등의 단계를 거치며 실제 서비스 구축 경험을 공유한다.
핵심 포인트
- 코드 작성보다 이후의 파이프라인 관리가 더 복잡하다.
- GitLab Duo 에이전트가 plan, review, fix, secure, release 등 다단계 작업을 수행했다.
- 실제 프로젝트 데이터를 기반으로 한 솔직한 기록과 경험을 제공한다.
간단 요약: 저는 작은 Python 서비스 주변에 다섯 개의 GitLab Duo 에이전트(plan, review, fix, secure, release)를 배치하고 코드를 작성한 후 작동하도록 했습니다. 이들은 약 2분 만에 기능을 계획했고, 검토를 위해 하나의 수정 사항을 세 번 되돌려 보냈으며, 파이프라인의 레이스 조건을 진단했고, 컨테이너 스캔 결과를 166개에서 1개로 줄였습니다. 그들은 아무것도 병합하지 않았습니다. 제가 직접 했고, 이 과정에서 실수도 하나 했습니다.
코드를 작성하는 것이 더 이상 작은 서비스를 구축하는 느린 부분이 아닙니다. 느린 부분은 그 이후에 오는 일입니다: 변경 사항을 계획하고, 검토하고, 파이프라인이 고장 났을 때 수정하며, 보안 발견 사항을 분류하고, 프로덕션을 중단 없이 출시하는 것입니다. 저는 AI 에이전트가 이 작업의 얼마나 많은 부분을 처리할 수 있는지, 그리고 어디에서 멈춰야 하는지를 알아보기 위해 GitLab Transcend 해커톤("Life After Code")에 참가했습니다.
이 글은 솔직한 기록입니다. 실제 프로젝트, 실제 머지 리퀘스트(merge requests), 그리고 두 번의 실수를 포함하여 실제 판결을 사용합니다. 모든 숫자는 프로젝트 자체의 파이프라인 및 머지 리퀘스트 이력에서 가져온 공개 데이터입니다.
프로젝트 소개
이 서비스는 ro-cited-answers라는 MIT 라이선스 데모로, 출처(source)가 없는 답변은 거부한다는 단 하나의 규칙을 가지고 루마니아어 공공 절차에 대한 질문에 답합니다. 네 개의 게이트가 문서로 뒷받침되지 않는 모든 것을 거부합니다. 저는 해커톤 이전에 첫 버전을 구축했습니다. 여기에 추가된 내용은 다음과 같습니다: GitLab CI/CD 파이프라인과 일련의 GitLab Duo 에이전트들로, 모두 공개 저장소에 있습니다:
https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/43427415/ro-cited-answers
헬스 엔드포인트에 버전이 표시되는 라이브 서비스:
https://ro-cited-210002791432.europe-north1.run.app/health
9단계와 담당 역할
대회는 코드 작성 이후의 아홉 가지 단계를 정의합니다: plan, create, verify, package, secure, release, configure, monitor, govern. 파이프라인은 다음과 같이 이 단계들을 처리합니다:
- Verify: 근거(grounding) 게이트에 대한 오프라인 테스트, 재현 가능한 평가 세트, 그리고 부팅 검사를 수행합니다.
- Package: 컨테이너 이미지를 생성하여 GitLab 레지스트리와 Google Artifact Registry에 푸시합니다.
- Secure: SAST(정적 분석 보안 테스트), 비밀 탐지 및 컨테이너 스캐닝을 수행합니다.
- Release: 트래픽을 받지 않는 Cloud Run 후보 리비전을 배포하고, 이에 대한 검사를 거친 후 프로모션하며, 만약 실패하면 자동 롤백됩니다.
- Configure: 운영 환경 설정이
deploy/service-config.json이라는 단일 파일에 저장되어 있으며, 드리프트(drift) 작업이 Cloud Run과 이 파일을 비교합니다. - Monitor: 스케줄러가 6시간마다 운영 환경을 재검사하며, 여기에는 의미 없는 경로 제어(nonsense-path control)도 포함됩니다. 또한, 모든 요청은 질문 텍스트가 아닌 결과와 게이트를 기록하는 하나의 스팬(span)을 GitLab Observability로 전송합니다.
- Govern:
AGENTS.md파일에 각 에이전트가 따라야 할 규칙이 담겨 있습니다. - Plan 및 생성: 아래의 에이전트들이 처리합니다.
어디에도 서비스 계정 키는 없습니다. 조직 정책이 키 생성을 차단하기 때문에, GitLab은 각 작업(job)에 대한 토큰을 서명하고 Google Cloud가 Workload Identity Federation을 통해 이를 신뢰합니다.
다섯 가지 에이전트
각 에이전트는 자체 서비스 계정을 가진 사용자 지정 GitLab Duo 플로우입니다. 정의는 레포지토리(.gitlab/duo/flows/)에 존재하며, 동기화 스크립트가 이를 적용하므로 레포지토리가 진실의 원천(source of truth)입니다. 이들 모두는 AGENTS.md에 의해 구속됩니다. 즉, 병합 요청을 열거나 노트를 작성할 수는 있지만, 병합하거나 배포할 수는 없습니다. 설정 드리프트를 위한 여섯 번째 플로우는 나중에 추가되었으며, 아래 다섯 가지가 핵심입니다.
1. Plan: rca-plan
이 에이전트는 이슈가 생성될 때 자체적으로 시작됩니다. 추적(tracing)을 요청한 이슈 #1에서, 이 에이전트는 약 2분 후에 전체 계획을 게시했습니다. 이는 AGENTS.md를 읽고 게이트 규칙에 변경 사항이 없다는 것을 확인했으며, 질문 텍스트를 절대 포함하지 않는 허용 목록(allowlist)으로 추적 속성을 제한했습니다. 그 계획은 실제 기능이 되었고, 나중에 !6으로 병합되었습니다.
한 가지 결함: issue #3을 보안 에이전트에게 할당했을 때, 'issue created' 역시 이벤트이기 때문에 플랜 에이전트가 그것에 대해서도 실행되었습니다. 이는 중복 실행이었으며 후속 조치로 기록되었습니다.
2. 검토(Review): rca-review
리뷰어(reviewer)로 할당될 때 시작됩니다. 이 에이전트의 유일한 질문은 변경 사항이 시스템이 이전에 거부했던 답변을 내놓을 수 있게 만들 수 있는지 여부입니다.
가장 좋은 예는 MR !5였습니다. 리뷰 에이전트는 이 PR에 대해 세 번의 라운드를 거쳤습니다. 첫 번째로 높은 수준의 발견 사항 두 가지, 다음으로 중간 수준의 발견 사항 세 가지를 제시했고, 마지막에는 최종 판정을 내렸습니다. 저는 머지 리퀘스트에서 낮은 수준의 발견 사항 두 가지를 수락했습니다. 이전 모든 라운드가 옳았습니다. 또한 나중에 발생한 머지 리퀘스트 !7에서도 실제 버그를 발견했는데, 코드가 첫 번째 트래픽 항목을 서비스 개정본(serving revision)으로 가정하고 있다는 것을 알아차렸고, 이는 잘못된 것이었습니다. 이 문제는 병합 전에 수정되었습니다.
제가 배운 한 가지 제한 사항은 Duo가 에이전트의 컨텍스트에서 루마니아 개인 식별 번호처럼 생긴 문자열을 마스킹(redact)한다는 것입니다. 그래서 !6에서는 제가 테스트에 샘플 값을 사용했음에도 불구하고 리뷰어가 "[REDACTED]"를 보았습니다. 또한 처음에 .gitlab/duo/ 디렉터리도 읽지 못했는데, 이 디렉터리가 Duo의 컨텍스트 제외 목록(context exclusion)에 있기 때문이었습니다. 따라서 경로별 검토 규칙은 AGENTS.md로 옮겨야 했습니다.
3. 수정(Fix): rca-fix
파이프라인이 실패할 때 시작됩니다. 저는 브랜치 !2에 현실적인 버그(NameError)를 심었습니다. 부팅 검사(boot check)가 파이프라인 2954432632에서 실패했습니다. 수정 에이전트는 한 글자만 고친 !3을 열고, 오프라인 게이트 테스트(offline gate tests) (6개 중 6개)와 로컬 스모크 검사(local smoke check) (4개 중 4개)를 실행했고, 머지 리퀘스트 파이프라인은 녹색으로 바뀌었습니다.
나중에는 제가 심지 않은 실패를 진단했습니다. 두 개의 병합이 8초 간격으로 도착했고 하나의 Cloud Run 태그인 candidate를 공유하고 있었습니다. 한 파이프라인이 다른 커밋의 개정본을 검증하며 7개 중 6개의 검사에서 실패했습니다. 아무것도 프로덕션에 도달하지 않았습니다. 수정 에이전트는 이 경쟁 상태(race)를 설명하는 issue #4를 열고, 세 가지 옵션을 제시했으며,
저는 스캐너 출력을 분류(triage)할 이슈를 할당했습니다. 이 결과는 173개의 발견 사항을 담은 표를 생성했는데, 여기에는 컨테이너 166개, SAST 7개, 시크릿 0개가 포함되어 있었습니다. 아무것도 무시하지 않았습니다. 대신 !4를 열어 기본 이미지를 python:3.12-slim에서 비(非)루트 사용자(non-root user)가 있는 Alpine으로 변경했습니다. 병합 후, 메인 파이프라인의 컨테이너 스캔 결과는 166개 발견 사항이 1개로 감소했으며, zlib에 Medium 등급 하나만 남아 있었습니다. 병합 요청(merge request) 파이프라인에서는 이를 보여줄 수 없었는데, 이는 컨테이너 스캐닝이 병합 요청 파이프라인에서 실행되지 않기 때문입니다. 따라서 '전'과 '후'의 숫자는 오직 병합 후에만 측정할 수 있었습니다. 사람이 직접 병합한 이유는 프로덕션 안전성(candidate 확인 및 자동 롤백)이 실제 제어 장치였기 때문입니다.
5. Release: rca-release
이것은 main 브랜치의 파이프라인이 성공하거나 실패할 때 시작됩니다. 이 과정은 이슈로 릴리스 요약(release summary)을 작성합니다. 첫 실행 시, 자체적으로 프로덕션을 확인하려고 했으나 Duo sandbox proxy에 의해 차단되었습니다. 추측하는 대신 '확인되지 않음(not verified)'이라고 보고했습니다. 이후 우리는 .gitlab/duo/agent-config.yml 파일에서 정확히 두 개의 Cloud Run 호스트 이름만 허용했고, 나중 실행에서는 라이브 서비스 자체를 확인하게 되었습니다.
그 '확인되지 않음'이라는 문구가 이 프로젝트의 제가 가장 좋아하는 결과입니다. 왜냐하면 전체 서비스가 자신이 뒷받침할 수 없는 것을 주장하기를 거부한다는 아이디어 위에 구축되었기 때문입니다.
무엇이 잘못되었는가 (What went wrong)
경쟁 조건(The race). 위에서 공유된 candidate 태그는 저의 설계 오류였으며, 파이프라인 자체 버전 확인 기능이 이를 잡아냈습니다. 에이전트들이 진단하는 데 도움을 주었지만, 막지는 못했습니다.
결과를 읽기 전에 병합하기 (Merging before reading the verdict). 저는 리뷰 판정(review verdict)을 읽고 한 번에 병합하는 명령어를 작성했습니다. !13의 경우, 픽스 에이전트(fix agent)의 중복 제거 수정 사항이었는데, 판정이 '준비되지 않음(NOT READY)'이었고 높은 발견 사항은 정확했습니다. 즉, 동일한 커밋을 푸시하면 두 번 성공한다는 것이었습니다. 제 테스트에서도 제안된 해결책은 실패했습니다. !14는 이를 고유 클레임 커밋과 브랜치가 없을 때만 성공하는 푸시로 대체했고, '준비됨(READY)' 판정 후에 병합되었습니다. 제가 지킨 규칙은 다음과 같습니다: 판정을 한 단계에서 읽고, 병합을 별도의 단계에서 수행한다.
AI 에이전트 기반 파이프라인의 작동 방식과 인간의 개입 필요성
중복 작업. 수정(fix) 에이전트는 하나의 YAML 실패에 대해 중복 병합 요청(!8 및 !9)을 열었고, 계획(plan) 에이전트는 #3에서 이중으로 실행되었습니다. 둘 다 후속 조치로 처리되었습니다.
제가 실시간으로 검증하지 못한 한 가지. !14는 에이전트 샌드박스 내의 git 도구가 push 시 임대 플래그(lease flag)를 수락하는 것에 의존합니다. 저는 로컬에서 논리를 테스트했습니다. 다음 실제 실패가 발생했을 때 샌드박스가 이를 수락하는지 알게 될 것입니다.
사람이 여전히 결정하는 것들
모든 병합(merge). 에이전트는 설계상 병합 권한이 없으며, 이 프로젝트에서는 저는 검토 결과를 읽은 후 매번 명시적으로 "병합"을 지시했습니다.
또한: 에이전트가 "인간의 결정이 필요함(needs a human decision)"이라고 작성했을 때 어떤 옵션을 취할지, 특정 발견 사항(finding)이 수용 가능한지 여부, 컨테스트 규칙과 관련된 모든 것, 그리고 비디오와 제출물 자체에 대한 판단입니다.
제가 주장하지 않을 부분들
파이프라인은 위의 경우들에 대해 핸즈오프(Hands-off) 경로에 도달하지만, 저는 해당 케이스만 테스트했습니다. 에이전트들은 수천 번이 아닌 몇 번 정도 실행되었습니다. 이 서비스 자체는 소규모 문서 세트에 대한 시연용이며, 모델 호출은 제가 로컬에서 실행하는 것이 아니라 호스팅된 오픈 가중치(open-weight) 모델로 전송됩니다. Duo의 실행당 크레딧 비용은 저에게 알려져 있지 않습니다.
재현 방법
- GitLab에서 공개 저장소(public repository)를 포크하세요. 이 저장소는 MIT 라이선스를 따르며, README 섹션 "The post-code pipeline"에 단계가 설명되어 있습니다.
- 파이프라인이 예상하는 CI 변수들(마스킹되고 보호되는 모델 API 키 및 프로덕션 URL)을 설정하고 Google Cloud Workload Identity Federation 조건을 사용자 네임스페이스에 지정하세요.
- GitLab 토큰을 사용하여
deploy/duo_sync.py로 흐름(flows)을 적용하세요. 변경되지 않은 흐름은 건너뛰고, 변경된 흐름은 새로운 동결 버전으로 배포됩니다. - 이슈를 열어 계획 에이전트가 응답하는 것을 지켜보세요. 병합 요청을 열고 검토 에이전트를 할당하세요. 테스트를 의도적으로 실패시키고 수정 에이전트의 작동을 관찰하세요.
기억해야 할 규칙: 에이전트들이 조언하고 병합 요청을 열도록 하되, 병합은 별도의 인간 단계로 유지하고, 트래픽을 받기 전에 프로덕션 환경이 스스로 증명하도록 해야 합니다.
자신의 파이프라인 중 어떤 단계를 에이전트에게 절대 맡기지 않을 것이며, 그 근거는 무엇입니까?
원문 출판: devaland.com - 코드 작성 이후의 다섯 가지 AI 에이전트: 실제 파이프라인에서 GitLab Duo가 수행한 작업
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기