use-local-llm: 실제 로컬에서 동작하는 AI를 위한 React Hooks

발행: (2026년 3월 12일 오전 06:08 GMT+9)
12 분 소요
원문: Dev.to

Source: Dev.to

로컬에서 실제로 작동하는 AI를 위한 React Hooks: use-local-llm

Pooya Golchian

드디어 로컬 LLM을 실행시켰습니다. 모델을 받아 curl 로 테스트해 보니 아름답게 동작했습니다. 그런데 이 모델을 React 앱에 통합하려고 하는 순간, 벽에 부딪히게 됩니다.

모두가 사용하는 도구들은 서버에서 OpenAI나 Anthropic을 호출한다는 전제를 가지고 있습니다. 브라우저에서 직접 localhost:11434 로 통신한다는 상황을 기대하지 않으며, 만약 가능하다고 해도 API 라우트를 만들고 백엔드를 추가하도록 강요해 프로토타입을 복잡하게 만듭니다.

이러한 좌절감에 지쳐 저는 use-local-llm 을 만들었습니다 — 로컬 모델에서 AI 응답을 브라우저에서 바로 스트리밍하는 한 가지 일을 탁월하게 수행하는 라이브러리입니다. 백엔드가 전혀 필요 없습니다.

왜 기존 도구들이 맞지 않을까

Vercel AI SDK를 바로 사용할 수 있을 것이라고 생각할 수 있습니다. 이것은 React + AI의 표준이며, 설계가 잘 되어 있고, 문서도 충실하며, 실전에서 검증되었습니다.

하지만 이것은 여러분이 하려는 일에 맞게 만들어진 것이 아닙니다.

Vercel AI SDK는 API 레이어가 필요합니다. 여러분의 React 앱이 POST 요청을 Next.js 서버에 보내고, 그 서버가 LLM을 호출한 뒤 스트리밍으로 결과를 반환합니다. 이는 OpenAI나 Anthropic을 사용하는 프로덕션 앱에서는 타당합니다—인증, 비용 추적, 보안을 위해 백엔드가 필요하기 때문이죠.

LLM이 이미 localhost:11434에서 로컬로 실행 중이라면, 그 서버는 오히려 마찰만 늘립니다: 작성해야 할 코드가 늘고, 지연 시간이 증가하며, 빠른 프로토타입을 만들 때 복잡성이 증가합니다.

제가 원했던 것은 간단했습니다: 로컬 모델과 직접 통신하는 단일 React 훅. 중간 매개자가 없습니다. API 라우트도 없습니다. 오직 React와 실행 중인 LLM만 있으면 됩니다.

Browser → fetch() → localhost:11434 → streaming tokens back

이것이 전체 아키텍처이며, 중간 단계가 전혀 없습니다.

작동 방식

use-local-llm은(는) 로컬 LLM으로부터 브라우저에서 직접 응답을 스트리밍하는 React 훅을 제공합니다. API 라우트가 없습니다. 백엔드도 없습니다. 하나의 훅과 실행 중인 모델만 있으면 됩니다.

하나의 훅. 그게 전부입니다.

function Chat() {
  const { messages, send, isStreaming } = useOllama("gemma3:1b");

  return (
    <>
      {messages.map((m, i) => (
        <p key={i}>
          <strong>{m.role}:</strong> {m.content}
        </p>
      ))}
      <button onClick={() => send("Hello!")} disabled={isStreaming}>
        {isStreaming ? "Generating…" : "Send"}
      </button>
    </>
  );
}

이것은 완전한 스트리밍 채팅 인터페이스입니다. 메시지 기록? 처리됩니다. 스트리밍 상태? 처리됩니다. 생성 중간에 중지? 처리됩니다. 모든 복잡성이 훅 내부에 감싸져 있습니다.

/api/chat 라우트가 없습니다. Next.js도 없습니다. 백엔드 설정도 없습니다. React가 가장 잘하는 일을 하는 것뿐입니다.

Any Local LLM과 함께 작동

Ollama, LM Studio, llama.cpp 또는 OpenAI와 호환되는 서버를 사용하든, 그대로 작동합니다:

const ollama = useLocalLLM({ endpoint: "http://localhost:11434", model: "gemma3:1b" });
const lmStudio = useLocalLLM({ endpoint: "http://localhost:1234", model: "local-model" });
const llamaCpp = useLocalLLM({ endpoint: "http://localhost:8080", model: "model" });

백엔드는 포트 번호를 기준으로 자동 감지됩니다. 각 도구는 자체 스트리밍 프로토콜을 사용하므로, 어떤 툴을 선택하든 최적의 성능을 얻을 수 있습니다.

고급: 토큰‑별 제어

세밀한 제어가 필요하신가요? 스트리밍되는 각 토큰에 연결하세요:

function Writer() {
  const { output, generate, isStreaming } = useStreamCompletion({
    endpoint: "http://localhost:11434",
    model: "gemma3:1b",
    onToken: (token) => console.log("Token:", token),
  });

  return (
    <>
      <pre>{output}</pre>
      <button onClick={() => generate("Write a haiku about React")}>
        Generate
      </button>
    </>
  );
}

사용 가능한 모델 찾기

사용자가 수동 설정 없이 사용 가능한 모델을 선택하도록 하세요:

function ModelPicker() {
  const { models, isLoading } = useModelList();

  return (
    <select disabled={isLoading}>
      {models.map((m) => (
        <option key={m.name} value={m.name}>
          {m.name}
        </option>
      ))}
    </select>
  );
}

How It Compares

FeatureVercel AI SDKuse‑local‑llm
TargetCloud LLMs (OpenAI, Anthropic…)Local LLMs (Ollama, LM Studio, llama.cpp)
ArchitectureClient → Server → Cloud APIClient → Local LLM directly
Backend neededYesNo
Setup time10 + minutes~2 minutes
Bundle size~50 KB+2.8 KB (gzipped)
DependenciesMultipleZero (React only)
PrivacyData leaves your machineNever leaves your machine

사용 사례에 맞는 도구를 선택하세요. 프로덕션 환경에서 OpenAI를 호출한다면 Vercel AI SDK를 사용하고, 로컬에서 프로토타이핑하거나 프라이버시를 우선시한다면 use‑local‑llm을 사용하세요.

Source:

왜 이렇게 설계되었을까

의존성 0개 (전체 2.8 KB)

전체 패키지는 gzipped 기준 2.8 KB입니다. 런타임 의존성이 없으며, React만 피어로 사용합니다.

왜 중요한가요? 프로토타입을 즉시 설치할 수 있고 프로젝트 내 다른 패키지와 절대 충돌하지 않기 때문입니다. 의존성 충돌도, 버전 불일치도, 불필요한 용량 증가도 없습니다.

React 외부에서도 동작

핵심 스트리밍 함수(streamChat()streamGenerate())는 async generator이며 React, Vue, 순수 JS, Node.js 스크립트 어디서든 사용할 수 있습니다. React 앱에서는 훅을, 그 외 환경에서는 제너레이터를 직접 사용하면 됩니다.

const stream = streamChat({
  endpoint: "http://localhost:11434",
  model: "gemma3:1b",
  messages: [{ role: "user", content: "Hello" }],
});

for await (const chunk of stream) {
  process.stdout.write(chunk.content);
}

AbortController 통합

모든 스트림은 즉시 취소할 수 있습니다. 사용자가 중단한 경우에도 오류 상태가 발생하지 않는데, 이는 생성 중단이 정상적인 사용자 행동이며 오류가 아니기 때문입니다.

완전한 TypeScript 지원

모든 것이 강력히 타입 지정됩니다. IDE 자동 완성, 타입 안전성, 각 함수에 대한 명확한 계약을 얻을 수 있습니다:

import type {
  Backend,        // "ollama" | "lmstudio" | "llamacpp" | "openai-compatible"
  ChatMessage,    // { role: "system" | "user" | "assistant", content: string }
  StreamChunk,    // { content: string, done: boolean, model?: string }
  LocalModel,     // { name, size?, modifiedAt?, digest? }
} from "use-local-llm";

아키텍처

┌─────────────────────────────────────────────────┐
│               Your React App                    │
│                                                 │
│               useOllama("gemma3:1b")           │
│                     │                           │
│                     ▼                           │
│   useLocalLLM({ endpoint, model, ... })         │
│                     │                           │
│                     ▼                           │
│   streamChat() / streamGenerate()               │
│                     │   async generators        │
│                     ▼                           │
│   parseStreamChunk()                             │
│                     │   NDJSON + SSE parser    │
│                     ▼                           │
│   fetch() + ReadableStream                       │
└─────────┬───────────────────────────────────────┘
          │ HTTP (no server in between)          │
          ▼                                      │
   ┌─────────────────────┐                      │
   │  Ollama    :11434   │                      │
   │  LM Studio :1234   │                      │
   │  llama.cpp :8080   │                      │
   └─────────────────────┘

각 레이어는 독립적으로 테스트할 수 있습니다. 훅은 어디서든 실행 가능한 순수 함수 위에 구성됩니다.

use‑local‑llm을 선택해야 할 때

이상적인 경우

  • 🚀 빠른 프로토타이핑 – 20분이 아니라 2분 안에 React 앱에서 AI 스트리밍을 시작하세요.
  • 🔒 프라이버시 우선 앱 – 데이터가 절대 머신을 떠나지 않습니다. 클라우드 API 호출 없음. 추적 없음.
  • 🏢 엔터프라이즈 / 오프라인 – 에어갭 네트워크와 연결이 끊긴 환경에서도 작동합니다.
  • 🎓 학습 – 서버 보일러플레이트 없이 LLM 스트리밍 작동 방식을 이해하세요.
  • 작은 발자국 – 번들 크기와 의존성이 중요할 때.

이 라이브러리를 건너뛰어야 할 경우

  • 프로덕션에서 OpenAI, Anthropic 등 클라우드 API를 사용하고 있다면.
  • 서버‑사이드 인증, 로깅, 혹은 속도 제한이 필요하다면.
  • 이미 다른 이유로 Vercel AI SDK를 사용 중이라면.

시작하기

1단계 – 라이브러리 설치

npm install use-local-llm

2단계 – 로컬 LLM 시작

ollama serve

3단계 – React 앱에서 AI 스트리밍

(위의 예시를 참고하세요.)

이게 전부입니다. API 라우트가 없습니다. 서버 설정이 필요 없습니다. 브라우저에서 2분 이내에 AI 스트리밍을 할 수 있습니다.

자세히 알아보기

0 조회
Back to Blog

관련 글

더 보기 »

트라비고

Gemini와 함께 말하는 속도만큼 빠르게 여행하세요! 라이브 에이전트가 몰입형 스토리텔링 및 3D 내비게이션과 만나는 곳. 이 프로젝트는 Gemini Live Ag...에 진입하기 위해 만들어졌습니다.