봇이 봇에게 일을 맡길 때: 위임장과 작업 ID 로 묶은 AI 에이전트 협업 구조
AI 에이전트 협업 구조 제안
발행일: 2026-09-30
소개
AI 코딩 에이전트 하나에게 일을 시키는 것은 이제 흔한 일이다. 어려워지는 것은 그다음이다. 에이전트가 다른 에이전트에게 일을 나눠 맡기고, 사람은 여러 에이전트가 동시에 하는 일을 한눈에 보고 싶어진다. 그 순간 세 가지 질문이 생긴다.
이 봇은 누구의 권한으로 이 일을 하고 있나?
그 권한은 어디까지 이고, 다른 봇에게 넘길 때 어떻게 줄어드나 ?
지금 무엇이 어디까지 진행됐고, 무슨 대화와 도구 호출이 있었나?
banya 는 이 세 질문에 답하기 위해 위임장 , 작업 ID , 중앙 원장 세 가지를 축으로 하는 협업 구조를 설계했다. 이 글은 그 설계와, 설계의 핵심 가정인 "모델이 위임장을 직접 읽고 판단할 수 있는가"를 실제 모델로 시험한 결과를 정리한다.
현재 상태: 설계를 마쳤고, 에이전트의 작업 계획 도구( work_plan )와 작업 기록 저장을 먼저 구현했다. 나머지는 아래 단계 순서대로 구현한다.
1. 한눈에 보는 구조
구성 요소
하는 일
허브
위임장 발급·재위임·폐기, 봇 세션 등록, 대화 원장, 작업 트리, 승인, 모델 게이트웨이
봇 세션
봇 하나. 위임장 하나, 대화 원장 하나, 실행 환경 하나
위임장
누가 누구에게 무엇을 어디까지 맡겼는지 적고 서명한 뒤 봉인한 증명서
작업
책임의 단위. 모든 기록이 작업 ID 를 가진다
대화 원장
봇 세션에서 일어난 일을 추가만 되는 이벤트로 쌓은 기록
봇 컨테이너
봇마다 하나씩 주어지는 독립 실행 환경. 외부 제공자가 만든다
봇은 허브를 거쳐서만 모델을 부르고 기록을 남긴다. 컨테이너에는 사용자의 키나 토큰이 들어가지 않는다. 컨테이너는 짧게 쓰는 부트스트랩 토큰 하나로 시작해, 그 세션의 단기 위임 토큰과 봉인된 위임장, 그 위임장만 풀 수 있는 세션 전용 파생 키로 바꿔 쓴다.
2. 기존 대화 기반 협업과 무엇이 다른가
지금 여러 에이전트가 함께 일하는 방식은 대개 대화 를 매개로 한다.
대화 이어 붙이기 : 앞 에이전트의 대화 전체나 요약을 다음 에이전트의 프롬프트에 붙여 넘긴다.
같은 자격으로 하위 에이전트 띄우기 : 오케스트레이터가 자기와 같은 키·권한으로 하위 에이전트를 띄우고, 결과를 텍스트로 돌려받는다.
공유 채팅방 : 사람과 봇들이 한 스레드에서 말로 조율한다.
셋 모두 시작은 쉽다. 하지만 권한과 책임이 대화 속 문장으로만 존재하는 탓에, 봇이 늘어날수록 다음 표의 왼쪽 문제가 커진다.
항목
대화 기반 협업
위임장·작업 ID 구조
권한의 근거
공유 키나 같은 자격을 그대로 물려받는다. 누가 허락했는지는 대화를 뒤져야 안다
서명된 위임장 체인. 최초로 허락한 사람(principal)이 모든 위임장에 적혀 있다
넘길 때 권한
전부 넘기거나 아예 안 넘긴다. 줄여서 넘길 방법이 없다
자식은 부모의 부분집합만 받는다. 토큰·시간·하위 봇 수 한도는 부모 잔량에서 예약한다
회수
키를 바꾸면 모든 봇이 함께 멈춘다
위임 하나를 폐기하면 그 아래만 다음 요청부터 멈춘다
추적 단위
대화(메시지 순서). "이 변경은 누가 무슨 권한으로?"에 답하기 어렵다
작업 ID. 담당 세션·위임장·도구 호출·승인이 한 작업에 묶인다
진행 파악
대화를 읽고 사람이 머릿속에서 합친다
작업 트리를 집계한다. 봇이 보고한 값과 허브가 관측한 값을 나눠 보여 준다
맥락 전달
대화를 통째로 붙인다. 토큰이 들고, 오래된 정보와 비밀값까지 같이 건너간다
브리프·체크포인트·agent.md 를 작업 트리를 따라 필요한 만큼 상속한다
비밀값
대화에 섞인 키가 다음 에이전트와 로그로 퍼진다
발생 지점에서 가리고, 쓸 때는 참조로만 쓴다
사람의 개입
매번 확인하거나(느리다) 아예 안 한다(위험하다)
정책이 정한 지점과 의심 정황에서만 멈춘다
감사·재현
에이전트마다 흩어진 로그
세션별 순서와 작업 ID 로 묶인 원장. 서버가 확인한 사실과 봇이 보고한 사실을 구분한다
권한 정보의 노출
권한 설명을 프롬프트에 평문으로 넣는다. 모든 모델 호출과 로그에 그대로 남는다
위임장은 봉인된 채 이동하고, 봇 컨테이너 안에서 도구를 부를 때만 풀린다
모델이 아는 자기 권한
프롬프트의 자연어 설명에 기댄다
위임장을 도구로 읽고 판단한다(아래 실험에서 111문항 중 110·111개 정답)
무엇이 더 나은가. 요점은 권한과 책임을 대화 밖으로 꺼내 기계가 검증하는 구조 로 만든 데 있다. 대화는 여전히 남고 중앙에서 추적된다. 달라진 점은 누가 무엇을 할 수 있는지를 대화가 아니라 위임장이 정하고, 무엇을 했는지를 작업 ID 가 묶는다는 것이다. 그래서 봇이 셋에서 서른으로 늘어도 질문의 답이 대화량에 비례해 흐려지지 않는다.
대가도 있다.
중앙 허브를 운영하고 신뢰해야 한다. 대화가 중앙에 쌓이므로, 개인정보를 제3자에게 넘기지 않는 운영과 비밀값 차단이 전제다.
위임 범위와 정책을 설계하는 수고가 든다.
요청마다 위임 체인을 확인하는 비용이 붙는다.
봇 하나가 혼자 하는 짧은 작업이라면 대화 기반 방식이 더 가볍다.
3. 작업이 뼈대이고, 세션은 담당자다
여러 봇이 얽히면 "세션" 단위로는 일이 추적되지 않는다. 한 세션이 여러 일을 하고, 한 일이 여러 세션에 걸치기 때문이다. 그래서 작업을 뼈대로 삼았다.
관계
규칙
작업 → 세션
작업 하나는 한 시점에 담당 세션이 정확히 하나다
세션 → 작업
세션은 여러 작업을 맡는다(자기 계획의 단계들, 이어서 들어온 요청들)
작업 → 작업
트리다. 부모는 사용자의 명시적 지시로만 바뀐다
위임장 ↔ 작업
담당 세션이 바뀌는 작업 간선에만 위임장이 생긴다
기록 → 작업
대화·모델 호출·도구 호출·승인·한도 사용·맥락 문서가 모두 작업 ID 를 가진다
이렇게 하면 "이 작업은 누가, 어떤 권한으로, 무엇을 했나"가 작업 ID 하나로 풀린다. 사람의 진행 확인도 작업 트리를 위로 굴려 올리는 집계가 된다.
ID 도 이 관계가 드러나게 다시 짰다. 모든 ID 는 접두사_ULID 형식이다. 전역에서 유일하고 시간순으로 정렬되며, 접두사가 종류를 알려 준다( tsk_ 작업, ags_ 봇 세션, dlg_ 위임장, evt_ 원장 이벤트, act_ 도구 호출, inv_ 모델 호출). 코드에서는 종류마다 타입을 달리 둬, 작업 ID 자리에 세션 ID 가 들어가는 실수를 컴파일 단계에서 막는다.
4. 위임장: 넘길수록 줄어드는 권한
위임장은 서명된 JSON 이다. 핵심 필드는 다음과 같다.
{
"principal": { "email": "…", "account_id": "acc_…" },
"delegator": { "kind": "session", "session_id": "ags_…" },
"delegate": { "session_id": "ags_…" },
"task": { "id": "tsk_…", "parent_task_id": "tsk_…" },
"parent_id": "dlg_…", "root_id": "dlg_…", "depth": 1,
"scope": ["banya:run", "model:…", "session:delegate", "observe:progress"],
"policy": { "id": "pol_…", "version": 3, "hash": "sha256:…" },
"limits": { "model_tokens": 2000000, "runtime_minutes": 240, "sub_sessions": 3, "max_depth": 2 },
"expires_at": "…"
}
principal 은 맨 처음 권한을 준 사람이고, 체인의 모든 위임장에 같은 값으로 들어간다. delegator 는 바로 위에서 맡긴 주체다.
서명하고, 봉인한다. 이 내용은 평문으로 돌아다니지 않는다.
사용자가 루트 위임을 승인할 때 자기 기기의 패스키로 위임장 해시에 서명한다. 허브 서명과 함께 들어가 체인의 뿌리가 된다.
서명된 위임장은 암호화한 봉인본(JWE)으로만 전달된다. 봉인 키는 계정마다 하나인 사용자 키에서 (위임장, 세션)마다 따로 파생한 세션 전용 키 다.
컨테이너에는 사용자 키 원본이 아니라 그 세션의 파생 키만, 그것도 메모리에만 들어간다. 디스크와 스냅숏에는 남지 않는다. 키가 새도 그 세션의 위임장 하나만 풀린다.
시스템 프롬프트에는 "위임이 있고 도구로 읽을 수 있다"는 안내만 들어간다. 사용자 정보·범위·한도는 모델이 도구를 불렀을 때 컨테이너 안에서 풀려 필요한 항목만 전달되고, 원장에는 "조회함"만 남는다.
재위임 규칙. 봇이 다른 봇에게 일을 맡기면 허브가 부모 위임장을 근거로 자식 위임장에 서명한다. 봇은 서명 키를 갖지 않는다.
부모에게 재위임 범위( session:delegate )가 있어야 한다.
자식의 범위는 부모 범위의 부분집합이다.
자식의 정책은 부모와 같거나 더 엄격하다.
자식의 한도는 부모의 남은 한도에서 예약한다.
만료는 부모보다 늦을 수 없고, 깊이에는 상한이 있다.
부모를 폐기하면 그 아래 전체가 다음 요청부터 멈춘다.
서명만으로는 부족하다. 서명은 "발급된 적이 있다"는 것만 증명한다. 폐기되었는지는 모른다. 그래서 모델 호출, 기록, 승인 요청마다 허브가 조상 체인 전체가 살아 있는지 확인한다.
승인은 권한을 넓히지 않는다. 정책상 사람이나 부모 봇의 승인이 필요한 행동이 있다. 승인은 이미 받은 범위 안에서 한 번의 실행을 허가하는 것이고, 대상·입력·세션·만료에 묶인다. 범위를 넓히려면 위임장을 다시 발급받아야 한다.
부모 변경. 사용자가 "이 작업은 나에게 직접 보고하라"고 지시하면 작업의 부모가 바뀐다. 위임장은 서명된 뒤 바뀌지 않으므로, 새 부모 체인 아래로 다시 발급 하고 이전 것은 대체된 것으로 끝낸다. 남은 한도는 옛 부모에게 돌려준다. 세션과 대화 기록은 끊기지 않는다.
5. 모델은 위임장을 읽을 수 있을까: 실험
위임을 다루는 도구에는 아직 표준이 없다. 그래서 봇이 자기 위임장을 직접 읽고 "이 행동을 해도 되는가"를 판단할 수 있는지부터 확인했다. 실제 위임장(v1)과 체인·정책·한도를 담은 시험용 위임장(v2)을 두 모델에 주고, 사실 추출과 권한 판단을 각 3회 물었다.
시험
Astra (banya 기본 모델)
Claude
v1 원본(JWS, base64) → 위임자·계정·세션·대리인·범위·만료 추출
18/18
18/18
v1 해독본 → 같은 사실 추출
18/18
18/18
v1 해독본 → 권한 판단(모델 호출, 관리 권한, 재위임, 만료 후, 범위 밖 모델)
15/15
15/15
v2 해독본 → 권한 판단(최초 위임자, 작업·부모 작업, 승인 필요 여부, 승인자, 하위 봇, 남은 토큰, 외부 접속, git push, 깊이)
29/30
30/30
v2 원본(JWS) → 같은 권한 판단
30/30
30/30
합계
110/111
111/111
두 모델 모두 위임장 안의 사람 정보와 작업 범위·권한을 직접 읽고 판단했다. base64 로 묶인 원본도 해독해 읽었다. 여기서 두 가지를 얻었다.
유일한 오답이 설계를 바꿨다. 시험용 v2 에서 최초 위임자가 delegator.on_behalf_of 안에 한 단계 들어가 있었고, 한 번 "알 수 없음"이 나왔다. 그래서 모든 위임장의 최상위에 principal 을 두기로 했다.
실제 경로는 도구다. 이 실험은 읽기 능력을 재려고 위임장을 프롬프트에 직접 넣었다. 실제로는 봉인을 컨테이너 안의 엔진이 풀고 서명·체인을 검증한 뒤, 모델이 delegation_info 를 부를 때만 필요한 항목을 준다. 모델은 서명을 검증할 수 없고 원본 해독은 시간도 더 들기 때문이다. 모델이 잘못 읽더라도 집행은 허브와 엔진이 하므로 막힌다. 모델이 위임장을 읽게 하는 목적은 헛수고를 줄이고 사람에게 설명할 수 있게 하는 데 있다.
이에 따라 봇에게는 위임 전용 도구를 준다.
도구
하는 일
delegation_info
컨테이너 안에서 봉인을 풀어 현재 위임(위임자, 작업, 범위, 정책 요약, 한도 잔량, 만료, 체인) 중 요청한 항목을 읽거나, 특정 행동의 가부를 묻는다
delegate_task
하위 작업을 다른 봇에게 맡긴다. 범위와 한도는 자기 것 이하
task_status
맡긴 작업의 상태와 결과 요약을 본다
request_approval
승인이 필요한 행동을 승인자에게 요청한다
hub_tree, hub_log
작업 트리의 진행을 보거나 기록을 읽는다(관찰 범위가 있을 때)
6. 대화와 맥락은 중앙에, 비밀값은 어디에도
봇 세션의 대화는 두 곳에서 모은다. 하나는 모델 게이트웨이로, 서버가 확인한 모델 입출력을 남긴다. 다른 하나는 봇으로, 봇이 보고한 사용자 메시지·도구 호출·계획 변경·승인을 남긴다. 둘 다 세션별로 추가만 되는 원장에 순서대로 쌓인다.
봇이 새 컨테이너에서 다시 시작하거나 다른 봇의 일을 이어받을 때는 맥락 문서 를 읽는다.
봇별 지시와 학습한 사실을 담은 agent.md
위임할 때 만든 작업 브리프
원장을 요약한 체크포인트
인계 문서, 계정 기억
맥락 문서는 작업 트리를 따라 부모에서 자식으로 상속된다.
사용자의 개인정보는 제3자에게 제공하지 않는다. 그리고 API 키, 토큰, 결제 정보는 원장에도 모델에도 전달하지 않는다.
봇과 CLI 가 보내기 전에 탐지해 [secret:종류] 로 바꾼다.
허브가 받을 때 한 번 더 걸러낸다.
봇이 비밀값을 써야 하면 값 대신 secret://이름 같은 참조를 쓰고, 값은 도구가 실행되는 순간 컨테이너 안에서만 채운다.
7. 자유와 안전장치
봇마다 독립된 가상 컨테이너가 주어지므로 컨테이너 안에서는 도구와 자원을 최대한 자유롭게 쓴다. 문제가 생기면 스냅숏으로 되돌리거나 컨테이너를 새로 만들면 된다. 대신 사람이 붙잡는 지점을 분명히 했다.
월간 재승인 : 루트 위임은 한 달마다 사람이 다시 승인한다. 만료 일주일 전부터 알린다.
의심 정황 재승인 : 감사 기록에서 이상한 흐름이 잡히면 허브가 그 봇과 하위 봇을 멈추고 근거와 함께 재승인을 요청한다. 정책 거부가 반복되거나, 비밀값이 반복해 탐지되거나, 사용량이 급증하거나, 재위임이 폭증하는 경우다. 사람은 재개, 범위를 좁혀 재개, 폐기 중 하나를 고른다.
폐기는 즉시 번진다 : 위임을 끊으면 다음 요청부터 그 아래 모든 봇이 멈춘다. 컨테이너 정지는 그다음이다.
8. 하루치 시나리오: 결제 API v2 전환
시각
무슨 일
09:00
사용자가 개발 리드 봇 A 에게 "결제 API 를 v2 로 옮기고 배포 전 점검까지"를 맡긴다
09:02
봇 A 가 자기 위임을 확인하고 맥락 문서를 읽은 뒤 6단계 계획을 세운다
09:40
봇 A 가 테스트를 봇 B 에게, 보안 점검을 봇 C 에게 맡긴다. 각자 줄어든 범위와 한도를 받는다
10:30
사용자가 관찰 세션에서 "지금 어디까지?"라고 묻는다. A 3/6, B 4/7, C 2/5, 대기 중 승인 1
10:50
봇 C 가 스캐너를 설치해 점검하고 git push 승인을 요청한다. 부모인 봇 A 가 범위 안이라 승인한다
11:20
봇 B 의 테스트 파일에서 실제 형태의 키가 반복 탐지된다. 값은 가려지고 B 는 멈춘다. 사용자가 근거를 보고 재개한다
11:40
봇 B 의 스크립트가 작업공간을 망가뜨린다. 스냅숏으로 되돌리고, 기록은 끊기지 않는다
13:00
사용자가 "보안 점검은 나에게 직접 보고"라고 지시한다. 작업의 부모가 바뀌고 위임장이 다시 발급된다
14:30
쉬고 있던 봇 A 의 컨테이너가 다시 뜬다. 맥락 문서로 기억을 되살려 문서 작업을 잇는다
16:00
모든 작업이 끝난다. 사용자는 변경·승인·재승인·복원·사용량을 한 화면에서 본다
사람이 손을 댄 것은 세 번이다: 시작, 의심 정황 재승인, 부모 변경. 나머지는 봇과 허브가 위임장 안에서 처리했다.
9. 표준과의 관계
"누가 누구를 대신해 행동하는가"를 체인으로 표현하는 가장 가까운 표준은 OAuth 2.0 토큰 교환(RFC 8693)의 act 클레임이다.
권한을 줄여 가며 넘기는 토큰 형식으로는 UCAN, Biscuit 이 있다.
모델이 이를 도구로 다루는 표준은 아직 없다.
그래서 위임 도구를 MCP 도구 형식(이름·설명·JSON 스키마)으로 정의한다. 다른 에이전트도 같은 도구로 위임에 참여할 수 있게 하기 위해서다.
10. 구현 순서
작업 ID 체계와 중앙 원장: 저장소, 봇 세션 등록, 이벤트 수집, 작업 트리 조회
위임장 v2 와 하위 작업: 재위임, 폐기 전파, 한도 예약, 위임장 봉인(패스키 서명·세션 전용 파생 키), 위임 도구, 부모 변경, 의심 정황 재승인
외부 컨테이너 제공자 연동: 실행·정지·스냅숏 요청과 봇 실행 모드
운영: 대시보드, 계정별 암호화, 검색
여러 봇이 한 사람의 권한으로 일하는 순간, 권한과 책임은 코드보다 먼저 설계돼야 한다. 위임장은 권한이 어떻게 줄어들며 넘어가는지를, 작업 ID 는 책임이 어디에 있는지를, 원장은 실제로 무슨 일이 있었는지를 말해 준다.
© 2026 banya. All rights reserved.
문서 생성일: 2026-09-30