개념 노트 2026년 10월 12일11분 읽기

AI 에이전트에게 일을 맡기려면 원장 하나와 계약 하나부터 두어야 합니다

더 똑똑한 프롬프트가 아니라, 상태를 적는 파일 하나와 결과를 거르는 조건 한 줄이 먼저입니다.

AI 에이전트에게 일을 맡기려면 원장 하나와 계약 하나부터 두어야 합니다

에이전트에게 일을 맡기기 시작하면 처음 몇 주는 속도에 감탄합니다. 그런데 에이전트가 둘, 셋이 되고 하나의 결과가 다음 에이전트의 입력이 되기 시작하면 익숙한 장면이 돌아옵니다. 지난주에 빼기로 한 기능이 어느 날 다시 기획서에 들어와 있고, 앞 에이전트가 넘긴 결과의 형식이 달라 뒤 에이전트가 멈추고, 지금 이 프로젝트의 상태가 무엇인지 물으면 대화 기록을 거슬러 올라가야 합니다.

이 글의 결론은 짧습니다. 에이전트에게 일을 맡기려면 더 정교한 프롬프트보다 먼저, 상태를 적는 원장(ledger, 지금 상태를 적는 유일한 정본 기록) 하나와 주고받는 것을 거르는 계약(contract, 결과를 받아들이는 조건) 하나를 파일로 두어야 합니다. 그리고 원장에서 상태를 정하는 칸, 이 글에서 결정 칸이라고 부를 자리는 사람만 채워야 합니다. 장치 둘과 규칙 하나입니다. 원장과 계약이 장치이고, 결정 칸은 원장 안의 한 칸을 사람만 채운다는 규칙입니다. 이 세 가지를 간단한 예시로 풀어 보겠습니다.

아래 예시는 설명을 위해 만든 가상의 장면입니다. 특정 회사나 프로젝트의 기록이 아닙니다. 프로젝트 관리와 회계에서 오래 쓰던 말을 다시 꺼낸 이유는 유행이 아니라, 사람이 하던 기본기를 에이전트에게 넘겼을 때 깨지는 자리가 정확히 그 두 단어가 가리키는 자리이기 때문입니다.

PART 01무엇이 깨지나

빼기로 한 기능이 다시 들어와 있는 이유는 원장이 없어서입니다

작은 팀이 서비스 기획을 에이전트 셋에게 나눠 맡겼다고 해 봅시다. 하나는 요구사항을 정리하고, 하나는 화면 흐름을 그리고, 하나는 테스트 항목을 뽑습니다. 월요일 회의에서 "회원 초대 기능은 이번 분기에서 뺀다"고 정했고, 요구사항 에이전트에게 그렇게 말했습니다. 수요일에 화면 흐름 에이전트가 새 안을 가져왔는데, 초대 화면이 들어 있습니다. 그 에이전트는 지난주 대화를 기억하고 있었고, 월요일의 결정은 다른 대화 창에서 일어났기 때문입니다.

에이전트가 잘못한 것은 없습니다. 각자 자기가 본 마지막 대화를 기준으로 성실하게 일했을 뿐입니다. 문제는 "지금 범위가 무엇인가"를 적어 둔 자리가 없었다는 것입니다. 대화 기록은 원장이 아닙니다. 대화는 창마다 다르고, 길어지면 앞부분이 사라지고, 에이전트마다 보는 범위가 다릅니다.

원장은 그 반대입니다. 상태 하나마다 "지금 참인 것은 여기 적힌 것"이라고 가리킬 수 있는 한 곳입니다. 위 예시라면 이번 분기 범위를 적은 파일 하나가 원장이고, 에이전트 셋은 일을 시작할 때 대화 기록이 아니라 그 파일을 먼저 읽습니다. 읽게 하는 방법은 단순합니다. 에이전트에게 주는 지시문 첫 줄에 "시작하기 전에 범위 원장을 읽고, status 가 in 인 항목만 다룬다"고 적습니다. 월요일의 결정은 그 파일에 한 줄로 적히고, 수요일의 화면 안을 받을 때 그 줄과 맞춰 보면 초대 화면은 바로 걸립니다. 무엇으로 맞춰 보는지는 다음 절의 계약입니다.

원장은 YAML 파일(사람과 기계가 함께 읽을 수 있는 설정 파일 형식) 하나입니다. 코드 저장소를 쓰는 팀이면 맨 위 폴더에 두고 에이전트와 사람이 같은 파일을 읽습니다. 채팅형 도구만 쓴다면 대화를 시작할 때마다 그 파일을 첨부하는 것으로 시작해도 됩니다. 형식만 보이면 이렇습니다. 값은 가상입니다.

# 범위 원장 scope.yaml — 파일 하나에 사람 칸과 기계 칸이 같이 있다
baseline_at: 2026-10-06        # 이 상태가 승인된 날
scope:                         # 사람만 쓰는 칸. 모든 항목에 결정 칸이 있다
  - id: S-01
    item: "회원 가입과 로그인"
    status: in                 # in, out 둘 중 하나
    decided_by: "PM"
    decided_at: 2026-10-06
  - id: S-02
    item: "회원 초대"
    status: out
    decided_by: "PM"
    decided_at: 2026-10-06
    reason: "이번 분기 인력 범위 밖"
requests:                      # 기계가 쓰는 칸. 범위를 바꾸자는 요청만, pending 까지
  - from: "화면 흐름 에이전트"
    asks: "S-02 를 in 으로"      # 걸린 결과 안에 들어 있던 요청. 결과 자체는 여기 없다
    status: pending            # 사람이 위 scope 를 바꾸기 전까지 pending 으로 남는다

이 파일에서 중요한 것은 칸이 두 영역으로 나뉜다는 점입니다. 위쪽 scope 는 사람만 씁니다. 항목마다 있는 status, decided_by, decided_at 세 칸을 이 글에서는 결정 칸이라고 부르겠습니다. 상태를 in 과 out 둘로 닫아 두고, 모든 항목에 누가 언제 결정했는지 적습니다. 상태 칸이 닫혀 있으면 에이전트가 "아마 빠진 것 같다"가 아니라 "out"을 읽고, 결정 칸이 있으면 그 상태를 바꿀 때 누구 손을 거쳐야 하는지가 정해집니다. 아래쪽 requests 는 기계가 씁니다. 여기에 들어가는 것은 한 가지, 범위를 바꾸자는 요청뿐입니다. 에이전트가 돌려준 결과 자체는 원장에 들어오지 않습니다. 결과는 다음 절의 검사를 통과하면 다음 에이전트에게 가고, 걸리면 돌려보냅니다. 그 결과 안에 "범위를 바꾸자"는 요청이 들어 있을 때만 그 요청이 requests 에 pending 으로 남고, 사람이 scope 를 고치기 전까지는 아무것도 바뀐 것이 아닙니다.

뒤 에이전트가 멈추는 이유는 계약이 없어서입니다

같은 팀의 둘째 장면입니다. 요구사항 에이전트가 정리한 항목을 테스트 에이전트가 받아 테스트 항목을 뽑습니다. 테스트 에이전트는 항목마다 번호와 인수 조건(이 항목이 끝났다고 볼 기준)이 있다고 가정하고 일합니다. 어느 날 요구사항 에이전트가 항목을 산문으로 돌려줬습니다. 번호도 인수 조건도 없는 문단 다섯 개였습니다. 테스트 에이전트는 되묻지 않았습니다. 문단에서 조건처럼 보이는 문장을 골라 테스트를 만들었고, 그 테스트는 실제 요구와 맞지 않았습니다.

사람끼리 일할 때는 이 자리에서 메신저로 "번호 붙여서 다시 주세요"라고 합니다. 에이전트 사이에는 그 메신저가 없습니다. 앞에서 어긋난 형식이 뒤로 그대로 흘러가고, 오류는 끝까지 번진 뒤에야 사람 눈에 띕니다.

계약은 그 메신저 대신 두는 것입니다. 에이전트가 돌려줄 결과를 받아들이는 조건을 먼저 파일로 적고, 결과가 오면 사람이 아니라 검사기가 그 조건으로 거릅니다. 위 예시라면 조건은 네 줄이면 됩니다. 이것도 형식만 보이면 이렇습니다.

# 계약 contract.yaml — 요구사항 에이전트 → 테스트 에이전트 전달에 거는 조건
from: "요구사항 에이전트"
to: "테스트 에이전트"
rules:
  - 항목마다 id 가 있다                         # 예: R-01
  - 항목마다 acceptance 가 한 줄 이상 있다       # 끝났다고 볼 기준
  - 항목의 scope_id 가 범위 원장의 id 와 맞는다   # 예: R-01 의 scope_id 는 S-01
  - 그 scope 항목의 status 가 in 이다

이 네 줄 중 하나라도 비면 테스트 에이전트에게 넘기지 않고 요구사항 에이전트에게 돌려보냅니다. 화면 흐름 에이전트의 결과를 받는 쪽에도 계약이 하나 더 걸립니다. 앞 두 줄은 화면 단위의 조건으로 바뀌지만 뒤 두 줄, 원장과 잇는 조건은 같습니다. 그래서 첫 장면의 초대 화면은 넷째 줄에서 걸립니다. S-02 가 out 이기 때문입니다. 걸린 결과는 돌려보내지만, 그 결과가 품고 있던 "초대를 다시 넣자"는 요청은 검사기가 버리지 않고 원장의 requests 에 pending 으로 적습니다. 결과를 거르는 길과 범위를 바꾸는 길은 다른 길입니다. 앞의 것은 검사기가 끝내고, 뒤의 것은 사람이 scope 를 고쳐야 끝납니다. 같은 네 줄은 요구사항 에이전트의 지시문에도 넣어 둡니다. 만들 때부터 id, acceptance, scope_id 를 적게 해야 받는 쪽에서 확인할 것이 생깁니다. 검사기는 거창할 필요가 없습니다. 처음에는 결과를 넘기기 전에 네 줄을 스스로 대조하라는 지시문 한 줄이 검사기인데, 만든 쪽의 자기 점검이라 빈 칸을 놓칠 수 있습니다. 그다음 단계는 받는 쪽 에이전트가 일을 시작하기 전에 같은 네 줄을 먼저 확인하게 하는 것이고, 익숙해지면 네 줄을 확인하는 작은 스크립트로 바꿉니다. requests 에 적는 주체도 그 검사기와 같습니다. 지시문 단계에서는 결과를 만든 에이전트가, 받는 쪽이 확인하는 단계에서는 받는 쪽 에이전트가, 스크립트 단계에서는 스크립트가 적습니다. 채팅형 도구만 쓴다면 에이전트가 돌려준 요청 줄을 사람이 파일에 옮겨 적는 것으로 시작해도 됩니다.

소프트웨어 개발에서는 이것을 계약 테스트(contract testing)라고 부릅니다. 서비스를 내놓는 쪽과 쓰는 쪽이 주고받을 형식을 기계가 읽는 약속으로 적어 두고, 바꾼 것을 내보내도 안전한지를 사람이 아니라 자동 검사가 답하게 하는 방식입니다. 에이전트 사이의 전달에 필요한 것도 같은 모양입니다. 다른 점은 약속이 프로그램 규격이 아니라 "이 칸이 비면 받지 않는다" 한 줄부터 시작한다는 것입니다.

초안 요구사항 화면 흐름 테스트 계약 검사 번호 인수 조건 원장 연결 상태 in 변경 요청만 통과한 결과는 다음 에이전트로 걸리면 되돌아간다 원장 (파일 하나) requests 칸 범위 변경 요청 pending 까지 기계가 적는다 scope 칸 사람만 채운다 검사는 전달마다 한 번씩
검사를 통과한 결과는 다음 에이전트에게 가고, 범위를 바꾸자는 요청만 원장의 requests 칸에 pending 으로 남으며, scope 칸은 사람만 채웁니다.
설명을 위한 전체 모양입니다. 결과 자체는 원장에 들어오지 않습니다. 검사 항목과 칸 이름은 팀마다 다르게 정합니다.
PART 02표준은 무엇을 말하고 있나

변경 통제 표준은 이미 기준선과 등록부를 말하고 있었습니다

이 두 장치는 새로 발명된 것이 아닙니다. 위 예시의 범위 원장 파일로 먼저 말하면, 승인된 날 이후의 그 파일 내용이 기준선(baseline, 승인된 뒤로는 정해진 절차를 거쳐야만 바꿀 수 있는 상태)입니다. 프로젝트 관리 국제 표준인 ISO 21502는 그 절차를 변경 통제(change control)라고 부르며 관리 실무의 하나로 두고, 변경을 등록부에 적어 승인을 거치게 하라고 권고합니다. 성과 관리는 기준선 대비 편차, 곧 승인된 계획과 실제가 얼마나 벌어졌는지를 세는 일로 봅니다. 영국에서 나온 프로젝트 관리 방법론인 PRINCE2 7판도 기준선을 "승인되면 변경 통제 대상이 되는 것"으로 정의합니다. 위 예시로 옮기면 표준의 두 개념이 원장 파일의 두 영역에 대응합니다. 기준선은 scope 칸이고, 변경 등록부(change register, 변경 요청을 적어 두는 목록)는 requests 칸입니다. 표준에서는 흔히 다른 문서 둘이지만, 에이전트가 읽는 파일은 하나가 낫기 때문에 이 글은 한 파일의 두 칸으로 둡니다. 이 글에서 원장이라고 하면 그 파일 하나를 가리킵니다. 승인은 둘로 나뉩니다. 받을 수 있는 형식인가는 계약 검사기가 맡고, 범위를 바꿀 것인가는 사람의 결정 칸이 맡습니다. 사람의 손이 필요한 것은 범위를 바꾸는 요청뿐이고, 검사를 통과한 결과는 사람을 거치지 않고 다음 에이전트에게 갑니다. 검사를 통과했다는 것은 받을 수 있다는 뜻이지 범위가 바뀌었다는 뜻이 아닙니다.

사람이 수행자일 때 이 규율은 느슨해도 티가 잘 나지 않았습니다. 기준선이 파일로 없어도 팀원들 머릿속에 합의가 있었고, 모호하면 서로 되물었습니다. 수행자가 에이전트로 바뀌면 두 가지가 동시에 사라집니다. 머릿속 합의가 없고, 되묻지 않습니다. 에이전트는 기준선 파일이 없으면 자기가 본 마지막 대화를 기준선으로 삼고, 승인을 기다리지 않고 결과를 돌려줍니다. 돌려준 것과 받아들인 것이 같은 순간 섞입니다. 표준이 옳았다는 이야기가 아니라, 표준이 사람을 전제로 쓰였고 수행자가 바뀌자 그 전제가 어디서 어긋나는지가 보인다는 이야기입니다.

구분 원장 계약
답하는 질문 지금 공식 상태는 무엇인가 무엇을 주고받기로 했는가
모양 파일 하나 (사람이 쓰는 scope 와 기계가 쓰는 requests) 받아들이는 조건 몇 줄과 그것을 확인하는 검사기
막는 문제 빠진 기능이 다시 들어옴, 대화마다 다른 상태 형식 불일치가 뒤로 번짐
PART 03사람은 무엇을 쥐나

결정 칸을 사람이 쥐어야 원장이 원장으로 남습니다

마지막은 규칙 하나, 원장의 결정 칸(scope 의 status, decided_by, decided_at)을 사람만 채우는 것입니다. 이 원칙이 가장 자주 흔들립니다. 에이전트가 requests 에 pending 으로 적는 데서 멈추지 않고 scope 까지 고치게 하면 빠르고, 당장은 문제가 보이지 않습니다. 그런데 그 순간 반환과 수용이 섞입니다. 에이전트가 "회원 초대를 다시 넣자"는 안을 돌려줬다는 것과, 팀이 그 안을 받아들여 범위를 바꿨다는 것은 다른 사건입니다. 둘을 같은 칸에 적으면 기준선은 마지막으로 돌아온 안이 됩니다.

미국 PMI가 펴내는 프로젝트 관리 지식 체계인 PMBOK 8판은 변경 요청을 평가해 받아들이거나 돌려보내는 일을 프로젝트를 통제하는 실무의 하나로 둡니다. 거기에 제가 보태어 쓰는 규칙은 한 줄입니다. 결정 칸은 사람이 채우고, 도구는 requests 에 pending 까지만 적는다. 표준이 말한 것은 앞 문장까지이고, 뒷 문장은 에이전트 환경에 맞춰 제가 좁힌 적용입니다. 에이전트는 초안을 만들고, 검사기는 조건을 보고, 사람은 결정 칸을 채웁니다. 원장에는 "돌아왔다"(requests 의 pending)와 "받아들였다"(scope 의 status 변경)가 다른 칸으로 남습니다.

이 방식은 세션 하나로 에이전트 하나만 쓸 때는 과합니다. 상태를 기억하는 사람이 한 명이고 전달이 일어나지 않으면 원장은 대화 기록으로 충분하고 계약은 프롬프트 한 줄로 충분합니다. 에이전트가 둘이 되거나, 한 에이전트의 결과가 다른 에이전트의 입력이 되는 순간부터 이 글의 내용이 필요해집니다.

마치며: ‘더 똑똑한 프롬프트’가 아니라 ‘원장 하나와 계약 하나’

에이전트에게 자율을 주면서 일이 탈선하지 않게 하는 방법은 더 정교한 지시가 아니라 상태를 적는 원장 하나와 결과를 거르는 계약 하나를 파일로 두고, 결정 칸을 사람이 쥐는 것입니다.

오늘 해 볼 일은 하나입니다. AI에게 맡기고 있는 일 하나를 골라, 그 일의 지금 상태를 보여 주는 정본 파일이 어디인지 한 줄로 적어 보시길 권합니다. 대답이 "대화 기록 어딘가"라면 그 자리가 원장이 들어갈 자리입니다. 그다음에는 그 일의 결과를 받아들이는 조건을 한 줄로 적어 두면, 계약의 첫 줄이 됩니다.

이 글은 AI의 도움을 받아 작성했습니다.

참고 자료

  1. ISO 21502:2020 Project, programme and portfolio management, Guidance on project management: https://www.iso.org/standard/74947.html
  2. PRINCE2 7th edition, PeopleCert: https://www.peoplecert.org/prince2
  3. PMBOK Guide 8th edition, Project Management Institute: https://www.pmi.org/standards/pmbok
  4. Pact, Consumer-driven contract testing: https://docs.pact.io/
  5. OpenAPI Specification: https://spec.openapis.org/oas/latest.html
이 글 공유하기
LinkedIn Threads X Facebook
다음 문