브라우저 하네스 (Browser Harness) 테스트: 에이전트가 스스로 브라우저 자동화를 확장할 수 있는가?
요약
에이전트가 브라우저 자동화 도구를 스스로 확장하고 재사용할 수 있는지 검증하는 '브라우저 하네스' 아키텍처와 테스트 방법론을 소개합니다. 단순한 작업 수행을 넘어, 에이전트가 검사 및 재호출이 가능한 헬퍼 코드를 생성하는 능력을 평가하는 데 중점을 둡니다.
핵심 포인트
- 기존 고정된 도구 집합의 한계를 극복하기 위한 레이어 분리 아키텍처 제안
- 에이전트의 능력을 일회성 완료, 하네스 확장, 재사용의 세 단계로 구분하여 검증
- 보호된 코어와 편집 가능한 워크스페이스를 분리하여 안전한 코드 확장을 유도
- 단순 성공이 아닌, 검사 및 재사용 가능한 헬퍼 생성 여부가 핵심 성공 지표
Agent Lab Journal
Agent Lab Journal
Guides
...
도구(Tools) · 브라우저 자동화 (Browser automation) · 재현 가능한 실험실 (Reproducible lab)
브라우저 하네스 (Browser Harness) 테스트: 에이전트가 스스로 브라우저 자동화를 확장할 수 있는가?
수준: 고급 (advanced)
읽기 및 실습 시간: 35분
결과: CDP가 연결된 브라우저와 에이전트가 생성한 재사용 가능한 헬퍼(helper)를 통한 재현 가능한 테스트
...
목차
-
테스트 중인 문제
-
하네스 (Harness) 아키텍처
-
성공 기준
-
환경 및 안전 경계
-
제어된 페이지 생성
-
브라우저 연결
-
베이스라인 (Baseline) 기록
-
에이전트에게 제한된 작업 부여
-
헬퍼 계약 (Helper contract) 검토
-
재사용 증명
-
독립적 검증
-
실패 사례
-
한계점
-
의사 결정 규칙
1. 테스트 중인 문제
기존의 브라우저 통합 방식은 페이지 열기, 요소 찾기, 클릭, 타이핑, 선택, 업로드, 스크린샷 찍기와 같이 고정된 작업 집합을 노출합니다. 이는 애플리케이션이 커스텀 에디터, 캔버스 (canvas), 폐쇄된 컴포넌트 트리 (component tree), 특이한 포인터 시퀀스 또는 도메인 특화 위젯을 사용하기 전까지는 잘 작동합니다. 그 시점이 되면, 개발자는 보통 에이전트가 작업을 계속하기 전에 새로운 작업을 추가하고, 새로운 도구 버전을 배포한 뒤 이를 적용해야 합니다.
브라우저 하네스 (browser harness)는 책임 분할 방식이 다릅니다. 보호된 핵심부 (protected core)가 브라우저 연결과 저수준 프리미티브 (low-level primitives)를 소유합니다. 작고 편집 가능한 레이어에는 작업 특화 헬퍼 (task-specific helpers)가 포함됩니다. 프리미티브가 불충분할 때, 에이전트는 오직 해당 레이어에만 코드를 추가할 수 있습니다.
실험은 다음 세 가지 결과를 구분해야 합니다:
-
일회성 완료 (One-off completion): 어떤 수단을 사용하든 페이지가 요청된 상태로 종료됨.
-
하네스 확장 (Harness extension): 에이전트가 입력값, 체크 사항, 명시적 실패 처리가 포함된 이름이 지정된 헬퍼 (helper)를 생성함.
-
재사용 (Reuse): 동일한 헬퍼가 수정 없이 리셋 후 두 번째 유효한 동작을 수행함.
단 한 번의 성공적인 클릭이 거의 아무것도 증명하지 못하는 이유
에이전트는 기억된 좌표를 클릭하거나, JavaScript를 사용하여 애플리케이션 상태를 수정하거나, 유사한 텍스트를 본 후 성공을 보고할 수 있습니다. 이러한 결과 중 그 어느 것도 자동화가 축적되었다는 것을 증명하지는 않습니다. 유용한 산출물은 검사(inspect), 테스트(test), 그리고 다시 호출(invoke)할 수 있는 좁은 범위의 역량(capability)입니다.
2. 하네스 아키텍처 (Harness architecture)
시스템을 다음과 같은 두 개의 명시적인 레이어(layer)로 분리하여 유지하십시오:
-
보호된 코어 (Protected core): 연결 관리(connection management), 탭 선택(tab selection), 탐색 정책(navigation policy), CDP 전송(CDP transport), 타임아웃(timeouts), 스크린샷(screenshots), 그리고 기본적인 입력 디스패치(input dispatch).
-
편집 가능한 워크스페이스 (Editable workspace): agent_helpers.py와 같이 버전 관리되는 하나의 파일, 그리고 테스트 및 기밀이 아닌 증거물.
에이전트는 코어 인터페이스를 읽을 수는 있지만, 그 구현(implementation)을 수정해서는 안 됩니다. 에이전트는 헬퍼 워크스페이스에만 쓸 수 있습니다. 테스트 페이지는 실행 중에 읽기 전용(read-only)입니다. 가능한 경우 파일 시스템 권한(filesystem permissions)을 사용하여 이러한 규칙을 강제하십시오. 텍스트 지침은 보안 경계(security boundary)가 될 수 없습니다. 이 설계가 소프트웨어 개발을 없애는 것은 아닙니다. 개발의 좁은 범위의 일부를 실행 루프(execution loop) 안으로 이동시키는 것입니다. 생성된 코드 역시 여전히 인자 검증(argument validation), 제한된 대기(bounded waits), 명확한 에러(clear errors), 제한된 디프(restricted diff), 그리고 회귀 테스트(regression test)가 필요합니다.
3. 에이전트를 실행하기 전에 성공을 정의하십시오
확인 (Check)
통과 (PASS)
실패 (FAIL)
...
4. 격리된 환경을 준비하십시오
다음이 필요합니다:
-
원격 디버깅 (remote debugging)을 지원하는 Chrome 또는 Chromium;
-
에이전트 환경과 호환되는 Browser Harness 설치;
-
로컬 픽스처 (fixture) 및 증거 (evidence) 스크립트를 위한 Python 3.12;
-
베이스라인 (baseline) 및 차이 (diff) 비교를 위한 Git;
-
헬퍼 워크스페이스 (helper workspace)만 편집할 수 있도록 허용된 코딩 에이전트;
-
작업 세션, 비밀번호, 확장 프로그램 또는 고객 데이터가 포함되지 않은 별도의 브라우저 프로필.
http://127.0.0.1:8765 만을 포함하는 허용 목록 (allowlist)을 적용하십시오. 페이지는 프롬프트 인젝션 (prompt injection)을 포함할 수 있으므로 페이지 콘텐츠를 신뢰할 수 없는 것으로 취급하십시오. 단순히 CDP가 편리하다는 이유만으로 이 실험을 일상적인 브라우저 프로필에 연결하지 마십시오.
실험실을 생성합니다:
mkdir -p browser-harness-lab/{fixture,workspace,evidence}
cd browser-harness-lab
...
실제 브라우저, 하네스 (harness), 에이전트 버전을 evidence/environment.txt에 기록하십시오. 모든 릴리스가 동일한 CLI를 가진다고 가정하지 말고, 설치된 하네스에서 지원하는 명령어를 사용하십시오. 도움말 출력 내용을 증거와 함께 저장하십시오:
browser-harness --help > evidence/browser-harness-help.txt
browser-harness --version > evidence/browser-harness-version.txt 2>&1 || true
만약 사용 중인 하네스가 다른 실행 파일을 사용하거나 --version 옵션을 제공하지 않는다면, 해당 명령어를 교체하고 설치된 패키지 버전을 명시적으로 작성하십시오. 재현성 (reproducibility)은 특정 명령어의 철자가 아니라 기록된 사실에 달려 있습니다.
5. 통제된 비표준 구성 요소 생성
다음 테스트 픽스처 (test fixture)는 닫힌 섀도우 루트 (closed shadow root) 내부에 두 개의 버튼을 배치합니다. 문서 수준의 선택자 (document-level selectors)로는 해당 버튼에 접근할 수 없습니다. 실제 포인터 클릭은 여전히 구성 요소를 활성화하고 애플리케이션 이벤트를 발생시킵니다.
fixture/index.html 생성:
<!doctype html>
<html lang="en">
<head>
...
옵션을 선택하기 위한 공개 메서드 (public method)가 의도적으로 존재하지 않습니다. result.dataset.status = "pickup"이라고 작성하는 것은 사후 조건 (postcondition)을 위조하는 것이며 실패로 간주되어야 합니다.
별도의 터미널에서 서버를 시작합니다:
python3 -m http.server 8765 \
--bind 127.0.0.1 \
--directory fixture
가용성을 확인하고, 베이스라인 (baseline)을 커밋한 뒤 서버를 실행 상태로 유지합니다:
curl --fail --silent http://127.0.0.1:8765/ | head -n 5
git add fixture/index.html workspace/agent_helpers.py evidence/
...
6. CDP를 통해 Chrome 연결하기
전용 프로필 (profile)과 원격 디버깅 (remote debugging)이 활성화된 상태로 Chrome을 시작합니다. 동일한 프로필 디렉토리를 사용하는 이전 프로세스가 있다면 종료하십시오. 실행 파일 이름은 플랫폼마다 다릅니다.
mkdir -p "$PWD/chrome-profile"
chromium \
...
macOS 또는 Windows에서는 해당되는 Chrome 실행 파일을 사용하십시오. 디버깅 엔드포인트 (endpoint)가 로컬 머신에 바인딩된 상태를 유지하십시오. 9222 포트를 공유 네트워크에 노출하지 마십시오.
브라우저 엔드포인트를 독립적으로 검증합니다:
curl --fail --silent \
http://127.0.0.1:9222/json/version \
| tee evidence/cdp-version.json
설치된 문서에 따라 하네스 (harness)가 http://127.0.0.1:9222를 사용하도록 구성하십시오. 그런 다음 가장 작은 읽기 전용 작업(target 목록 나열 또는 현재 페이지 출력)을 실행합니다. 정확한 명령과 출력 내용을 evidence/connection.txt에 저장하십시오.
연결에 성공했다는 것은 단지 채널이 존재한다는 것만을 증명합니다. 모든 동작을 수행하기 전에 대상 URL과 제목을 확인하십시오. 대상 순서는 신뢰할 수 있는 탭 식별자 (tab identifier)가 아닙니다.
7. 에이전트가 행동하기 전에 베이스라인 기록하기
하네스를 통해 새 탭에서 http://127.0.0.1:8765/을 엽니다. 다음 의사코드 (pseudocode)를 사용 중인 설치 환경에서 제공하는 프리미티브 (primitives)에 맞게 조정하십시오.
new_tab("http://127.0.0.1:8765/")
wait_for_load()
...
필요한 베이스라인은 다음과 같습니다:
{
"title": "Browser Harness Fixture",
"url": "http://127.0.0.1:8765/",
...
이 값들은 기대치 (expectations)이며, 보고된 테스트 결과가 아닙니다. 실행 시의 실제 출력값을 저장하십시오. 상태가 다르다면 진행하기 전에 픽스처 (fixture)를 초기화하거나 다시 로드하십시오.
8. 에이전트에게 제한된 작업 부여하기
구현 내용을 미리 제공하지 마십시오. 그렇게 하면 확장성 (extension)이 아니라 전사 (transcription)를 테스트하게 됩니다. 허용된 파일, 금지된 단축키, 요구되는 증거, 그리고 중단 조건 (stopping conditions)을 제공하십시오.
http://127.0.0.1:8765/ 와
browser-harness-lab 디렉토리만 사용하십시오.
...
이 프롬프트는 실험 내용을 전달하지만, 에이전트 런타임 (agent runtime)이 지원하는 경우 기술적 제어 (technical controls)를 통해 쓰기 경계 (write boundary)와 네트워크 제한을 강제해야 합니다.
9. 인터페이스로서의 헬퍼 (helper) 검토
하나의 참조 구현 (reference implementation)을 맞추는 것보다 적절한 계약 (contract)을 정의하는 것이 더 중요합니다:
def select_shipping_method(label: str) -> dict:
"""
shipping-picker 내부의 실제 옵션을 클릭합니다.
...
검토 가능한 헬퍼는 다음과 같아야 합니다:
- 좌표 대신 의미 있는 레이블 (label)을 수락해야 합니다.
- 상호작용하기 전에 허용된 값을 검증해야 합니다.
- 호출할 때마다 현재 노드 (node)와 기하학적 구조 (geometry)를 탐색해야 합니다.
- 브라우저를 통해 일반적인 마우스 입력을 수행해야 합니다.
- 유한한 타임아웃 (timeout)을 사용해야 합니다.
- 결과 상태와 이벤트 횟수를 확인해야 합니다.
- 구조화된 데이터 (structured data)를 반환해야 합니다.
- 사후 조건 (postcondition)이 없을 경우 명확하게 실패(fail loudly)해야 합니다.
- 쿠키, 토큰, 외부 URL 또는 특정 머신 전용 경로를 포함해서는 안 됩니다.
한 가지 가능한 전략은 접근성 트리 (accessibility tree)를 요청하여 역할 (role)과 접근 가능한 이름 (accessible name)으로 버튼을 찾고, CDP를 통해 박스 모델 (box model)을 얻은 다음, 현재 중심점에서 마우스 클릭을 발송하는 것입니다. 동일한 동작과 제약 조건을 유지한다면 다른 전략도 허용됩니다.
def select_shipping_method(label: str) -> dict:
expected = {
"Courier": "courier",
...
이 예제는 일반적인 하네스 프리미티브 (harness primitives)를 사용하며, 설치된 API에 맞게 조정이 필요할 수 있습니다. 에이전트가 누락된 작업을 스스로 찾아낼 수 있는지 테스트하는 것이 목적이라면, 에이전트 실행 전에 이를 주입(inject)하지 마십시오.
10. 헬퍼가 재사용됨을 증명하기
첫 번째 선택이 성공적으로 완료된 후, 실제 페이지 상태와 헬퍼 차이(helper diff)를 저장합니다:
git diff -- workspace/agent_helpers.py \
| tee evidence/helper.diff
...
출력 필드를 재할당하는 방식이 아니라, 화면에 보이는 Reset 버튼을 통해 리셋하십시오. 페이지가 status="empty" 및 events=0 상태로 돌아오는지 확인합니다.
이제 이전 하네스(harness) 명령을 종료하고 새로운 프로세스를 시작합니다. 저장된 헬퍼를 임포트(import)하고 다음을 호출합니다:
print(select_shipping_method("Courier"))
두 번째 상태를 저장하고 해시(hash)를 다시 계산합니다:
sha256sum workspace/agent_helpers.py \
| tee evidence/helper-after-reuse.sha256
...
해시 차이가 없다는 것은 측정 사이에 파일이 변경되지 않았음을 증명합니다. 이것이 올바른 브라우저 동작을 증명하는 것은 아닙니다. 이를 위해서는 독립적인 상태 확인(state check)이 필요합니다.
11. 독립적으로 검증하기
페이지 상태 (Page state)
에이전트의 최종 응답 외부에서 읽기 전용 쿼리(read-only query)를 실행합니다:
print(js("""
() => {
const out = document.querySelector("#result");
...
리셋 및 두 번째 호출 이후, 예상되는 상태는 로컬 픽스처(fixture) URL, status="courier", 그리고 정확히 하나의 이벤트입니다. 명령이 실제로 무엇을 반환하는지 기록하십시오.
변경된 파일 (Changed files)
git status --short | tee evidence/git-status.txt
git diff -- fixture/index.html | tee evidence/fixture.diff
git diff --stat | tee evidence/diff-stat.txt
픽스처 차이(fixture diff)는 비어 있어야 합니다. 만약 브라우저 하네스(Browser Harness) 워크스페이스가 이 리포지토리(repository) 외부에 있다면, 실행 전에 해당 위치에 별도의 리포지토리를 초기화하거나 정제된 헬퍼 차이(helper diff)를 evidence/ 폴더로 복사하십시오.
알 수 없는 옵션 (Unknown option)
try:
select_shipping_method("Drone delivery")
except ValueError as exc:
...
그 후에 상태 쿼리를 반복합니다. 상태(status)와 이벤트 횟수(event count)는 변경되지 않은 채로 유지되어야 합니다. 클릭 이후에 잘못된 입력을 거부하는 것은 너무 늦습니다.
리뷰 우회 (Bypass review)
rg -n \
'dispatchEvent|shipping-change|dataset.*=|fixture/index.html|https?://' \
workspace/agent_helpers.py \
...
매칭(match)은 검토를 위한 단서일 뿐, 비행(misconduct)에 대한 자동적인 증거는 아닙니다. 검증을 위해 데이터셋(dataset)을 읽는 것은 정당합니다. 하지만 예상되는 상태(expected status)를 직접 쓰거나 애플리케이션 이벤트(application event)를 수동으로 발송하는 것은 정당하지 않습니다.
증거 체크리스트 (Evidence checklist)
날짜 (Date):
운영 체제 (Operating system):
Chrome/Chromium 버전:
Browser Harness 버전:
에이전트 및 모델 (Agent and model):
헬퍼 경로 (Helper path):
CDP 연결 (CDP connection): PASS / FAIL
초기 상태 (Initial state): PASS / FAIL
첫 번째 픽업 동작 (First Pickup action): PASS / FAIL
shipping-change 이벤트 (shipping-change event): PASS / FAIL
리셋 (Reset): PASS / FAIL
두 번째 쿠리어 동작 (Second Courier action):
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기