매일 브라우저 확장 프로그램을 개발하는 이들 사이에서 로컬 AI를 브라우저 내부에 직접 심으려는 시도가 늘고 있다. 특히 복잡한 서버 통신 없이 브라우저 자체 자원만으로 추론을 수행하려는 개발자들에게 Transformers.js(브라우저 환경에서 머신러닝 모델을 실행하는 라이브러리)는 필수적인 선택지가 되었다. 하지만 크롬 확장 프로그램의 Manifest V3(확장 프로그램의 보안과 성능을 위해 구글이 도입한 최신 아키텍처 규격) 환경은 서비스 워커의 생명 주기와 메모리 제한이라는 독특한 제약을 가지고 있어, 단순히 코드를 옮기는 것만으로는 원활한 구동이 어렵다.
확장 프로그램의 아키텍처와 모델 호스팅
이번 프로젝트는 세 가지 핵심 진입점을 통해 구성된다. Manifest V3의 제약 사항을 준수하기 위해 모든 무거운 연산은 백그라운드 서비스 워커(확장 프로그램의 로직을 처리하는 백그라운드 프로세스)가 담당한다. 모델 로딩과 추론은 백그라운드에서 단일 인스턴스로 관리되며, 사이드 패널(브라우저 우측에 고정된 UI 영역)은 채팅 인터페이스를, 콘텐츠 스크립트(웹 페이지의 DOM에 접근하는 스크립트)는 페이지 수준의 동작을 수행한다. 모델은 다음과 같이 백그라운드에서 명시적으로 관리된다.
// 모델 로드 및 초기화 예시
import { pipeline } from '@xenova/transformers';let model = null;
async function getModel() {
if (!model) {
model = await pipeline('text-generation', 'Xenova/gemma-2-2b-it');
}
return model;
}
이 구조는 모델을 여러 번 로드하는 중복을 방지하고, 확장 프로그램 설치 단위로 캐시를 공유하여 메모리 효율을 극대화한다. 서비스 워커가 일시 중단될 수 있는 환경을 고려하여, 모델 상태는 언제든 복구 가능하도록 설계해야 한다.
기존 방식과의 차이점과 메시지 통신
예전에는 UI와 로직이 뒤섞여 모델 추론이 발생할 때마다 브라우저가 멈추거나 메모리 부족 현상을 겪곤 했다. 이제는 백그라운드를 유일한 오케스트레이터(전체 흐름을 제어하는 관리자)로 설정하고, 사이드 패널과 콘텐츠 스크립트는 요청을 보내고 결과를 렌더링하는 클라이언트 역할만 수행한다. 이들 사이의 통신은 타입이 지정된 메시지 구조를 따른다. 예를 들어, 사이드 패널이 AGENT_GENERATE_TEXT 이벤트를 보내면 백그라운드가 이를 받아 추론을 수행하고 MESSAGES_UPDATE를 다시 UI로 전달한다. 이러한 분리는 UI의 반응성을 유지하면서도 크롬의 보안 경계를 준수하는 핵심 설계다.
결과적인 상태 관리와 도구 호출
개발자가 바로 체감하는 변화는 상태 관리의 명확성이다. 대화 기록은 백그라운드에 저장하여 모든 탭과 세션에서 일관된 상태를 유지하고, 설정 값은 확장 프로그램 저장소(chrome.storage)에, 대규모 데이터는 로컬 데이터베이스에 분산 배치한다. 특히 에이전트 워크플로우를 위해 모델이 도구를 호출할 때는 모델 출력값을 결정론적인 도구 실행으로 변환하는 정규화 계층이 필수적이다. 모델이 특정 토큰을 출력하면 이를 파싱하여 브라우저 탭 제어, 웹사이트 검색 등 실제 동작으로 연결한다.
// 도구 호출 파싱 예시
const toolCalls = extractToolCalls(modelOutput);
for (const call of toolCalls) {
await executeTool(call.name, call.parameters);
}로컬 AI 기능을 확장 프로그램에 통합할 때는 오직 필요한 권한(sidePanel, storage, scripting 등)만 명시하여 사용자 신뢰를 확보하는 것이 아키텍처의 완성이다.




