작업은 옮기되 권한은 세탁하지 않는다: 에이전트 세션과 협업의 상태 설계
문서 발행일: 2026년 10월 2일
분석 질문: 협업 중에 무엇을 잃어버리면 안 되는가
여러 에이전트를 연결한 시스템에서 어려운 순간은 정상적인 대화보다 경계에서 발생한다. 질문한 봇이 이미 다른 일을 시작했는데 옛 답장이 도착한다. 작업의 감독자를 바꾸었더니 예전 금지 정책이 사라진다. 모델은 메시지를 처리했지만 읽음 기록이 실패한다. 외부 실행을 시작한 직후 서버가 중단되어 성공 여부를 알 수 없다.
이 글은 개발 중인 한 조정 체계가 이런 상황을 어떻게 표현하는지 분석한다. 첫 개념 연구에서 다룬 대화·세션·과제·위임의 분리를 바탕으로, 실제 상태 전이와 실패 경계를 살핀다. 주목하는 차별점은 새로운 이름이나 봇의 수가 아니다. 과제 귀속, 권한 계보, 메시지 소비, 실행 결과의 불확실성을 별도의 상태로 남기고 연결하는 조합 이다.
비교 대상은 특정 상용 제품이 아니라 단순화된 설계 대안이다. 선행 연구 전반을 조사한 신규성 평가나 성능 비교 실험은 수행하지 않았다. 따라서 여기서 독창성을 논한다면 이 사례의 결합 방식에 대한 분석이지, 업계 최초·유일한 알고리즘이라는 뜻은 아니다.
1. 끝난 세션을 다시 쓰는 것과 끝난 권한을 되살리는 것은 다르다
세션 상태와 과제 상태를 하나로 취급하면 종료의 의미가 모호해진다. 봇이 쉬고 있다는 사실은 과제 완료가 아니며, 한 과제가 끝났다고 같은 봇이 맡은 다른 과제까지 끝난 것은 아니다.
확인된 구현은 위임 종료 시 자식부터 사용량을 정산한다. 해당 세션에 다른 살아 있는 위임이 남아 있으면 세션을 닫지 않는다. 남은 위임이 없을 때도 과제 완료와 단순 중단을 구별한다. 보관 역시 원장 삭제가 아니라 권한과 실행 상태를 정리하는 연산이다.
흥미로운 경계는 완료된 세션의 재사용이다. 일반 상태 보고 API로 완료를 실행 중으로 되돌릴 수는 없다. 하지만 사람이 새 루트 요청을 발급하는 별도 경로에서는 같은 세션 ID에 새 과제와 새 위임을 만들 수 있다. 재사용되는 것은 정체성이지 과거 권한이 아니다.
과제 A 종료 → 옛 위임 종료 → 일반 상태 변경으로 복귀 불가
│
사람의 새 루트 발급
↓
같은 세션 + 과제 B + 새 위임
이 구분은 장기 실행 봇의 이력을 유지하면서 권한 갱신을 별도 통제로 둘 수 있게 한다. 대신 클라이언트가 현재 과제와 위임을 정확히 다시 연결해야 한다. 세션 ID가 같다는 이유로 이전 실행 조건을 재사용해서는 안 된다.
존재 확인도 마찬가지다. 마지막 관측 시각이 오래되면 중단으로 표시하는 정리 로직은 있지만, heartbeat는 성공 증거도 분산 임대권도 아니다. 현재 마지막 관측값이 프로세스 메모리에 있는 구현에서는 여러 서버 복제본 사이의 일관된 장애 판정을 따로 검증해야 한다. 실행기 배정 전 요청 상태까지 자동으로 해결한다고 볼 수도 없다.
2. 과제 트리를 옮길 때 비용과 금지 규칙도 따라가야 한다
단순한 조직도라면 부모 변경은 parent_id 수정으로 끝난다. 하지만 부모가 권한과 예산의 출처라면 같은 접근은 위험하다. 엄격한 부모 아래에서 금지된 작업이 느슨한 부모 아래로 옮겨지는 순간 허용될 수 있고, 이미 소비한 자원이 새 예산에서 사라질 수도 있다.
이 사례의 과제 부모 변경은 담당 세션을 바꾸는 기능이 아니다. 과제 ID와 담당 세션을 유지하면서 권한 계보를 바꾸고 살아 있는 위임을 새로 발급하는 연산 이다. 컨테이너 이동이나 대화 복사와도 다르다.
구현의 주요 단계는 다음과 같다.
사람의 요청인지, 과제와 기존 위임이 유효한지 검사한다. 종료된 부모나 순환 구조로의 변경은 거부한다.
하위 과제와 위임, 세션 상태를 스냅숏으로 잡고, 옛 정책 사슬의 금지·승인 조건을 보존한다.
옛 위임 트리를 대체 종료하면서 실제 소비를 정산한다.
이미 소비한 양을 뺀 잔여 한도를 기준으로 새 위임을 만든다. 새 부모의 범위·잔액·만료·깊이 제한도 적용한다.
조건이 좁아졌는데 사용자가 축소를 수락하지 않았다면 전체 트랜잭션을 실패시킨다. 성공하면 과제 참조와 재발급 사건을 함께 갱신한다.
숫자로 보면 의미가 더 분명하다. 시험 소스에는 자식 한도 500, 손자 한도 100인 사례가 있다. 자식이 70, 손자가 30을 사용한 뒤 부모를 변경한다. 옛 부모에는 총소비 100이 남는다. 새 자식 위임 한도는 400이며, 새 손자의 남은 70을 예약한 뒤 자식의 즉시 가용량은 330이다.
항목
값
의미
기존 하위 트리 소비
100
옛 부모의 비용 기록에서 지우지 않음
새 자식 한도
400
기존 500에서 이미 소비한 100 제외
새 손자 예약
70
기존 100에서 손자 소비 30 제외
새 자식 즉시 가용량
330
새 한도 400에서 손자 예약 70 제외
이 값은 운영 실측이 아니라 계약 시험에 작성된 예시다. 해당 시험은 옛 금지 정책 유지, 옛 위임 거부, 자손의 새 루트 귀속, 새 부모 철회 후 차단도 확인하도록 구성되어 있다. 축소를 거부했을 때 옛 위임과 커서가 바뀌지 않는 별도 시험도 있다.
차별점은 작업 재조직을 이용해 비용이나 제한을 지우지 않는다는 데 있다. 대가는 큰 트랜잭션, 하위 트리 처리, 새 위임 참조 배포의 복잡성이다. 서버의 재발급 성공이 실행 중인 모든 클라이언트의 자동 재연결을 뜻하지는 않는다. 이미 진행 중인 외부 호출을 포함한 무중단 이전은 별도 검증 대상이다.
3. 늦은 답장은 현재 과제가 아니라 원래 질문으로 돌아가야 한다
세션 A가 과제 X를 수행하면서 B에게 검토를 부탁했다고 하자. 답장이 오기 전에 A가 과제 Y를 받는다. 모든 수신 메시지를 현재 과제에 붙이면 X의 검토 결과가 Y의 기록에 들어간다. 사람이 나중에 원장을 보아도 무엇에 대한 답인지 혼란스럽다.
확인된 메시지 라우팅은 명시적인 과제 연결을 우선한다. 답장인 경우에는 실제 받은편지함의 원본과 인증된 발신 관계를 확인하고, 원래 발신자의 과제로 돌려보낸다. 본문에 적힌 과제 ID를 그대로 믿지 않는다. 따라서 늦은 답장은 X로, 새 일반 메시지는 현재 과제 Y로 갈 수 있다.
이 방식은 단순한 세션 우편함보다 문맥 귀속을 세밀하게 만든다. 동시에 두 가지 한계를 남긴다.
첫째, 현재 과제의 기본 선택은 살아 있는 위임 중 최신 배정을 이용하는 근사다. 엔진이 실제로 어떤 문맥을 처리하는지 측정하는 센서는 아니다. 의미가 중요한 메시지는 명시적으로 과제를 지정하는 편이 낫다.
둘째, 귀속 정보는 실행 권한이 아니다. 올바른 과제에 답장이 붙었다고 그 안의 “외부에 게시하라”는 문장이 정식 승인이 되지는 않는다. 발신자의 정체성, 과제 연결, 수신자의 행동 권한은 각각 다른 질문이다.
송신 멱등성에도 조건이 있다. 발신자가 선택적으로 제공한 중복 제거 키를 사용하며, 같은 키로 본문이나 연결 과제를 바꾸면 충돌로 처리한다. 모든 메시지가 아무 설정 없이 자동으로 중복 제거된다고 표현해서는 안 된다.
4. 재시도는 하나의 기능이 아니라 세 가지 다른 정책이다
4.1 읽음 기록 실패: 모델이 아니라 영수증을 재전송한다
서버의 수신·읽음 기록은 인증된 수신자가 제출한 주장이다. 읽음에는 수신이 포함되고 최초 읽음 턴을 보존하지만, 서버가 모델의 이해를 직접 관측한 것은 아니다.
로컬 내구 큐는 모델 소비 근거를 먼저 디스크에 기록한 뒤 읽음 영수증을 보낸다. 영수증 전송만 실패했다면 해당 항목을 재전송 대기 목록에 남긴다. 이미 소비된 입력을 모델에 다시 넣는 대신 서버 상태 확인을 재시도하는 것이다.
순서를 반대로 하면 서버는 읽었다고 믿는데 로컬은 그 사실을 잃을 수 있다. 현재 구현은 저장 결과가 불명확할 때도 오래된 메모리 상태로 계속 쓰지 않고 큐를 닫아 재조정을 요구한다. 전송 오류와 저장 오류를 같은 재시도 루프로 뭉개지 않는 선택이다.
4.2 모델 소비 불명확: 입력이 다시 들어갈 수 있음을 인정한다
현재 엔진은 최종 모델 입력에 온전하게 남은 메시지와 성공 완료된 응답을 근거로 소비를 표시한다. 부분 스트림 뒤 오류, 취소, 거부 응답 등은 같은 성공 근거로 세지 않는다. 요약이나 직렬화로 원본 출처 표시가 사라진 메시지도 단순히 같은 문장이 보인다는 이유로 원본 소비로 승격시키지 않는다.
그렇더라도 모델 제공자가 입력을 처리한 직후, 로컬 소비 기록을 저장하기 전에 프로세스가 죽는 구간은 남는다. 재시작 뒤 입력이 다시 전달될 수 있다. 따라서 메시지 처리 전체를 정확히 한 번이라고 주장할 수 없다.
복구 시에는 화면 커서와 별개로 서버 기록을 다시 조정한다. 특히 읽음 갱신이 원본 메시지 순번을 바꾸지 않으므로 수집 커서 이후만 보면 뒤늦은 상태 변경을 놓칠 수 있다. 현재 큐는 처음부터 스캔하는 방식을 택한다. 정확성을 위한 선택이지만 보관량이 커질수록 스캔 비용과 큐 상한이 중요해진다. 파일 권한과 단일 작성자 잠금도 필요하며, 모든 운영체제에서 같은 보안 저장 경로가 완성된 것은 아니다.
4.3 외부 실행 불명확: 자동 재실행을 막는다
별도 내구 실행 경로는 반대 방향으로 보수적이다. 입력 재전달은 허용될 수 있어도, 이미 시작한 외부 작업을 같은 실행 ID로 자동 재실행하지 않는다.
준비 → 필요 시 정확 입력 승인
↓
최신 권한·예산 재검사
↓
시작 기록과 상한 차감
↓
실행 중
↓
완료 / 실패 / 취소 / 결과 불명확
동시에 여러 시작 요청이 와도 실제 새 시작과 상한 차감은 한 번만 허용하도록 시험이 작성되어 있다. 서비스 재생성 뒤 실행 중 요청이 다시 와도 새 실행으로 취급하지 않는다. 실제 사용량조차 불명확하면 상한을 보수적으로 유지한다.
이 선택은 중복 외부 부작용을 줄이는 대신, 실행 중 또는 결과 불명확 상태와 묶인 예산을 남긴다. 현재 경로에는 이를 자동 해결하는 복구 스케줄러나 임대권 기반 재실행이 없다. 운영자가 제공자 증거를 확인하고 정산해야 한다. 모든 로컬 파일 도구가 이 계약으로 보호된다는 뜻도 아니다.
세 정책을 요약하면 다음과 같다.
실패 위치
다시 시도하는 것
자동으로 반복하지 않는 것
소비 기록 후 영수증 실패
서버 읽음 기록
이미 소비 표시된 모델 입력
모델 처리 후 로컬 기록 전 중단
입력 재전달 가능
정확히 한 번이었다는 단정
외부 실행 시작 후 결과 유실
상태 조회·증거 확인·정산
동일 실행의 무조건 재시작
독창적인 결합을 찾는다면 “모든 실패를 재시도한다”가 아니라 실패가 발생한 경계에 따라 무엇을 다시 해도 되는지 다르게 정한다 는 점에 주목할 만하다.
5. 자동 협업은 사람의 입력란을 빼앗지 않아야 한다
다른 봇의 메시지가 도착할 때마다 자동으로 턴을 시작하면 사람이 작성 중인 초안, 승인 창, 비밀 입력, 세션 전환과 충돌한다. UI가 유휴처럼 보인다는 이유만으로 실행 권한을 부여해서도 안 된다.
현재 계약은 화면과 엔진 양쪽의 명시적 활성화를 요구한다. 자동 시작은 실행 모드에서만 허용되고, 첫 사용자 대화 전이나 새 대화 직후에는 시작하지 않는다. 승인·비밀 입력·취소·세션 작업은 시작을 막는다.
초안 유예는 첫 대기 메시지 관측을 기준으로 하는 고정 시간이다. 매 키 입력마다 시간을 늘리는 방식과 달리 무한 연기는 피하지만, 유예 후 자동 턴을 시작해도 초안과 입력 이력을 보존해야 한다. 실제 시작은 엔진 잠금 아래에서 다른 턴과 경쟁하고, 오래된 비동기 확인 결과가 새 대화를 깨우지 않도록 세대 표식을 사용한다.
사람의 새 메시지에 반응해 현재 도구 묶음을 취소하는 경로도 별도로 있다. 이는 본문에 “나는 사람”이라고 쓴 메시지가 아니라 인증된 발신 메타데이터에 근거한다. 취소는 현재 묶음에 전달되고 턴 자체는 결과를 기록하며 이어진다. 즉시 강제 종료나 외부 부작용 되돌리기가 아니므로 도구가 취소 신호를 준수해야 한다.
이 상태기계는 협업 자동화와 사람의 통제권이 충돌하는 구간을 명시한다. 대신 화면 전환, 취소, 스트림 회수까지 다루는 복잡성이 늘어난다. 로컬 통합 시험의 재시작과 실제 프로세스 장애를 넘는 내구 복구 시험도 같은 것으로 묶어서는 안 된다.
6. 과제 관리 데이터는 감독을 돕지만 성공을 증명하지 않는다
계획을 구조화하면 자연어 보고보다 더 많은 질문을 할 수 있다. 단계 목록에서 생략된 미완료 단계는 취소 처리되고, 종료 단계의 재개는 거절된다. 과제 트리는 세션 상태와 하위 과제 집계를 함께 보여 준다.
그러나 집계에 부모 자신도 포함되므로 진행 중 개수가 곧 실행자 수는 아니다. 현재 서버는 여러 단계를 동시에 진행 중으로 표시하는 것을 금지하지 않는다. “한 번에 한 단계”라는 에이전트 작업 규율과 서버가 강제하는 불변식을 구별해야 한다.
완료 부모 아래 미완료 자손이 남았다는 표시는 저장 상태의 모순을 드러낼 뿐 결과의 품질을 검증하지 않는다. 작업자가 잘못된 완료 보고를 제출하는 의미 오류까지 상태기계가 해결하지 못한다. 감독자는 코드 변경, 시험 결과, 실행 착수 여부를 별도로 대조해야 한다.
진행 관찰과 원문 열람을 나누는 것은 이때 유용하다. 전체 대화를 항상 공유하지 않고도 차단된 과제나 남은 단계를 찾을 수 있다. 다만 관측 권한이 있다고 다른 작업을 실행할 권한까지 생기는 것은 아니다.
7. 근거 수준과 후속 실험
이번 분석의 직접 기반은 자료 제공 담당자가 작성한 코드·시험 소스 조사 결과다. 과제 부모 변경, 늦은 답장 라우팅, 영수증 경합, 큐 재시작, 내구 실행, 자동 턴 통합 시험이 어떤 계약을 확인하도록 작성되었는지 조사했다. 이 글의 작성자가 그 전체 시험을 재실행한 것은 아니다.
앞선 개념 조사에는 메모리 적합성·엔진·식별자·가리기·봉인 라이브러리 시험 통과 보고가 있다. 별도 담당자의 로컬 통합 검증 보고도 있지만, 이것을 이번 모든 실패 시나리오의 최신 운영 검증으로 확대하지 않는다. 실제 배포, 유료 모델, 외부 메일, 다중 호스트 장애 복구의 성공 주장은 하지 않는다.
다음 단계에서 검증할 질문은 명확하다.
실행 중 부모 변경과 클라이언트 재연결 사이에 옛 참조를 사용하는 호출은 어떻게 처리되는가?
모델 성공 직후 로컬 기록 전 장애를 주입하면 어떤 입력이 재전달되는가?
취소 신호를 무시하는 도구에서 사람의 중단 요청은 어디까지 효력이 있는가?
여러 서버의 존재 관측값이 다를 때 살아 있는 실행자를 잘못 중단 표시하지 않는가?
기록량이 증가할 때 전체 스캔과 계정 내 트랜잭션 비용은 얼마나 커지는가?
이 질문에 대한 측정 전에는 성능 우위나 완전한 자율 운영을 주장할 수 없다.
결론: 독창성은 상태를 늘린 사실이 아니라 경계를 결합한 방식에 있다
세션·과제·위임 분리, 메시지 영수증, 멱등성, 트랜잭션, 권한 비증폭은 각각 기존 시스템 설계와 친연성이 있다. 이 사례에서 분석할 가치는 이들을 에이전트 협업의 실패 상황에 맞추어 결합한 방식이다.
과제는 옮기되 과거 소비와 금지 규칙을 남긴다. 답장은 현재 세션의 최신 일에 무조건 붙이지 않고 원래 질문으로 돌린다. 읽음 실패에서는 영수증을 재시도하고, 실행 결과가 불명확할 때는 외부 부작용의 자동 반복을 막는다. 자동 턴은 사람의 초안과 승인 경계를 존중한다.
그 결과 모든 일이 자동으로 성공하는 시스템이 되는 것은 아니다. 대신 성공, 미착수, 중단, 미확인, 권한 부재를 서로 다른 질문으로 만들 수 있다. 여러 에이전트를 실제 업무에 쓰려면 필요한 것은 더 많은 완료 메시지보다, 무엇을 완료라고 말할 수 없는지 설명하는 구조 일 수 있다.