AI Agent가 "달리면서 고치는" 법을 배웠을 때

2026년, AI Agent의 브라우저 조작 경쟁은 이미 붉은 바다가 되었다—Browser Use, Agent-E, WebVoyager가 각자의 재주를 뽐내고 있다. 하지만 browser-use 팀의 오픈소스 프로젝트 하나가 600줄도 안 되는 Python 코드로 두각을 나타냈다: Browser Harness가 그것이다.

2026년 8월 현재, 이 프로젝트는 GitHub에서 17,100개 이상의 Star를 획득하며 브라우저 Agent 분야에서 가장 빠르게 성장하는 프로젝트 중 하나가 되었다. 핵심 철학은 단 한 문장: LLM을 Chrome의 CDP 포트에 직접 연결하고, 부족한 함수는 AI가 스스로 쓰게 하라.

이것은 또 하나의 "Playwright를 감싸는" 미들웨어 프레임워크가 아니다. Browser Harness의 설계 철학은 미니멀리즘—셀렉터 엔진도 없고, 페이지 모델도 없고, 사전 정의된 워크플로도 없다. 최소한의 CDP 헬퍼 함수만 제공할 뿐, 나머지는 LLM이 실행 시 동적으로 생성한다.

더 놀라운 것은 그 자가 복구 능력이다: Agent가 프레임워크에서 커버하지 못하는 작업을 만나도, 에러로 종료하는 대신 스스로 새로운 헬퍼 함수를 써서 로컬 워크스페이스에 저장하고, 다음에 바로 재사용한다. 프레임워크는 쓸수록 강해진다—이것이 "자가 복구"의 의미다.

Playwright/Puppeteer와의 본질적 차이

많은 사람들이 물을 것이다: 이건 그냥 Playwright의 Python 래퍼 아닌가? 답은 아니다.

Playwright와 Puppeteer는 전통적인 자동화 프레임워크다. 설계 목표는 "인간이 스크립트를 작성해 브라우저를 제어하는 것"이며, 풍부한 셀렉터 엔진(CSS, XPath, 텍스트), 페이지 모델, 대기 메커니즘, 어서션 라이브러리를 제공한다. 어떤 요소를 클릭할지, 어떤 폼에 입력할지, 어떤 조건을 기다릴지 미리 알아야 한다.

Browser Harness는 AI 네이티브 프레임워크다. 브라우저를 제어하는 것이 인간 스크립트가 아니라 LLM이라고 가정한다. 따라서: - 셀렉터에 의존하지 않고, CDP를 통해 좌표와 DOM을 직접 조작 - 고급 대기 메커니즘을 제공하지 않고, LLM이 스스로 페이지 준비 시점을 판단 - 워크플로를 사전 정의하지 않고, LLM이 현재 페이지 상태에 따라 다음 단계를 결정 - 에러로 종료하지 않고, LLM이 부족한 헬퍼 함수를 동적으로 생성

이 설계로 Browser Harness는 전에 본 적 없는 웹 페이지 구조도 처리할 수 있다. 전통적인 자동화 스크립트는 새로운 DOM 구조를 만나면 실패하지만, Browser Harness의 Agent는 페이지를 "이해"하고, 새로운 코드를 작성해 작업을 완료한다.

핵심 아키텍처: 592줄 코드의 구성 방식

Browser Harness의 코드베이스는 극도로 간결하며, 핵심은 단 5개 파일:

src/browser_harness/
├── __init__.py      # 37줄, 패키지 초기화
├── _ipc.py          # 201줄, Unix Socket/TCP 프로세스 간 통신
├── helpers.py       # 564줄, 핵심 CDP 헬퍼 함수
├── daemon.py        # 850줄, 백그라운드 데몬 관리
├── run.py           # 407줄, CLI 진입점 및 REPL
└── admin.py         # 1191줄, 설치, 업데이트, 진단 도구

총 약 3,250줄의 코드(592줄이 아니다. 592줄은 초기 버전의 코드량). 하지만 3,000줄 이상으로 확장되어도, 이 코드량은 여전히 Playwright의 1/50에 불과하다.

주요 모듈 분석

helpers.py는 전체 프레임워크의 영혼이다. 20여 개의 기본 함수만 제공한다:

PYTHON
# 네비게이션 및 페이지 정보
goto_url(url)              # URL로 네비게이션
page_info()                # 현재 페이지 정보 가져오기 (URL, 제목, 크기, 스크롤 위치)
wait_for_load()            # 페이지 로딩 완료 대기

# 요소 상호작용
click_at_xy(x, y)          # 좌표 클릭
type_text(text)            # 텍스트 입력
fill_input(selector, text) # 폼 필드 채우기

# JavaScript 실행
js(expression)             # JavaScript 실행 및 결과 반환

# CDP 원시 접근
cdp(method, **params)      # Chrome DevTools Protocol 직접 호출

# 스크린샷 및 녹화
capture_screenshot(path)   # 스크린샷 찍기
start_recording(name)      # 작업 녹화 시작
stop_recording()           # 녹화 중지

이 함수들은 Unix Socket(또는 Windows TCP)을 통해 백그라운드 데몬 프로세스와 통신한다. 데몬은 Chrome CDP 포트로의 WebSocket 연결을 유지한다.

daemon.py의 책임: - 실행 중인 Chrome 인스턴스 자동 발견 - 백그라운드 데몬 프로세스 시작 - CDP 연결 풀 관리 - 다중 탭 전환 - 클라우드 브라우저 지원 (Browser Use Cloud)

run.py는 CLI 진입점이다. REPL(Read-Eval-Print Loop)을 시작하여 LLM이 heredoc 방식으로 Python 코드를 실행할 수 있게 한다:

BASH
browser-harness <<'PY'
goto_url("https://example.com")
print(page_info())
PY

이 설계로 LLM은 함수를 호출하는 것처럼 브라우저를 제어할 수 있으며, 기저의 CDP 프로토콜 세부 사항을 이해할 필요가 없다.

자가 복구 메커니즘: AI가 부족한 함수를 동적으로 생성하는 방법

Browser Harness의 가장 핵심적인 혁신은 자가 복구(Self-Healing) 메커니즘이다. 전통적인 프레임워크는 지원하지 않는 작업을 만나면 예외를 던지지만, Browser Harness는 LLM이 스스로 코드를 작성해 문제를 해결하게 한다.

워크플로

1. Agent가 작업 수신: X(Twitter)의 최신 20개 영상 다운로드
2. Agent가 goto_url("https://x.com/profile") 호출
3. Agent가 page_info()를 호출해 페이지 정보 가져오기
4. Agent가 페이지를 스크롤해 더 많은 게시물을 로드해야 하지만, 프레임워크에 scroll_to_bottom() 함수가 없음
5. Agent가 스스로 작성:
   def scroll_to_bottom(times=10):
       for _ in range(times):
           js("window.scrollTo(0, document.body.scrollHeight)")
           time.sleep(2)
6. agent-workspace/agent_helpers.py에 저장
7. 다음 작업에서 바로 재사용

이 메커니즘의 핵심은 agent_helpers.py 파일에 있다. 이는 Agent의 워크스페이스에 위치하며, 프레임워크 소스 코드 디렉토리에 있지 않다. Agent는 이 파일을 자유롭게 수정하여 필요한 헬퍼 함수를 추가할 수 있다.

코드 예시

PYTHON
# agent-workspace/agent_helpers.py
# Agent가 자동 생성한 헬퍼 함수

def scroll_to_bottom(times=10):
    """페이지 하단으로 스크롤하여 더 많은 콘텐츠 로드"""
    for _ in range(times):
        js("window.scrollTo(0, document.body.scrollHeight)")
        time.sleep(2)

def extract_video_urls():
    """페이지의 모든 비디오 링크 추출"""
    return js("""
        Array.from(document.querySelectorAll('video source'))
            .map(el => el.src)
            .filter(src => src)
    """)

def download_file(url, filename):
    """파일을 로컬로 다운로드"""
    import urllib.request
    urllib.request.urlretrieve(url, filename)

Agent가 작업을 실행할 때, 이러한 사용자 정의 함수는 자동으로 로드된다. 프레임워크는 from agent_helpers import *를 통해 REPL 환경에 주입한다.

이것이 중요한 이유

전통적인 자동화 프레임워크의 확장에는 다음이 필요하다: 1. 프레임워크의 플러그인 메커니즘 이해 2. 엄격한 API 사양 준수 3. 패키지 관리자에 배포 4. 사용자 설치 대기

Browser Harness의 자가 복구 메커니즘은 확장을 즉각적이고 개인화된 것으로 만든다: - Agent가 현재 작업 요구에 따라 코드 생성 - 코드는 로컬에 저장되어 즉시 사용 가능 - 배포나 설치 불필요 - 각 사용자의 Agent는 자신의 사용 패턴에 따라 진화

이것이 "프레임워크는 쓸수록 강해진다"는 의미다. Agent가 처리한 작업이 많을수록, 축적되는 헬퍼 함수가 풍부해지고, 미래의 유사한 작업 처리 효율이 높아진다.

기술 구현 세부 사항

Chrome DevTools Protocol (CDP)

Browser Harness의 핵심 통신 프로토콜은 CDP다. CDP는 Chrome 브라우저가 제공하는 디버깅 인터페이스로, 외부 프로그램이 브라우저의 거의 모든 동작을 제어할 수 있게 한다.

PYTHON
# helpers.py의 cdp() 함수
def cdp(method, session_id=None, **params):
    """CDP 메서드 직접 호출"""
    return _send({
        "method": method,
        "params": params,
        "session_id": session_id
    }).get("result", {})

# 사용 예시
cdp("Page.navigate", url="https://example.com")
cdp("Input.dispatchMouseEvent", type="mousePressed", x=100, y=200)
cdp("Runtime.evaluate", expression="document.title")

CDP의 장점: - 셀렉터 불필요: 좌표 직접 클릭으로 복잡한 CSS/XPath 셀렉터 우회 - 크로스 오리진 지원: CDP는 브라우저 기저 수준에서 작동하여 동일 오리진 정책의 제약을 받지 않음 - 완전한 제어: 네트워크 요청, DOM, JavaScript 런타임, 성능 데이터 등에 접근 가능

프로세스 간 통신 (IPC)

Browser Harness는 Unix Socket(POSIX) 또는 TCP(Windows)를 사용하여 CLI와 데몬 간 통신을 구현한다.

PYTHON
# _ipc.py의 핵심 로직
def connect(name, timeout=1.0):
    """데몬에 연결"""
    if not IS_WINDOWS:
        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        s.connect(str(_sock_path(name)))
        return s, None
    # Windows는 TCP 사용
    port, token = _read_port_file(name)
    s = socket.create_connection(("127.0.0.1", port))
    return s, token

def request(c, token, req):
    """요청 전송 및 응답 수신"""
    if token:
        req = {**req, "token": token}
    c.sendall((json.dumps(req) + "\n").encode())
    data = b""
    while not data.endswith(b"\n"):
        chunk = c.recv(1 << 16)
        if not chunk:
            break
        data += chunk
    return json.loads(data or b"{}")

이 설계의 장점: - 저지연: Unix Socket은 HTTP보다 훨씬 빠름 - 보안성: Unix Socket은 파일 권한으로 접근 제어 - 단순성: HTTP 서버, 라우팅, 직렬화 등 복잡한 로직 불필요

Chrome 인스턴스 자동 발견

daemon.py는 시스템에서 실행 중인 Chrome 인스턴스를 자동으로 스캔한다:

PYTHON
# daemon.py의 브라우저 발견 로직
_MAC_PROFILES = (
    "Library/Application Support/Google/Chrome",
    "Library/Application Support/Google/Chrome Canary",
    "Library/Application Support/Arc/User Data",
    # ... 더 많은 브라우저
)

_LINUX_PROFILES = (
    ".config/google-chrome",
    ".config/chromium",
    ".config/microsoft-edge",
    # ... 더 많은 브라우저
)

def supported_browser_running():
    """지원되는 브라우저가 실행 중인지 감지"""
    return any(browser_running_for_profile(base) for base in PROFILES)

SingletonLock 파일과 DevToolsActivePort 파일을 확인하여 브라우저가 실행 중인지, 원격 디버깅이 활성화되었는지 판단한다.

다른 브라우저 Agent와 비교

특성 Browser Harness Browser Use Agent-E WebVoyager
코드량 3,250줄 15,000+줄 20,000+줄 10,000+줄
설계 철학 미니멀리즘 완전한 기능 엔터프라이즈급 연구 지향
자가 복구 ✅ 핵심 특성 ❌ ❌ ❌
CDP 직접 접근 ✅ ✅ ✅ ✅
셀렉터 엔진 ❌ 좌표 우선 ✅ ✅ ✅
클라우드 브라우저 ✅ ✅ ❌ ❌
녹화 기능 ✅ ✅ ❌ ❌
학습 곡선 낮음 중간 높음 높음

Browser Harness의 핵심 우위는 미니멀리즘 + 자가 복구다. 모든 기능을 제공하려 하지 않고, LLM이 요구에 따라 동적으로 코드를 생성하게 한다. 이 설계로 전에 본 적 없는 시나리오를 처리할 수 있으며, 다른 프레임워크는 사전에 어댑터를 작성해야 한다.

실무 사례: 복잡한 웹 작업 자동화

사례 1: X(Twitter) 영상 다운로드

PYTHON
# 작업: X의 최신 20개 영상 다운로드

browser-harness <<'PY'
# 1. X 프로필 페이지로 네비게이션
goto_url("https://x.com/username/media")
wait_for_load()

# 2. 스크롤하여 더 많은 게시물 로드
scroll_to_bottom(20)  # Agent가 자동 생성한 함수

# 3. 비디오 URL 추출
videos = extract_video_urls()  # Agent가 자동 생성한 함수

# 4. 영상 다운로드
for i, url in enumerate(videos[:20]):
    download_file(url, f"video_{i+1}.mp4")
    print(f"Downloaded {i+1}/20")
PY

사례 2: 복잡한 폼 작성

PYTHON
# 작업: 등록 폼 자동 작성

browser-harness <<'PY'
goto_url("https://example.com/register")
wait_for_load()

# 페이지 정보 가져오기
info = page_info()
print(f"Page: {info['title']}")

# 접근성 트리를 사용하여 폼 요소 찾기
tree = cdp("Accessibility.getFullAXTree")["nodes"]
# 입력 필드 필터링
inputs = [n for n in tree if n.get("role") == "textbox"]

# 폼 작성
for input_node in inputs:
    # 좌표 가져오기
    box = cdp("DOM.getBoxModel", backendNodeId=input_node["backendDOMNodeId"])
    x = sum(box["model"]["content"][0::2]) / 4
    y = sum(box["model"]["content"][1::2]) / 4

    # 클릭 및 입력
    click_at_xy(x, y)
    type_text("test@example.com")
PY

사례 3: 동적 로드 콘텐츠 스크래핑

PYTHON
# 작업: 무한 스크롤 상품 목록 스크래핑

browser-harness <<'PY'
goto_url("https://example.com/products")
wait_for_load()

products = []
last_height = 0

# 새 콘텐츠가 없을 때까지 스크롤
for _ in range(50):
    # 현재 상품 가져오기
    new_products = js("""
        Array.from(document.querySelectorAll('.product-card'))
            .map(card => ({
                name: card.querySelector('.name').textContent,
                price: card.querySelector('.price').textContent
            }))
    """)

    # 새 콘텐츠가 있는지 확인
    if len(new_products) == len(products):
        break

    products = new_products

    # 스크롤
    js("window.scrollTo(0, document.body.scrollHeight)")
    time.sleep(2)

print(f"Found {len(products)} products")
PY

한계와 적용 시나리오

한계

  1. Chrome 의존: Chrome/Chromium 계열 브라우저만 지원, Firefox/Safari는 미지원
  2. 원격 디버깅 수동 활성화 필요: 첫 사용 시 chrome://inspect에서 "원격 디버깅 허용"을 체크해야 함
  3. 좌표 클릭 불안정성: 페이지 레이아웃 변경으로 좌표가 무효화될 수 있음 (단, LLM이 적응 가능)
  4. 대규모 크롤링에 부적합: 단일 인스턴스 설계로 수천 페이지의 동시 크롤링에 부적합
  5. LLM 지원 필요: LLM이 없으면 자가 복구 능력을 발휘할 수 없음

적용 시나리오

✅ 개인 자동화 작업: 영상 다운로드, 폼 작성, 데이터 추출 ✅ 테스트 및 디버깅: 웹 기능 신속 검증 ✅ 복잡한 상호작용 플로우: 동적 의사결정이 필요한 다단계 작업 ✅ 로그인된 세션: Chrome의 로그인 상태를 활용하여 인증이 필요한 사이트에 접근 ✅ 봇 보호 사이트: 실제 브라우저를 사용하여 안티 스크래핑 메커니즘 우회

❌ 대규모 데이터 수집: Scrapy + Playwright가 더 적합 ❌ 크로스 브라우저 테스트: Playwright의 다중 브라우저 지원 사용 ❌ 단순한 HTTP 요청: requests/httpx가 더 효율적

설치 및 빠른 시작

설치

BASH
# uv를 사용하여 설치 (권장)
uv tool install --python 3.12 browser-harness

# 또는 pip 사용
pip install browser-harness

초기 설정

  1. Chrome을 열고 chrome://inspect/#remote-debugging에 접근
  2. "이 브라우저 인스턴스의 원격 디버깅 허용" 체크
  3. 연결 테스트:
BASH
browser-harness <<'PY'
print(page_info())
PY

현재 페이지의 정보(URL, 제목, 크기)가 보이면 연결 성공이다.

Claude Code와 통합

BASH
# browser-harness 설치
uv tool install --python 3.12 browser-harness

# skill로 등록
mkdir -p ~/.codex/skills/browser-harness
browser-harness skill > ~/.codex/skills/browser-harness/SKILL.md

그 후 Claude Code에서 Agent는 자동으로 browser-harness를 사용하여 모든 브라우저 작업을 처리한다.

총평

Browser Harness는 AI Agent 도구 설계의 중요한 트렌드를 대표한다: 복잡한 프레임워크에서 미니멀리즘으로.

핵심 통찰은: 가능한 모든 브라우저 작업을 사전 정의하려 하기보다, 최소한의 기본 함수를 제공하고 LLM이 구체적인 작업에 따라 동적으로 코드를 생성하게 하는 것이 더 낫다는 것이다. 이 설계는 코드량을 줄일 뿐만 아니라 유연성도 높인다—Agent는 전에 본 적 없는 시나리오를 처리할 수 있다.

장점: - ✅ 코드가 극도로 간결하여 이해와 커스터마이징이 용이 - ✅ 자가 복구 메커니즘으로 프레임워크는 쓸수록 강해짐 - ✅ CDP 직접 접근으로 우수한 성능 - ✅ 클라우드 브라우저 지원으로 대규모 작업으로 확장 가능 - ✅ 녹화 기능으로 디버깅과 되돌아보기가 편리

단점: - ❌ Chrome에 의존하여 다른 브라우저는 미지원 - ❌ 초기 설정 시 원격 디버깅 수동 활성화 필요 - ❌ 레이아웃 변경 시 좌표 클릭이 불안정 - ❌ 대규모 동시 작업에 부적합

추천 지수: ⭐⭐⭐⭐⭐ (5/5)

브라우저 자동화 작업이 필요한 개발자에게, Browser Harness는 현재 가장 우아한 선택이다. 미니멀리스트 설계와 자가 복구 능력으로 다양한 복잡한 시나리오에 적응할 수 있으며, 3,000줄 이상의 코드량은 모든 구현 라인을 쉽게 이해할 수 있음을 의미한다.

AI Agent를 구축하고 있거나 복잡한 웹 작업을 자동화해야 한다면, Browser Harness를 시도해 볼 만하다. 브라우저 자동화에 대한 인식을 바꿀 수 있다—최고의 프레임워크는 기능이 가장 많은 것이 아니라, AI가 스스로 문제를 해결할 수 있게 하는 것이다.


참고 링크: - GitHub: browser-use/browser-harness - 문서: SKILL.md - 설치 가이드: install.md - Browser Use Cloud: cloud.browser-use.com

FAQ

1. Browser Harness와 Playwright의 차이점은 무엇입니까?

Browser Harness는 AI 네이티브 프레임워크로, LLM이 브라우저를 제어하도록 설계되었으며 셀렉터 엔진이나 고급 대기 메커니즘을 제공하지 않고 CDP를 통해 좌표와 DOM을 직접 조작한다. Playwright는 전통적인 자동화 프레임워크로, 인간이 스크립트를 작성하도록 설계되었으며 풍부한 셀렉터와 대기 메커니즘을 제공한다. Browser Harness의 핵심 우위는 자가 복구 능력—지원하지 않는 작업을 만나면 LLM이 스스로 코드를 작성한다.

2. Browser Harness는 어떤 브라우저를 지원합니까?

현재 Chrome/Chromium 계열 브라우저만 지원하며, Google Chrome, Chrome Canary, Microsoft Edge, Brave, Arc 등을 포함한다. Firefox와 Safari는 지원하지 않는다. Browser Harness는 Chrome DevTools Protocol (CDP)에 의존하기 때문이다.

3. Chrome의 원격 디버깅을 활성화하려면?

Chrome을 열고 chrome://inspect/#remote-debugging에 접근하여 "이 브라우저 인스턴스의 원격 디버깅 허용"을 체크한다. macOS 사용자는 시스템 설정에서 터미널에 접근성 권한을 부여해야 할 수 있다.

4. Browser Harness는 대규모 크롤링에 적합한가요?

적합하지 않다. Browser Harness는 단일 인스턴스 설계로, 주로 개인 자동화 작업을 대상으로 한다. 수천 페이지를 동시에 크롤링해야 한다면 Scrapy + Playwright 또는 Browser Use Cloud의 클라우드 브라우저 기능을 사용하는 것을 권장한다.

5. 자가 복구 메커니즘은 어떻게 작동합니까?

Agent가 프레임워크에서 커버하지 못하는 작업을 만나면, 스스로 새로운 Python 함수를 작성하여 agent-workspace/agent_helpers.py 파일에 저장한다. 다음에 작업을 실행할 때 이 함수가 자동으로 로드된다. 이렇게 프레임워크는 새로운 능력을 "학습"하여 쓸수록 강해진다.