개요

browser-use 생태계에서 만든 TypeSafe Jev 기반 브라우저 에이전트 프로젝트. 하나의 자연어 목표를 주면 Jev가 operation(클릭·입력·선택·스크롤·대기·완료) 과 target element를 함께 결정하고, 텍스트 입력이 필요한 경우에만 소형 LLM이 텍스트를 생성한다. Google Flights에서 취리히→런던 편도 검색을 7.1초에 수행한 실제 녹화 데모가 있다.

한 줄 핵심: 스크린샷 대신 구조화된 DOM 스냅샷과 색인 요소 테이블을 사용하고, operation-target 결정을 하나의 TypeSafe 요청으로 묶어 브라우저 프로토콜 호출 수를 1,092→101로 90% 이상 줄인 실험적 고속 에이전트 루프.

배경

왜 만들었나: 브라우저 에이전트의 가장 큰 비용 중 하나가 매 스텝마다 많은 브라우저 프로토콜 호출과 스크린샷/이미지 기반 추론에 의존하는 것. jev-ultrafast는 (1) 한 번의 DOM 읽기로 현재 보이는 컨트롤만 원자적으로 스냅샷하고, (2) operation 질문과 target 질문을 하나의 TypeSafe 요청으로 처리하여 라운드 트립을 줄이며, (3) 텍스트 생성이 필요한 경우에만 소형 LLM을 호출하는 식으로 이 비용을 낮춘다.

무엇이 아닌가: 사이트별 액션 스크립트나 사전 준비된 필드 문자열을 내장한 정책이 아니다. Flights 예제는 목표와 독립적인 결과 검증만 제공하고, 스크린샷 렌더러는 사후에 레이블만 붙인다. 모델 출력이 셀렉터·좌표·셸 명령·실행 가능한 JavaScript가 되는 일도 없도록 설계되어 있다.

구조

액션 공간: 관찰마다 새 요소 테이블이 생성된다. 예: [1] button Change ticket type · Round trip, [2] combobox Where from? · San Francisco 등.

  • 연산(operation): CLICK, TYPE_TEXT, SELECT, SCROLL_UP, SCROLL_DOWN, WAIT, DONE, BLOCKED
  • operation 질문과 target 질문은 speculative: operation이 CLICK이면 click_target만 실행 가능
  • 각 target head는 호환되는 요소만 담고, 네이티브 드롭다운 선택은 관찰된 element/option index를 함께 전달
  • operation + target 결정 = 한 번의 TypeSafe 요청 (두 결정을 하나의 라운드 트립으로 처리)

루프 구조 (핵심 파일):

파일역할
jev_ultrafast/agent.py완전한 루프 + 텍스트 헬퍼 핸드오프
jev_ultrafast/snapshot.js원자적 DOM 스냅샷, 색인된 컨트롤, 신선도 가드
jev_ultrafast/browser.py브라우저 연결, 현재 기하 정보, 실행
jev_ultrafast/model.py동적 operation/target head + 텍스트 생성
jev_ultrafast/questions.py모델 지시문
jev_ultrafast/demo.py로컬 인스펙터

성능 (발표된 수치)

주의: 아래 수치는 “하나의 작업을 하나의 브라우저 프로필에서 3회 반복”한 측정으로, 일반 신뢰성 벤치마크가 아니다.

  • Google Flights 데모: 7,073ms. 초기 페이지 관찰 후 타이밍 시작, 모델 호출·생성 텍스트·브라우저 작업·stale 결정·로딩 대기 포함.
  • 교대 실행 6회(동일 모델·설정)에서 두 버전 모두 3/3 통과. 중앙값 작업 시간 9.450s → 7.092s (25% 감소), 중앙값 브라우저 프로토콜 호출 1,092 → 101.
  • 같은 정책으로 Wikipedia 요청 기사 열기 2.798s, 로컬 호텔 검색/필터 작업 1.896s 통과.

자세한 실행·실패·소스 해시·측정 경계는 저장소의 performance.md에 있다.

동작 원리 (왜 빠른가)

  • 결정 주기당 하나의 요청: operation head와 target head가 같은 관찰 상태를 공유.
  • 기본 에이전트 루프에 스크린샷 없음: Jev는 구조화된 상태만 소비. 인스펙터는 선택적으로 스크린샷을 쓰고, 비디오는 별도 연속 화면 녹화.
  • 스냅샷당 하나의 브라우저 호출: 보이는 컨트롤·이름·값·텍스트를 원자적으로 읽고 실제 DOM 노드 참조를 유지.
  • 선택된 target 검증: 클릭 시 문서·폼 값·타겟·주변 컨텍스트를 재확인. 애니메이션만으로 재예측을 강제하지 않음. 현재 기하 정보 해상도와 가려진 컨트롤 거부 후 입력.
  • 유용한 상태 대기: 콤보박스에 입력 후 보이는 제안 대기(최대 200ms). 다른 상호작용은 최대 2프레임 또는 50ms. 실행이 기록된 후 이 읽기가 발생.
  • 숨겨진 탭 렌더링 유지: 포커스 에뮬레이션으로 Chrome의 보이는 탭을 전환하지 않고 백그라운드 애니메이션 스로틀링 방지.
  • 보이는 텍스트만 전송: 화면 밖 본문·푸터가 모델 컨텍스트를 채우지 않음.
  • 중단된 텍스트 요청 재사용: 생성된 값이 stale-page 재시도를 견디려면 텍스트 헬퍼 입력 전체가 불변이어야 함.

안전 장치: 실행된 모든 target은 관찰된 노드에서 해석됨. 실행기가 페이지 신선도와 클릭 가림을 재확인. 모델 출력은 셀렉터·좌표·셸 명령·실행 가능 JavaScript가 되지 않음. 텍스트 헬퍼 출력은 타이핑 전 소형 JSON 객체로 파싱되어야 함.

한계 (MVP 기준)

  • DONE 선택은 여전히 독립적 결과 검증이 필요.
  • DOM 리더는 일반적인 HTML·ARIA 컨트롤을 다루며, 전체 accessible-name 명세까지는 아님.
  • 범위 밖: Shadow roots, frames, canvas, 업로드, 팝업 탭, 중첩 스크롤, 임의 키보드 위젯.
  • 소유 탭은 기존 Chrome 프로필을 공유.

사용법

실행 (데모)

git clone https://github.com/browser-use/jev-ultrafast.git
cd jev-ultrafast
uv sync
cp .env.example .env
# TYPESAFE_API_KEY, TEXT_MODEL_API_KEY 추가
uv run jev

http://127.0.0.1:8766에서 Start demo → Run automatically 클릭. 인스펙터에 번호 붙은 요소, operation 확률, target 확률, 실행된 액션이 표시됨. Choose next로 실행 전 일시 정지 가능.

Chrome은 Browser Harness 를 통해 연결되며, uv sync 시 설치됨. 연결이 필요하면 uv run browser-harness --doctor 실행, 프롬프트 시 Chrome 원격 디버깅 허용.

TEXT_MODEL_API_KEY는 예제 구성에서 OpenRouter 키. 현재 데모는 inception/mercury-2.5를 리asoning 비활성화 상태로 사용. Gemini, GLM, DeepSeek도 OpenAI 호환 텍스트 헬퍼를 쓸 수 있음(모델·엔드포인트·리asoning 설정 구성).

라이브러리 사용

from jev_ultrafast import Agent
 
with Agent(
    "https://www.google.com/travel/flights?hl=en",
    "Find one-way flights from Zurich to London on September 20, 2026, "
    "for one adult in economy. Stop when matching flight options are visible.",
) as agent:
    for state in agent.run():
        print(state["elapsed_ms"], state["status"])

uv run --env-file .env python your_script.py로 실행. 같은 정책으로 다른 작업도 가능:

uv run --env-file .env python examples/run.py \
  --url https://en.wikipedia.org/wiki/Main_Page \
  --goal 'Find and open the Wikipedia article about Gödel's incompleteness theorems.'

examples/flights.py --keep-open은 항공 검색을 수행하고 실제 경로·날짜·결과를 확인해 트레이스를 저장하지만, 항공편을 선택하거나 예약하지는 않는다.

개발

uv run ruff check .
uv run pytest
node --check jev_ultrafast/static/app.js
node --check jev_ultrafast/snapshot.js
uv build

테스트는 오프라인. uv run python scripts/check_guards.py는 모델 호출 없이 로컬 브라우저에서 실제 컨트롤을 검사. 라이브 예제와 녹화 스크립트는 유료 API 호출 발생. scripts/record_flights.py <new-folder>가 원본 브라우저 타임스탬프를 캡처, scripts/render_demo.py <recording-folder>가 검증된 실행을 1×로 렌더링하고 Google 계정 스트립을 잘라냄. 자격 증명·원본 트레이스는 무시(ignore) 상태로 유지.

관계

참고

  • 저장소: https://github.com/browser-use/jev-ultrafast (별 415, 포크 18)
  • 라이선스: MIT
  • 주요 기여자: gregpr07 (Gregor Žunič)
  • 작성 시점 기준 2 커밋, 브랜치 3개, 태그 0개
  • 언어 비율: Python 57.8%, HTML 18.5%, JavaScript 13.3%, CSS 10.4%
  • 최신 커밋(2026-09-17): “Reduce browser round trips and record a 7-second Flights demo” (452c1ad)