실행 프로그램과 확장

Transformers.js로 브라우저 안에서 로컬 LLM 실행하기

질문을 입력하면 내 브라우저에서 답변을 만드는 작은 웹 앱을 만들어봐요.

Transformers.js는 AI 모델을 JavaScript로 실행하는 라이브러리예요. ONNX 형식의 모델을 내려받으면 브라우저에서도 답변을 생성할 수 있어요. 이 글에서는 4.3.0의 공식 예제 모델인 LFM2.5-350M을 사용해 질문 입력창과 답변 버튼을 만들어요.

실행 조건과 핵심 내용
  • 정적 HTML은 `localhost` 또는 HTTPS에서 열고, ES module로 Transformers.js 4.3.0을 가져옵니다.
  • CPU/WASM은 기본 경로이고, `device: 'webgpu'`는 호환되는 브라우저·GPU가 있을 때만 선택합니다.
  • 입력 문장은 브라우저 안에서 실행되는 모델로 전달되며 별도 추론 서버를 호출하지 않습니다.

브라우저 로컬 추론은 무엇을 바꾸나요?

보통 웹에서 AI에 질문하면 서버가 답변을 만들어 보내줘요. 브라우저 로컬 추론은 이 작업을 사용자의 컴퓨터가 맡는 방식이에요. Transformers.js의 `pipeline1()`을 한 번 만들고 입력 문장을 전달하면, 내려받은 모델이 같은 페이지에서 답변을 생성해요.

별도 Python 추론 서버를 설치할 필요가 없어 작은 웹 기능을 시험하기 좋아요. 텍스트 분류나 짧은 답변처럼 부담이 작은 작업부터 시작해보세요. 많은 사용자를 동시에 처리하거나 큰 모델을 계속 제공할 때는 별도 서빙 엔진을 검토하는 편이 좋아요.

책상 위 노트북 화면에 Transformers.js가 동작하는 브라우저 창과 ONNX 모델이 보이는 장면
모델을 한 번 불러오면 입력한 질문을 같은 브라우저에서 처리해요.

4.3.0에서 확인할 모델과 장치 선택

Transformers.js 4.3.0은 2026년 9월 16일 공개됐어요. 릴리스 예제는 `onnx-community/LFM2.5-350M-ONNX`에 WebGPU2용 `q4f16`을 사용합니다. 이 모델 저장소에는 CPU/WASM에서 선택할 수 있는 `q4` 파일도 있지만 `q8` 파일은 확인되지 않아, 아래 코드는 장치에 따라 두 형식 중 하나를 고릅니다.

다른 ONNX 모델로 바꿀 때는 선택한 dtype 파일이 해당 저장소에 있는지 확인하세요. 파일 이름과 추론 설정이 일치해야 모델을 불러올 수 있어요.

공식 자료는 이 모델의 최소 시스템 RAM3·GPU4 메모리를 제시하지 않아요. 모델 파일 크기만으로 실행 가능 여부를 단정하지 말고, 처음 실행할 때 브라우저 작업 관리자에서 탭의 메모리 사용량을 확인하세요.

이 모델 저장소에서 확인한 실행 형식과 브라우저 장치 경로예요.
브라우저 실행 경로설정사용 조건
CPU/WASM`device` 생략, `dtype: 'q4'`이 저장소에 있는 q4 파일을 사용하는 기본 추론 경로
지원 GPU`device: 'webgpu'`, `dtype: 'q4f16'`WebGPU adapter를 얻고 해당 형식을 지원할 때
q8이 모델에서는 선택하지 않음공식 모델 저장소에 q8 ONNX 파일이 없어 사용할 수 없음

이 모델 저장소에서 확인한 실행 형식과 브라우저 장치 경로예요.

CPU/WASM

설정
`device` 생략, `dtype: 'q4'`
사용 조건
이 저장소에 있는 q4 파일을 사용하는 기본 추론 경로

지원 GPU

설정
`device: 'webgpu'`, `dtype: 'q4f16'`
사용 조건
WebGPU adapter를 얻고 해당 형식을 지원할 때

q8

설정
이 모델에서는 선택하지 않음
사용 조건
공식 모델 저장소에 q8 ONNX 파일이 없어 사용할 수 없음
책상 위 노트북과 옆의 워크스테이션이 나란히 놓이고 각각 CPU와 GPU 실행 경로를 보여주는 장면
WebGPU를 사용할 수 없으면 CPU/WASM으로 실행해요. 기기마다 처리 속도와 메모리 사용량이 달라요.

localhost에서 여는 정적 HTML 준비

정적 파일 두 개만 있으면 시작할 수 있어요. ES module의 CDN import를 사용하므로 파일을 탐색기에서 직접 여는 대신 로컬 웹 서버를 띄웁니다. `localhost`는 WebGPU가 요구하는 secure context로 취급됩니다. 공개 배포에는 HTTPS를 사용하세요.

새 빈 폴더에서 `index.html`과 `main.js`를 만들고 아래 HTML을 저장하세요. 이 경로는 jsDelivr CDN에서 라이브러리를 모듈로 불러오는 공식 문서 방식입니다. 버전을 URL에 고정하면 이후 CDN의 기본 태그가 바뀌어도 이 예제는 4.3.0을 요청합니다.

index.html — 입력과 결과 표시 영역
<!doctype html>
<html lang="en">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Browser-local text generation</title>
  <label>Prompt <input id="prompt" value="Reply in one short sentence: local AI runs in a browser."></label>
  <button id="run" disabled>Generate</button>
  <pre id="status">Loading model…</pre>
  <pre id="output"></pre>
  <script type="module" src="./main.js"></script>
</html>
ES module 스크립트가 같은 폴더의 `main.js`를 불러옵니다.
브라우저 다운로드 목록과 모델 파일이 저장된 폴더가 열린 노트북 화면
처음 모델 파일을 내려받은 뒤에는 같은 브라우저에서 실행을 이어갑니다.

모델을 불러와 한 번 생성하기

아래 `main.js`는 WebGPU를 사용할 수 있는지 확인한 뒤 모델을 불러와요. GPU를 사용할 수 있으면 `q4f16`, 사용할 수 없거나 확인 과정에서 오류가 나면 CPU/WASM용 `q4`를 선택해요. 모델이 준비되면 Generate 버튼이 활성화돼요.

첫 실행에서는 CDN에서 라이브러리를, Hugging Face Hub에서 모델 파일을 받아요. 이 예제의 질문은 별도 추론 서버로 보내지 않고 브라우저 안에서 처리해요. 서비스에 붙일 때는 분석 도구나 로그 수집 코드가 입력을 전송하는지도 확인하세요. 모델을 불러오는 작업은 한 번만 하고, 버튼을 누를 때마다 같은 실행기를 재사용해요.

main.js — WebGPU 확인 후 로컬 pipeline 실행
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@4.3.0';

const status = document.querySelector('#status');
const output = document.querySelector('#output');
const promptInput = document.querySelector('#prompt');
const button = document.querySelector('#run');
const modelId = 'onnx-community/LFM2.5-350M-ONNX';
let adapter = null;
try {
  adapter = await navigator.gpu?.requestAdapter() ?? null;
} catch (error) {
  console.warn('WebGPU unavailable; using CPU/WASM.', error);
}
const device = adapter ? 'webgpu' : undefined;
const dtype = adapter ? 'q4f16' : 'q4';
let generator;

try {
  status.textContent = `Loading ${modelId} (${device ?? 'CPU/WASM'}, ${dtype})…`;
  generator = await pipeline('text-generation', modelId, { dtype, ...(device ? { device } : {}) });
  status.textContent = `Ready: ${device ?? 'CPU/WASM'} / ${dtype}`;
  button.disabled = false;
} catch (error) {
  status.textContent = `Model load failed: ${error.message}`;
  console.error(error);
}

button.addEventListener('click', async () => {
  if (!generator) return;
  button.disabled = true;
  status.textContent = 'Generating…';
  try {
    const result = await generator(promptInput.value, { max_new_tokens: 48 });
    const generated = result[0]?.generated_text;
    output.textContent = typeof generated === 'string'
      ? generated
      : Array.isArray(generated)
        ? generated.at(-1)?.content ?? JSON.stringify(result)
        : JSON.stringify(result);
    status.textContent = 'Done.';
  } catch (error) {
    status.textContent = `Generation failed: ${error.message}`;
    console.error(error);
  } finally {
    button.disabled = false;
  }
});
Transformers.js 4.3.0 릴리스가 제시한 ONNX 모델과 `q4f16`을 사용합니다. 생성은 페이지 안의 pipeline에 입력을 전달합니다.

서버를 띄워 결과와 첫 다운로드 확인

파일을 저장한 폴더에서 터미널을 열고 아래 명령 중 하나만 실행하세요. `http://127.0.0.1:8000`에 접속해 상태 문구가 `Ready:`로 바뀌면 Generate를 눌러요. 처음에는 모델 파일을 받느라 시간이 걸려요. 준비가 끝나면 입력한 문장에 대한 짧은 결과가 표시돼요.

두 명령 모두 내 컴퓨터에서만 접속할 수 있도록 주소를 제한했어요. Node.js를 쓰면 첫 명령을, Python이 설치돼 있으면 두 번째 명령을 선택하면 돼요. 공개 웹사이트에서는 HTTPS를 사용하세요.

서버 실행 — Node.js 또는 Python 중 하나
# Option A: Node.js
npx serve --listen tcp://127.0.0.1:8000 .

# Option B: Python (choose one server, not both)
python3 -m http.server 8000 --bind 127.0.0.1
어느 명령을 선택하든 `http://127.0.0.1:8000`에서 열어요.

모델이 열리지 않으면 다운로드와 GPU 오류를 확인해요.

WebGPU adapter가 없으면 CPU/WASM용 `q4`를 사용해요. Safari에서는 Transformers.js 4.3.0이 지원을 추가한 Safari 26 이상인지 확인하고, 다른 브라우저는 해당 버전의 WebGPU 지원을 따로 확인하세요. adapter가 반환돼도 메모리 부족으로 모델 적재가 실패할 수 있습니다.

모델 파일을 불러오지 못하면 브라우저 개발자 도구의 Network에서 CDN 또는 Hub 요청의 차단·실패를 확인하세요. GPU device 오류가 나면 다른 탭과 앱을 닫고 CPU5용 `q4`로 다시 열거나 더 작은 지원 모델을 선택해요. 입력 뒤 오류가 발생하면 콘솔의 첫 에러와 모델 ID·dtype·device 조합을 기록하면 재현에 도움이 됩니다.

브라우저 추출 결과를 JSON 형식으로 받기

답변을 다음 프로그램에 넘기려면 문장보다 JSON이 편할 때가 있어요. 예를 들어 상품 의견에서 감성과 주제만 뽑을 수 있어요. 4.3.0의 실험 기능인 구조화 출력은 JSON Schema로 출력할 필드와 값을 제한해요. 현재는 한 번에 결과 하나를 생성해요.

이 기능에는 별도 패키지가 필요해요. 아래 코드는 앞의 CDN HTML에 그대로 붙이는 대신, Vite 같은 모듈 번들러가 있는 웹 프로젝트에서 사용해요. 의존성을 설치하고 JavaScript 파일에 넣으면 돼요. 출력은 `JSON.parse()`로 읽고, 필요한 필드가 있는지 확인한 뒤 사용하세요.

번들러 프로젝트에 의존성 설치
npm install @huggingface/transformers@4.3.0 @huggingface/transformers-structured-output
정적 HTML 예제와 달리, 이 코드는 npm 패키지를 처리하는 개발 환경이 필요해요.
StructuredOutputProcessor로 감성과 주제 제한
import { pipeline } from '@huggingface/transformers';
import { StructuredOutputProcessor } from '@huggingface/transformers-structured-output';

const generator = await pipeline('text-generation', 'onnx-community/LFM2.5-350M-ONNX', {
  dtype: 'q4f16', device: 'webgpu',
});

const processor = new StructuredOutputProcessor(generator.tokenizer, {
  type: 'json_schema',
  json_schema: {
    type: 'object',
    properties: {
      sentiment: { enum: ['positive', 'negative', 'neutral'] },
      topic: { enum: ['price', 'quality', 'delivery', 'other'] },
    },
    required: ['sentiment', 'topic'],
    additionalProperties: false,
  },
});

const result = await generator(
  [{ role: 'user', content: 'Classify this feedback: Shipping was fast, but the product is expensive.' }],
  { max_new_tokens: 48, do_sample: false, logits_processor: [processor] },
);
const jsonText = result[0].generated_text.at(-1).content;
console.log(JSON.parse(jsonText));
WebGPU를 지원하는 브라우저에서 실행해요.

용어 각주

  1. 파이프라인 — 입력부터 결과까지 이어지는 처리 단계의 묶음입니다. 각 단계에서 서로 다른 모델이나 도구를 사용할 수 있습니다.

    본문으로 돌아가기
  2. WebGPU — 웹 브라우저에서 그래픽과 범용 GPU 계산을 수행하기 위한 웹 표준 API입니다. 브라우저와 기기별 지원 기능은 다를 수 있습니다.

    본문으로 돌아가기
  3. 시스템 RAM — 프로그램이 실행되는 동안 데이터를 임시로 보관하는 시스템 메모리입니다.

    본문으로 돌아가기
  4. GPU — 많은 계산을 병렬로 처리하는 프로세서입니다. AI 모델 실행에서는 모델 계산을 맡습니다.

    본문으로 돌아가기
  5. CPU — 컴퓨터에서 일반적인 프로그램 명령을 실행하는 중앙 처리 장치입니다. AI 작업에서는 GPU 등 다른 프로세서와 역할을 나누기도 합니다.

    본문으로 돌아가기