4부 19장. 오류 처리, 재시도, 실패 복구
에이전트를 처음 만들 때 사람들은 대개 두 가지 장면을 상상한다. 하나는 모델이 멋지게 추론하는 장면이고, 다른 하나는 도구를 척척 호출하며 문제를 해결하는 장면이다. 그런데 실제 서비스에서 더 자주 마주치는 장면은 조금 다르다. 검색 도구가 갑자기 응답하지 않고, 외부 API가 느려지고, 모델이 중간 판단을 틀리고, 한참 돌던 작업이 프로세스 재시작과 함께 끊긴다.
이때 시스템의 수준이 드러난다. 실패 한 번에 그대로 멈추면 그것은 똑똑한 데모일 수는 있어도 운영 가능한 시스템은 아니다. 반대로 실수하고, 넘어지고, 잠깐 멈췄다가도 다시 이어서 갈 수 있다면 비로소 제품이 된다.
운영 가능한 에이전트는 완벽한 에이전트가 아니다. 실패를 전제로 설계된 에이전트다. 더 정확히 말하면, 실패했을 때 무엇을 다시 시도하고, 무엇은 포기하고, 무엇은 사람에게 넘기고, 어디서부터 다시 시작할지를 알고 있는 에이전트다.
이번 장에서는 바로 그 감각을 잡아 보려 한다. 도구 실패, 네트워크 오류, 잘못된 중간 판단, 중단된 작업을 어떻게 분류하고, 어떤 패턴으로 복구할지 차근차근 정리해 보자.

실패는 예외가 아니라 기본값이다
실행 루프를 구현할 때 가장 위험한 생각은 "정상 흐름 하나만 잘 만들면 되겠지"라는 믿음이다. 하지만 에이전트는 외부 세계와 자주 연결된다. 파일을 읽고, 검색을 하고, API를 호출하고, 코드를 실행하고, 사람의 입력을 기다린다. 이 모든 연결점은 실패 지점이기도 하다.
즉, 에이전트 시스템에는 원래부터 금이 많이 가 있다. 모델은 애매한 지시를 오해할 수 있고, 도구는 잘못된 인자를 받을 수 있고, 네트워크는 느려질 수 있고, 상태 저장은 중간에 꼬일 수 있다. 따라서 좋은 설계는 실패를 "드물게 발생하는 이상 현상"으로 보지 않는다. 오히려 언젠가 반드시 일어나는 정상 사건으로 본다.
이 관점을 받아들이면 설계 질문도 바뀐다. "어떻게 실패를 없앨까?"보다 "이 실패를 시스템이 어떻게 흡수할까?"가 더 중요해진다.
먼저 실패를 네 종류로 나눠 보자
실무에서는 모든 실패를 한꺼번에 뭉뚱그리면 대응이 어지러워진다. 실패는 겉모습은 비슷해 보여도 성질이 다르기 때문이다. 대체로 에이전트의 실패는 네 갈래로 나누어 생각하면 정리가 쉽다.
첫째는 도구 실행 실패다. 존재하지 않는 도구를 부르거나, 인자가 잘못되거나, 파일이 없거나, 권한이 부족하거나, 도구 내부에서 예외가 터지는 경우다.
둘째는 일시적 인프라 실패다. 네트워크 타임아웃, 외부 API의 순간적인 장애, 레이트 리밋, 데이터베이스 잠금처럼 잠깐 후 다시 시도하면 풀릴 가능성이 있는 문제다.
셋째는 잘못된 중간 판단이다. 모델이 이미 충분한 정보를 가지고도 엉뚱한 다음 행동을 고르거나, 부족한 정보를 확정 사실처럼 다루거나, 실패 원인을 잘못 해석해 더 나쁜 방향으로 가는 경우다.
넷째는 중단된 작업이다. 프로세스가 죽거나, 워커가 재시작되거나, 사용자 승인을 기다리다가 세션이 끊기거나, 오래 걸리는 배치 작업이 절반에서 멈추는 상황이다.
이 네 가지는 처리법이 서로 다르다. 도구 인자 오류는 재시도해도 소용이 없고, 네트워크 타임아웃은 한두 번 다시 시도하면 해결될 수 있다. 잘못된 중간 판단은 모델을 혼내는 것이 아니라 검증 구조를 넣어야 하고, 중단된 작업은 체크포인트와 재개 설계가 필요하다.
에이전트 복구 설계의 첫걸음은 바로 이것이다. 모든 실패를 같은 방식으로 다루지 말 것.
실패 복구의 기본 원리: 다시 시도하기 전에 먼저 분류하라
많은 시스템이 실패를 만나면 반사적으로 재시도부터 한다. 하지만 재시도는 만능 열쇠가 아니다. 오히려 잘못 쓰면 문제를 키운다. 없는 파일을 열다 실패했는데 다섯 번 더 같은 경로를 읽게 하면 무슨 일이 생길까. 실패 원인은 그대로인데 비용과 지연만 늘어난다.
그래서 재시도보다 먼저 필요한 것은 분류다. 최소한 다음 세 가지 질문을 던져야 한다.
이 실패는 일시적인가, 아니면 구조적인가?
같은 입력으로 다시 해도 성공 가능성이 있는가?
재시도가 부작용을 만들 수 있는가?
예를 들어 네트워크 타임아웃은 일시적일 수 있다. 그러나 customer_id가 빠진 주문 조회는 구조적 오류다. 전자는 재시도 후보이고, 후자는 인자 수정이나 사용자 확인이 먼저다. 또 결제 요청처럼 한 번 더 실행하면 중복 부과가 생길 수 있는 작업은 무턱대고 재시도하면 안 된다.
이 판단을 코드로도 분리하는 편이 좋다. 실패를 단순 문자열로 뭉개지 말고, 적어도 retryable, fatal, requires_user, requires_approval 같은 속성으로 표현하면 복구 정책을 자동화하기 쉬워진다.
도구 실패는 메시지가 아니라 구조로 다뤄야 한다
도구를 많이 연결할수록 에이전트는 더 유능해 보인다. 동시에 더 쉽게 깨진다. 어떤 도구는 성공 시 JSON을 주고, 어떤 도구는 문자열을 주고, 어떤 도구는 실패하면 예외를 던진다. 이 상태로는 실패를 일관되게 처리하기 어렵다.
그래서 도구 계층에서는 성공과 실패를 같은 형식으로 감싸는 것이 중요하다. 예를 들면 이런 식이다.
from dataclasses import dataclass
from typing import Any, Optional
@dataclass
class ToolResult:
ok: bool
data: Optional[Any] = None
error_code: Optional[str] = None
error_message: Optional[str] = None
retryable: bool = False이렇게 통일해 두면 상위 실행 루프는 훨씬 단순해진다. ok=False일 때 실패 종류를 확인하고, 재시도 가능한지 보고, 아니면 다른 도구로 우회하거나 사용자에게 묻거나 실패 상태로 종료하면 된다.
핵심은 에이전트가 도구 실패를 "알 수 없는 폭발"로 받아들이지 않게 만드는 것이다. 실패도 하나의 관찰 결과여야 한다. 즉, 실패는 예외가 아니라 상태 업데이트의 입력이어야 한다.
재시도는 횟수보다 정책이 중요하다
재시도는 흔한 패턴이지만, 아무렇게나 넣으면 시스템을 금세 지치게 만든다. 좋은 재시도에는 항상 정책이 있다. 대개 다음 네 가지를 함께 생각한다.
어떤 오류에만 재시도할 것인가
몇 번까지 시도할 것인가
시도 사이에 얼마나 기다릴 것인가
같은 요청을 다시 보내도 안전한가
예를 들어 타임아웃이나 일시적 네트워크 오류는 재시도 후보가 된다. 하지만 인증 실패, 잘못된 인자, 존재하지 않는 리소스는 보통 재시도해도 달라지지 않는다.
가장 많이 쓰는 방식은 지수 백오프다. 첫 실패 후 조금 기다리고, 다시 실패하면 더 길게 기다리는 방식이다. 바로바로 연속 호출하면 상대 시스템이 이미 힘든데 더 두드리는 꼴이 된다. 지수 백오프는 "잠깐 숨을 고르고 다시 해 보자"라는 태도에 가깝다.
import time
def retry_tool(call, max_attempts=3, base_delay=1.0):
attempt = 0
while attempt < max_attempts:
result = call()
if result.ok:
return result
if not result.retryable:
return result
attempt += 1
if attempt >= max_attempts:
return result
delay = base_delay * (2 ** (attempt - 1))
time.sleep(delay)
return result여기서 중요한 것은 max_attempts보다 retryable이다. 다시 말해, 재시도는 횟수 제한이 아니라 판단 체계다.
재시도하면 안 되는 작업도 있다
에이전트 시스템에서 은근히 위험한 것이 바로 이 부분이다. 실패했으니 다시 해 보자는 생각이 너무 자연스럽기 때문이다. 그러나 어떤 작업은 재시도할수록 더 위험하다.
예를 들어 메일 발송, 결제 승인, 환불 요청, 티켓 생성, 데이터 삭제 같은 쓰기 작업은 한 번 더 실행되는 순간 부작용이 생길 수 있다. 첫 시도가 실제로는 성공했는데 응답만 유실되었다면, 재시도는 중복 실행이 된다.
그래서 이런 작업에는 멱등성이 필요하다. 멱등성이란 같은 요청을 여러 번 보내도 결과가 한 번 실행한 것과 같게 유지되는 성질이다. 이름은 조금 딱딱하지만, 감각은 단순하다. "다시 눌러도 두 번 처리되지 않게 하자"는 뜻이다.
보통은 요청마다 고유한 idempotency_key를 붙인다. 시스템은 이 키를 보고 이미 처리한 요청이면 같은 결과를 돌려주고, 새 요청이면 처음 한 번만 처리한다.
def send_payment(payment_request, idempotency_key):
existing = find_processed_request(idempotency_key)
if existing:
return existing
result = actually_charge(payment_request)
save_processed_request(idempotency_key, result)
return result에이전트에게 도구를 연결할 때 이 개념을 놓치면, 실패 복구를 열심히 구현해 놓고도 복구 과정에서 더 큰 사고를 만들 수 있다.
잘못된 중간 판단은 재시도가 아니라 검증으로 막는다
모델이 틀릴 때 많은 사람이 즉시 떠올리는 해결책은 "한 번 더 생각하게 하자"다. 물론 도움이 될 때도 있다. 하지만 운영 관점에서 더 믿을 만한 방법은 추론을 길게 만드는 것보다, 중요한 지점에 검증을 넣는 것이다.
잘못된 중간 판단은 대개 이런 모양으로 나타난다. 검색 결과가 없었는데도 있다고 착각한다. 불완전한 데이터를 확정값으로 취급한다. 이미 실패 원인이 밝혀졌는데 엉뚱한 도구를 다시 호출한다. 사용자 의도가 모호한데도 혼자 확정하고 진행한다.
이 문제는 모델을 더 오래 말하게 한다고 근본적으로 사라지지 않는다. 오히려 더 그럴듯한 틀린 설명이 붙을 수도 있다. 그래서 중요한 행동 전에는 별도의 검사를 두는 편이 낫다.
예를 들어 다음과 같은 검증 장치를 둘 수 있다.
응답에 필요한 필수 근거가 실제로 상태에 있는지 확인한다.
쓰기 작업 전에는 대상 리소스와 인자가 완전한지 검사한다.
사용자 요청이 모호하면 자동 진행 대신 질문 상태로 전환한다.
모델이 내린 계획과 실제 관찰 결과가 충돌하면 다시 판단하게 한다.
이를 아주 단순하게 쓰면 이런 식이다.
def can_finalize_answer(state):
required_facts = ['target_user', 'requested_action']
return all(key in state.verified_facts for key in required_facts)
def should_ask_user(state):
return state.missing_required_inputs or state.intent_ambiguous여기서 중요한 단어는 verified_facts다. 에이전트 안에는 생각보다 많은 "추정"이 떠다닌다. 그중 일부만 실제로 확인된 사실이다. 복구 가능한 시스템은 이 둘을 구분한다.
상태를 믿지 말고, 상태의 품질을 관리하라
실패 복구를 어렵게 만드는 진짜 원인 중 하나는 상태 오염이다. 처음에는 도구 결과가 정확했는데, 중간 요약이 부정확했고, 그 요약을 다음 바퀴에서 사실처럼 읽었고, 결국 잘못된 결론까지 흘러가는 식이다.
즉, 에이전트는 한 번의 큰 오답보다 작은 오해가 누적되는 구조에서 더 자주 망가진다.
그래서 상태에는 모든 것을 한 바구니에 담지 않는 편이 좋다. 적어도 다음 정도는 나눠 두면 복구가 쉬워진다.
원본 관찰 결과
요약된 작업 메모
검증된 사실
가설 또는 추정
실패 기록
원본 결과와 검증된 사실을 분리해 두면, 나중에 중간 판단이 틀렸을 때 어디서부터 잘못되었는지 추적할 수 있다. 반대로 모든 것을 스크래치패드 한 칸에 섞어 버리면, 에이전트는 자기 추정을 자기 증거로 착각하기 쉬워진다.
간단히 말해 좋은 상태 설계는 메모를 잘하는 것이 아니라 사실과 해석을 구분하는 것이다.
중단된 작업은 체크포인트가 있어야 살아난다
오래 걸리는 작업을 다루기 시작하면 실패의 모습이 조금 달라진다. 이번에는 도구가 틀린 게 아니라 작업이 중간에 끊긴다. 예를 들어 5천 개 문서를 분석하던 중 워커가 재시작될 수 있고, 브라우저 자동화가 7단계에서 멈출 수 있고, 사용자 승인을 기다리다 세션이 끊길 수 있다.
이런 상황에서는 "다시 처음부터"가 너무 비싸다. 비용도 들고 시간도 들고, 외부 시스템에 중복 요청을 보낼 위험도 생긴다. 그래서 필요한 것이 체크포인트다.
체크포인트는 거창한 것이 아니다. 현재 작업이 어디까지 진행되었는지, 무엇은 이미 끝났는지, 다음 재개 지점이 어디인지만 남겨 두면 된다. 예를 들어 작업 상태를 이런 식으로 둘 수 있다.
from dataclasses import dataclass, field
@dataclass
class JobState:
job_id: str
status: str # pending, running, waiting, retrying, failed, completed
current_step: int = 0
completed_steps: list[int] = field(default_factory=list)
last_result_ref: str | None = None
retry_count: int = 0핵심은 current_step과 completed_steps다. 작업이 끊겨도 다음에 다시 시작할 때 "아까 어디까지 했지?"를 알 수 있어야 한다. 이 정보가 없으면 재개는 사실상 불가능하다.
재개 가능한 루프는 한 번에 다 하지 않는다
실행 루프를 while True로 길게 돌리는 방식은 작은 실험에서는 편하다. 하지만 운영 환경에서는 재개 가능한 구조가 더 중요해진다. 좋은 시스템은 가능한 한 일을 짧은 단위로 나누고, 각 단계가 끝날 때 상태를 저장한다.
예를 들어 문서 분석 작업이라면 다음처럼 끊어 생각할 수 있다.
대상 문서 목록을 확정한다.
문서 묶음 하나를 가져온다.
그 묶음을 분석한다.
부분 결과를 저장한다.
남은 묶음이 있으면 다음 묶음으로 간다.
이 구조의 장점은 분명하다. 세 번째 묶음에서 프로세스가 죽어도 첫 번째와 두 번째 묶음까지의 결과는 살아 있다. 다시 시작하면 네 번째 체크포인트 이후부터 이어 가면 된다.
즉, 실패 복구를 쉽게 만드는 가장 실용적인 방법 중 하나는 작업을 잘게 쪼개는 것이다. 작은 단위는 재시도도 쉽고, 원인 파악도 쉽고, 재개도 쉽다.
실패 후 복구에는 세 가지 선택지가 있다
에이전트가 실패를 만나면 항상 같은 결론으로 가는 것은 아니다. 실제로는 세 가지 선택지 사이를 오간다.
첫 번째는 같은 작업을 다시 시도하는 것이다. 타임아웃, 일시적 네트워크 오류, 순간적인 API 장애처럼 재시도가 합리적인 경우다.
두 번째는 다른 경로로 우회하는 것이다. 기본 검색 API가 실패하면 캐시를 조회하거나, 브라우저 자동화가 막히면 직접 API 경로를 사용하거나, 고급 분석이 실패하면 간단한 요약 모드로 낮추는 식이다.
세 번째는 멈추고 넘기는 것이다. 사용자 확인이 필요하거나, 권한이 없거나, 위험한 쓰기 작업이 걸려 있거나, 반복 시도에도 해결되지 않을 때 사람에게 넘긴다.
좋은 시스템은 이 셋을 구분한다. 나쁜 시스템은 언제나 같은 답만 갖고 있다. 무한 재시도, 또는 즉시 포기. 둘 다 운영에서는 좋지 않다.
우아한 실패가 때로는 최선이다
복구라고 하면 흔히 반드시 성공까지 가야 할 것처럼 느껴진다. 하지만 실전에서는 잘 실패하는 능력도 중요하다. 특히 외부 시스템을 많이 다루는 에이전트라면, 모든 문제를 자동으로 해결하려고 고집하는 것이 오히려 위험하다.
예를 들어 계정 삭제, 대규모 환불, 법적 문서 발송, 고객 데이터 수정 같은 작업은 실패 복구보다 안전한 중단이 더 중요할 수 있다. 불확실성이 높을수록 자동 복구는 좁게, 사람 승인 지점은 넓게 잡는 편이 낫다.
우아한 실패란 이런 것이다. 무엇이 안 되었는지 분명히 알리고, 어디까지는 성공했는지 설명하고, 다음에 사용자가 무엇을 하면 되는지 알려 주는 것. 즉, 실패했더라도 사용자를 어둠 속에 두지 않는 것이다.
"문제가 발생했습니다"라는 한 줄보다 훨씬 좋은 메시지는 이런 형태다. "외부 결제 시스템 응답이 지연되어 결제 확정은 진행하지 않았습니다. 동일 요청이 중복 처리되지 않도록 저장해 두었으며, 잠시 후 다시 시도하거나 운영자 승인을 기다릴 수 있습니다."
이런 메시지는 시스템의 품질을 보여 준다. 멋진 말투 때문이 아니라, 실패를 통제하고 있다는 신호를 주기 때문이다.
실패 복구를 위한 상태 머신을 가져라
복구 가능한 에이전트는 대개 상태가 분명하다. 그냥 running과 done만 있는 시스템은 현실을 담기 어렵다. 적어도 다음 정도는 구분하는 편이 좋다.
running: 현재 실행 중waiting_user: 사용자 입력 대기waiting_approval: 사람 승인 대기retrying: 재시도 예정failed: 복구 불가 또는 정책상 중단completed: 성공적으로 완료cancelled: 사용자 또는 시스템에 의해 취소
이 구분이 왜 중요할까. 실패 후 행동이 상태에 따라 달라지기 때문이다. waiting_user는 실패가 아니라 정지 상태다. retrying은 아직 끝난 것이 아니다. failed는 다시 시작하려면 새 입력이나 운영 개입이 필요하다는 뜻이다.
상태 머신이 있으면 시스템의 태도도 일정해진다. 지금은 어떤 상태인지, 이 상태에서 어떤 이벤트가 오면 어디로 이동하는지, 재개는 가능한지, 자동 재시도 대상인지가 분명해진다.
에이전트가 커질수록 이 명확함은 큰 힘이 된다. 혼란스러운 시스템은 대개 추론이 나빠서가 아니라 상태가 흐릿해서 망가진다.
복구 설계의 핵심은 로그가 아니라 재생 가능성이다
문제가 터진 뒤 운영자가 가장 먼저 묻는 질문은 대체로 비슷하다. 왜 이 도구를 다시 불렀지? 어디서부터 잘못됐지? 이미 성공한 작업을 왜 또 실행했지? 여기서 필요한 것은 장황한 로그가 아니라 실행을 다시 따라가 볼 수 있는 기록이다.
그래서 복구를 잘하는 시스템은 이벤트를 남긴다. 예를 들면 이런 식이다.
step_startedtool_requestedtool_failedretry_scheduledstate_updatedjob_checkpointedresumed_from_checkpointstatus_changed
이 기록이 있으면 나중에 정확히 볼 수 있다. 실패는 어디서 발생했는지, 재시도는 왜 일어났는지, 재개는 어떤 체크포인트에서 시작되었는지 말이다.
특히 중요한 것은 실패 기록도 구조화해서 저장하는 것이다. 단순 텍스트 로그 한 줄보다 error_code, retryable, attempt, step, tool_name 같은 필드가 있는 이벤트가 훨씬 유용하다.
실전 예시: 고객 보고서 생성 에이전트가 넘어졌을 때
한 번 상상해 보자. 사용자가 "지난달 VIP 고객 이탈 원인을 분석한 보고서를 만들어 달라"고 요청했다. 에이전트는 고객 데이터 조회, 최근 상담 내역 분석, 이탈 징후 요약, 보고서 생성까지 여러 단계를 거친다.
첫 번째 단계에서 데이터 조회 API가 타임아웃이 났다. 이 경우는 일시적 실패일 가능성이 있으니 지수 백오프로 두 번 정도 재시도할 수 있다. 세 번째까지 실패하면 다른 리전의 읽기 복제본으로 우회하거나, 오늘은 원천 데이터가 불안정하다고 판단하고 보고서 생성을 보류할 수 있다.
두 번째 단계에서는 모델이 상담 내역 일부만 보고 성급하게 "가격 인상이 주요 원인"이라고 결론내렸다고 해 보자. 그런데 상태의 검증된 사실을 보면 실제 가격 관련 불만 비율은 높지 않다. 이때는 재시도가 아니라 검증 실패로 보고, 원인 상위 항목을 다시 계산하게 해야 한다.
세 번째 단계에서 보고서 PDF 생성 도중 워커가 재시작되었다. 체크포인트가 있다면 이미 분석된 고객군 요약과 초안 텍스트는 살아 있다. 재개 시에는 데이터 조회부터 다시 하지 않고, 문서 렌더링 단계부터 이어서 하면 된다.
마지막으로 보고서 이메일 발송 직전에 외부 메일 API 응답이 끊겼다. 이 작업은 재시도 시 중복 발송 위험이 있으므로 멱등 키를 붙여 한 번만 발송되도록 해야 한다. 응답이 없더라도 시스템은 "발송 요청 확인 중" 상태로 남기고, 나중에 발송 이력을 확인한 뒤 최종 상태를 확정하는 편이 안전하다.
이 예시를 보면 알 수 있다. 실패는 하나가 아니라 연쇄적으로 나타난다. 그리고 각각의 실패는 서로 다른 방식으로 다뤄야 한다. यही—아, 이런 외국어 장난은 집어치우자. 중요한 것은 하나다. 복구는 기술 하나가 아니라 태도의 조합이라는 점이다.
자주 하는 실수: 모든 것을 모델에게 맡기는 것
에이전트를 만들다 보면 이런 유혹이 생긴다. "모델이 알아서 실패를 해석하고 적절히 다시 시도하게 하면 되지 않을까?" 물론 어느 정도는 가능하다. 하지만 운영 안정성까지 모델에 맡기면 금세 흔들린다.
모델은 실패 이유를 설명하는 데는 도움을 줄 수 있다. 그러나 재시도 횟수 제한, 멱등 키 관리, 체크포인트 저장, 권한 조건, 승인 정책, 타임아웃 기준 같은 것은 시스템 계층이 잡아야 한다.
이 선이 흐려지면 어떤 일이 생길까. 모델이 같은 실패를 표현만 바꿔 계속 시도하고, 이미 위험한 작업인데도 "이번에는 될지도 모른다"는 식으로 밀어붙일 수 있다. 즉, 추론은 모델이 도와주고, 복구 규칙은 시스템이 쥐어야 한다.
복구 패턴을 설계할 때 꼭 붙들어야 할 질문
실패 복구를 설계할 때는 복잡한 프레임워크 이름보다 다음 질문이 더 중요하다.
이 실패는 다시 시도할 가치가 있는가? 이 작업은 다시 시도해도 안전한가? 어디까지는 성공했고, 어디서부터 다시 시작해야 하는가? 모델의 판단과 검증된 사실이 충돌하는가? 지금 멈춰야 하는가, 우회해야 하는가, 사람에게 넘겨야 하는가?
이 질문에 명확히 답할 수 있으면 설계도 단단해진다. 실패가 문자열이 아니라 구조가 되고, 상태가 흐름을 가지며, 작업이 체크포인트를 갖고, 재시도가 습관이 아니라 정책이 된다.
실패 후에도 다시 일어나는 시스템이 진짜 시스템이다
에이전트 세계에서는 종종 추론 능력에 시선이 쏠린다. 물론 중요하다. 하지만 실제 제품은 추론만으로 서 있지 않는다. 네트워크는 흔들리고, 도구는 실패하고, 상태는 꼬이고, 사람의 요청은 모호하다. 현실은 늘 잡음이 많다.
그래서 운영 가능한 에이전트의 핵심은 똑똑함 그 자체가 아니다. 망가졌을 때 어떻게 복구되는가다. 재시도할 것을 알고, 재시도하면 안 될 것을 알고, 추정과 사실을 구분하고, 중단된 작업을 이어서 하고, 필요하면 사람 앞에서 겸손하게 멈출 줄 아는 시스템. 그런 시스템이 오래 간다.
좋은 에이전트는 한 번도 넘어지지 않는 에이전트가 아니다. 넘어져도 어디를 짚고 일어날지 아는 에이전트다. 그리고 그 차이는 모델의 재치보다 설계의 성실함에서 나온다.
다음 장에서는 이 지점을 한 단계 더 확장해 본다. 모든 결정을 자동으로 밀어붙이지 않고, 사람의 승인과 개입을 어디에 두어야 하는지 살펴보게 될 것이다. 실패 복구가 시스템을 다시 일으키는 기술이라면, 사람 승인은 애초에 큰 사고를 피하게 해 주는 브레이크에 가깝다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.