4부 20장. 사람 승인과 Human-in-the-loop 설계
자동화를 오래 만지다 보면 이상한 순간이 온다. 처음에는 버튼 하나만 덜 누르게 되어도 감탄한다. 그러다 조금 지나면 더 많은 일을 자동화하고 싶어진다. 메일도 보내고, 티켓도 닫고, 환불도 처리하고, 데이터도 바꾸고 싶어진다. 그런데 바로 그 지점에서 질문이 달라진다.
"얼마나 많이 자동화할 수 있는가?"가 아니라, "어디까지 자동화해도 되는가?"가 된다.
이 질문 앞에서 많은 팀이 두 극단으로 흔들린다. 하나는 모든 것을 자동으로 밀어붙이는 방식이다. 시연은 멋지다. 하지만 작은 오판이 큰 사고로 이어질 수 있다. 다른 하나는 거의 모든 단계에 사람 확인을 붙이는 방식이다. 안전해 보이지만, 이렇게 되면 에이전트는 비싼 알림 봇이 되기 쉽다.
실전의 답은 늘 그 사이 어딘가에 있다. 위험한 순간에는 사람을 끼워 넣고, 안전한 구간에서는 시스템이 스스로 달리게 만드는 것. 바로 그것이 Human-in-the-loop, 즉 사람을 실행 루프 안에 적절히 배치하는 설계다.
이번 장에서는 세 가지를 중심으로 살펴본다. 고위험 행동 전에 어떤 승인 지점을 둬야 하는지, 불확실성이 높아질 때 언제 사람에게 올려야 하는지, 그리고 리뷰 인터럽트 지점을 실행 루프 안에 어떻게 심어야 하는지다. 핵심은 단순하다. 자동화를 늘리되, 통제력은 잃지 않는 것이다.

사람이 끼어든다고 해서 자동화가 실패한 것은 아니다
에이전트를 처음 설계할 때 흔히 드는 오해가 있다. 사람이 개입하면 자동화 수준이 낮아진다고 생각하는 것이다. 하지만 실제 제품에서는 오히려 반대인 경우가 많다. 사람 개입이 잘 설계되어 있으면 시스템은 더 넓은 범위를 안전하게 자동화할 수 있다.
왜 그럴까. 이유는 단순하다. 사람 승인은 자동화를 방해하는 벽이 아니라, 자동화의 안전 범위를 넓혀 주는 울타리이기 때문이다. 예를 들어 에이전트가 고객 데이터를 읽어 요약 보고서를 만드는 일은 꽤 자유롭게 자동화할 수 있다. 하지만 실제 고객에게 메일을 발송하거나, 결제를 취소하거나, 계약 내용을 바꾸는 순간은 이야기가 달라진다. 이때 승인 지점이 없다면 시스템 전체를 좁게 설계할 수밖에 없다. 반대로 중요한 순간에만 사람을 끼워 넣을 수 있다면, 그 전 단계까지는 훨씬 적극적으로 자동화해도 된다.
즉, Human-in-the-loop는 "사람이 대신 한다"는 뜻이 아니다. 정확히는 "시스템이 대부분을 처리하되, 사고 비용이 큰 지점은 사람이 쥔다"는 뜻이다.
승인, 리뷰, 에스컬레이션은 비슷해 보여도 다르다
이 셋은 자주 섞여 쓰이지만, 설계 관점에서는 구분하는 편이 좋다.
승인은 어떤 행동이 실행되기 전에 허가를 받는 것이다. 메일 발송, 환불 승인, 계정 삭제, 운영 명령 실행처럼 돌이키기 어렵거나 외부 효과가 큰 행동 앞에 둔다.
리뷰는 결과물을 검토하는 것이다. 초안, 보고서, 답변, 분류 결과, 추천안처럼 사람이 한 번 보고 품질을 보정하면 가치가 큰 산출물에 붙는다.
에스컬레이션은 시스템이 스스로 처리하지 않고 상위 주체에게 넘기는 것이다. 이유는 대개 불확실성, 권한 부족, 위험 상승, 정책 충돌이다.
이 셋을 뭉쳐서 "사람이 한 번 보면 되지"라고 생각하면 금방 꼬인다. 승인에는 실행 전 차단 기능이 중요하고, 리뷰에는 비교와 수정 도구가 중요하며, 에스컬레이션에는 왜 넘겼는지 설명하는 근거가 중요하기 때문이다.
어떤 행동이 고위험인가
사람 승인을 설계할 때 첫 번째 실수는 "중요해 보이면 일단 승인"이다. 그러면 승인 요청이 눈덩이처럼 불어난다. 결국 사람은 지치고, 시스템은 느려지고, 어느 순간부터는 아무 생각 없이 승인 버튼만 누르게 된다. 이것을 승인 피로라고 생각하면 이해가 쉽다.
그래서 먼저 고위험 행동의 기준을 분명히 잡아야 한다. 실무에서는 보통 네 가지 질문이 유용하다.
이 행동은 되돌리기 어려운가
이 행동은 외부 세계에 직접 영향을 주는가
이 행동은 금전, 법적 책임, 보안, 개인정보와 연결되는가
이 행동이 틀렸을 때 영향 범위가 큰가
예를 들어 내부 문서를 읽어 요약하는 일은 상대적으로 저위험이다. 반면 고객 계정 비활성화, 환불 승인, 대량 메일 발송, 운영 환경 설정 변경, 개인정보 수정, 결제 요청 생성은 훨씬 고위험이다.
여기서 중요한 감각은 행동 자체보다 결과의 무게를 보는 것이다. 같은 도구 호출이라도 상황에 따라 위험이 달라질 수 있다. 고객 한 명에게 초안을 보여 주는 것과, 고객 5만 명에게 실제 메일을 발송하는 것은 전혀 다른 일이다.
위험도는 도구 이름이 아니라 행동 맥락으로 판단해야 한다
초기 구현에서는 종종 이런 규칙을 쓴다. send_email은 승인 필요, search_docs는 승인 불필요. 출발점으로는 나쁘지 않다. 하지만 곧 문제가 생긴다. 같은 send_email이라도 자기 자신에게 테스트 메일을 보내는 것과, 전 고객에게 안내 메일을 보내는 것은 위험도가 다르다. 같은 update_record라도 메모 한 줄을 고치는 것과, 고객 등급을 바꾸는 것은 무게가 다르다.
그래서 승인 정책은 도구 이름만 보지 말고 행동의 맥락까지 함께 봐야 한다. 예를 들어 다음 요소를 같이 판단하면 훨씬 현실적이다.
대상이 누구인가
몇 건에 영향을 주는가
읽기 작업인가, 쓰기 작업인가
되돌릴 수 있는가
개인정보나 금전이 얽혀 있는가
현재 사용자의 권한 수준은 어떤가
결국 승인 정책은 어떤 도구인가보다 무엇을 누구에게 어떤 규모로 하려는가를 묻는 쪽이 더 정확하다.
승인 정책은 규칙표로 시작하는 편이 좋다
사람 승인은 프롬프트 한 줄로 해결할 문제가 아니다. "중요한 일은 사람에게 물어봐"라고 적어 두면 그럴듯해 보이지만, 운영 단계에서는 거의 반드시 흔들린다. 승인 규칙은 모델의 재치가 아니라 시스템 정책으로 표현해야 한다.
가장 실용적인 출발점은 간단한 규칙표다.
| 행동 유형 | 예시 | 기본 정책 |
|---|---|---|
| 읽기 | 문서 검색, 주문 조회, 요약 생성 | 자동 진행 |
| 저위험 쓰기 | 내부 초안 저장, 개인 작업 메모 업데이트 | 자동 진행 가능 |
| 중위험 쓰기 | 티켓 상태 변경, 일정 예약, 테스트 환경 변경 | 조건부 승인 |
| 고위험 쓰기 | 결제, 환불, 계정 삭제, 대량 발송, 개인정보 수정 | 사전 승인 필수 |
| 고권한 작업 | 운영 시스템 변경, 관리자 권한 부여 | 이중 승인 또는 제한 |
이 표가 완벽할 필요는 없다. 중요한 것은 팀이 같은 기준으로 이야기할 수 있게 만드는 것이다. 승인 설계가 어려운 이유 중 하나는 기술 문제가 아니라, 조직 안에서 위험 기준이 말로만 존재하는 경우가 많기 때문이다.
가장 위험한 지점은 "실행 직전"이다
리뷰 인터럽트를 어디에 둘지 고민할 때 많은 팀이 산출물의 마지막만 본다. 하지만 실전에서는 행동이 실제로 외부 세계에 닿는 직전이 가장 중요하다.
예를 들어 고객 응대 에이전트를 생각해 보자. 이 에이전트는 고객 문의를 읽고, 필요한 정보를 찾고, 답변 초안을 만든다. 여기까지는 대부분 자동으로 처리할 수 있다. 하지만 "실제 발송"은 완전히 다른 단계다. 초안 생성과 발송은 언뜻 한 흐름처럼 보여도, 설계상으로는 분리하는 편이 안전하다.
이 원칙은 여러 곳에 적용된다. 보고서 초안 작성과 외부 공유, 구매 추천안 작성과 실제 주문 생성, 운영 변경 계획 수립과 실제 배포 실행은 같은 일이 아니다. 계획과 실행 사이에 브레이크를 넣는 것, 이것이 승인 설계의 핵심 감각이다.
실행 루프 안에 승인 상태를 넣어야 한다
앞 장에서 실행 루프와 상태 머신을 다뤘다면, 이번 장은 그 위에 사람 개입 상태를 더 얹는 작업이라고 보면 된다. 사람 승인은 루프 바깥의 예외 처리처럼 붙이는 것이 아니라, 루프 안의 정상 상태로 취급해야 한다.
예를 들어 상태는 최소한 다음처럼 나뉠 수 있다.
running: 자동 실행 중waiting_user: 사용자 정보 대기waiting_review: 사람 리뷰 대기waiting_approval: 고위험 행동 승인 대기approved: 승인 후 재개 가능rejected: 승인 거절completed: 완료failed: 실패
중요한 점은 waiting_review와 waiting_approval가 실패가 아니라는 사실이다. 이것은 시스템이 올바르게 멈춘 것이다. 오히려 좋은 시스템일수록 이런 상태 전환이 자연스럽다.
간단한 의사코드로 보면 감각이 더 분명해진다.
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class ApprovalRequest:
action_name: str
summary: str
risk_level: str
reason: str
payload_ref: str
@dataclass
class AgentState:
status: str = 'running'
pending_approval: Optional[ApprovalRequest] = None
pending_review_ref: Optional[str] = None
approved_by: Optional[str] = None
rejection_reason: Optional[str] = None그리고 실행 직전의 게이트는 대략 이런 식이 된다.
def maybe_pause_for_approval(state, action):
if requires_approval(action, state):
state.status = 'waiting_approval'
state.pending_approval = ApprovalRequest(
action_name=action.name,
summary=build_action_summary(action),
risk_level=classify_risk(action, state),
reason=explain_why_approval_is_needed(action, state),
payload_ref=save_action_payload(action)
)
return True
return False핵심은 간단하다. 실행 전에 멈추고, 승인 정보를 구조화해서 남기고, 나중에 같은 지점에서 재개할 수 있어야 한다.
불확실성 기반 에스컬레이션은 "자신 없음" 한 줄로는 부족하다
사람들은 종종 이렇게 묻는다. "모델이 자신 없을 때만 사람에게 넘기면 되지 않나요?" 얼핏 맞는 말처럼 들린다. 하지만 여기에는 함정이 있다. 모델이 말하는 자신감은 실제 정답 확률과 잘 맞지 않을 때가 많다. 틀린 답도 아주 당당하게 말할 수 있고, 맞는 답도 지나치게 조심스럽게 표현할 수 있다.
그래서 불확실성 기반 에스컬레이션은 단순한 자기 보고형 confidence 하나에 기대면 안 된다. 대신 여러 신호를 함께 보아야 한다.
대표적인 신호는 이렇다.
요청 자체가 모호하다
필수 정보가 비어 있다
도구 결과끼리 서로 충돌한다
검증된 사실보다 추정이 더 많다
같은 문제에서 여러 번 방향을 바꿨다
반복 실패가 발생했다
행동의 영향 범위가 크다
현재 사용자 권한과 요청 수준이 맞지 않는다
즉, 에스컬레이션은 감정이 아니라 상태와 증거의 함수여야 한다.
불확실성은 숫자 하나보다 신호 묶음으로 다루는 편이 낫다
실전에서는 불확실성을 점수 하나로 만들고 싶어진다. 물론 그렇게 해도 된다. 다만 그 숫자가 어디서 나왔는지가 더 중요하다. 예를 들어 다음처럼 여러 조건을 합산해 점수를 만들 수 있다.
def compute_escalation_score(state) -> int:
score = 0
if state.intent_ambiguous:
score += 3
if state.missing_required_inputs:
score += 3
if state.conflicting_evidence:
score += 4
if state.unverified_assumptions_count >= 2:
score += 2
if state.recent_failures >= 2:
score += 2
if state.action_risk == 'high':
score += 4
if state.requires_privileged_access:
score += 4
return score
def should_escalate_to_human(state) -> bool:
return compute_escalation_score(state) >= 6이 예시는 단순하지만 중요한 메시지를 준다. 에스컬레이션은 "모델이 좀 불안해 보였다"가 아니라, 왜 불안한지 설명 가능한 구조여야 한다는 것이다.
그리고 이 점수는 어디까지나 신호를 모으는 도구일 뿐이다. 실제 정책은 조직과 서비스에 따라 달라질 수 있다. 의료, 금융, 보안, 법률처럼 민감한 분야일수록 기준은 훨씬 보수적이어야 한다.
리뷰 인터럽트는 어디에 두어야 할까
승인 지점은 비교적 눈에 잘 보인다. 외부 발송 전, 결제 전, 삭제 전처럼 행동 직전에 두면 되기 때문이다. 반면 리뷰 인터럽트는 더 섬세하다. 너무 일찍 넣으면 사람은 덜 익은 결과만 계속 보게 되고, 너무 늦게 넣으면 이미 잘못된 방향으로 멀리 와 버린다.
실무에서는 보통 세 군데가 특히 중요하다.
첫째는 계획 직후다. 사용자의 요청이 복잡하고 비용이 큰 작업이라면, 실제 실행 전 계획을 한 번 보여 주는 것이 좋다. 예를 들어 "이 보고서를 만들기 위해 고객 데이터 조회, 최근 상담 분석, 이탈 원인 분류를 수행하겠습니다" 같은 계획 검토 단계다.
둘째는 고비용 단계 직전이다. 긴 브라우저 자동화, 대량 API 호출, 대규모 코드 수정처럼 한번 시작하면 시간과 비용이 큰 작업 앞에서는 중간 검토가 의미 있다.
셋째는 외부 공유 직전이다. 초안 품질, 톤, 민감 정보 포함 여부, 근거의 정확성은 이 지점에서 가장 잘 잡힌다.
여기서 감각이 중요하다. 리뷰 인터럽트는 모든 단계에 두는 것이 아니라, 방향이 결정되거나 피해가 커질 수 있는 갈림길에 두는 것이다.
좋은 승인 요청은 "왜 눌러야 하는지"를 설명한다
사람에게 승인 요청을 보냈는데, 화면에는 버튼 두 개와 장문의 원문만 덩그러니 있는 경우가 많다. 이런 요청은 거의 항상 품질이 떨어진다. 사람은 무엇을 보고 판단해야 하는지 모른 채, 결국 감으로 승인하거나 반려하게 된다.
좋은 승인 요청에는 최소한 다섯 가지가 들어가야 한다.
무엇을 하려는지
왜 이 행동이 필요한지
어떤 근거로 여기까지 왔는지
실행되면 어떤 영향이 있는지
승인, 수정 요청, 거절 중 무엇을 할 수 있는지
예를 들어 "메일을 보내도 될까요?"는 나쁜 요청이다. 반면 이런 요청은 훨씬 낫다.
"VIP 고객 1,240명에게 배송 지연 사과 메일을 발송하려고 합니다. 발송 대상은 지난 7일간 배송 지연이 확인된 고객이며, 이미 환불 처리된 고객은 제외했습니다. 예상 영향 범위는 전체 대상 1,240건입니다. 실제 발송 전 최종 확인이 필요합니다."
사람이 알아야 할 것은 모델의 장황한 추론이 아니라, 판단에 필요한 요약과 근거다.
승인 화면은 원문보다 차이점과 영향 범위를 먼저 보여 주는 편이 좋다
사람 리뷰는 시간이 비싼 과정이다. 따라서 승인 인터페이스는 사람의 주의를 가장 가치 있는 곳에 써야 한다. 특히 수정 가능한 산출물에서는 원문 전체보다 무엇이 바뀌는지를 먼저 보여 주는 것이 효과적이다.
예를 들어 코드 에이전트라면 파일 전체보다 diff를 보여 주는 편이 낫다. 메일 발송이라면 템플릿 원문보다 수신자 수, 제목, 본문 핵심, 금지 표현 포함 여부, 첨부 파일 여부를 먼저 보여 주는 편이 좋다. 데이터 수정이라면 바뀌는 필드와 대상 레코드 수를 먼저 보여 줘야 한다.
결국 사람은 모든 것을 처음부터 읽고 싶어 하지 않는다. 결정에 영향을 주는 핵심 차이와 위험 신호를 먼저 보고 싶어 한다.
사람 승인은 "한 번 더 확인"이 아니라 권한 분리이기도 하다
Human-in-the-loop를 단지 품질 검수 장치로만 보면 중요한 절반을 놓치게 된다. 사람 승인은 종종 권한 분리의 문제이기도 하다.
예를 들어 에이전트가 관리자 권한이 필요한 작업을 직접 실행하지 못하도록 막고, 승인권자가 확인한 뒤에만 실행되게 할 수 있다. 이 구조는 두 가지 효과를 낸다. 첫째, 잘못된 추론이 곧바로 고권한 실행으로 이어지는 것을 막는다. 둘째, 누가 어떤 이유로 허가했는지 기록을 남길 수 있다.
특히 운영 시스템, 재무 시스템, 개인정보 시스템처럼 민감한 영역에서는 이 구조가 매우 중요하다. 단순히 사람이 한 번 보는 것만으로는 부족하고, 누가 승인할 자격이 있는지까지 분리해야 한다.
승인 이후 재개는 같은 상태에서 이어져야 한다
사람 승인을 붙인 시스템이 자주 망가지는 이유 중 하나는, 승인 후 재개가 엉성하기 때문이다. 승인 버튼을 누른 뒤 아예 처음부터 다시 돌거나, 반대로 승인 당시의 맥락을 잃어버리고 엉뚱한 행동을 하는 경우가 생긴다.
그래서 승인 대기 상태에서는 적어도 다음 정보가 저장되어야 한다.
승인 대상 행동의 구조화된 페이로드
승인 요청을 만든 시점의 핵심 근거
승인 전 마지막 상태 스냅샷
승인 만료 시간이나 재검토 조건
승인자와 승인 시각
이 정보가 있어야 시스템은 "무엇을 승인받았는지"를 정확히 알고, 승인 후에도 같은 행동만 이어서 실행할 수 있다. 승인 이후에 새로운 정보가 생겨 상황이 달라졌다면, 원래 승인으로는 부족할 수도 있다. 그래서 어떤 경우에는 승인 재검증도 필요하다.
간단한 예시는 이렇다.
def resume_after_approval(state, approval_event):
if state.status != 'waiting_approval':
raise ValueError('not waiting for approval')
if approval_event.decision == 'reject':
state.status = 'rejected'
state.rejection_reason = approval_event.reason
return
state.approved_by = approval_event.approver
action = load_action_payload(state.pending_approval.payload_ref)
if approval_has_expired(approval_event):
state.status = 'waiting_approval'
return
if action_has_materially_changed(action, state):
state.status = 'waiting_approval'
return
state.status = 'running'
execute_approved_action(action)이 코드의 핵심은 승인 자체보다, 승인 이후에도 조건이 여전히 유효한지 다시 확인한다는 점이다.
사람이 너무 자주 끼어들면 시스템은 둔해진다
사람 승인은 안전하지만 공짜가 아니다. 검토 시간, 운영 피로, 대기 시간, 책임 분산 같은 비용이 생긴다. 그래서 설계의 목표는 사람을 많이 넣는 것이 아니라, 사람을 가장 효과적인 순간에만 넣는 것이어야 한다.
이 원칙을 잊으면 두 가지 부작용이 생긴다. 첫째, 승인이 너무 많아져 결국 형식적 절차가 된다. 둘째, 사용자가 시스템을 느리고 귀찮게 느껴 자동화를 피하게 된다.
이 문제를 줄이는 좋은 방법은 저위험 구간을 넓게 자동화하고, 중위험 구간은 조건부 승인을 붙이고, 고위험 구간만 강한 승인을 거는 것이다. 그리고 같은 유형의 반복 작업은 사전 승인된 정책 안에서 자동 처리하게 만들 수 있다. 예를 들어 "한도 10만 원 이하의 환불은 특정 조건 하에 자동 승인" 같은 운영 정책이 여기에 해당한다.
즉, Human-in-the-loop는 무조건 사람을 불러오는 구조가 아니라, 사람의 판단을 정책으로 압축해 자동화 범위를 넓혀 가는 과정이기도 하다.
리뷰어가 판단하기 쉽게 만드는 것이 설계의 절반이다
많은 팀이 승인 정책만 만들고 끝낸다. 하지만 실제로는 리뷰어 경험이 절반이다. 사람이 판단하기 어렵게 만들어 놓으면 좋은 정책도 제대로 작동하지 않는다.
리뷰어는 보통 다음 질문에 빨리 답하고 싶어 한다.
지금 무엇을 승인하라는 것인가
왜 이 단계에서 내가 필요한가
틀렸다면 어디가 가장 위험한가
승인하지 않으면 다음에 어떤 일이 일어나는가
수정하려면 무엇을 바꾸면 되는가
이 질문에 빠르게 답할 수 있게 만들면 리뷰 품질이 올라간다. 반대로 시스템이 내부 추론 로그와 장황한 도구 출력을 그대로 던져 주면, 사람은 금방 피로해진다. 좋은 리뷰 인터페이스는 엔진룸을 다 보여 주는 것이 아니라, 핸들을 잡는 데 필요한 계기판만 보여 준다.
실전 예시 1: 고객 메일 발송 에이전트
고객 지원 팀이 사용하는 에이전트를 상상해 보자. 이 에이전트는 고객 문의를 읽고, 주문 상태를 조회하고, 반품 규정을 확인한 뒤 답변 초안을 만든다. 여기까지는 자동화하기 좋다. 조회와 초안 작성은 비용은 들어도 상대적으로 되돌리기 쉽기 때문이다.
하지만 실제 메일 발송은 다른 문제다. 잘못된 약속을 하거나, 민감 정보를 잘못 노출하거나, 잘못된 고객에게 발송하면 피해가 커진다. 따라서 이 시스템은 draft_reply까지는 자동으로 돌리고, send_reply 앞에서 승인 인터럽트를 건다.
그리고 불확실성이 높을 때는 더 일찍 사람에게 넘긴다. 예를 들어 주문 정보와 고객 진술이 충돌하거나, 환불 가능 여부가 정책상 애매하거나, VIP 고객이어서 대응 수위가 중요한 경우다. 이때는 발송 직전 승인만으로는 늦을 수 있으므로, 초안 단계에서 리뷰 요청을 띄우는 편이 낫다.
여기서 핵심은 승인 하나만 두는 것이 아니라, 위험이 올라가는 지점마다 개입 방식이 달라진다는 것이다.
실전 예시 2: 내부 운영 작업 에이전트
이번에는 사내 운영 에이전트를 생각해 보자. 누군가 "어제 실패한 배치를 다시 돌리고 관련 로그를 정리해 줘"라고 요청했다. 로그 조회, 실패 원인 요약, 재실행 계획 수립까지는 비교적 안전하다. 하지만 실제 재실행은 운영 환경에 영향을 준다.
이 경우 좋은 설계는 이렇다. 에이전트는 먼저 현황을 분석하고 재실행 계획을 만든다. 그 다음 실행 대상, 예상 영향, 롤백 가능성, 시간대를 정리해 운영자에게 보여 준다. 운영자가 승인하면 그때 실제 재실행을 수행한다.
만약 에이전트가 중간에 환경 설정 이상이나 권한 부족을 발견했다면, 그 순간 에스컬레이션한다. 중요한 점은 "실패했으니 사람에게 넘긴다"가 아니라, 리스크가 커졌으니 사람에게 넘긴다는 것이다.
사람 개입은 실패 처리와 다르다
앞 장에서 우리는 실패 복구를 다뤘다. 이번 장의 사람 승인은 그와 비슷해 보이지만, 목적이 다르다. 실패 복구는 말 그대로 문제가 생겼을 때 다시 일어나는 방법에 가깝다. 반면 사람 승인은 사고가 나기 전에 속도를 조절하는 브레이크다.
물론 둘은 만나기도 한다. 예를 들어 반복 실패가 누적되면 사람에게 넘길 수 있다. 하지만 그것이 Human-in-the-loop의 전부는 아니다. 정상적으로 잘 돌아가는 상황에서도, 정책상 사람이 봐야 하는 지점은 존재한다. 이를 분리해 이해하는 것이 중요하다.
정리하면 이렇다. 실패 때문에 사람에게 넘기는 것은 복구 전략이다. 위험 때문에 사람에게 넘기는 것은 승인 전략이다. 둘을 구분해야 설계가 또렷해진다.
자주 하는 실수: 모델에게 승인 필요 여부까지 맡기는 것
많은 구현이 이런 모양으로 시작한다. "중요하면 사람에게 물어봐." 겉으로는 합리적이다. 하지만 운영에서는 위험하다. 모델은 상황 설명에는 강하지만, 정책 집행자 역할까지 안정적으로 맡기기 어렵다. 어떤 날은 지나치게 보수적으로 굴고, 어떤 날은 너무 자신 있게 밀어붙일 수 있다.
그래서 승인 필요 여부는 원칙적으로 시스템이 결정하는 편이 좋다. 모델은 행동 계획을 제안할 수 있다. 그러나 그 행동이 승인 대상인지, 어떤 권한이 필요한지, 누가 승인할 수 있는지는 정책 계층이 판단해야 한다.
이 역할 분담은 중요하다. 모델은 제안하고, 시스템은 판정하고, 사람은 책임을 진다. 이 선이 흐려질수록 사고가 나기 쉽다.
Human-in-the-loop 설계 체크리스트
실제로 설계할 때는 거창한 용어보다 다음 질문이 더 유용하다.
이 행동은 되돌릴 수 있는가. 실행되면 외부 세계에 어떤 변화가 생기는가. 위험이 높아지기 전에 멈출 인터럽트 지점이 있는가. 사람에게 넘길 때 그 이유를 구조화해서 설명할 수 있는가. 승인 이후에 같은 상태에서 안전하게 재개할 수 있는가. 승인 요청이 너무 자주 발생해 사람을 마비시키지 않는가. 누가 승인할 자격이 있는지 분명한가. 승인, 리뷰, 거절, 수정 요청의 결과가 상태 머신에 반영되는가.
이 질문에 답할 수 있다면, 사람 개입은 어색한 덧붙임이 아니라 시스템의 일부가 된다.
통제력을 잃지 않는 자동화가 오래 간다
에이전트는 일을 대신해 주는 존재처럼 보이지만, 제품으로 가는 순간 더 중요한 역할이 생긴다. 바로 위험한 일을 함부로 하지 않게 만드는 것이다. 잘 설계된 Human-in-the-loop는 자동화를 약하게 만드는 장치가 아니다. 오히려 자동화를 더 멀리, 더 안전하게 가져가게 해 주는 장치다.
고위험 행동 전 승인, 불확실성 기반 에스컬레이션, 리뷰 인터럽트 지점 설계는 모두 같은 방향을 가리킨다. 시스템이 똑똑해질수록, 어디서 멈춰야 하는지도 더 똑똑해져야 한다는 것이다.
좋은 에이전트는 모든 것을 혼자 처리하는 에이전트가 아니다. 스스로 달릴 때와 사람에게 핸들을 넘길 때를 구분하는 에이전트다. 자동화를 늘리면서도 통제력을 잃지 않는 가장 현실적인 방법은, 결국 사람을 빼는 것이 아니라 제대로 배치하는 것에 있다.
다음 장부터는 이 감각을 더 큰 시스템으로 확장해 본다. 코드 에이전트와 브라우저 에이전트처럼 실제 실행력이 강한 형태로 넘어갈수록, 지금 다룬 승인과 개입 설계는 더 중요해진다. 더 많이 할 수 있는 시스템일수록, 더 잘 멈출 수 있어야 하기 때문이다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.