AI 에이전트가 브라우저를 다루다가 갑자기 멈추는 이유는 대부분 모델의 능력 부족이 아니다. 셀렉터가 바뀌었기 때문이다. React 앱을 CSS Modules이나 styled-components로 빌드하면 배포 때마다 클래스명과 id에 새로운 해시가 붙는다. 어제 잘 작동하던 자동화 스크립트가 오늘 아무 설명 없이 타임아웃으로 죽는 이유가 바로 이것이다. 에이전트는 여전히 화면에 있는 버튼을 클릭하려 했을 뿐이지만, 그 버튼을 가리키던 문자열이 더 이상 유효하지 않았다.
이 문제는 프론트엔드 개발자에게 낯설지 않다. button[id^="submit"] 같은 셀렉터에 의존하는 E2E 테스트가 CI에서 플래키(flaky)하게 깨지는 패턴과 정확히 같은 구조다. Playwright는 이미 getByRole("button", { name: "Submit" }) 같은 역할 기반 로케이터로 해시 변동 문제를 상당 부분 해소했다. 그런데 dev.to에 올라온 BrowserAct 테스트 사례는 더 근본적인 질문을 던진다. "AI 에이전트가 페이지를 탐색할 때 필요한 것은 셀렉터가 아니라, 지금 이 순간 상호작용 가능한 요소들의 목록이 아닐까?"
BrowserAct의 접근은 단순하다. 에이전트에게 셀렉터를 주는 대신 state 명령으로 현재 시점의 인터랙티브 요소 인덱스를 반환한다. [5]<button id=submit-btn-ckeewz /> 같은 형태로. 에이전트는 이 인덱스를 기반으로 click 5를 실행하고, 실행 직후 다시 state를 호출해 페이지가 어떻게 바뀌었는지 확인한다. 인덱스는 스냅샷에 귀속되기 때문에 페이지가 리렌더링되는 순간 만료된다. 낡은 참조를 재사용하려 하면 타임아웃 대신 명확한 에러가 반환된다. "스냅샷이 만료됐습니다. state를 다시 실행하세요." 이 한 줄이 에이전트의 복구 루프를 완성한다.
이 모델이 흥미로운 이유는 단순히 셀렉터 문제를 우회해서가 아니다. 페이지를 정적인 구조가 아니라 매 순간 변화하는 상태로 다룬다는 설계 철학 때문이다. React 앱의 실제 렌더링 방식과 훨씬 잘 맞는 멘탈 모델이다. 상태가 바뀌면 UI가 바뀌고, 에이전트는 그 변화를 감지하고 재평가한다. 사람이 화면을 보면서 하는 행동과 구조적으로 동일하다. 반면 셀렉터 기반 자동화는 페이지가 마치 고정된 DOM 트리인 것처럼 가정하는데, 현대 프론트엔드는 그 가정을 단 한 번의 배포로도 무너뜨린다.
물론 한계도 솔직하게 드러난다. state는 인터랙티브 요소만 인덱싱한다. 텍스트 콘텐츠나 문서 구조를 읽으려면 get markdown, get text 같은 별도 명령이 필요하다. 그리고 인증 세션은 여전히 개발자가 명시적으로 설계해야 한다. BrowserAct 세션이 살아있어도 웹사이트 로그인이 만료되면 에이전트는 로그인 페이지의 상태를 충실하게 반환할 뿐이다. 이 결정을 자동으로 처리하지 않는다는 점이 오히려 올바른 설계 선택처럼 보인다. 재인증 여부는 비즈니스 맥락이 있는 판단이기 때문이다.
한편 같은 시기에 배포된 mcp-handler 2.0은 다른 각도에서 비슷한 구조 문제를 다룬다. 이전 MCP 스펙은 서버 사이드 세션 상태를 전제했다. Redis, 스티키 세션, 지속 연결—Lambda나 Cloudflare Workers 같은 에페머럴 컴퓨팅 환경과 근본적으로 충돌하는 가정들이었다. 2026-07-28 스펙을 구현한 2.0은 Streamable HTTP 트랜스포트를 통해 세션 상태 없이 동작하는 무상태 경로를 추가했다. 기존 클라이언트는 그대로 동작하고, 새 클라이언트는 자동으로 무상태 경로를 사용한다. SSE 엔드포인트(/sse, /message)는 완전히 제거되어 410을 반환하므로, 업그레이드 전 의존성 확인은 필수다.
같은 맥락에서 Vercel Sandbox의 createUser() / createGroup() API도 주목할 만하다. 기존에는 에이전트 간 격리를 위해 컨테이너를 에이전트 수만큼 띄워야 했다. 이제는 단일 샌드박스 환경 안에서 파일시스템 네임스페이스를 분리하고, 필요할 때만 공유 디렉터리로 협업할 수 있다. 멀티에이전트 워크플로우를 위한 인프라 복잡도를 크게 낮춘다. AI 에이전트가 프론트엔드 인프라와 교차하는 지점이 빠르게 넓어지고 있다는 신호다.
두 업데이트가 함께 가리키는 방향은 하나다. AI 에이전트를 실제 UI 환경에서 안정적으로 운용하려면 '상태를 어떻게 표현하고 전달하는가'라는 설계 문제가 셀렉터나 세션 관리보다 먼저 해결되어야 한다. 동적 렌더링 환경에서 셀렉터는 태생적으로 불안정하다. 무상태 서버리스 환경에서 지속 연결은 태생적으로 충돌한다. 에이전트가 '지금 이 순간의 상태'를 읽고, 행동하고, 다시 읽는 루프를 설계 레벨에서 지원할 때 비로소 동적 UI 앞에서 멈추지 않는다.
프론트엔드 개발자 입장에서 이 흐름이 의미하는 바는 구체적이다. AI 에이전트가 내 앱을 안정적으로 다루게 하려면 에이전트 친화적인 DOM 설계—시맨틱 마크업, 안정적인 aria-label, 의미 기반 역할 속성—가 성능 최적화만큼이나 중요해진다. 해시 기반 클래스명은 빌드 최적화를 위한 선택이지만, 그 선택이 자동화 레이어에 얼마나 큰 비용을 만드는지 이제는 제품 설계 단계에서 함께 고려해야 한다.