<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LLM on kenji.blog</title><link>http://kenji.blog/ko/tags/llm/</link><description>Recent content in LLM on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ko</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 11:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ko/tags/llm/index.xml" rel="self" type="application/rss+xml"/><item><title>llama.cpp 사용법 및 C++를 이용한 커스터마이징 입문</title><link>http://kenji.blog/ko/p/llama-cpp-cxx-customization/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/ko/p/llama-cpp-cxx-customization/</guid><description>&lt;img src="http://kenji.blog/p/llama-cpp-cxx-customization/img/eyecatch.jpg" alt="Featured image of post llama.cpp 사용법 및 C++를 이용한 커스터마이징 입문" />&lt;p>최근 대규모 언어 모델(LLM)의 진화는 매우 빠르며, 그 응용 범위는 나날이 확대되고 있습니다. 하지만 수십억, 수백억 개의 매개변수를 가진 모델을 로컬 환경에서 구동하려면 보통 방대한 VRAM을 갖춘 하이엔드 GPU가 필요합니다. 이러한 &amp;lsquo;하드웨어의 벽&amp;rsquo;을 허물고, 일반적인 PC나 Mac, 심지어 Raspberry Pi와 같은 기기 위에서 LLM의 실용적인 추론을 가능하게 한 것이 바로 &lt;strong>llama.cpp&lt;/strong>입니다.&lt;/p>
&lt;p>본 기사에서는 단순한 명령줄 도구의 사용법에 그치지 않고, 그 기반 기술인 &lt;code>ggml&lt;/code>의 아키텍처, Transformer 및 양자화(Quantization)의 수학적 배경, 그리고 C++ API를 이용하여 독자적인 애플리케이션에 LLM을 통합하고 커스터마이징하는 방법까지 엔지니어를 위해 매우 상세하게 해설합니다.&lt;/p>
&lt;hr>
&lt;h2 id="1-llamacpp-및-ggml-개요">1. llama.cpp 및 ggml 개요
&lt;/h2>&lt;p>&lt;code>llama.cpp&lt;/code>는 Georgi Gerganov 씨가 개발한, C/C++로 작성된 경량 LLM 추론 엔진입니다. 원래는 Meta의 LLaMA 모델을 Apple Silicon(M1/M2 Mac) 위에서 고속으로 동작시키는 것을 목적으로 탄생했지만, 현재는 다양한 아키텍처와 모델을 지원하고 있습니다.&lt;/p>
&lt;p>가장 큰 특징은 &lt;strong>외부 의존성을 가지지 않는 순수한 C/C++ 구현&lt;/strong>이라는 점입니다. Python이나 PyTorch 등의 거대한 에코시스템을 필요로 하지 않고, 단일 실행 파일로 컴파일할 수 있기 때문에 배포가 매우 쉽습니다.&lt;/p>
&lt;p>이 &lt;code>llama.cpp&lt;/code>의 심장부 역할을 하는 것이 텐서 연산 라이브러리 &lt;strong>ggml&lt;/strong>입니다. ggml은 머신러닝에서의 행렬 연산을 CPU(및 일부 GPU) 상에서 극한까지 최적화하기 위해 처음부터 설계되었습니다.&lt;/p>
&lt;h3 id="11-llamacpp는-왜-빠른가">1.1 llama.cpp는 왜 빠른가?
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>메모리 매핑(mmap) 활용&lt;/strong>: 모델의 가중치를 메모리에 로드할 때 OS의 &lt;code>mmap&lt;/code>을 이용함으로써 RAM 전체 로드를 피하고, 빠른 실행과 메모리 절약을 실현합니다.&lt;/li>
&lt;li>&lt;strong>SIMD 명령의 철저한 최적화&lt;/strong>: AVX2, AVX-512, ARM NEON, Apple AMX 등 CPU 고유의 명령 세트를 활용하여 행렬 곱을 초고속화하고 있습니다.&lt;/li>
&lt;li>&lt;strong>양자화(Quantization)&lt;/strong>: 16-bit 부동소수점(FP16) 가중치를 4-bit, 5-bit, 8-bit 정수로 압축하여 메모리 대역폭의 병목 현상을 해소합니다(자세한 내용은 후술).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-수학적-배경-transformer와-양자화quantization">2. 수학적 배경: Transformer와 양자화(Quantization)
&lt;/h2>&lt;p>llama.cpp를 깊이 이해하기 위해서는 그것이 계산하고 있는 수식과, 어떻게 계산을 근사화하고 있는지 알아야 합니다.&lt;/p>
&lt;h3 id="21-transformer의-추론-프로세스">2.1 Transformer의 추론 프로세스
&lt;/h3>&lt;p>LLaMA 등의 모델은 자기회귀형(Auto-regressive) Transformer 디코더 아키텍처를 채택하고 있습니다. 텍스트 생성의 핵심이 되는 것은 &lt;strong>Self-Attention&lt;/strong> 메커니즘입니다.&lt;/p>
&lt;p>입력이 되는 은닉 상태의 행렬 $X \in \mathbb{R}^{N \times d}$에 대해, 쿼리 $Q$, 키 $K$, 값 $V$는 가중치 행렬과의 곱으로 계산됩니다.&lt;/p>
$$
Q = X W_Q, \quad K = X W_K, \quad V = X W_V
$$
&lt;p>여기서 Attention의 출력은 다음과 같이 정의됩니다.&lt;/p>
$$
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
&lt;p>llama.cpp의 추론 루프에서 병목 현상이 발생하는 부분은 이 거대한 행렬 $W_Q, W_K, W_V$나 피드 포워드 네트워크(FFN)의 가중치 행렬과 벡터 $X$(생성 단계에서는 1토큰씩 처리하므로 $N=1$)의 곱, 즉 **GEMV (General Matrix-Vector Multiplication)**입니다.&lt;/p>
&lt;h3 id="22-양자화quantization의-수학적-기초">2.2 양자화(Quantization)의 수학적 기초
&lt;/h3>&lt;p>메모리 액세스 대역이 병목이 되는 추론에 있어서, 가중치 매개변수를 작은 비트 수로 표현하는 양자화는 필수적입니다. llama.cpp에서 널리 쓰이는 블록 단위의 양자화(예: &lt;code>Q4_K&lt;/code>나 &lt;code>Q4_0&lt;/code>)의 기본 원리를 설명합니다.&lt;/p>
&lt;p>예를 들어 FP16 가중치 행렬 $W$의 일부인 길이 $B$(보통 32나 64)의 블록 $w = [w_1, w_2, \dots, w_B]$를 생각합니다. 이 블록을 4-bit 정수 $q_i \in [-8, 7]$과 단일 스케일링 팩터 $\Delta$(FP16 또는 FP32)로 근사합니다.&lt;/p>
$$
w_i \approx \Delta \times q_i
$$
&lt;p>$\Delta$는 블록 내의 최대 절댓값을 바탕으로 결정됩니다.&lt;/p>
$$
\Delta = \frac{\max_i |w_i|}{7}
$$
&lt;p>양자화 후의 가중치를 이용해 내적 $y = w \cdot x$를 계산할 경우, 입력 벡터 $x$도 동일하게 양자화하여 $x_i \approx \Delta_x \times q_{x, i}$로 두면,&lt;/p>
$$
y = \sum_{i=1}^{B} w_i x_i \approx \Delta \Delta_x \sum_{i=1}^{B} q_i q_{x, i}
$$
&lt;p>이 $\sum q_i q_{x, i}$ 부분은 &lt;strong>순수한 정수 연산&lt;/strong>이 되며, SIMD 명령을 사용하여 매우 빠르게 병렬 계산할 수 있습니다. 이것이 llama.cpp가 CPU 상에서 경이로운 속도를 내는 수학적인 트릭입니다.&lt;/p>
&lt;hr>
&lt;h2 id="3-아키텍처-및-추론-흐름">3. 아키텍처 및 추론 흐름
&lt;/h2>&lt;p>llama.cpp의 내부 동작을 이해하기 위해, 다음의 Mermaid 다이어그램으로 시스템 전체의 아키텍처와 데이터 흐름을 나타냅니다.&lt;/p>
&lt;div class="mermaid">graph TD
A["사용자 입력 (String)"] --> B["llama.cpp Tokenizer"]
B --> C["Token IDs (int32 배열)"]
C --> D["컨텍스트 버퍼 (KV Cache)"]
D --> E["ggml 계산 그래프"]
E --> F["Transformer 레이어"]
subgraph "ggml 엔진"
F --> G["Self-Attention (RoPE)"]
G --> H["Feed Forward Network"]
H --> F
end
F --> I["Logits (어휘 크기)"]
I --> J["Sampler (Temperature, Top-K, Top-P)"]
J --> K["선택된 토큰 ID"]
K --> L["llama.cpp Detokenizer"]
L --> M["출력 문자열"]
K -. "자기회귀 루프" .-> D&lt;/div>
&lt;p>텍스트 생성은 하나의 토큰이 출력될 때마다 그것이 다음 입력으로 KV Cache에 추가되고, 다시 계산 그래프를 통과하는 자기회귀적인 루프로 되어 있습니다.&lt;/p>
&lt;hr>
&lt;h2 id="4-환경-구축-및-빌드-방법">4. 환경 구축 및 빌드 방법
&lt;/h2>&lt;p>llama.cpp를 C++ 프로젝트에 통합하기 전에 먼저 소스 코드를 빌드해 봅시다.&lt;/p>
&lt;h3 id="41-리포지토리-클론">4.1 리포지토리 클론
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git clone https://github.com/ggerganov/llama.cpp.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> llama.cpp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="42-cmake를-사용한-빌드">4.2 CMake를 사용한 빌드
&lt;/h3>&lt;p>C++ 프로젝트로서 다른 앱에 통합할 경우, CMake를 이용하는 것이 가장 표준적입니다. 플랫폼별 가속기(백엔드)를 활성화함으로써 연산을 고속화할 수 있습니다.&lt;/p>
&lt;p>&lt;strong>CPU 전용 (기본 빌드):&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>NVIDIA GPU (CUDA)를 사용할 경우:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_CUDA&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Apple Silicon (Metal)을 사용할 경우:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_METAL&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>빌드가 성공하면 &lt;code>build/bin/&lt;/code> 디렉터리에 &lt;code>llama-cli&lt;/code> 등의 실행 파일과 후술할 C++ API에서 링크하기 위한 &lt;code>llama&lt;/code> 라이브러리(및 &lt;code>ggml&lt;/code> 라이브러리)가 생성됩니다.&lt;/p>
&lt;hr>
&lt;h2 id="5-c-커스터마이징-입문-llamacpp-api-활용">5. C++ 커스터마이징 입문: llama.cpp API 활용
&lt;/h2>&lt;p>여기서부터는 본론인 C++ 코드를 통한 llama.cpp의 제어에 대해 해설합니다.
명령줄 도구를 사용하는 것뿐만 아니라, 자신의 애플리케이션(예: 게임 엔진, 데스크톱 앱, 임베디드 시스템 등)에 LLM을 포함시키려면 C++ API를 직접 호출해야 합니다.&lt;/p>
&lt;p>llama.cpp는 주로 &lt;code>llama.h&lt;/code>라는 헤더 파일로 C언어 인터페이스를 제공하고 있습니다. C++에서 호출할 때도 이 인터페이스를 이용합니다.&lt;/p>
&lt;h3 id="51-필요-최소한의-인클루드-및-설정">5.1 필요 최소한의 인클루드 및 설정
&lt;/h3>&lt;p>자신의 프로젝트에서 llama.cpp를 사용할 경우, 이하를 인클루드합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;#34;llama.h&amp;#34;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 에러 핸들링을 위한 매크로
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#define LLAMA_ASSERT(x) \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> do { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> if (!(x)) { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::cerr &amp;lt;&amp;lt; &amp;#34;Assertion failed: &amp;#34; &amp;lt;&amp;lt; #x &amp;lt;&amp;lt; std::endl; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::terminate(); \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> } \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> } while (0)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="52-모델-로드-및-컨텍스트-초기화">5.2 모델 로드 및 컨텍스트 초기화
&lt;/h3>&lt;p>먼저 &lt;code>.gguf&lt;/code> 형식의 모델 파일을 로드하고, 추론을 위한 컨텍스트(메모리 공간과 KV 캐시)를 확보합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">argc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">argc&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Usage: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; &amp;lt;model.gguf&amp;gt;&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">model_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. 백엔드 초기화(CPU/GPU 등의 환경 셋업)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_backend_init&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. 모델 매개변수의 기본 설정 가져오기
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_model_params&lt;/span> &lt;span class="n">model_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_model_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_gpu_layers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">35&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// GPU로 오프로드할 레이어 수
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. 모델 로드
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_model&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_load_model_from_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">model_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to load model&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. 컨텍스트 매개변수 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context_params&lt;/span> &lt;span class="n">ctx_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_context_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2048&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 최대 컨텍스트 크기(토큰 수)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_threads&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 추론에 사용할 CPU 스레드 수
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. 컨텍스트 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_new_context_with_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to create context&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Model and context loaded successfully!&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... 이후의 처리
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-프롬프트-토큰화-tokenization">5.3 프롬프트 토큰화 (Tokenization)
&lt;/h3>&lt;p>LLM은 텍스트를 직접 이해하는 것이 아니라, 정수 ID(토큰)의 나열로써 처리합니다. 입력 문자열을 토큰으로 변환할 필요가 있습니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Q: 일본의 수도는 어디인가요?&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">A:&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 여유를 둔 버퍼 크기
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 특수 토큰(BOS: Begin of Sequence 등)을 맨 앞에 추가할지 여부
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">add_special&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 문자열을 토큰 ID의 배열로 변환
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_tokenize&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">add_special&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">false&lt;/span> &lt;span class="c1">// parse_special
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 버퍼가 부족한 경우는 재할당하여 재시도하는 처리가 필요(간략화를 위해 생략)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to tokenize prompt&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_tokens&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="54-추론-루프-및-샘플링">5.4 추론 루프 및 샘플링
&lt;/h3>&lt;p>토큰을 모델에 입력하고, 다음 토큰의 확률 분포(Logits)를 구한 뒤 거기서 샘플링을 수행해 다음 토큰을 결정하는 루프를 구축합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 생성할 최대 토큰 수
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">max_gen_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 배치 평가를 위한 구조체를 초기화
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch&lt;/span> &lt;span class="n">batch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_batch_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">512&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 프롬프트의 토큰을 배치에 추가
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 프롬프트의 마지막 토큰에서만 로짓(예측 결과)을 출력하도록 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 첫 번째 평가(프롬프트를 모델에 제공)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;llama_decode() failed&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_cur&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 현재의 컨텍스트 길이
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_decode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">Output: &amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 샘플러 컨텍스트 초기화(Temperature, Top-K, Top-P 등의 설정)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">smpl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_chain_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">llama_sampler_chain_default_params&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_k&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.9f&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_temp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.7f&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_dist&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 시드 값
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_decode&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">max_gen_tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. 샘플링: 현재 컨텍스트를 바탕으로 다음 토큰을 예측
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_token&lt;/span> &lt;span class="n">new_token_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_sample&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. 토큰이 EOS (End of Sequence) 라면 루프 종료
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token_is_eog&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. 토큰을 문자열(텍스트)로 디코드하여 표시
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">128&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_chars&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_token_to_piece&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_chars&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_chars&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">flush&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. 새롭게 생성된 토큰을 다음 배치로 준비
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch_clear&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_cur&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. 모델 평가(KV 캐시를 갱신하고, 다음을 예측)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to evaluate&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_cur&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_decode&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 정리(클린업)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_backend_free&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>이 코드는 llama.cpp의 기본 API를 사용하여 독자적인 추론 루프를 구현한 것입니다.
&lt;code>llama_batch&lt;/code> 구조체를 이용해 토큰 그룹을 관리하고, &lt;code>llama_decode&lt;/code>로 신경망의 순전파(Forward Pass)를 실행합니다.&lt;/p>
&lt;hr>
&lt;h2 id="6-고급-커스터마이징-사례-c에-의한-로짓-조작-및-페널티-제어">6. 고급 커스터마이징 사례: C++에 의한 로짓 조작 및 페널티 제어
&lt;/h2>&lt;p>단순한 텍스트 생성에 그치지 않고, 특정 포맷(예: JSON만)의 출력을 강제하거나, 특정한 금지 단어를 출력하지 않도록 제어하는 경우 샘플링 전의 **로짓(Logits)**을 C++ 쪽에서 직접 조작합니다.&lt;/p>
&lt;p>모델이 각 토큰을 출력하기 직전의 원시 점수(확률로 변환되기 전의 값) 배열을 가져올 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 추론 직후, 샘플링을 실시하기 전에 원시 로짓 배열을 취득
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">float&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">logits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_get_logits_ith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="n">n_vocab&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_n_vocab&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 금지 토큰의 ID 목록 (예: 1234, 5678)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5678&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 금지 토큰의 출현 확률을 0(Logit을 마이너스 무한대)으로 만든다
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token&lt;/span> &lt;span class="nl">bad_tok&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">bad_tok&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">INFINITY&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>이처럼 C++ API를 직접 다룸으로써 LangChain이나 Python 경유로는 실현하기 어렵거나 오버헤드가 커지는 **&amp;lsquo;추론 사이클마다 마이크로 밀리초 단위의 개입&amp;rsquo;**이 가능해집니다.&lt;/p>
&lt;hr>
&lt;h2 id="7-성능-튜닝의-극의">7. 성능 튜닝의 극의
&lt;/h2>&lt;p>C++로 구현을 마친 후, 실제 운영을 위해 속도를 한계까지 높이기 위한 체크 포인트를 몇 가지 소개합니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>배치 처리 최적화:&lt;/strong> 여러 사용자의 요청을 동시에 처리할 경우, &lt;code>llama_batch&lt;/code>에 여러 시퀀스를 포함하여 한 번에 &lt;code>llama_decode&lt;/code>를 호출합니다(Continuous Batching). 이를 통해 메모리 액세스를 공유하여 처리량(스루풋)을 획기적으로 향상할 수 있습니다.&lt;/li>
&lt;li>&lt;strong>Flash Attention 활성화:&lt;/strong>
컨텍스트 매개변수에서 &lt;code>ctx_params.flash_attn = true;&lt;/code>를 설정함으로써, 메모리 사용량을 줄이면서 Attention 계산을 고속화할 수 있습니다. 긴 컨텍스트(수만 토큰)를 다룰 때는 필수적인 설정입니다.&lt;/li>
&lt;li>&lt;strong>NUMA 지원:&lt;/strong>
멀티 소켓 서버 환경에서는 &lt;code>llama_backend_init()&lt;/code> 전에 NUMA 설정을 적절히 수행함으로써 메모리 액세스 대기 시간(레이턴시)을 줄일 수 있습니다.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-마치며">8. 마치며
&lt;/h2>&lt;p>본 기사에서는 &lt;code>llama.cpp&lt;/code>의 수학적인 배경부터 시작해 아키텍처 해설, 그리고 C++ API를 구사한 맞춤형 추론 엔진 구축 방법까지 상세하게 해설했습니다.&lt;/p>
&lt;p>Python 생태계는 프로토타이핑에는 매우 편리하지만, 엣지 디바이스로의 배포, 게임에 통합, 실시간 처리가 요구되는 프로덕션 환경에서는 C/C++ 기반의 &lt;code>llama.cpp&lt;/code> 직접 제어가 압도적인 힘을 발휘합니다.&lt;/p>
&lt;p>여러분도 꼭 직접 C++ 코드를 작성하고, 로컬 환경에서 LLM을 자유자재로 다루는 즐거움을 경험해 보시길 바랍니다.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>참고 링크 모음&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>llama.cpp Official Repository&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/ggml" target="_blank" rel="noopener"
>ggml - Tensor Library&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://arxiv.org/abs/1706.03762" target="_blank" rel="noopener"
>Attention Is All You Need (Vaswani et al., 2017)&lt;/a>&lt;/li>
&lt;/ul>
&lt;/blockquote></description></item><item><title>【2026년 최신】 로컬 LLM을 Windows 환경에서 구동하는 완전 가이드</title><link>http://kenji.blog/ko/p/local-llm-windows-2026/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/ko/p/local-llm-windows-2026/</guid><description>&lt;img src="http://kenji.blog/p/local-llm-windows-2026/img/eyecatch.jpg" alt="Featured image of post 【2026년 최신】 로컬 LLM을 Windows 환경에서 구동하는 완전 가이드" />&lt;h1 id="1-소개-왜-지금-windows에서-로컬-llm인가">1. 소개: 왜 지금 Windows에서 로컬 LLM인가?
&lt;/h1>&lt;p>2026년 현재, 생성형 AI와 대규모 언어 모델(LLM)의 진화는 클라우드 상의 거대한 API 서비스에서 개인 PC나 온프레미스 환경에서 동작하는 &amp;lsquo;로컬 LLM&amp;rsquo;으로 큰 패러다임 전환을 보여주고 있습니다. OpenAI의 GPT-5나 Anthropic의 Claude 3.5와 같은 클라우드 AI는 매우 강력하지만, 기업이나 개인이 모든 데이터를 클라우드로 전송할 수 있는 것은 아닙니다. 개인정보 보호, 보안, 대기 시간(레이턴시), 그리고 장기적이고 지속 가능한 비용 관점에서 로컬 LLM에 대한 수요는 그 어느 때보다 폭발적으로 증가하고 있습니다.&lt;/p>
&lt;p>특히 Windows 환경에서 로컬 LLM 생태계의 발전은 눈부십니다. 몇 년 전까지만 해도 &amp;ldquo;AI 개발 및 실행은 Linux&amp;quot;라는 것이 상식이었지만, 2026년 현재 Windows는 매우 강력하고 편리한 AI 플랫폼으로 변모했습니다.&lt;/p>
&lt;p>본 기사에서는 2026년 최신 기술 동향을 바탕으로 Windows 환경에서 로컬 LLM을 구축, 운영 및 최적화하기 위한 완전한 가이드를 제공합니다. 초보자를 위한 Ollama를 사용한 간단한 구축부터, 고급 사용자를 위한 llama.cpp를 활용한 극한의 최적화, 나아가 VRAM 계산의 수학적 접근 및 아키텍처에 대한 깊은 이해, 그리고 로컬에서의 파인튜닝(미세조정)까지 압도적인 분량으로 철저하게 해설합니다.&lt;/p>
&lt;h2 id="11-2026년-로컬-llm을-둘러싼-기술-트렌드">1.1 2026년 로컬 LLM을 둘러싼 기술 트렌드
&lt;/h2>&lt;p>현재의 로컬 LLM 생태계를 형성하는 주요 트렌드는 다음과 같습니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>GGUF 포맷의 완전한 보급&lt;/strong>: 메타데이터와 텐서를 단일 파일로 통합한 GGUF(GPT-Generated Unified Format)가 완전히 사실상 표준(De facto standard)이 되었습니다. 이를 통해 Hugging Face에서 파일 하나를 다운로드하는 것만으로 어떤 환경에서든 실행할 수 있게 되었습니다.&lt;/li>
&lt;li>&lt;strong>MoE(Mixture of Experts) 아키텍처의 대중화&lt;/strong>: 소규모이면서도 고성능인 MoE 모델이 다수 출시되었으며, 추론 시 일부 전문가(Expert)만 활성화함으로써 일반 소비자용 PC의 계산 부하를 억제하면서 거대 모델에 필적하는 성능을 내고 있습니다.&lt;/li>
&lt;li>&lt;strong>추론 엔진의 고도화된 추상화 및 최적화&lt;/strong>: Ollama, LM Studio, AnythingLLM 등의 도구가 세련되어져서 사용자가 CUDA 드라이버 설치 등 복잡한 의존성을 신경 쓸 필요가 없어졌습니다. 또한 FlashAttention 3의 Windows 네이티브 지원으로 추론 속도가 극적으로 향상되었습니다.&lt;/li>
&lt;li>&lt;strong>NPU 활용과 Windows Copilot+ PC의 대두&lt;/strong>: GPU가 없는 노트북에서도 탑재된 NPU(Neural Processing Unit)를 활용하여 소규모 LLM(SLM: Small Language Models)을 저전력으로 구동하는 기술이 실용화 단계에 접어들었습니다.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-하드웨어-요구-사항-및-os-준비">2. 하드웨어 요구 사항 및 OS 준비
&lt;/h1>&lt;p>로컬 LLM을 실용적인 속도(초당 15~30 토큰 이상)로 구동하기 위해서는 하드웨어 선택이 가장 중요합니다.&lt;/p>
&lt;h2 id="21-권장-하드웨어-구성">2.1 권장 하드웨어 구성
&lt;/h2>&lt;p>AI PC의 진화에 따라 요구 스펙도 변화하고 있습니다.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OS&lt;/strong>: Windows 11 Pro (24H2 이후). WSL2의 완전한 기능과 고급 메모리 관리, 나아가 DirectML의 최신 API를 활용하기 위해 필수적입니다.&lt;/li>
&lt;li>&lt;strong>CPU&lt;/strong>: Intel Core Ultra 200 시리즈 이상 또는 AMD Ryzen 9000 시리즈 이상. CPU 추론을 병행할 경우, 광대역 메모리 통신이 필수적입니다.&lt;/li>
&lt;li>&lt;strong>RAM&lt;/strong>: 최소 32GB, 권장 64GB 이상. 메인 메모리의 대역폭(MB/s)이 CPU 추론 시나 오프로드(Offload) 시 결정적인 병목 지점이 됩니다. DDR5-6000 이상의 고속 메모리가 이상적입니다.&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>: NVIDIA RTX 4000/5000 시리즈. 로컬 LLM에서 가장 중요한 것은 연산 성능이 아니라 &amp;lsquo;VRAM 용량&amp;rsquo;입니다.
&lt;ul>
&lt;li>&lt;strong>엔트리&lt;/strong>: RTX 4060 Ti (16GB 버전) - 가성비 최강. 8B~14B 클래스의 모델에 최적입니다.&lt;/li>
&lt;li>&lt;strong>미들레인지&lt;/strong>: RTX 4070 Ti SUPER (16GB) / RTX 4080 SUPER (16GB)&lt;/li>
&lt;li>&lt;strong>하이엔드&lt;/strong>: RTX 4090 (24GB) / RTX 5090 (32GB) - 30B~70B 클래스의 양자화 모델을 구동하기 위해 필요합니다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>스토리지&lt;/strong>: PCIe Gen4 또는 Gen5 NVMe SSD. 수십 GB에 달하는 모델 로드 시간을 극적으로 단축시킵니다.&lt;/li>
&lt;/ul>
&lt;h2 id="22-wsl2-windows-subsystem-for-linux-2-설정">2.2 WSL2 (Windows Subsystem for Linux 2) 설정
&lt;/h2>&lt;p>많은 GUI 도구는 Windows 네이티브로 동작하지만, Python을 사용한 개발, 최신 도구 컴파일, 후술할 LoRA 파인튜닝에는 WSL2가 매우 편리합니다. Windows 11의 최신 환경에서는 호스트 쪽에 NVIDIA 드라이버를 설치하는 것만으로 WSL2에서 투명하게 GPU(CUDA)를 사용할 수 있습니다.&lt;/p>
&lt;p>관리자 권한으로 PowerShell을 열고 다음을 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># WSL2와 최신 Ubuntu 설치&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span> &lt;span class="n">-d&lt;/span> &lt;span class="n">Ubuntu&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">24.04&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 커널 업데이트&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-update&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>설치 후 WSL2 터미널 내에서 &lt;code>nvidia-smi&lt;/code>를 실행하여 GPU가 정상적으로 인식되면 성공입니다.&lt;/p>
&lt;hr>
&lt;h1 id="3-로컬-llm-아키텍처-및-추론-메커니즘">3. 로컬 LLM 아키텍처 및 추론 메커니즘
&lt;/h1>&lt;p>로컬 환경에서 모델이 어떻게 텍스트를 생성하는지, 그 내부 구조를 이해하는 것은 문제 해결(트러블슈팅)이나 최적화에 매우 유용합니다.&lt;/p>
&lt;p>다음 Mermaid 다이어그램은 전형적인 로컬 LLM의 추론 파이프라인을 보여줍니다.&lt;/p>
&lt;div class="mermaid">graph TD
User["사용자 입력 (프롬프트)"] --> Tokenizer["토크나이저 (Tokenizer)"]
Tokenizer --> Embedding["임베딩 계층 (Embedding)"]
subgraph "Transformer Block (x Layers)"
Embedding --> Attn["자기 주의 (Self-Attention)"]
Attn --> KVCache["KV 캐시 (Key/Value 유지)"]
Attn --> FFN["피드 포워드 네트워크 (FFN)"]
end
FFN --> Logits["로짓 계산 (Logits)"]
Logits --> Sampler["샘플러 (Temperature, Top-K, Top-P)"]
Sampler --> OutputToken["출력 토큰"]
OutputToken --> |"자기 회귀 생성 (Autoregressive)"| Tokenizer
OutputToken --> Decoder["디토크나이저 (Detokenizer)"]
Decoder --> FinalOutput["최종 출력 텍스트"]&lt;/div>
&lt;h2 id="31-2가지-단계-prefill과-decode">3.1 2가지 단계: Prefill과 Decode
&lt;/h2>&lt;p>LLM의 텍스트 생성은 계산 특성이 다른 두 가지 단계로 나뉩니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Prefill (프롬프트 처리) 단계&lt;/strong>: 입력된 프롬프트 전체를 한 번에 처리하고 이해하는 단계입니다. 병렬 계산이 가능하므로 GPU의 계산 능력(FLOPS)이 속도에 직결됩니다. 프롬프트가 길 경우 이 단계에 몇 초가 걸릴 수 있습니다.&lt;/li>
&lt;li>&lt;strong>Decode (토큰 생성) 단계&lt;/strong>: 1 토큰씩 예측하고 다음 입력으로 넘기는(자기 회귀, Autoregressive) 단계입니다. 이 단계에서는 병렬 계산이 제한되므로 GPU의 VRAM 대역폭(Memory Bandwidth)이 결정적인 병목 지점이 됩니다.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="4-vram-소비량-계산-및-모델-크기의-수학적-이해">4. VRAM 소비량 계산 및 모델 크기의 수학적 이해
&lt;/h1>&lt;p>&amp;ldquo;내 PC에서 어떤 모델이 돌아갈까?&amp;ldquo;를 정확히 판단하려면 VRAM 계산 공식을 이해해야 합니다. VRAM 부족으로 인해 시스템 메모리(RAM)로의 폴백(Fallback)이 발생하면 추론 속도는 10배~100배 느려집니다.&lt;/p>
&lt;h2 id="41-파라미터-크기-기반-기본-vram">4.1 파라미터 크기 기반 기본 VRAM
&lt;/h2>&lt;p>모델의 가중치(웨이트)를 VRAM에 로드하기 위한 메모리 양입니다.
모델 크기 $P$ (파라미터 수, 단위: 10억 = 1B)와 1 파라미터당 바이트 수 $B$를 사용하여 계산합니다.&lt;/p>
$$
V_{base} = P \times B \quad \text{(GB)}
$$
&lt;p>예를 들어, 8B(80억) 파라미터 모델을 FP16(반정밀도 부동소수점, 16비트=2바이트)으로 로드할 경우:&lt;/p>
$$
V_{base} = 8 \times 2 = 16 \text{ GB}
$$
&lt;p>즉, 16GB VRAM을 가진 GPU라도 모델을 로드하는 것만으로 거의 한계에 도달하게 됩니다.&lt;/p>
&lt;h2 id="42-양자화quantization의-마법">4.2 양자화(Quantization)의 마법
&lt;/h2>&lt;p>여기서 &amp;lsquo;양자화&amp;rsquo;가 등장합니다. 파라미터의 정밀도를 낮춰 모델 크기를 극적으로 축소합니다. 가장 일반적인 4bit 양자화(예: Q4_K_M)의 경우, 1 파라미터당 평균 약 0.55바이트가 됩니다.&lt;/p>
$$
V_{base\_4bit} = 8 \times 0.55 = 4.4 \text{ GB}
$$
&lt;p>이를 통해 16GB의 VRAM이 있다면 충분한 여유를 가지고 8B 모델을 구동할 수 있습니다.&lt;/p>
&lt;h2 id="43-kv-캐시-계산-gqa-지원-버전">4.3 KV 캐시 계산 (GQA 지원 버전)
&lt;/h2>&lt;p>추론 시에는 과거의 문맥을 유지하기 위한 &amp;lsquo;KV 캐시&amp;rsquo;가 VRAM을 소비합니다. Llama 3 등 최신 모델에서는 메모리 절약을 위해 GQA(Grouped Query Attention)가 채택되었습니다.&lt;/p>
&lt;p>KV 캐시 소비량 $V_{kv}$ (기가바이트)는 다음 수식으로 표현됩니다.&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times \left( \frac{h_{kv}}{h_q} \right) \times h_q \times d \times B_{kv} \div 10^9
$$
&lt;p>정리하면, 키와 값의 헤드 수 $h_{kv}$를 사용하여 단순하게 계산할 수 있습니다.&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times h_{kv} \times d \times B_{kv} \div 10^9
$$
&lt;p>여기서:&lt;/p>
&lt;ul>
&lt;li>$b$: 배치 크기 (개인의 로컬 사용이라면 보통 1)&lt;/li>
&lt;li>$s$: 시퀀스 길이 (컨텍스트 길이, 예: 8192)&lt;/li>
&lt;li>$l$: 레이어 수 (예: 32)&lt;/li>
&lt;li>$h_{kv}$: KV 헤드 수 (예: 8)&lt;/li>
&lt;li>$d$: 헤드당 차원 수 (예: 128)&lt;/li>
&lt;li>$B_{kv}$: KV 캐시의 바이트 수 (FP16이면 2)&lt;/li>
&lt;/ul>
&lt;p>계산 예 (Llama 3 8B, 컨텍스트 8192, FP16 캐시):
$V_{kv} = 2 \times 1 \times 8192 \times 32 \times 8 \times 128 \times 2 \div 10^9 \approx 1.07 \text{ GB}$&lt;/p>
&lt;p>컨텍스트 길이 $s$를 길게 할수록 필요한 VRAM은 선형적으로 증가한다는 점에 주의하십시오.&lt;/p>
&lt;hr>
&lt;h1 id="5-실전-1-ollama를-이용한-가장-빠르고-짧은-설정">5. 실전 1: Ollama를 이용한 가장 빠르고 짧은 설정
&lt;/h1>&lt;p>이론을 이해했으니, 실제로 Windows 환경에서 LLM을 구동해 봅시다.
2026년 현재 가장 사용자 친화적인 도구가 &amp;lsquo;Ollama&amp;rsquo;입니다. Docker와 유사한 직관적인 CLI를 제공합니다.&lt;/p>
&lt;h2 id="51-설치-및-실행">5.1 설치 및 실행
&lt;/h2>&lt;ol>
&lt;li>&lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
>Ollama 공식 웹사이트&lt;/a>에서 Windows 버전 설치 프로그램을 다운로드하여 실행합니다.&lt;/li>
&lt;li>PowerShell을 열고 다음 명령어를 입력합니다. 여기서는 일본어/한국어 등을 지원하는 &lt;code>llama3:8b&lt;/code>를 사용합니다.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">llama3&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="n">8b&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>최초 실행 시 모델 다운로드가 진행됩니다. 완료되면 터미널에서 바로 대화가 가능합니다.&lt;/p>
&lt;h2 id="52-modelfile을-통한-사용자-정의-ai-생성">5.2 Modelfile을 통한 사용자 정의 AI 생성
&lt;/h2>&lt;p>특정 페르소나를 가진 AI를 쉽게 생성할 수 있습니다. 임의의 위치에 &lt;code>Modelfile&lt;/code>을 생성합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">FROM llama3:8b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SYSTEM &amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">당신은 매우 뛰어난 시니어 소프트웨어 엔지니어입니다.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">사용자의 질문에 대해 반드시 코드 예시를 곁들여 논리적이고 간결하게 답변해 주세요.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER temperature 0.3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER num_ctx 8192
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>다음 명령어로 자체 모델을 빌드하고 실행합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="n">SeniorDev&lt;/span> &lt;span class="o">-f&lt;/span> &lt;span class="p">./&lt;/span>&lt;span class="n">Modelfile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">SeniorDev&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="53-외부-앱-ai-에디터에서-활용">5.3 외부 앱 (AI 에디터)에서 활용
&lt;/h2>&lt;p>Ollama는 &lt;code>http://localhost:11434&lt;/code>에 OpenAI 호환 API 엔드포인트를 공개합니다.
Cursor나 Continue.dev와 같은 VS Code 확장 프로그램의 백엔드 설정에서 URL을 위와 같이 지정하고, 모델 이름에 &lt;code>SeniorDev&lt;/code> 등을 지정하기만 하면 무료로 강력한 로컬 코딩 어시스턴트가 실현됩니다.&lt;/p>
&lt;hr>
&lt;h1 id="6-실전-2-llamacpp에-의한-극한의-성능-튜닝">6. 실전 2: llama.cpp에 의한 극한의 성능 튜닝
&lt;/h1>&lt;p>세밀한 메모리 관리나 최신 포맷(EXL2나 IQ 양자화 등)을 가장 먼저 시도해보고 싶다면, 핵심 엔진인 &lt;code>llama.cpp&lt;/code>를 직접 조작합니다.&lt;/p>
&lt;h2 id="61-llamacpp-빌드-절차">6.1 llama.cpp 빌드 절차
&lt;/h2>&lt;p>Windows 환경에서는 CUDA Toolkit과 CMake를 사용하여 소스에서 빌드하는 것이 가장 좋습니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">git&lt;/span> &lt;span class="n">clone&lt;/span> &lt;span class="n">https&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="p">//&lt;/span>&lt;span class="n">github&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">ggerganov&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">&lt;/span>&lt;span class="n">mkdir&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># CUDA 지원으로 구성하고 컴파일&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">..&lt;/span> &lt;span class="n">-DLLAMA_CUBLAS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">ON&lt;/span> &lt;span class="n">-DBUILD_SHARED_LIBS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">OFF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-build&lt;/span> &lt;span class="p">.&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-config&lt;/span> &lt;span class="n">Release&lt;/span> &lt;span class="n">-j&lt;/span> &lt;span class="mf">16&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="62-서버-모드에서의-고급-실행">6.2 서버 모드에서의 고급 실행
&lt;/h2>&lt;p>빌드된 &lt;code>llama-server.exe&lt;/code>를 사용하여 모델을 호스팅합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="p">.\&lt;/span>&lt;span class="n">bin&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="n">Release&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="nb">llama-server&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">exe&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-model&lt;/span> &lt;span class="s2">&amp;#34;C:\models\Llama-3-8B-Instruct.Q4_K_M.gguf&amp;#34;&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-ctx-size&lt;/span> &lt;span class="mf">8192&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-n-gpu-layers&lt;/span> &lt;span class="mf">99&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-threads&lt;/span> &lt;span class="mf">8&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-flash-attn&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-port&lt;/span> &lt;span class="mf">8080&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>&lt;code>--n-gpu-layers 99&lt;/code>: 가능한 모든 레이어를 GPU VRAM으로 오프로드합니다.&lt;/li>
&lt;li>&lt;code>--flash-attn&lt;/code>: FlashAttention 3을 활성화하여 추론 속도를 향상시키고 KV 캐시의 VRAM 소비를 줄입니다.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="7-gui-프론트엔드-lm-studio-및-로컬-rag-구축">7. GUI 프론트엔드: LM Studio 및 로컬 RAG 구축
&lt;/h1>&lt;p>명령줄(CLI)에 거부감이 있거나 RAG(검색 증강 생성)를 직관적으로 수행하고 싶은 경우 GUI를 이용합니다.&lt;/p>
&lt;h2 id="71-lm-studio">7.1 LM Studio
&lt;/h2>&lt;p>LM Studio는 모델 검색, 다운로드, 시스템 요구 사항 사전 확인, 그리고 채팅 UI까지 하나로 통합한 훌륭한 애플리케이션입니다. 앱 내의 &amp;ldquo;Local Server&amp;rdquo; 버튼을 누르기만 하면 OpenAI 호환 API가 시작됩니다.&lt;/p>
&lt;h2 id="72-anythingllm을-이용한-rag-아키텍처">7.2 AnythingLLM을 이용한 RAG 아키텍처
&lt;/h2>&lt;p>사내 문서나 개인 메모를 읽게 하는 RAG 환경의 아키텍처 다이어그램입니다.&lt;/p>
&lt;div class="mermaid">graph LR
Document["문서 (PDF, MD)"] --> Chunking["청크 분할 (Chunking)"]
Chunking --> EmbedModel["임베딩 모델"]
EmbedModel --> VectorDB["벡터 데이터베이스"]
UserQuery["사용자 질문"] --> EmbedQuery["질문 임베딩"]
EmbedQuery --> VectorDB
VectorDB --> |"유사도 검색"| RetrievedDocs["관련 문서 추출"]
UserQuery --> PromptBuilder["프롬프트 생성"]
RetrievedDocs --> PromptBuilder
PromptBuilder --> LocalLLM["로컬 LLM"]
LocalLLM --> Answer["최종 답변"]&lt;/div>
&lt;p>AnythingLLM 데스크톱 버전(Windows)을 사용하면 설정 화면에서 Ollama(LLM 및 Embedding)를 지정하고, 로컬 VectorDB(LanceDB)를 사용하도록 설정하는 것만으로 몇 분 만에 이 아키텍처가 완성됩니다. 데이터를 외부에 전혀 전송하지 않는 프라이빗 AI의 탄생입니다.&lt;/p>
&lt;hr>
&lt;h1 id="8-windows-wsl2-상에서의-파인튜닝-lora">8. Windows WSL2 상에서의 파인튜닝 (LoRA)
&lt;/h1>&lt;p>로컬에서 구동할 뿐만 아니라 내 데이터로 모델을 똑똑하게 만들고 싶다면, LoRA(Low-Rank Adaptation)를 이용한 파인튜닝이 가능합니다. 2026년 현재 &amp;lsquo;Unsloth&amp;rsquo;라는 라이브러리를 사용하면 Windows의 WSL2 환경에서 16GB VRAM으로도 8B 모델의 학습을 몇 시간 만에 완료할 수 있습니다.&lt;/p>
&lt;p>WSL2의 Ubuntu 내에서 다음을 실행하여 환경을 구축합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">conda create --name unsloth_env &lt;span class="nv">python&lt;/span>&lt;span class="o">=&lt;/span>3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">conda activate unsloth_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install &lt;span class="s2">&amp;#34;unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install --no-deps trl peft accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Unsloth는 CUDA 커널을 극한까지 최적화하여, 표준 Hugging Face 라이브러리와 비교해 학습 속도가 약 2배, VRAM 소비량이 약 절반이 됩니다. Jupyter Notebook을 실행하고 데이터 세트(JSONL 형식)를 읽어 들이는 것만으로, VRAM 12GB~16GB의 RTX 4060 Ti 등에서도 몇 에포크(epoch)의 학습이 가능합니다.&lt;/p>
&lt;hr>
&lt;h1 id="9-성능-및-문제-해결-트러블슈팅">9. 성능 및 문제 해결 (트러블슈팅)
&lt;/h1>&lt;p>자주 직면하는 문제와 그 해결책입니다.&lt;/p>
&lt;h3 id="1-추론-속도가-극단적으로-느림-12-tokenss">1. 추론 속도가 극단적으로 느림 (1~2 tokens/s)
&lt;/h3>&lt;p>&lt;strong>원인&lt;/strong>: 모델이 VRAM에 다 들어가지 못하고 시스템 메모리(RAM)로 오프로드되었습니다.
&lt;strong>대책&lt;/strong>: 작업 관리자에서 &amp;ldquo;전용 GPU 메모리&amp;quot;를 확인해 주세요. 한계에 도달한 경우 컨텍스트 크기(&lt;code>-c&lt;/code>)를 줄이거나 더 낮은 비트 수의 양자화 모델(Q4_K_M 등)을 사용하십시오.&lt;/p>
&lt;h3 id="2-cuda-out-of-memory-에러">2. &amp;ldquo;CUDA out of memory&amp;rdquo; 에러
&lt;/h3>&lt;p>&lt;strong>원인&lt;/strong>: VRAM이 완전히 고갈되었습니다. 특히 대화가 길어져 KV 캐시가 비대해졌을 때 발생합니다.
&lt;strong>대책&lt;/strong>: Ollama의 경우 &lt;code>num_ctx&lt;/code>, llama.cpp의 경우 &lt;code>-c&lt;/code> 값을 의도적으로 작게 제한합니다.&lt;/p>
&lt;h3 id="3-언어일본어한국어-등-생성이-이상함">3. 언어(일본어/한국어 등) 생성이 이상함
&lt;/h3>&lt;p>&lt;strong>원인&lt;/strong>: 프롬프트 템플릿의 불일치 또는 지원하지 않는 모델입니다.
&lt;strong>대책&lt;/strong>: 모델 이름에 &lt;code>Instruct&lt;/code>가 포함된 것을 사용하고, ChatML이나 Llama3 포맷 등 모델 작성자가 지정한 올바른 템플릿이 도구 측에서 선택되어 있는지 확인하십시오.&lt;/p>
&lt;hr>
&lt;h1 id="10-요약-및-향후-전망">10. 요약 및 향후 전망
&lt;/h1>&lt;p>2026년, Windows 환경에서의 로컬 LLM 구축은 더 이상 일부 엔지니어들만의 특권이 아닙니다. GGUF 포맷의 사실상 표준화, Ollama나 LM Studio와 같이 세련된 생태계의 등장, 그리고 FlashAttention을 비롯한 하드웨어 최적화 덕분에 누구나 쉽게 엔터프라이즈급 AI 환경을 구축할 수 있게 되었습니다.&lt;/p>
&lt;p>이 기사에서 설명한 다음 요점들을 꼭 활용해 보시기 바랍니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>VRAM의 수학적 계산&lt;/strong>을 활용하여 내 PC 스펙에 최적화된 모델 크기와 양자화 수준을 논리적으로 선택한다.&lt;/li>
&lt;li>&lt;strong>Ollama&lt;/strong>를 사용하여 가장 빠르게 환경을 구축하고, AI 에디터와 연동하여 생산성을 극적으로 향상시킨다.&lt;/li>
&lt;li>&lt;strong>llama.cpp&lt;/strong>의 고급 파라미터 제어로 하드웨어의 한계 성능을 끌어낸다.&lt;/li>
&lt;li>&lt;strong>AnythingLLM&lt;/strong>으로 기밀 데이터를 다루는 안전한 로컬 RAG 시스템을 구축한다.&lt;/li>
&lt;li>**Unsloth (WSL2)**를 활용하여 나만의 전문 지식을 가진 커스텀 AI를 육성한다.&lt;/li>
&lt;/ol>
&lt;p>AI의 &amp;lsquo;대중화&amp;rsquo;는 더 이상 버즈워드가 아니라 여러분의 Windows 데스크톱에서 작동하는 현실의 시스템입니다. 클라우드 API 사용 비용이나 정보 유출 위험에서 벗어나, 자유롭고 강력한 프라이빗 AI의 세계로 지금 당장 발을 들여놓아 보시기 바랍니다.&lt;/p></description></item></channel></rss>