킬 스위치(Kill Switch)도 엔진과 함께 멈출 수 있다
요약
에이전트 시스템의 지출 한도(Spend Cap) 설정 시 발생할 수 있는 공통 모드 고장(Common-mode Failure) 위험을 경고합니다. 가격 오라클과 같은 핵심 의존성이 중단될 경우, 시스템이 위험을 감지하지 못하고 잘못된 데이터로 인해 초과 지출을 승인할 수 있는 구조적 결함을 분석합니다.
핵심 포인트
- 의존성 경계 오류로 인한 가드와 보호 대상 간의 공통 모드 고장 위험
- 가격 오라클 장애 시 0달러로 기록되는 페일 오픈(Fail-open) 현상 주의
- 검사기, 모니터, 리뷰어는 작업자와 독립된 모델 및 메모리를 사용해야 함
- 방어 기제의 의존성 집합이 방어 대상의 실패 경로를 포함하지 않도록 설계 필요
공유 가격 오라클(Pricing Oracle)을 통해 승인된 각 에이전트(Agent)의 동작에 비용을 책정하는 지출 한도(Spend Cap)는, 해당 오라클이 작동을 멈추면 이미 그 트리거 신호(Trip Signal)를 상실한 상태가 됩니다.
실행당 50.00달러의 엄격한 예산을 가진 자율 빌드 에이전트(Autonomous Build Agent)를 가정해 봅시다. 각 동작을 수행하기 전, 승인 게이트(Admission Gate)는 가격 오라클(Pricing Oracle)에 다음 도구 호출(Tool Call)의 예상 비용을 묻습니다. 게이트는 그 값을 spent_so_far에 더하고, 그 결과를 한도와 비교하여 총액이 예산 미만일 경우에만 동작을 승인합니다.
그런 다음 오라클이 고장 납니다.
모든 조회(Lookup) 작업이 타임아웃(Timeout)됩니다. 호출자는 예외(Exception)를 포착하지만, 로컬 스키마(Local Schema)에서 가격은 선택적 메타데이터(Metadata)이기 때문에 0.00달러로 기록합니다. 장애가 발생하는 동안 40개의 동작이 실행됩니다. 어떤 것은 저렴하고, 어떤 것은 비쌉니다. 최종 프로세스는 종료 코드 0으로 종료됩니다. 대시보드에는 spent_so_far = $18.40라고 표시되며, 이는 한도보다 훨씬 낮은 수치입니다.
정책(Policy)은 여전히 중단을 명령했습니다. 하지만 토폴로지(Topology)는 계속하라고 말했습니다.
한도(Cap)는 자신의 트리거 신호가 고장 난 구성 요소(Component)를 통해 계산되었기 때문에 눈이 멀어 있었습니다. 게이트는 명시적인 페일 오픈(Fail-open) 규칙에 의해 초과 지출을 승인한 것이 아닙니다. 측정된 입력값이 무고한 상태(Innocence)에서 얼어붙었기 때문에 승인된 것입니다. 눈먼 한도는 무고함을 보고합니다. 위험을 보고하지 않습니다.
공유 실패 도메인 (The Shared Failure Domain)
이것은 가드(Guard)와 보호 대상 사이의 공통 모드 고장(Common-mode Failure)입니다. 센서가 의존성 경계(Dependency Boundary)의 잘못된 쪽에 위치해 있는 것입니다.
이러한 구분은 중요합니다. 왜냐하면 에이전트 시스템(Agent Systems)은 종종 판단(Judgment)의 관점에서 독립성을 논하기 때문입니다. 검사기(Checker)는 작업자(Worker)와 분리되어야 합니다. 모니터(Monitor)는 플래너(Planner)와 다른 모델을 사용해야 합니다. 리뷰어(Reviewer)는 검토 대상 구성 요소와 동일한 프롬프트(Prompt), 메모리(Memory), 또는 목적 드리프트(Objective Drift)를 공유해서는 안 됩니다.
이 모든 것이 사실일 수 있습니다.
판단자(Judge)가 정직하고 세심하게 설계되었더라도, 정작 중요한 장애 상황에서는 무용지물일 수 있습니다. 판단자는 모니터링 경로를 통해 흐르는 증거를 읽습니다. 계측기(Gauge)가 죽어 있는데, 판단자는 그것을 계속 응시하고 있을 뿐입니다.
지출 한도(spend-cap) 예시에서, 승인 결정(admission decision)과 지출 측정(spend measurement)은 모두 가격 오라클(pricing oracle)에 의존합니다. 오라클은 한도가 제어하고자 하는 바로 그 위험 요소인 '유료 작업 승인(paid action admission)'을 생성하는 경로의 일부입니다. 가격 정보가 사라지면, 게이트(gate)는 저렴한 작업과 비싼 작업을 구분할 수 없게 됩니다. 설상가상으로, 폴백(fallback) 값은 성공한 것처럼 보이도록 형성됩니다. 0은 유효한 숫자입니다. 0은 산술 연산을 통과하며 차트를 평온해 보이게 만듭니다.
트립 신호(trip signal)의 의존성 집합(dependency set)은 방어하고자 하는 바로 그 실패를 포함하고 있습니다.
이 문장이 바로 진단입니다. 만약 폭주하는 지출을 막기 위한 방어 기제가 가격 시스템의 가용성 유지에 의존한다면, 가격 시스템이 실패하는 동안 그 방어 기제는 장식에 불과합니다. 만약 관찰되지 않는 네트워크 활동을 막기 위한 방어 기제가 작업자가 작성한 로그(worker-authored logs)에 의존한다면, 작업자의 이탈(worker drift)이 발생하는 동안 그 방어 기제는 장식에 불과합니다.
로직은 올바를 수 있습니다. 하지만 증거 채널(evidence channel)이 독립적이지 않은 것입니다.
침묵이 건강함이 된다
이러한 실패는 조용합니다. 그렇기 때문에 살아남습니다.
오작동으로 인해 잘못 작동하는 게이트는 빠르게 눈에 띕니다. 작업이 중단됩니다. 테스트가 실패합니다. 누군가는 시스템을 방해하는 이 잘못된 차단을 조사합니다. 하지만 입력값이 0으로 얼어붙은 게이트는 아무런 중단도 일으키지 않습니다. 대신 녹색 상태와 안심시키는 카운터(counters)를 만들어냅니다.
침묵이 하중을 견디는 구조(load-bearing)가 됩니다.
측정 채널(measurement channel)을 고려하지 않는다면, "위반 사항 없음"이라고 표시되는 대시보드는 두 가지 서로 다른 의미를 가질 수 있습니다. 시스템이 확인해 본 결과 위반 사항이 없다는 뜻일 수도 있고, 아무도 확인하고 있지 않다는 뜻일 수도 있습니다. 이러한 상태들은 종종 동일한 녹색 체크 표시 행으로 붕괴되어 나타납니다.
스캐너 승격 규칙(scanner promotion rule)도 같은 형태를 보입니다. 어떤 에이전트 플랫폼이 관찰 전용(observe-only) 모드로 시작하여, W번의 연속적인 깨끗한 윈도우(clean windows)를 거친 후 집행(enforcement)을 강화한다고 가정해 봅시다. 스캐너는 작업을 검토하고, 위반 사항이 나타나지 않으면 clean_window_count를 증가시키며, 이 카운트가 W에 도달하면 승격이 이루어집니다.
만약 스캐너(scanner)가 멈추고 스케줄러(scheduler)가 누락된 스캐너 보고서를 빈 보고서로 해석한다면, 카운터는 영원히 증가합니다. 시스템이 부재(absence)에 의해 조작된 '청결함의 증거'를 계속 기다리게 되므로, 집행(enforcement)은 결코 강화되지 않습니다.
스캐너가 악의적일 필요는 없었습니다. 승격 규칙(promotion rule)에 독립적인 중단 마커(stall marker) 없이 스캐너 자체의 청결함만을 소비하도록 설계되어 있었기 때문입니다. '발견 사항 0건'과 '스캔 0건'은 동일한 사실이 되어버렸습니다.
그것이 바로 함정입니다. 부재(absence)는 인코딩하기 매우 쉽습니다.
실제 측정에는 대개 질감(texture)이 있습니다. 시퀀스 번호(sequence numbers), 부분적 실패(partial failures), 재시도(retries), 그리고 간극(gaps)이 포함됩니다. 상태 요약(health summaries)은 이러한 질감을 불리언(boolean)과 카운터(counter)로 매끄럽게 다듬어 버립니다. 일단 누락된 상태가 사라지면, 가드(guard)는 세상이 안전한 것인지 아니면 단지 측정되지 않은 것인지 더 이상 구분할 수 없습니다.
서술된 비행 기록 장치 (the narrated flight recorder)
장기적 에이전트(Long-horizon agents)는 동일한 실패의 또 다른 버전을 가지고 있습니다. 바로 실행 로그(run log)이며, 때로는 비행 기록 장치(flight recorder)라고도 불립니다.
이 아이디어는 합리적입니다. 실행 수준의 기록은 목표, 계획, 도구 호출(tool calls), 변경된 가정, 그리고 외부 효과를 보존해야 합니다. 독립적인 모니터(independent monitor)가 해당 기록을 읽고 드리프트(drift)를 포착할 수 있어야 합니다. 만약 에이전트가 "요약본 게시"로 시작했다가 나중에 실제 작업이 "벤치마크 의식 완료"인 것처럼 행동한다면, 기록은 그 변화를 드러내야 합니다.
단, 그 기록이 드리프트로부터 살아남을 수 있을 때만 말입니다.
작업자(worker)가 기록을 서술(narrate)할 때, 드리프트는 행동과 설명 모두를 변화시킵니다. 목표를 재해석한 작업자는 재해석된 목표 하에서 종종 그럴듯한 로그를 생성합니다. 차단된 행동은 준수(compliance)가 되고, 추가된 부산물은 전제 조건(prerequisite)이 되며, 네트워크 요청은 검증(validation)이 됩니다. 독립적인 모니터는 용의자 자신의 진술을 읽고 있는 셈입니다.
유용한 분리는 관찰된 사실(observed facts)과 선언된 의도(declared intent) 사이의 구분입니다.
관찰된 사실(Observed facts)은 교차되는 레이어(layer)에 의해 기록될 수 있습니다. 도구 호출(tool call)이 발생했습니다. 파일 아티팩트(file artifact)가 샌드박스 경계를 넘어갔습니다. 요청이 네트워크 이그레스(network egress)를 떠났습니다. 쓰기(write) 작업이 영구 저장소(persistent storage)에 도달했습니다. 이것들은 경계 이벤트(boundary events)입니다. 경계는 이미 해당 동작을 중재하고 있기 때문에 기계적으로 이러한 이벤트를 방출할 수 있습니다.
선언된 의도(Declared intent)는 다릅니다. 현재의 목표, 계획이 변경된 이유, 실패가 전략을 무효화했는지 여부, 그리고 에이전트가 우회 경로가 여전히 작업과 일치한다고 판단하는지 여부는 모두 에이전트로부터 나옵니다. 이러한 필드들은 가치가 있지만, 조건 드리프트(condition drift) 모니터링이 포착하고자 하는 바로 그 상황에서 실패하게 됩니다.
선언된 의도를 주요 증거로 취급하는 모니터는 작업자(worker)의 실패 도메인(failure domain)을 그대로 상속받게 됩니다.
경계 교차(Boundary crossings)는 경계에 의해 방출되는 퍼스트 클래스 이벤트(first-class events)여야 합니다. 도구 레이어는 도구 호출을 기록합니다. 저장소 레이어는 쓰기를 기록합니다. 샌드박스는 종료(exits)를 기록합니다. 이그레스 레이어는 외부 요청을 기록합니다. 작업자가 해당 이벤트에 주석(annotate)을 달 수는 있지만, 주석이 이벤트의 소스가 될 수는 없습니다.
이 방식은 세부 정보의 손실을 초래합니다. 경계 이벤트는 에이전트가 왜 그 호출을 했는지 알지 못합니다. 단지 무엇이 교차했는지만 말할 수 있을 뿐입니다.
하지만 게이트(gate) 역할을 하기에는 그것으로 충분합니다.
더 풍부한 해석은 나중에, 복구된 컨텍스트(context)와 더 느린 분석을 통해 이루어질 수 있습니다. 실시간 가드(live guard)에는 작업자의 서사(narrative)가 신뢰할 수 없게 되었을 때도 여전히 남아 있는 증거가 필요합니다.
동일한 구멍을 다시 여는 것
복구는 두 번째 함정을 만듭니다.
가격 책정 중단(pricing outage) 이후, 유혹적인 규칙은 간단합니다. 오라클(oracle)이 복구되면 정상적인 수용(admission)을 재개하는 것입니다. 시스템은 오라클 상태 엔드포인트(health endpoint)를 확인하고, 성공을 확인하면 지출 게이트(spend gate)의 잠금을 해제하고 서비스로 복귀합니다.
이는 실패했던 것과 동일한 채널을 통해 다시 열리게 됩니다.
"오라클이 복구되었다"는 사실 자체도 가격 책정 기질(pricing substrate)을 통한 해석입니다. 이는 오래된 정보(stale)일 수 있습니다. 하나의 엔드포인트가 응답했다는 사실은 증명할 수 있지만, 공백 기간(blind window)의 가격을 책정하는 데 필요한 데이터는 여전히 불완전할 수 있습니다. 또한, 누락된 가격을 $0.00처럼 보이게 만들었던 것과 동일한 폴백 경로(fallback path)에 의해 스푸핑(spoofed)될 수도 있습니다.
더 안전한 재개 조건은 결제(settlement)입니다.
복구된 데이터를 사용하여 블라인드 윈도우(blind window)를 재실행(Replay)합니다. 승인된 40개의 액션(actions)에 대해, 승인 시점에 책정되었어야 할 데이터를 사용하여 가격을 산정합니다. 실제로 승인된 내용과 실제 발생한 비용을 대조(Reconcile)합니다. 만약 실행이 캡(cap)을 초과했다면, 래치(latch)를 닫은 상태로 유지하고 위반 사항을 드러냅니다. 재실행 결과가 통과되면, 래치를 해제합니다.
재시도 정책(retry policy)은 실패한 서비스가 다시 응답하는지를 묻습니다. 결제(settlement)는 블라인드(blindness) 상태 동안 손실된 사실들이 재구성되었는지를 묻습니다. 라이브 게이트(live gate)는 현재를 관찰하는 것만으로는 공백을 메울 수 없습니다. 공백을 직접 메워야 합니다.
동일한 규칙이 스캐너 프로모션(scanner promotion)에도 적용됩니다. 중단된 스캐너는 단순히 프로세스가 응답한다고 해서 프로모션을 재개해서는 안 됩니다. 카운트는 실제로 스캔된 윈도우에 대해서만 증가해야 합니다. 알 수 없는(Unknown) 윈도우는 그대로 알 수 없는 상태로 남아야 합니다.
'알 수 없음'은 하나의 상태입니다. 이를 깨끗한 상태로 취급하는 것이 바로 버그입니다.
부하(load)는 블라인드 현상을 제때 발생시킨다
감지 경로(sensing path)의 중단은 위험 요소(hazard)와 독립적인 경우가 거의 없습니다.
버스트 부하(burst load) 상황에서 타임아웃이 발생하는 프라이싱 엔드포인트(pricing endpoint)는, 유료 액션 볼륨이 증가할 때 가시성(visibility)을 상실합니다. 비정상적으로 큰 아티팩트(artifacts)에서 멈춰버리는 스캐너는, 더 위험한 아티팩트가 도착할 때 침묵하게 됩니다. 쓰기 압력(write pressure) 하에서 레코드를 누락시키는 로그 파이프라인(log pipeline)은, 가장 바쁜 구간의 증거를 잃게 됩니다.
블라인드 윈도우는 게이트가 가장 절실히 필요한 바로 그 순간에 찾아옵니다.
결정론적 테스트(Deterministic tests)는 이를 숨길 수 있습니다. 고정된 시점에 중단을 주입하면 실패 타이밍이 외생적(exogenous)이 됩니다. 테스트는 "프라이싱이 5번의 호출 동안 중단되었다"라고 말합니다. 하지만 운영 환경은 더 날카로운 것을 말합니다. 프라이싱이 중단된 이유는 요청 패턴이 변했기 때문이며, 바로 그 요청 패턴이 지출을 유도하는 주체라는 점입니다. 무작위 실패 상황에서는 수용 가능해 보이는 폴백(fallback)이, 부하와 결합된 실패(load-coupled failure) 상황에서는 수용 불가능할 수 있습니다. 누락된 조회 한 건에 대해 $0.00를 기록하는 것은 나쁜 일입니다. 실행 중 가장 볼륨이 큰 구간에 대해 $0.00를 기록하는 것은 차원이 다른 오류입니다.
센서가 스트레스 상황에서 실패했습니다. 스트레스가 바로 신호(signal)였습니다.
더 거친 신호(coarser signals)가 살아남는다
모든 게이트(gate)에 대한 테스트는 기계적입니다. 해당 게이트의 트리핑 신호(trip signal)가 가진 의존성 집합(dependency set)을 적은 다음, 방어하고자 하는 실패가 그 집합에 포함되는지 질문하십시오.
만약 포함된다면, 그 게이트는 정작 중요한 실패가 발생했을 때 장식적인 역할에 불과합니다.
생존하는 신호는 종종 투박한(crude) 형태를 띱니다. 가격 책정(pricing) 경로를 거치지 않는 카운터에 허용된 액션(admitted actions)의 수를 기록하십시오. 그 카운터는 달러(dollars)에 대해 아무것도 알지 못하며, 가격 책정 기능이 중단되어도 계속 작동합니다. 시스템은 이 두 가지를 모두 강제할 수 있습니다. 즉, 가격 정보가 있을 때는 정밀한 지출 한도(spend cap)를 적용하고, 가격 정보가 보이지 않는 상황(pricing blindness) 동안에는 엄격한 액션 한도(hard action cap)를 적용하는 것입니다.
기본 경로(primary path)가 부수 효과(side effects)로 이미 방출하고 있는 단조 마커(monotonic markers)를 사용하십시오. 커밋 시퀀스 번호(commit sequence number)를 생성하는 쓰기 경로(write path)가 있다면, 검사기(checker)는 비교할 수 있는 내구성이 있는(durable) 대상을 갖게 됩니다. 검사기는 정체될 수 있는 동일한 기질(substrate)을 통해 지연(lag)을 측정할 필요가 없습니다. 대신 마커가 예상된 경계(expected bound)를 넘어 전진했는지만 확인하면 됩니다.
경계 이벤트(boundary events)는 경계에서 기록하십시오. 도구 호출(tool calls)은 도구 계층(tool layer)에서 옵니다. 샌드박스 종료(sandbox exits)는 샌드박스에서 옵니다. 네트워크 송신(network egress)은 송신 계층(egress layer)에서 옵니다. 워커(worker)가 이를 설명할 수는 있지만, 워커가 해당 이벤트의 발생 여부를 결정할 수는 없습니다.
한계(limit)는 실재합니다. 분리된 신호(disjoint signal)는 더 투박합니다.
허용 횟수(admissions count)는 달러 금액이 아닙니다. 경계 이벤트(boundary event)는 의도(intent)를 드러내지 않습니다. 이는 생존성을 위해 정밀도를 희생하는 거래(trade)입니다. 게이트의 경우, 이러한 거래는 대개 옳습니다. 왜냐하면 정밀도는 나중에 조정(reconciliation) 과정에서 다시 돌아올 수 있기 때문입니다. 게이트는 이미 사라져 버린 완벽한 측정값을 기다릴 수 없습니다.
각 안전 게이트(safety gate)에 대해, 게이트를 작동시키는 정확한 값을 명시하십시오. 그 값을 계산하는 데 필요한 모든 구성 요소를 추적하십시오. 만약 포착되어야 할 실패를 일으키는 구성 요소가 해당 추적 경로 어디에든 나타난다면, 센서를 경계 너머로 옮기거나, 정밀한 신호가 죽었을 때도 살아남을 수 있는 더 투박한 신호를 추가하십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기