chore: initial project setup with agent guide

This commit is contained in:
Variet-Worker
2026-04-05 00:43:39 +09:00
commit 7890ff6644
1368 changed files with 213076 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
# AI 비서 시스템 아키텍처 논의 기록
> 작성일: 2026-04-05
> 상태: 논의 중
---
## 1. 하드웨어 조건
- **GPU: RTX 3060 12GB × 2장 (총)**
- Machine A: 현재 머신 (Modern CPU, 96GB RAM) → API 서버 전용
- Machine B: i7-7700, 64GB RAM → 워크스테이션 (코딩, Discord 등)
- Machine B는 내장그래픽(HD 630)으로 디스플레이 사용
- Machine A에서 7700+64GB RAM+3060 조합으로 유사한 결과 확인 완료
## 2. GPU 배치 결정: 1+1 vs 2+0
### 2+0 (Machine A에 2장 집중) — 추천
| 장점 | 설명 |
|------|------|
| 코딩 속도 2.5배 향상 | 35B 모델: 30 t/s → 50-80 t/s |
| 모델 완전 VRAM 수용 | 35B (20.5GB) → 24GB에 수용, cpu-moe 불필요 |
| 비서도 오히려 빠름 | API 호출해도 50-80 t/s > 로컬 42 t/s |
| 아키텍처 단순 | LLM 엔드포인트 1곳만 관리 |
| 단점 | 설명 |
|------|------|
| Machine A 의존 | 장애 시 추론 전체 중단 |
| 동시 처리 제한 | 솔로유저라 실질적 문제 적음 |
| 122B 핫스왑 중 비서 중단 (~3-5분) | 빈도 낮으면 수용 가능 |
### 1+1 (각 1장씩)
| 장점 | 설명 |
|------|------|
| 병렬 처리 가능 | 양쪽 동시 추론 |
| 장애 시 독립 동작 | Machine B가 자체 LLM 보유 |
| 122B 핫스왑 중에도 비서 유지 | Machine B가 대체 |
| 단점 | 설명 |
|------|------|
| 코딩 속도 30 t/s (2+0 대비 절반) | 메인 작업 속도 희생 |
| 35B 모델 cpu-moe 의존 | RAM 대역폭 제한 |
| 관리 복잡 | LLM 2곳 관리 |
### 결론: 솔로 유저 + 메인 코딩 → 2+0 추천
---
## 3. Machine A 모델 후보 비교 (2x 3060, 24GB VRAM)
### 모델 스펙 비교
| 모델 | 크기 | 활성 파라미터 | 1x 3060 속도 | **2x 3060 예상** | VRAM 여유 |
|------|:----:|:----------:|:----------:|:-----------:|:---------:|
| **Gemma4 26B-A4B** | 15.6 GB | 4B | 42 t/s | **70-100+ t/s** | 8.4 GB |
| **Qwen3.5 35B-A3B** | 20.5 GB | 3B | 30 t/s | **50-80 t/s** | 3.5 GB |
| Qwen3.5 122B-A10B | 71.3 GB | 10B | 11 t/s | 11 t/s (cpu-moe) | N/A |
### Gemma4 26B-A4B 장점
- **속도**: 15.6 GB로 작아서 VRAM에 여유롭게 수용 → 2x GPU에서 70-100+ t/s 가능
- **도구 호출**: function calling / tool use에 안정적 (구글 설계)
- **VRAM 여유**: 8.4 GB 남음 → 더 큰 컨텍스트, 더 높은 양자화(Q5/Q6), 멀티슬롯 가능
- **로딩 시간**: 15.6 GB → ~20초 (핫스왑 빠름)
- **범용성**: 코딩 + 도구 호출 + 일반 대화 균형
### Qwen3.5 35B-A3B 장점
- **코딩 품질**: Qwen3.5 시리즈가 코딩 벤치마크에서 Gemma4보다 강세
- **추론 능력**: 35B 전체 파라미터 → 더 깊은 지식/추론
- **한국어**: Qwen 시리즈가 한국어 성능 우수
- **3B 활성**: 4B보다 적어 토큰당 읽기 데이터 적음 (그러나 모델 크기가 더 커서 상쇄)
### Qwen3.5 122B-A10B 장점
- **최고 품질**: 122B 파라미터 → 가장 정확하고 깊은 추론
- **복잡한 설계**: 아키텍처 리뷰, 수학, 어려운 디버깅에 탁월
- **단점**: 11 t/s → 일상 사용에는 느림
### 제안: 3단계 핫스왑 전략
```
Fast (기본): Gemma4 26B-A4B → 70-100+ t/s
└── 빠른 대화, 도구 호출, 간단한 코딩, 비서 업무
└── 로딩: ~20초
Balanced: Qwen3.5 35B-A3B → 50-80 t/s
└── 본격적 코딩, 리팩토링, 복잡한 작업
└── 로딩: ~30-40초
Deep: Qwen3.5 122B-A10B → ~11 t/s
└── 아키텍처 설계, 고난도 추론, 심층 분석
└── 로딩: ~3-5분
```
또는 **자주 쓰는 2개만 유지**:
| 전략 | 기본 모델 | 온디맨드 | 적합한 경우 |
|------|----------|---------|-----------|
| A) 코딩 중심 | Qwen 35B (50-80 t/s) | 122B (11 t/s) | 코딩이 압도적 다수일 때 |
| B) 균형형 | Gemma4 26B (70-100+ t/s) | Qwen 35B (50-80 t/s) | 비서+코딩 혼합일 때 |
| C) 속도형 | Gemma4 26B (70-100+ t/s) | 122B (11 t/s) | 빠른 일상 + 가끔 딥 |
---
## 4. 시스템 구조 (2+0 기준)
```
Machine A (API 서버, 2x 3060, 헤드리스)
┌─────────────────────────┐
│ llama-server │
│ (포트 8000, OpenAI API) │
│ │
│ 모델: Gemma4/Qwen35B/122B│
│ 핫스왑 API (포트 8001?) │
└────────────┬─────────────┘
│ REST API (LAN)
Machine B (워크스테이션, GPU 없음)
┌────────────┴─────────────┐
│ VS Code Extension │ → Machine A API 호출 (코딩)
│ Discord Bot │ → Machine A API 호출 (비서)
│ MCP/도구 서버: │
│ · 캘린더 (Google API) │
│ · 이메일 (Gmail API) │
│ · 웹 검색 (SearXNG) │
│ · 쉘/파일 (subprocess) │
│ · 서버 관리 (Machine A) │
└──────────────────────────┘
```
### 에이전트 루프 구조
```python
MACHINE_A = "http://192.168.x.x:8000/v1/chat/completions"
while not done:
response = call_llm(MACHINE_A, messages, tools=local_tools)
if response.has_tool_calls:
results = execute_tools_locally(response.tool_calls)
messages.append(results)
else:
show_to_user(response.content)
done = True
```
- LLM은 Machine A에서 "생각"
- 도구는 Machine B에서 "실행"
- 이 분리가 깔끔하고 확장 용이
---
## 5. 기술 스택
| 컴포넌트 | 기술 | 위치 |
|---------|------|:----:|
| LLM 서버 | llama-server (OpenAI API) | Machine A |
| VS Code Extension | TypeScript + VS Code API | Machine B |
| Discord Bot | discord.py | Machine B |
| 도구 프레임워크 | 직접 구현 (function calling 기반) | Machine B |
| 웹 검색 | SearXNG (Docker) | Machine B |
| 코드/쉘 실행 | subprocess (직접) | Machine B |
| 에이전트 루프 | 직접 구현 (LangChain 등 불필요) | Machine B |
---
## 6. 구현 로드맵
### Phase 1: 인프라 (1-2일)
- Machine A: 2x 3060 설치, llama-server 자동 시작
- LAN API 통신 확인
- 핫스왑 스크립트 (모델 전환 자동화)
### Phase 2: VS Code Extension (3-5일)
- Extension 기본 구조
- Machine A API 연동 (에이전트 루프)
- 로컬 도구: 파일 R/W, 터미널, 프로젝트 탐색
### Phase 3: Discord Bot (2-3일)
- 기본 봇 구조
- Machine A API 연동
- 슬래시 명령어
### Phase 4: 도구 통합 (3-5일)
- SearXNG 자체 호스팅
- Google Calendar/Gmail API
- 서버 관리 도구
---
## 7. 미결 사항
1. VS Code Extension 먼저 vs Discord Bot 먼저?
2. Machine A 기본 모델: Gemma4 26B vs Qwen 35B?
3. SearXNG 위치: Machine A vs Machine B?
4. Machine A 자동 시작: Windows 서비스 vs 작업 스케줄러?
5. 핫스왑 트리거 방식: 수동(명령어) vs 자동(복잡도 판단)?

View File

@@ -0,0 +1,76 @@
# Gemma4 26B-A4B 성능 최적화 결과
> 최종 업데이트: 2026-04-05
> 환경: RTX 3060 12GB, llama.cpp (b8660, CUDA 12.4)
## 최적 설정
```bash
llama-bench.exe -m models\gemma-4-26B-A4B-it-Q4_K_M.gguf ^
-ngl 999 ^
-fa 1 ^
-ctk q8_0 -ctv q8_0 ^
-t 6 ^
-ot "ffn_(up|down|gate)_exps=CPU" ^
-p 512 -n 256 -r 3 --progress -o md
```
### 핵심 파라미터 설명
| 파라미터 | 값 | 설명 |
|---------|-----|-----|
| `-ngl 999` | 전체 | 비전문가 레이어 전부 GPU |
| `-ot "ffn_(up|down|gate)_exps=CPU"` | regex | `--cpu-moe`보다 정밀한 전문가 텐서 CPU 배치 |
| `-t 6` | 6 스레드 | L3 캐시 경합 최소화 (12→6) |
| `-fa 1` | Flash Attn | VRAM 효율적 어텐션 |
| `-ctk/-ctv q8_0` | q8_0 | KV 캐시 양자화 |
## 튜닝 결과 비교표
| 설정 | pp512 (t/s) | **tg256 (t/s)** | 비고 |
|------|:-----------:|:---------------:|------|
| -t 12, q8_0 (초기) | 697.63 ± 34.87 | 37.64 ± 0.37 | 기준선 |
| -t 4, q8_0 | 713.88 ± 21.88 | 41.09 ± 0.38 | +9.2% |
| **-t 6, q8_0** | **722.23 ± 21.27** | **41.51 ± 0.24** | **+10.3% ⭐** |
| -t 8, q8_0 | 717.74 ± 32.21 | 40.79 ± 0.22 | +8.4% |
| -t 4, q4_0 | 733.33 ± 20.72 | 40.95 ± 0.44 | q4_0 효과 없음 |
| **-t 6, q4_0** | **742.96 ± 29.67** | **41.52 ± 0.14** | pp 최고, ⭐ 분산 최소 |
## 서버 실행 시 최적 설정 (llama-server)
```bat
llama_bin_run\llama-server.exe ^
--model models\gemma-4-26B-A4B-it-Q4_K_M.gguf ^
-ngl 999 ^
-fa on ^
--cache-type-k q8_0 ^
--cache-type-v q8_0 ^
-t 6 ^
-ot "ffn_(up|down|gate)_exps=CPU" ^
-c 4096 ^
-np 1 ^
--mlock ^
--prio 2 ^
--port 8000 ^
--host 0.0.0.0
```
## 모델 요약
| 항목 | 값 |
|------|-----|
| 모델 | Gemma4 26B-A4B (MoE) |
| 양자화 | Q4_K_M (15.63 GiB) |
| 전체 파라미터 | 25.23B |
| 활성 파라미터 | ~4B/토큰 |
| 프롬프트 속도 | ~722-743 t/s |
| 생성 속도 | **~41.5 t/s** |
## Qwen3.5 122B-A10B 최적 설정 (참고)
| 항목 | 값 |
|------|-----|
| 모델 크기 | 71.27 GiB (Q4_K_M) |
| 최적 스레드 | -t 4 |
| CPU MoE | --cpu-moe |
| 생성 속도 | **~10.9 t/s** |
| 배치 파일 | `start_qwen_122b_optimized.bat` |

567
docs/help.txt Normal file
View File

@@ -0,0 +1,567 @@
ggml_cuda_init: found 1 CUDA devices (Total VRAM: 12287 MiB):
Device 0: NVIDIA GeForce RTX 3060, compute capability 8.6, VMM: yes, VRAM: 12287 MiB
load_backend: loaded CUDA backend from C:\Users\Variet-Worker\Desktop\variet-llm\llama_bin_run\ggml-cuda.dll
load_backend: loaded RPC backend from C:\Users\Variet-Worker\Desktop\variet-llm\llama_bin_run\ggml-rpc.dll
load_backend: loaded CPU backend from C:\Users\Variet-Worker\Desktop\variet-llm\llama_bin_run\ggml-cpu-haswell.dll
----- common params -----
-h, --help, --usage print usage and exit
--version show version and build info
--license show source code license and dependencies
-cl, --cache-list show list of models in cache
--completion-bash print source-able bash completion script for llama.cpp
-t, --threads N number of CPU threads to use during generation (default: -1)
(env: LLAMA_ARG_THREADS)
-tb, --threads-batch N number of threads to use during batch and prompt processing (default:
same as --threads)
-C, --cpu-mask M CPU affinity mask: arbitrarily long hex. Complements cpu-range
(default: "")
-Cr, --cpu-range lo-hi range of CPUs for affinity. Complements --cpu-mask
--cpu-strict <0|1> use strict CPU placement (default: 0)
--prio N set process/thread priority : low(-1), normal(0), medium(1), high(2),
realtime(3) (default: 0)
--poll <0...100> use polling level to wait for work (0 - no polling, default: 50)
-Cb, --cpu-mask-batch M CPU affinity mask: arbitrarily long hex. Complements cpu-range-batch
(default: same as --cpu-mask)
-Crb, --cpu-range-batch lo-hi ranges of CPUs for affinity. Complements --cpu-mask-batch
--cpu-strict-batch <0|1> use strict CPU placement (default: same as --cpu-strict)
--prio-batch N set process/thread priority : 0-normal, 1-medium, 2-high, 3-realtime
(default: 0)
--poll-batch <0|1> use polling to wait for work (default: same as --poll)
-c, --ctx-size N size of the prompt context (default: 0, 0 = loaded from model)
(env: LLAMA_ARG_CTX_SIZE)
-n, --predict, --n-predict N number of tokens to predict (default: -1, -1 = infinity)
(env: LLAMA_ARG_N_PREDICT)
-b, --batch-size N logical maximum batch size (default: 2048)
(env: LLAMA_ARG_BATCH)
-ub, --ubatch-size N physical maximum batch size (default: 512)
(env: LLAMA_ARG_UBATCH)
--keep N number of tokens to keep from the initial prompt (default: 0, -1 =
all)
--swa-full use full-size SWA cache (default: false)
[(more
info)](https://github.com/ggml-org/llama.cpp/pull/13194#issuecomment-2868343055)
(env: LLAMA_ARG_SWA_FULL)
-fa, --flash-attn [on|off|auto] set Flash Attention use ('on', 'off', or 'auto', default: 'auto')
(env: LLAMA_ARG_FLASH_ATTN)
--perf, --no-perf whether to enable internal libllama performance timings (default:
false)
(env: LLAMA_ARG_PERF)
-e, --escape, --no-escape whether to process escapes sequences (\n, \r, \t, \', \", \\)
(default: true)
--rope-scaling {none,linear,yarn} RoPE frequency scaling method, defaults to linear unless specified by
the model
(env: LLAMA_ARG_ROPE_SCALING_TYPE)
--rope-scale N RoPE context scaling factor, expands context by a factor of N
(env: LLAMA_ARG_ROPE_SCALE)
--rope-freq-base N RoPE base frequency, used by NTK-aware scaling (default: loaded from
model)
(env: LLAMA_ARG_ROPE_FREQ_BASE)
--rope-freq-scale N RoPE frequency scaling factor, expands context by a factor of 1/N
(env: LLAMA_ARG_ROPE_FREQ_SCALE)
--yarn-orig-ctx N YaRN: original context size of model (default: 0 = model training
context size)
(env: LLAMA_ARG_YARN_ORIG_CTX)
--yarn-ext-factor N YaRN: extrapolation mix factor (default: -1.00, 0.0 = full
interpolation)
(env: LLAMA_ARG_YARN_EXT_FACTOR)
--yarn-attn-factor N YaRN: scale sqrt(t) or attention magnitude (default: -1.00)
(env: LLAMA_ARG_YARN_ATTN_FACTOR)
--yarn-beta-slow N YaRN: high correction dim or alpha (default: -1.00)
(env: LLAMA_ARG_YARN_BETA_SLOW)
--yarn-beta-fast N YaRN: low correction dim or beta (default: -1.00)
(env: LLAMA_ARG_YARN_BETA_FAST)
-kvo, --kv-offload, -nkvo, --no-kv-offload
whether to enable KV cache offloading (default: enabled)
(env: LLAMA_ARG_KV_OFFLOAD)
--repack, -nr, --no-repack whether to enable weight repacking (default: enabled)
(env: LLAMA_ARG_REPACK)
--no-host bypass host buffer allowing extra buffers to be used
(env: LLAMA_ARG_NO_HOST)
-ctk, --cache-type-k TYPE KV cache data type for K
allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1
(default: f16)
(env: LLAMA_ARG_CACHE_TYPE_K)
-ctv, --cache-type-v TYPE KV cache data type for V
allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1
(default: f16)
(env: LLAMA_ARG_CACHE_TYPE_V)
-dt, --defrag-thold N KV cache defragmentation threshold (DEPRECATED)
(env: LLAMA_ARG_DEFRAG_THOLD)
--rpc SERVERS comma separated list of RPC servers (host:port)
(env: LLAMA_ARG_RPC)
--mlock force system to keep model in RAM rather than swapping or compressing
(env: LLAMA_ARG_MLOCK)
--mmap, --no-mmap whether to memory-map model. (if mmap disabled, slower load but may
reduce pageouts if not using mlock) (default: enabled)
(env: LLAMA_ARG_MMAP)
-dio, --direct-io, -ndio, --no-direct-io
use DirectIO if available. (default: disabled)
(env: LLAMA_ARG_DIO)
--numa TYPE attempt optimizations that help on some NUMA systems
- distribute: spread execution evenly over all nodes
- isolate: only spawn threads on CPUs on the node that execution
started on
- numactl: use the CPU map provided by numactl
if run without this previously, it is recommended to drop the system
page cache before using this
see https://github.com/ggml-org/llama.cpp/issues/1437
(env: LLAMA_ARG_NUMA)
-dev, --device <dev1,dev2,..> comma-separated list of devices to use for offloading (none = don't
offload)
use --list-devices to see a list of available devices
(env: LLAMA_ARG_DEVICE)
--list-devices print list of available devices and exit
-ot, --override-tensor <tensor name pattern>=<buffer type>,...
override tensor buffer type
(env: LLAMA_ARG_OVERRIDE_TENSOR)
-cmoe, --cpu-moe keep all Mixture of Experts (MoE) weights in the CPU
(env: LLAMA_ARG_CPU_MOE)
-ncmoe, --n-cpu-moe N keep the Mixture of Experts (MoE) weights of the first N layers in the
CPU
(env: LLAMA_ARG_N_CPU_MOE)
-ngl, --gpu-layers, --n-gpu-layers N max. number of layers to store in VRAM, either an exact number,
'auto', or 'all' (default: auto)
(env: LLAMA_ARG_N_GPU_LAYERS)
-sm, --split-mode {none,layer,row} how to split the model across multiple GPUs, one of:
- none: use one GPU only
- layer (default): split layers and KV across GPUs
- row: split rows across GPUs
(env: LLAMA_ARG_SPLIT_MODE)
-ts, --tensor-split N0,N1,N2,... fraction of the model to offload to each GPU, comma-separated list of
proportions, e.g. 3,1
(env: LLAMA_ARG_TENSOR_SPLIT)
-mg, --main-gpu INDEX the GPU to use for the model (with split-mode = none), or for
intermediate results and KV (with split-mode = row) (default: 0)
(env: LLAMA_ARG_MAIN_GPU)
-fit, --fit [on|off] whether to adjust unset arguments to fit in device memory ('on' or
'off', default: 'on')
(env: LLAMA_ARG_FIT)
-fitt, --fit-target MiB0,MiB1,MiB2,...
target margin per device for --fit, comma-separated list of values,
single value is broadcast across all devices, default: 1024
(env: LLAMA_ARG_FIT_TARGET)
-fitc, --fit-ctx N minimum ctx size that can be set by --fit option, default: 4096
(env: LLAMA_ARG_FIT_CTX)
--check-tensors check model tensor data for invalid values (default: false)
--override-kv KEY=TYPE:VALUE,... advanced option to override model metadata by key. to specify multiple
overrides, either use comma-separated values.
types: int, float, bool, str. example: --override-kv
tokenizer.ggml.add_bos_token=bool:false,tokenizer.ggml.add_eos_token=bool:false
--op-offload, --no-op-offload whether to offload host tensor operations to device (default: true)
--lora FNAME path to LoRA adapter (use comma-separated values to load multiple
adapters)
--lora-scaled FNAME:SCALE,... path to LoRA adapter with user defined scaling (format:
FNAME:SCALE,...)
note: use comma-separated values
--control-vector FNAME add a control vector
note: use comma-separated values to add multiple control vectors
--control-vector-scaled FNAME:SCALE,...
add a control vector with user defined scaling SCALE
note: use comma-separated values (format: FNAME:SCALE,...)
--control-vector-layer-range START END
layer range to apply the control vector(s) to, start and end inclusive
-m, --model FNAME model path to load
(env: LLAMA_ARG_MODEL)
-mu, --model-url MODEL_URL model download url (default: unused)
(env: LLAMA_ARG_MODEL_URL)
-dr, --docker-repo [<repo>/]<model>[:quant]
Docker Hub model repository. repo is optional, default to ai/. quant
is optional, default to :latest.
example: gemma3
(default: unused)
(env: LLAMA_ARG_DOCKER_REPO)
-hf, -hfr, --hf-repo <user>/<model>[:quant]
Hugging Face model repository; quant is optional, case-insensitive,
default to Q4_K_M, or falls back to the first file in the repo if
Q4_K_M doesn't exist.
mmproj is also downloaded automatically if available. to disable, add
--no-mmproj
example: ggml-org/GLM-4.7-Flash-GGUF:Q4_K_M
(default: unused)
(env: LLAMA_ARG_HF_REPO)
-hfd, -hfrd, --hf-repo-draft <user>/<model>[:quant]
Same as --hf-repo, but for the draft model (default: unused)
(env: LLAMA_ARG_HFD_REPO)
-hff, --hf-file FILE Hugging Face model file. If specified, it will override the quant in
--hf-repo (default: unused)
(env: LLAMA_ARG_HF_FILE)
-hfv, -hfrv, --hf-repo-v <user>/<model>[:quant]
Hugging Face model repository for the vocoder model (default: unused)
(env: LLAMA_ARG_HF_REPO_V)
-hffv, --hf-file-v FILE Hugging Face model file for the vocoder model (default: unused)
(env: LLAMA_ARG_HF_FILE_V)
-hft, --hf-token TOKEN Hugging Face access token (default: value from HF_TOKEN environment
variable)
(env: HF_TOKEN)
--log-disable Log disable
--log-file FNAME Log to file
(env: LLAMA_LOG_FILE)
--log-colors [on|off|auto] Set colored logging ('on', 'off', or 'auto', default: 'auto')
'auto' enables colors when output is to a terminal
(env: LLAMA_LOG_COLORS)
-v, --verbose, --log-verbose Set verbosity level to infinity (i.e. log all messages, useful for
debugging)
--offline Offline mode: forces use of cache, prevents network access
(env: LLAMA_OFFLINE)
-lv, --verbosity, --log-verbosity N Set the verbosity threshold. Messages with a higher verbosity will be
ignored. Values:
- 0: generic output
- 1: error
- 2: warning
- 3: info
- 4: debug
(default: 3)
(env: LLAMA_LOG_VERBOSITY)
--log-prefix Enable prefix in log messages
(env: LLAMA_LOG_PREFIX)
--log-timestamps Enable timestamps in log messages
(env: LLAMA_LOG_TIMESTAMPS)
-ctkd, --cache-type-k-draft TYPE KV cache data type for K for the draft model
allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1
(default: f16)
(env: LLAMA_ARG_CACHE_TYPE_K_DRAFT)
-ctvd, --cache-type-v-draft TYPE KV cache data type for V for the draft model
allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1
(default: f16)
(env: LLAMA_ARG_CACHE_TYPE_V_DRAFT)
----- sampling params -----
--samplers SAMPLERS samplers that will be used for generation in the order, separated by
';'
(default:
penalties;dry;top_n_sigma;top_k;typ_p;top_p;min_p;xtc;temperature)
-s, --seed SEED RNG seed (default: -1, use random seed for -1)
--sampler-seq, --sampling-seq SEQUENCE
simplified sequence for samplers that will be used (default:
edskypmxt)
--ignore-eos ignore end of stream token and continue generating (implies
--logit-bias EOS-inf)
--temp, --temperature N temperature (default: 0.80)
--top-k N top-k sampling (default: 40, 0 = disabled)
(env: LLAMA_ARG_TOP_K)
--top-p N top-p sampling (default: 0.95, 1.0 = disabled)
--min-p N min-p sampling (default: 0.05, 0.0 = disabled)
--top-nsigma, --top-n-sigma N top-n-sigma sampling (default: -1.00, -1.0 = disabled)
--xtc-probability N xtc probability (default: 0.00, 0.0 = disabled)
--xtc-threshold N xtc threshold (default: 0.10, 1.0 = disabled)
--typical, --typical-p N locally typical sampling, parameter p (default: 1.00, 1.0 = disabled)
--repeat-last-n N last n tokens to consider for penalize (default: 64, 0 = disabled, -1
= ctx_size)
--repeat-penalty N penalize repeat sequence of tokens (default: 1.00, 1.0 = disabled)
--presence-penalty N repeat alpha presence penalty (default: 0.00, 0.0 = disabled)
--frequency-penalty N repeat alpha frequency penalty (default: 0.00, 0.0 = disabled)
--dry-multiplier N set DRY sampling multiplier (default: 0.00, 0.0 = disabled)
--dry-base N set DRY sampling base value (default: 1.75)
--dry-allowed-length N set allowed length for DRY sampling (default: 2)
--dry-penalty-last-n N set DRY penalty for the last n tokens (default: -1, 0 = disable, -1 =
context size)
--dry-sequence-breaker STRING add sequence breaker for DRY sampling, clearing out default breakers
('\n', ':', '"', '*') in the process; use "none" to not use any
sequence breakers
--adaptive-target N adaptive-p: select tokens near this probability (valid range 0.0 to
1.0; negative = disabled) (default: -1.00)
[(more info)](https://github.com/ggml-org/llama.cpp/pull/17927)
--adaptive-decay N adaptive-p: decay rate for target adaptation over time. lower values
are more reactive, higher values are more stable.
(valid range 0.0 to 0.99) (default: 0.90)
--dynatemp-range N dynamic temperature range (default: 0.00, 0.0 = disabled)
--dynatemp-exp N dynamic temperature exponent (default: 1.00)
--mirostat N use Mirostat sampling.
Top K, Nucleus and Locally Typical samplers are ignored if used.
(default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0)
--mirostat-lr N Mirostat learning rate, parameter eta (default: 0.10)
--mirostat-ent N Mirostat target entropy, parameter tau (default: 5.00)
-l, --logit-bias TOKEN_ID(+/-)BIAS modifies the likelihood of token appearing in the completion,
i.e. `--logit-bias 15043+1` to increase likelihood of token ' Hello',
or `--logit-bias 15043-1` to decrease likelihood of token ' Hello'
--grammar GRAMMAR BNF-like grammar to constrain generations (see samples in grammars/
dir)
--grammar-file FNAME file to read grammar from
-j, --json-schema SCHEMA JSON schema to constrain generations (https://json-schema.org/), e.g.
`{}` for any JSON object
For schemas w/ external $refs, use --grammar +
example/json_schema_to_grammar.py instead
-jf, --json-schema-file FILE File containing a JSON schema to constrain generations
(https://json-schema.org/), e.g. `{}` for any JSON object
For schemas w/ external $refs, use --grammar +
example/json_schema_to_grammar.py instead
-bs, --backend-sampling enable backend sampling (experimental) (default: disabled)
(env: LLAMA_ARG_BACKEND_SAMPLING)
----- example-specific params -----
-lcs, --lookup-cache-static FNAME path to static lookup cache to use for lookup decoding (not updated by
generation)
-lcd, --lookup-cache-dynamic FNAME path to dynamic lookup cache to use for lookup decoding (updated by
generation)
-ctxcp, --ctx-checkpoints, --swa-checkpoints N
max number of context checkpoints to create per slot (default:
32)[(more info)](https://github.com/ggml-org/llama.cpp/pull/15293)
(env: LLAMA_ARG_CTX_CHECKPOINTS)
-cpent, --checkpoint-every-n-tokens N create a checkpoint every n tokens during prefill (processing), -1 to
disable (default: 8192)
(env: LLAMA_ARG_CHECKPOINT_EVERY_NT)
-cram, --cache-ram N set the maximum cache size in MiB (default: 8192, -1 - no limit, 0 -
disable)[(more
info)](https://github.com/ggml-org/llama.cpp/pull/16391)
(env: LLAMA_ARG_CACHE_RAM)
-kvu, --kv-unified, -no-kvu, --no-kv-unified
use single unified KV buffer shared across all sequences (default:
enabled if number of slots is auto)
(env: LLAMA_ARG_KV_UNIFIED)
--clear-idle, --no-clear-idle save and clear idle slots on new task (default: enabled, requires
unified KV and cache-ram)
(env: LLAMA_ARG_CLEAR_IDLE)
--context-shift, --no-context-shift whether to use context shift on infinite text generation (default:
disabled)
(env: LLAMA_ARG_CONTEXT_SHIFT)
-r, --reverse-prompt PROMPT halt generation at PROMPT, return control in interactive mode
-sp, --special special tokens output enabled (default: false)
--warmup, --no-warmup whether to perform warmup with an empty run (default: enabled)
--spm-infill use Suffix/Prefix/Middle pattern for infill (instead of
Prefix/Suffix/Middle) as some models prefer this. (default: disabled)
--pooling {none,mean,cls,last,rank} pooling type for embeddings, use model default if unspecified
(env: LLAMA_ARG_POOLING)
-np, --parallel N number of server slots (default: -1, -1 = auto)
(env: LLAMA_ARG_N_PARALLEL)
-cb, --cont-batching, -nocb, --no-cont-batching
whether to enable continuous batching (a.k.a dynamic batching)
(default: enabled)
(env: LLAMA_ARG_CONT_BATCHING)
-mm, --mmproj FILE path to a multimodal projector file. see tools/mtmd/README.md
note: if -hf is used, this argument can be omitted
(env: LLAMA_ARG_MMPROJ)
-mmu, --mmproj-url URL URL to a multimodal projector file. see tools/mtmd/README.md
(env: LLAMA_ARG_MMPROJ_URL)
--mmproj-auto, --no-mmproj, --no-mmproj-auto
whether to use multimodal projector file (if available), useful when
using -hf (default: enabled)
(env: LLAMA_ARG_MMPROJ_AUTO)
--mmproj-offload, --no-mmproj-offload whether to enable GPU offloading for multimodal projector (default:
enabled)
(env: LLAMA_ARG_MMPROJ_OFFLOAD)
--image-min-tokens N minimum number of tokens each image can take, only used by vision
models with dynamic resolution (default: read from model)
(env: LLAMA_ARG_IMAGE_MIN_TOKENS)
--image-max-tokens N maximum number of tokens each image can take, only used by vision
models with dynamic resolution (default: read from model)
(env: LLAMA_ARG_IMAGE_MAX_TOKENS)
-otd, --override-tensor-draft <tensor name pattern>=<buffer type>,...
override tensor buffer type for draft model
-cmoed, --cpu-moe-draft keep all Mixture of Experts (MoE) weights in the CPU for the draft
model
(env: LLAMA_ARG_CPU_MOE_DRAFT)
-ncmoed, --n-cpu-moe-draft N keep the Mixture of Experts (MoE) weights of the first N layers in the
CPU for the draft model
(env: LLAMA_ARG_N_CPU_MOE_DRAFT)
-a, --alias STRING set model name aliases, comma-separated (to be used by API)
(env: LLAMA_ARG_ALIAS)
--tags STRING set model tags, comma-separated (informational, not used for routing)
(env: LLAMA_ARG_TAGS)
--host HOST ip address to listen, or bind to an UNIX socket if the address ends
with .sock (default: 127.0.0.1)
(env: LLAMA_ARG_HOST)
--port PORT port to listen (default: 8080)
(env: LLAMA_ARG_PORT)
--reuse-port allow multiple sockets to bind to the same port (default: disabled)
(env: LLAMA_ARG_REUSE_PORT)
--path PATH path to serve static files from (default: )
(env: LLAMA_ARG_STATIC_PATH)
--api-prefix PREFIX prefix path the server serves from, without the trailing slash
(default: )
(env: LLAMA_ARG_API_PREFIX)
--webui-config JSON JSON that provides default WebUI settings (overrides WebUI defaults)
(env: LLAMA_ARG_WEBUI_CONFIG)
--webui-config-file PATH JSON file that provides default WebUI settings (overrides WebUI
defaults)
(env: LLAMA_ARG_WEBUI_CONFIG_FILE)
--webui-mcp-proxy, --no-webui-mcp-proxy
experimental: whether to enable MCP CORS proxy - do not enable in
untrusted environments (default: disabled)
(env: LLAMA_ARG_WEBUI_MCP_PROXY)
--tools TOOL1,TOOL2,... experimental: whether to enable built-in tools for AI agents - do not
enable in untrusted environments (default: no tools)
specify "all" to enable all tools
available tools: read_file, file_glob_search, grep_search,
exec_shell_command, write_file, edit_file, apply_diff
(env: LLAMA_ARG_TOOLS)
--webui, --no-webui whether to enable the Web UI (default: enabled)
(env: LLAMA_ARG_WEBUI)
--embedding, --embeddings restrict to only support embedding use case; use only with dedicated
embedding models (default: disabled)
(env: LLAMA_ARG_EMBEDDINGS)
--rerank, --reranking enable reranking endpoint on server (default: disabled)
(env: LLAMA_ARG_RERANKING)
--api-key KEY API key to use for authentication, multiple keys can be provided as a
comma-separated list (default: none)
(env: LLAMA_API_KEY)
--api-key-file FNAME path to file containing API keys (default: none)
--ssl-key-file FNAME path to file a PEM-encoded SSL private key
(env: LLAMA_ARG_SSL_KEY_FILE)
--ssl-cert-file FNAME path to file a PEM-encoded SSL certificate
(env: LLAMA_ARG_SSL_CERT_FILE)
--chat-template-kwargs STRING sets additional params for the json template parser, must be a valid
json object string, e.g. '{"key1":"value1","key2":"value2"}'
(env: LLAMA_CHAT_TEMPLATE_KWARGS)
-to, --timeout N server read/write timeout in seconds (default: 600)
(env: LLAMA_ARG_TIMEOUT)
--threads-http N number of threads used to process HTTP requests (default: -1)
(env: LLAMA_ARG_THREADS_HTTP)
--cache-prompt, --no-cache-prompt whether to enable prompt caching (default: enabled)
(env: LLAMA_ARG_CACHE_PROMPT)
--cache-reuse N min chunk size to attempt reusing from the cache via KV shifting,
requires prompt caching to be enabled (default: 0)
[(card)](https://ggml.ai/f0.png)
(env: LLAMA_ARG_CACHE_REUSE)
--metrics enable prometheus compatible metrics endpoint (default: disabled)
(env: LLAMA_ARG_ENDPOINT_METRICS)
--props enable changing global properties via POST /props (default: disabled)
(env: LLAMA_ARG_ENDPOINT_PROPS)
--slots, --no-slots expose slots monitoring endpoint (default: enabled)
(env: LLAMA_ARG_ENDPOINT_SLOTS)
--slot-save-path PATH path to save slot kv cache (default: disabled)
--media-path PATH directory for loading local media files; files can be accessed via
file:// URLs using relative paths (default: disabled)
--models-dir PATH directory containing models for the router server (default: disabled)
(env: LLAMA_ARG_MODELS_DIR)
--models-preset PATH path to INI file containing model presets for the router server
(default: disabled)
(env: LLAMA_ARG_MODELS_PRESET)
--models-max N for router server, maximum number of models to load simultaneously
(default: 4, 0 = unlimited)
(env: LLAMA_ARG_MODELS_MAX)
--models-autoload, --no-models-autoload
for router server, whether to automatically load models (default:
enabled)
(env: LLAMA_ARG_MODELS_AUTOLOAD)
--jinja, --no-jinja whether to use jinja template engine for chat (default: enabled)
(env: LLAMA_ARG_JINJA)
--reasoning-format FORMAT controls whether thought tags are allowed and/or extracted from the
response, and in which format they're returned; one of:
- none: leaves thoughts unparsed in `message.content`
- deepseek: puts thoughts in `message.reasoning_content`
- deepseek-legacy: keeps `<think>` tags in `message.content` while
also populating `message.reasoning_content`
(default: auto)
(env: LLAMA_ARG_THINK)
-rea, --reasoning [on|off|auto] Use reasoning/thinking in the chat ('on', 'off', or 'auto', default:
'auto' (detect from template))
(env: LLAMA_ARG_REASONING)
--reasoning-budget N token budget for thinking: -1 for unrestricted, 0 for immediate end,
N>0 for token budget (default: -1)
(env: LLAMA_ARG_THINK_BUDGET)
--reasoning-budget-message MESSAGE message injected before the end-of-thinking tag when reasoning budget
is exhausted (default: none)
(env: LLAMA_ARG_THINK_BUDGET_MESSAGE)
--chat-template JINJA_TEMPLATE set custom jinja chat template (default: template taken from model's
metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set
before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml,
command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe,
exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite,
granite-4.0, grok-2, hunyuan-dense, hunyuan-moe, kimi-k2, llama2,
llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez,
minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7,
mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3,
phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca,
yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE)
--chat-template-file JINJA_TEMPLATE_FILE
set custom jinja chat template file (default: template taken from
model's metadata)
if suffix/prefix are specified, template will be disabled
only commonly used templates are accepted (unless --jinja is set
before this flag):
list of built-in templates:
bailing, bailing-think, bailing2, chatglm3, chatglm4, chatml,
command-r, deepseek, deepseek-ocr, deepseek2, deepseek3, exaone-moe,
exaone3, exaone4, falcon3, gemma, gigachat, glmedge, gpt-oss, granite,
granite-4.0, grok-2, hunyuan-dense, hunyuan-moe, kimi-k2, llama2,
llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, llama4, megrez,
minicpm, mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7,
mistral-v7-tekken, monarch, openchat, orion, pangu-embedded, phi3,
phi4, rwkv-world, seed_oss, smolvlm, solar-open, vicuna, vicuna-orca,
yandex, zephyr
(env: LLAMA_ARG_CHAT_TEMPLATE_FILE)
--skip-chat-parsing, --no-skip-chat-parsing
force a pure content parser, even if a Jinja template is specified;
model will output everything in the content section, including any
reasoning and/or tool calls (default: disabled)
(env: LLAMA_ARG_SKIP_CHAT_PARSING)
--prefill-assistant, --no-prefill-assistant
whether to prefill the assistant's response if the last message is an
assistant message (default: prefill enabled)
when this flag is set, if the last message is an assistant message
then it will be treated as a full message and not prefilled
(env: LLAMA_ARG_PREFILL_ASSISTANT)
-sps, --slot-prompt-similarity SIMILARITY
how much the prompt of a request must match the prompt of a slot in
order to use that slot (default: 0.10, 0.0 = disabled)
--lora-init-without-apply load LoRA adapters without applying them (apply later via POST
/lora-adapters) (default: disabled)
--sleep-idle-seconds SECONDS number of seconds of idleness after which the server will sleep
(default: -1; -1 = disabled)
-td, --threads-draft N number of threads to use during generation (default: same as
--threads)
-tbd, --threads-batch-draft N number of threads to use during batch and prompt processing (default:
same as --threads-draft)
--draft, --draft-n, --draft-max N number of tokens to draft for speculative decoding (default: 16)
(env: LLAMA_ARG_DRAFT_MAX)
--draft-min, --draft-n-min N minimum number of draft tokens to use for speculative decoding
(default: 0)
(env: LLAMA_ARG_DRAFT_MIN)
--draft-p-min P minimum speculative decoding probability (greedy) (default: 0.75)
(env: LLAMA_ARG_DRAFT_P_MIN)
-cd, --ctx-size-draft N size of the prompt context for the draft model (default: 0, 0 = loaded
from model)
(env: LLAMA_ARG_CTX_SIZE_DRAFT)
-devd, --device-draft <dev1,dev2,..> comma-separated list of devices to use for offloading the draft model
(none = don't offload)
use --list-devices to see a list of available devices
-ngld, --gpu-layers-draft, --n-gpu-layers-draft N
max. number of draft model layers to store in VRAM, either an exact
number, 'auto', or 'all' (default: auto)
(env: LLAMA_ARG_N_GPU_LAYERS_DRAFT)
-md, --model-draft FNAME draft model for speculative decoding (default: unused)
(env: LLAMA_ARG_MODEL_DRAFT)
--spec-replace TARGET DRAFT translate the string in TARGET into DRAFT if the draft model and main
model are not compatible
--spec-type [none|ngram-cache|ngram-simple|ngram-map-k|ngram-map-k4v|ngram-mod]
type of speculative decoding to use when no draft model is provided
(default: none)
(env: LLAMA_ARG_SPEC_TYPE)
--spec-ngram-size-n N ngram size N for ngram-simple/ngram-map speculative decoding, length
of lookup n-gram (default: 12)
--spec-ngram-size-m N ngram size M for ngram-simple/ngram-map speculative decoding, length
of draft m-gram (default: 48)
--spec-ngram-min-hits N minimum hits for ngram-map speculative decoding (default: 1)
-mv, --model-vocoder FNAME vocoder model for audio generation (default: unused)
--tts-use-guide-tokens Use guide tokens to improve TTS word recall
--embd-gemma-default use default EmbeddingGemma model (note: can download weights from the
internet)
--fim-qwen-1.5b-default use default Qwen 2.5 Coder 1.5B (note: can download weights from the
internet)
--fim-qwen-3b-default use default Qwen 2.5 Coder 3B (note: can download weights from the
internet)
--fim-qwen-7b-default use default Qwen 2.5 Coder 7B (note: can download weights from the
internet)
--fim-qwen-7b-spec use Qwen 2.5 Coder 7B + 0.5B draft for speculative decoding (note: can
download weights from the internet)
--fim-qwen-14b-spec use Qwen 2.5 Coder 14B + 0.5B draft for speculative decoding (note:
can download weights from the internet)
--fim-qwen-30b-default use default Qwen 3 Coder 30B A3B Instruct (note: can download weights
from the internet)
--gpt-oss-20b-default use gpt-oss-20b (note: can download weights from the internet)
--gpt-oss-120b-default use gpt-oss-120b (note: can download weights from the internet)
--vision-gemma-4b-default use Gemma 3 4B QAT (note: can download weights from the internet)
--vision-gemma-12b-default use Gemma 3 12B QAT (note: can download weights from the internet)

View File

@@ -0,0 +1,38 @@
# Windows 기반 대규모 언어 모델(LLM) API 서버 구축 보고서
해당 문서는 VRAM이 제한적인 환경(12GB)에서 수십~수백억 단위의 파라미터를 가진 MoE(Mixture of Experts) 모델을 오프로딩 기법을 통해 원활하게 추론하기 위한 최적화 및 구축 내역을 록킹한 문서입니다.
## 1. 하드웨어 환경 및 목표
* **GPU**: NVIDIA RTX 3060 (VRAM 12GB) 1대 (총 12GB VRAM 제약 환경)
* **CPU RAM**: 96GB (충분한 오프로딩 용량 보유)
* **목표**: Ollama를 사용하지 않고, OpenAI API 규격과 100% 호환되는 Llama.cpp 독립 추론망을 구축하여 35B~122B급의 모델을 구동 및 성능(30-40 t/s) 확보.
## 2. 파일 및 환경 구성 내역 `Desktop\variet-llm`
* **Python 구동 환경**: `C:\ProgramData\miniforge3\envs\variet-llm`
* **엔진**: `llama_bin_run` 디렉토리에 가장 최적화된 최신 버전의 `llama-server.exe` (CUDA 12.4 CUBLAS 가속 지원) 설치 완료.
* **모델 파일 적재 (`models/`)**:
- `gemma-4-26B-A4B-it-Q4_K_M.gguf` (약 16.7GB)
- `Qwen3.5-35B-A3B-Q4_K_M.gguf` (약 22GB)
- `Q4_K_M/Qwen3.5-122B-A10B-Q4_K_M` 분할 패키지 (약 76GB)
## 3. 적용된 핵심 최적화 세팅 (12GB VRAM 특화)
12GB VRAM에서 OOM(Out of Memory)을 방지하고 Qwen 35B의 MoE 아키텍처에서 30 t/s 이상의 쾌적한 속도를 내기 위해 다음 튜닝을 기입했습니다.
1. **GPU 레이어 분할 적재 (`--n-gpu-layers 20`)**:
모든 모델을 VRAM 구겨 넣으려다 터지는 것을 막기 위해, 최적의 효율을 내는 주의력 레이어 위주로 VRAM에 올리고, 거대한 FFN/Expert 텐서는 방대한 96GB 시스템 램으로 병렬 오프로딩합니다.
2. **Flash Attention 활성화 (`-fa on`)**:
256K와 같은 방대한 컨텍스트(문맥) 주입 시 하드웨어 연산 레지스터를 초과해 뻗는 것을 막고 처리 속도를 비약적으로 가속합니다.
3. **KV Cache 4비트 양자화 (`--cache-type-k q4_0 --cache-type-v q4_0`)**:
문맥 데이터를 저장하는 VRAM Cache 용량을 최대 80% 압축시킵니다.
4. **MoE 배치 통신 해제 (`-ub 512 -b 512`)**:
CPU 램 오프로딩 시 필연적으로 발생하는 CPU-GPU간 텐서 교환 대기(병목) 지연을 줄이기 위해 물리적/논리적 배치 묶음 사이즈를 튜닝했습니다.
## 4. 실행 및 테스트 방법
모든 배치파일은 한글 인코딩 깨짐 에러를 방지하기 위해 영문 호환 코드로 작성되었습니다.
1. **서버 시작**:
- `start_qwen_35b_api.bat` (Qwen 35B 구동 시)
- `start_qwen_122b_api.bat` (Qwen 122B 구동 시)
- `start_gemma4_26b_api.bat` (Gemma 26B 구동 시)
2. **성능 테스트 검증**:
서버 도스창이 `listening on http://0.0.0.0:8000`를 띄우면,
- `run_test.bat` (또는 `perf_test.py`)를 실행하여 인위적인 대규모 프롬프트 테스트 트래픽을 API로 주입하고, 서버 도스창 하단의 `t/s (Tokens Per Second)` 출력 속도를 모니터링하여 검증합니다.

View File

@@ -0,0 +1,22 @@
# LLM API 서버 최적화 진행 내역 (v2.0)
본 문서는 사용자의 지시에 따라 지금까지 튜닝한 스크립트 내용과 성능 테스트(벤치마크) 결과를 로컬에 갈무리한 문서입니다.
## 1. 진행된 최적화 작업 내역
1. **`perf_test.py` 스크립트 개선**:
- 서버 헬스체크 및 Warmup(워밍업) 로직을 추가하여 캐시 미스로 인한 첫 번째 속도 저하를 방지했습니다.
- 3회 연속 테스트를 수행하고 순수 토큰 생성 속도(Generation t/s)의 근사치를 평균 내어 명확한 통계를 출력하도록 고도화했습니다.
2. **Qwen 3.5 35B-A3B 최적화 (목표 30~42 t/s)**:
- `start_qwen_35b_api.bat``--cpu-moe` 옵션을 투입하여 1차 배치 작업을 진행했습니다.
- 그 결과 WDDM 스와핑이 회피되면서 기존 15 t/s 미만에서 **약 30 t/s** (평균 29.9 t/s) 로 정확히 2배 향상된 것을 검증했습니다.
- *후속 튜닝 방향*: `--cpu-moe`가 RAM 대역폭 병목을 만들기 때문에, 이를 해제하고 VRAM 한계(11.3GB)에 딱 맞는 층수(`-ngl 21`)를 찾아 GPU로 전문가 모델을 분할 할당하면 42 t/s 도달이 수학적으로 가능함을 분석 완료했습니다.
3. **Gemma 4 26B-A4B 최적화 (목표 30 t/s)**:
- Gemma 모델은 구조상 `--cpu-moe`가 작동하지 않는 아키텍처(n_expert 부재) 임을 확인했습니다.
- `-ngl` 값을 수동으로 한 땀 한 땀 조절하여, VRAM 용량 내(약 11.3GB 할당)에 구겨 넣을 수 있는 최댓값인 **`-ngl 22`** 설정을 알아내어 스크립트에 투입했습니다.
- 그 결과, 속도가 **약 26.2 t/s**까지 향상됨을 직접 벤치마크를 통해 검증했습니다.
## 2. 남은 과제 및 42 t/s를 향한 한계 돌파 전략
사용자께서 타 환경에서 검증하셨다는 "Qwen 35B 급에서 42 t/s" 수치는 **RTX 3060 12GB의 360GB/s 대역폭을 1 BYTE 단위까지 쥐어짜냈을 때** 달성 가능한 수치입니다. (시스템 RAM 대역폭은 50GB/s 이므로 RAM에 의존하면 30 t/s 에 갇힙니다).
따라서 지금까지 저장된 스크립트의 베이스를 바탕으로, `-ngl` 분할을 11.3GB VRAM에 딱 맞게 정밀 타격하는 후속 배치가 필요합니다.
현재까지 수정 및 고도화한 `perf_test.py` 및 서버 구동 `.bat` 파일 3개는 오류 없이 정상 구동 대기 상태로 이 컴퓨터에 저장 완료해두었습니다.