
브라우저 에이전트를 위한 검증 레이어: Amazon 사례 연구
요약
Amazon 쇼핑 사례를 통해 브라우저 에이전트의 신뢰성을 높이는 검증 레이어(verification layer) 구축 방법을 소개합니다. 시맨틱 스냅샷과 어설션을 활용해 소형 로컬 모델로도 복잡한 작업을 성공적으로 수행할 수 있음을 입증합니다.
핵심 포인트
- 검증 게이트를 통해 3B 소형 모델로도 복잡한 브라우저 작업 완수 가능
- 시맨틱 스냅샷 활용으로 토큰 사용량 90% 절감 및 효율성 증대
- 어설션을 통한 조용한 실패(Silent failures) 감지 및 신뢰성 확보
- 실행 전 정책 게이트를 통해 결제 등 위험한 작업에 대한 보안 강화
TL;DR
- ✅ 3B 로컬 모델이 복잡한 브라우저 작업을 완료함: 모든 단계를 검증 게이트(verification gates)로 통제할 때 (7/7 단계 완료, 비용 $0.001) - ✅
- ✅ 90% 토큰 감소: 원시 HTML/스크린샷 대신 시맨틱 스냅샷(semantic snapshots)을 사용하여 소형 모델의 활용 가능성 증대 - ✅
- ✅ 조용한 실패(Silent failures) 포착: "작동하는" 것처럼 보이지만 상태를 변경하지 않는 클릭을 에이전트의 추측이 아닌 어설션(assertions)을 통해 감지 - ✅
- ✅ 클라우드로의 데이터 전송 제로: 금융, 의료 및 컴플라이언스 민감 워크플로우를 위해 로컬 LLM에서 완전히 실행 - ✅
- ✅ 실행 전 정책 게이트(Pre-action policy gates): 실행 전 위험한 작업(결제 승인 등)을 차단 — 에이전트가 우회할 수 없음
이미 에이전트 스택을 보유하고 계신가요? Predicate Debugger를 연결하세요.
이 포스트는 동일한 Amazon 쇼핑 흐름을 네 번 실행한 것에 대한 기술 보고서이며, 실행 전 승인(pre-action authorization)을 보여주는 금융 운영 데모를 포함합니다. 이 목적은 하나의 주장, 즉 신뢰성은 모델에게 더 많은 픽셀이나 더 많은 파라미터를 제공하는 것이 아니라 검증(verification)에서 온다는 점을 입증하는 것입니다.
Predicate는 여기서 검증 레이어(verification layer)로 사용됩니다. 각 단계는 구조화된 스냅샷에 대한 명시적인 어설션(assertions)에 의해 게이트가 설정됩니다. 이를 통해 소형 로컬 모델을 실행자(executors)로 사용하는 것이 가능해지며, 필요한 경우 더 큰 모델을 계획(reasoning) 용도로 예약할 수 있습니다. 아래에서 논의되는 로컬 실행의 핵심 루프에는 비전 모델(vision models)이 필요하지 않습니다.
주요 결과
| 결과 | 증거 (로그 / 보고서 기준) |
|---|---|
| 모든 단계를 검증 게이트로 통제할 때 로컬 모델로 완전 자율 실행이 가능함. | 데모 3 재실행: Steps passed: 7/7 및 success: True |
| ... |
각 단계를 검증 게이트로 통제하는 엔드 투 엔드(End-to-end) 실행 클립 (Amazon: 검색 → 첫 번째 제품 → 장바구니 담기 → 결제 진행).
주요 데이터 포인트:
| 지표 | 데모 0 (클라우드 베이스라인) | 데모 3 (로컬 자율성) |
|---|---|---|
| 성공 | 1/1 실행 | 7/7 단계 (재실행) |
| ... |
작업 (실행 간 동일):
Amazon → "thinkpad" 검색 → 첫 번째 제품 클릭 → 장바구니 담기 → 결제로 진행







제1원칙: 구조 > 픽셀
스크린샷 기반 에이전트(Screenshot-based agents)는 픽셀을 제어 평면(control plane)으로 사용합니다. 이는 모호한 클릭 대상, 감지되지 않는 탐색 실패, 상태 변화 없는 "진행" 등 예측 가능한 방식으로 자주 실패합니다.
대안은 페이지를 구조화된 스냅샷 (structured snapshot) (역할(roles), 텍스트, 기하학적 구조(geometry), 그리고 소량의 현저성(salience))으로 취급한 다음, 각 동작 후에 **명시적인 통과/실패 검증 (explicit pass/fail verification)**을 요구하는 것입니다. 이것이 바로 "에이전트를 위한 Jest"라는 아이디어입니다. 즉, 모델이 성공했다고 말해서 단계가 성공하는 것이 아니라, 브라우저 상태에 대한 단언(assertion)이 통과되었기 때문에 성공하는 것입니다.
"불가능한 벤치마크 (impossible benchmark)"
목표 구성은 강력한 플래너(planner)와 소규모 로컬 실행기(executor)를 결합하여 여전히 신뢰할 수 있는 엔드-투-엔드(end-to-end) 동작을 달성하는 것입니다. 구체적으로는 DeepSeek-R1 (planner) + 약 3B급 로컬 실행기를 사용하며, Predicate가 단계 사이에 검증 게이트(verification gates)를 제공합니다.
출처에 관한 참고 사항: 이 포스트에 포함된 실행 로그는 결과(지속 시간/토큰/단계)를 보고하지만 모델 식별자를 일관되게 출력하지는 않습니다. 아래에서 특정 모델 이름이 언급되는 경우, 이는 **실행 구성 (run configuration)**으로 명시적으로 라벨링됩니다.
이것이 유용한 벤치마크인 이유:
- 실행기는 의도적으로 "멍청하게(dumb)" 설계되었습니다: 실행기는 컴팩트한 표현(compact representation)에 대해 DOM 동작(CLICK/TYPE)을 선택하기만 하면 됩니다.
- 신뢰성은 검증 레이어(verification layer)에서 나옵니다: 각 동작 뒤에는 성공 여부를 결정하고 제한된 재시도(bounded retries)를 유도하는 스냅샷 + 단언(assertions)이 뒤따릅니다.
다시 말해, 핵심은 소규모 모델이 마법처럼 능력이 뛰어나다는 것이 아니라, 검증이 능력을 사용 가능하게 만든다는 점입니다.
설정 및 의존성 (Setup and dependencies)
이 데모들은 Predicate Python SDK, 브라우저 제어를 위한 Playwright, 그리고 계획/실행을 위한 로컬 LLM을 사용합니다. 최소 설치 순서는 SDK README에 나와 있는 그대로입니다:
# PyPI에서 설치
pip install predicate-runtime
# Playwright 브라우저 설치 (필수)
...
비디오 아티팩트는 스크린샷으로부터 생성됩니다. ffmpeg를 사용할 수 있으면 실행 시 짧은 요약 클립을 조립합니다 (로그를 보면 일부 실행에서 ffmpeg 오류가 발생할 때도 생성이 이루어짐을 확인할 수 있습니다).
아키텍처: 3-모델 스택 (planner, executor, verifier)
Predicate는 계획(planning)과 실행(execution)을 분리하고, 그 사이에 검증(verification)을 삽입합니다:
Planner LLM → JSON Plan (단계 + 필요한 검증)
↓
AgentRuntime
...
핵심은 런타임(runtime)입니다. 모든 동작은 통과/실패 증거를 생성하는 스냅샷(snapshot) + 검증 사이클 내에 래핑(wrapped)됩니다. 검증은 사후 분석(post-hoc analysis)이 아니라, 인라인 런타임 게이팅(inline runtime gating, 단계의 성공 여부를 결정함)입니다.
아래에서 사용되는 용어에 대한 설명:
Planner (추론, reasoning): 구조화된 계획(단계 + 필요한 검증)을 생성합니다.
Executor (동작, action): 현재 스냅샷에 대해 구체적인 DOM 동작(CLICK/TYPE)을 선택합니다.
Verifier (단언, assertions): 스냅샷에 대한 명시적인 단언(assertions)을 평가하고 단계/태스크의 성공 여부를 결정합니다 (의도가 명확할 때는 결정론적 오버라이드(deterministic overrides)를 사용함).
Amazon 쇼핑 흐름의 2단계 간 스냅샷 차이(diff) 상태 (LLM 동작의 성공 여부를 보여줌)

상위 요소의 중요도에 따른 Amazon 쇼핑 흐름 스냅샷 히트맵(heatmap)

검증 레이어 (복사하여 사용할 수 있는 SDK 코드)
런타임 레벨에서 단언(assertions)은 일급 객체(first-class)이며, 이벤트로 기록되고 성공 여부를 제어(gate)할 수 있습니다. AgentRuntime.assert_()에서 확인 가능합니다:
def assert_(
self,
predicate: Predicate,
...
비동기 UI를 지원하기 위해, 런타임은 유연한 재시도 로직(fluent retry logic)을 노출합니다:
def check(self, predicate: Predicate, label: str, required: bool = False) -> AssertionHandle:
"""
.once() / .eventually()의 유연한 사용을 위한 AssertionHandle을 생성합니다.
...
Predicate는 명시적이고 조합 가능하며(composable), 의미론적 스냅샷(semantic snapshots) 위에서 작동합니다. 예를 들어:
def url_contains(substring: str) -> Predicate:
def _pred(ctx: AssertContext) -> AssertOutcome:
url = ctx.url or ""
...
def exists(selector: str) -> Predicate:
def _pred(ctx: AssertContext) -> AssertOutcome:
snap = ctx.snapshot
...
이것이 이 시스템이 테스트 하네스(test harness)처럼 동작하는 이유입니다. 단언(assertions)은 결정론적(deterministic)이며, 실패 시 조용한 드리프트(silent drift) 대신 아티팩트(artifacts)를 생성합니다.
아주 작은 비교 표 (제어 평면 및 실패 모드)
| 접근 방식 | 제어 평면 (Control Plane) | 실패 모드 (Failure Mode) |
|---|---|---|
| Vision 에이전트 | 스크린샷 (Screenshots) | 조용한 재시도 (Silent retries) |
| ... |
여기서 토큰 효율성(Token efficiency)은 부수적인 효과가 아닙니다. 구조 우선 스냅샷(structure-first snapshot)과 역할 필터링(role filtering)을 통해 동일한 결정론적 검증 루프(deterministic verification loop)를 유지하면서도, 클라우드 LLM 베이스라인(Demo 0)에서 프롬프트 양을 약 43% 감소시켰습니다.
네 가지 데모 (동일한 작업, 다른 자율성)
데모 3 — 검증 게이트(verification gates)를 갖춘 로컬 자율성 (Planner + Executor)
입력값 (Inputs)
Planner (추론): DeepSeek-R1 제품군 (실행 구성; 위 주석 참조)
Executor (동작): 로컬 Qwen 제품군 (실행 구성; "불가능한 벤치마크(impossible benchmark)" 타겟은 ~3B급 모델)
Verifier (단언/검증): 술어 런타임 게이트 (Predicate runtime gates) (구조화된 스냅샷 + 명시적 단언(explicit assertions) + 결정론적 오버라이드(deterministic overrides))
검증 (Verification)
- 각 단계는 스냅샷에 대한 명시적 단언(URL 술어, 요소 존재 여부 등)에 의해 게이트(gated)됩니다.
- 의도가 모호하지 않을 때(예: 서랍 메뉴 닫기)는 결정론적 오버라이드가 적용됩니다.
결과 (Outcome)
재실행이 엔드 투 엔드(end-to-end)로 완료되었습니다:
=== Run Summary ===
success: True
duration_ms: 405740
...
실질적인 핵심은 Executor가 "Amazon을 이해한다"는 것이 아닙니다. Executor는 (단언을 통해) 결과를 증명하는 루프 내에서 동작을 선택하며, 의도가 명확할 때(결정론적 오버라이드를 통해) 올바른 분기(branch)를 강제합니다.
데모 3은 이 사례 연구의 최신 결과이자 우리가 가장 중요하게 생각하는 부분(검증을 갖춘 로컬 자율성)입니다. 전체적인 맥락을 제공하기 위해, 다음 섹션에서는 가장 초기 베이스라인(Demo 0)으로 돌아갔다가 Demo 1과 Demo 2를 거쳐 앞으로 나아가며 진화 과정을 보여줍니다. 즉, 완전한 자율성에 도달하기 전, 구조 우선 스냅샷, 검증 게이트, 요소 필터링이 어떻게 시스템을 더 저렴하고 신뢰할 수 있게 만들었는지 보여줍니다.
데모 0 — 클라우드 LLM + 술어 SDK (Structured JSON)
이전 베이스라인 (2025년 12월 보고서). 이 실행은 Predicate의 구조화된 스냅샷 파이프라인 (structured snapshot pipeline)과 클라우드 모델 (GLM-4.6)을 사용했습니다. 핵심적인 기여는 문제를 구조화된 요소 (structured elements)로 축소하고, 각 단계를 검증 (verification)을 통해 게이팅 (gating)한 것입니다.
요소 필터링을 통한 토큰 감소량 (보고된 내용):
| 지표 (Metric) | 이전 (Before) | 이후 (After) | 감소량 (Reduction) |
|---|---|---|---|
| 프롬프트 토큰 (Prompt tokens, 추정치) | ~35,000 | 19,956 | ~43% |
데모 1 — 인간의 단계 + 로컬 Qwen 2.5-3B 실행기 (executor)
입력값 (Inputs)
플래너 (Planner): 인간이 작성한 단계 (human-authored steps)
실행기 (Executor): 로컬 Qwen 2.5-3B (실행 구성)
검증기 (Verifier): Predicate 어설션 (assertions)
결과 (Outcome)
이 데모는 작은 로컬 실행기를 사용하여 검증 레이어 (verification layer)와 구조화된 스냅샷 형식 (structured snapshot format)을 분리하여 보여줍니다.
데모 2 — 로컬 Qwen 2.5-7B 플래너 + Qwen 2.5-3B 실행기 (자율형)
입력값 (Inputs)
플래너 (Planner): 로컬 Qwen 2.5-7B (실행 구성)
실행기 (Executor): Qwen 2.5-3B (실행 구성)
검증기 (Verifier): Predicate 어설션 (assertions) + 오버라이드 (overrides)
검증 (Verification)
UI의 모호함으로 인해 플래너의 검증 대상이 취약해질 경우, 런타임 (runtime)은 (조용히 진행하는 대신) 명시적인 검증 실패를 통해 불일치를 드러냅니다.
컨텍스트: 데모 간 결과 요약. 아래 표는 네 가지 데모(클라우드 베이스라인 → 인간 계획 제어 → 자율 계획 → 로컬 자율성)를 압축하여 비교한 것으로, 소요 시간, 토큰 사용량 및 단계 완료 여부를 강조합니다.
| 데모 (Demo) | 플래너 / 실행기 (Planner / Executor) | 소요 시간 (Duration) | 토큰 (Tokens) | 단계 (Steps) |
|---|---|---|---|---|
| 0 | Cloud LLM (실행 구성) + Predicate SDK | ~60,000ms | 19,956 | 1/1 실행 |
| ... |
로그가 보여주는 것 (구체적인 증거)
결정론적 오버라이드 (deterministic overrides) (첫 번째 제품)
런타임이 더 안전한 결정론적 선택지를 가질 때 실행기의 결정은 무효화(overruled)될 수 있습니다:
[fallback] first_product_link preselect -> CLICK(1022)
Executor decision: {"action": "click", "id": 884, "raw": "CLICK(884)"}
[override] first_product_link -> CLICK(1022)
이것은 모델의 선호도가 아닙니다. "첫 번째 결과"라는 의도를 보존하는 명시적인 가드레일 (guardrail)입니다.
Drawer 처리 (추가 상품 업셀) (Drawer handling (add-on upsell))
Amazon이 추가 상품 드로어 (add-on drawer)를 열 때, 런타임 (runtime)은 이를 결정론적 (deterministically)으로 해제합니다:
[fallback] add_to_cart drawer detected -> CLICK(6926)
Executor decision: {"action": "click", "id": 1214, "raw": "CLICK(1214)"}
[override] add_to_cart -> CLICK(6926)
결과:
result: PASS | add_to_cart_verified_after_drawer
플래너 드리프트 (취약한 셀렉터) (Planner drift (brittle selector))
자율 플래너 (autonomous planner) 실행 중, 검증 대상이 잠시 취약한 셀렉터 (brittle selector)로 드리프트 (drift)되었습니다. 런타임은 여전히 결정론적으로 합격/불합격 (pass/fail)을 강제하며, 이로 인해 불일치가 무시되지 않고 표면화됩니다:
"intent": "checkout_button",
"verify": [
{
...
시스템은 어설션 (assertions)을 통해 불일치를 포착했지만, 이는 모델 규모 (model scale)가 효과를 발휘하기 전에 왜 검증 (verification)이 강력해야 하는지를 강조합니다.
실행 요약 (로그 기준) (Run summaries (from logs))
Demo 0 (Cloud LLM + Predicate SDK; 보고서 발췌):
success: True
duration_ms: ~60000
tokens_total: 19956
...
Demo 1 (사람의 단계 + Qwen 2.5-3B 실행기):
=== Run Summary ===
success: True
duration_ms: 207569
...
Demo 2 (Qwen 2.5-7B 플래너 + Qwen 2.5-3B 실행기):
=== Run Summary ===
success: True
duration_ms: 435446
...
Demo 3 Run A (DeepSeek-R1-Distill-Qwen-14B 플래너 + Qwen 2.5-7B 실행기):
(모델 식별자는 실행 구성이며, 발췌된 로그는 주로 결과 지표를 보고합니다.)
=== Run Summary ===
success: True
duration_ms: 496863
...
Demo 3 재실행 (Re-run):
=== Run Summary ===
success: True
duration_ms: 405740
...
실행 시 트레이스 업로드 확인 메시지도 출력됩니다:
✅ [Predicate] Trace uploaded successfully
일부 실행은 MLX 백엔드 (Apple Silicon)를 사용합니다. MLX는 토큰 사용량 지표를 노출하지 않으므로, 총 토큰 수는 방향성 지표일 수 있습니다. 이러한 경우 계획 안정성 (plan stability)과 재시도 횟수 (retry counts)가 더 신뢰할 수 있는 신호입니다.
관측 가능성 및 아티팩트 (Observability and artifacts)
AI 자동 생성 콘텐츠
본 콘텐츠는 HN OpenAI Codex의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기