본문으로 건너뛰기

© 2026 Molayo

GitHub요약2026. 06. 15. 10:04

RAG를 넘어서: 문서 전체를 당신의 노트북에서 로드하세요

요약

KV 압축 기술을 통해 소비자용 하드웨어에서도 대규모 컨텍스트를 처리할 수 있게 하는 quantcpp 라이브러리를 소개합니다. 6.4배의 KV 압축을 통해 메모리 사용량을 획기적으로 줄이면서도 FP32 수준의 품질을 유지합니다.

핵심 포인트

  • 6.4배 KV 압축으로 16GB Mac에서 128K 컨텍스트 구현
  • 의존성 없는 17,600줄의 C 언어 기반 경량 라이브러리
  • Ollama 스타일의 CLI 및 OpenAI 호환 API 지원
  • FP32 품질을 유지하며 메모리 사용량 3배 절감 가능

RAG (Retrieval-Augmented Generation)를 넘어서: 문서 전체를 당신의 노트북에서 로드하세요.

청킹 (Chunking)은 작은 컨텍스트 윈도우 (Context Window)를 해결하기 위한 임시방편이었습니다. 우리는 그것을 불필요하게 만들었습니다.

6.4배의 KV 압축 (KV compression)을 통해 소비자용 하드웨어에서도 문서 전체를 이해할 수 있게 합니다.

pip install quantcpp

— 17,600줄의 C 언어, 의존성 제로 (zero dependencies).

12K 토큰에서 10/10 RLV가 절벽을 넘음 |
7/7 vs 0/7 RAG 측정 결과 |
6.4배 압축 + 3% PPL (Perplexity) |
16GB Mac에서 128K 컨텍스트 (Context) |
17.6K LOC (Lines of Code), 의존성 없음 |

Ollama 스타일의 CLI (v0.12.0+):

pip install quantcpp
quantcpp pull qwen3 # Qwen3-4B Q4_K_M 다운로드 (~2.5 GB)
quantcpp run qwen3 # 대화형 채팅
...

권장 기본값: Qwen3-4B (4B 파라미터, MMLU 73, M3에서 4.5 tok/s). 속도와 품질 모두 최상 — Q4 NEON 융합 도트 경로 (fused dot path) 덕분에 더 큰 어휘 집합 (vocab)에도 불구하고 Phi-3.5-mini보다 2.4배 빠릅니다. 기타 별칭: phi3.5, smollm2, llama3.2:1b. 첫 번째 run / serve 시 자동으로 다운로드됩니다.

serve 서브 명령은 8080 포트에서 POST /v1/chat/completions (OpenAI 호환)를 노출합니다 — 클라이언트는 SSE 스트리밍을 위해 "stream": true를 전달하거나, 단일 JSON 응답을 위해 이를 생략할 수 있습니다. 내장된 quantcpp client는 두 모드(기본값: 스트리밍, 단일 응답은 --no-stream)를 모두 지원합니다.

원샷 질문 (One-shot question):

quantcpp run qwen3 "What is gravity?"

Python API (3줄):

from quantcpp import Model
m = Model.from_pretrained("Qwen3-4B")
print(m.ask("What is gravity?"))

첫 사용 시 다운로드되며 ~/.cache/quantcpp/에 캐시됩니다. API 키도, GPU도 필요 없습니다. 아키텍처 지원 매트릭스와 모델 선택 가이드는 docs/supported_models.md를 참조하세요. 브라우저에서 시도해 보세요 → · 대화형 가이드 →

128개의 FP32 토큰 + 그 외 모든 것은 4비트 = 컨텍스트 길이에 관계없이 FP32 품질을 제공합니다.

Llama 3.2 3B, 3970 토큰에서 측정됨 (k128 = 3.2% FP32):

설정 (Configuration)PPLvs FP32KV 메모리 (32K)속도
FP32 (기준점)19.417.17 GB기준점
4-bit + 점진적 (progressive)19.39-0.1%2.33 GB+13%
4-bit flat20.02+3.1%2.30 GB+13%

m = Model("model.gguf", progressive=True) # ← FP32 품질, 메모리 3배 절감, 13% 더 빠름

작동 원리: Transformer 어텐션 (Attention)은 가중치의 약 70%를 마지막 약 128개의 토큰 (tokens)에 집중시킵니다. 나머지 모든 것을 압축하면서 이 토큰들을 전체 정밀도 (full precision)로 유지하는 것은 저장 정밀도를 정보 가치와 일치시키는 것이며, 이는 속도-왜곡 이론 (rate-distortion theory) 측면에서 거의 최적에 가깝습니다.

컨텍스트 길이 불변성 (Context-length invariant): 동일한 128-토큰 윈도우 (window)가 4K, 32K 또는 128K에서도 작동합니다. 128K 컨텍스트 (context)에서는 토큰의 0.1%만이 FP32이며, 사실상 FP32 품질을 가진 올-4비트 (all-4-bit) 방식과 같습니다.

6.4배 KV 압축을 적용한 Llama 3.2 3B. M1 Pro 16GB에서 측정한 실제 RSS:

컨텍스트 (Context)FP32 KVquant.cpp 6.4x절감량 (Savings)속도 (Speed)
16K8.5 GB6.5 GB-2.0 GB6.6 tok/s
32K9.6 GB8.2 GB-1.4 GB4.9 tok/s
65K8.5 GB1.6 tok/s
128KOOM9.5 GB0.8 tok/s

3B 모델로 128K 컨텍스트를 9.5 GB 내에서 구현했습니다. 생성 속도는 FP32와 동일합니다 (16K 기준 6.6 vs 6.5 tok/s).

m = Model("llama-3b.gguf", aggressive=True, context_length=131072) # 9.5 GB로 128K 구현

청킹 (Chunking) RAG는 작은 컨텍스트 윈도우 (context windows)를 위한 임시방편이었습니다. 그 임시방편이 교리 (dogma)가 되었습니다. 이제 컨텍스트 윈도우가 충분히 커졌기 때문에 더 이상 임시방편이 필요하지 않습니다.

Llama 3.2 3B Q8_0를 사용한 직접 비교: 5개 섹션의 합성 문서, 7개 질문 (4개 단일 홉 (single-hop), 3개 다중 홉 (multi-hop)):

방법 (Method)정확도 (Accuracy)실패 시 동작 (Behavior on failure)
Chunk-RAG (잘못된 섹션 검색됨)0/7모든 답변을 환각 (Hallucinated)
전체 문서 (Full Document, FP32 KV)7/7정확함
전체 문서 (Full Document, 6.4× 압축된 KV)7/7정확함 — 품질 저하 없음

Chunk-RAG의 숨겨진 실패 모드

Chunk-RAG가 잘못된 섹션을 검색할 때, 모델은 "모르겠습니다"라고 말하지 않습니다. 대신 그럴듯하게 들리는 거짓말을 생성합니다:

질문Chunk-RAG (잘못된 섹션)진실
"CTO는 누구인가요?""John Smith" ❌Maria Santos
...

이것은 아무도 측정하지 않는 운영상의 리스크입니다: 검색 실패 시 발생하는 침묵하는 환각 (silent hallucination on retrieval failure). 모니터링 시스템은 100% 가동 시간(uptime)을 보여주지만, 사용자는 잘못된 답변을 받게 됩니다.

**6.4배의 KV 압축 (KV compression)**을 통해, 5개 섹션으로 구성된 전체 문서를 16GB Mac의 컨텍스트(context) 안에 담을 수 있습니다. 모델은 섹션 간의 정보를 연결해야 하는 멀티홉 추론 (multi-hop reasoning)을 포함하여 7개의 질문 모두에 정확히 답변합니다:

"어떤 리스크가 성장 지역에 영향을 미칩니까?" → 환율 변동 (섹션 3 "Asia growth"와 섹션 5 "Asia currency risk"를 연결해야 함)

Chunk-RAG는 이를 수행할 수 없습니다. 각 청크 (chunk)가 독립적으로 검색되기 때문입니다.

이것은 "RAG가 끝났다"는 뜻이 아닙니다. 10만 개 이상의 문서 코퍼스 (corpora)를 처리하는 데 있어 RAG는 여전히 유일한 방법입니다. 하지만:

RAG는 결정합니다 (검색 문제) 어떤 문서를 찾아볼 것인가
Long-context는 결정합니다 (추론 문제) 그것들을 얼마나 깊게 이해할 것인가

문제는 두 가지 모두에 동일한 도구를 사용했다는 점이었습니다. 해결책은 각 도구를 그에 적합한 용도로 사용하는 것입니다.

5분 안에 재현하기: bench/document_level_rag_test.sh
전체 벤치마크 보고서: bench/results/document_level_rag_breakthrough.md
매니페스토 (Manifesto): docs/beyond-rag-manifesto.md

솔직한 고지: v1은 단일 3B 모델을 사용하여 7개의 질문이 포함된 합성된 5개 섹션 문서입니다. 저희는 이것이 LongBench라고 주장하는 것이 아닙니다. Chunk-RAG가 숨겨왔던 실패 모드 (failure mode)에 대해 대화를 시작하기에 충분하다는 점을 주장하는 것입니다.

v2 업데이트 — Working Memory Cliff (2026-04-11):
우리는 v1 결과에 이어, 256–2048의 컨텍스트 길이(context length)에서 1B 및 3B 모델을 대상으로 204회의 NIAH(Needle In A Haystack) 테스트를 수행했으며, 6회의 FP32 가중치(weights) 대조군 테스트를 추가했습니다. 두 모델 모두 명목상 128K인 컨텍스트 창(context window)의 1% 미만 지점에서 급격한 절벽(cliff) 현상을 보였습니다 (계단 함수(step function) 형태로, 1B Q8 모델은 512–1024에서, 3B Q4 모델은 1024–1280에서 발생). 6.4배의 KV 압축(KV compression)은 20개 셀 중 18개에서 FP32 베이스라인과 비트 단위로 동일하므로, 이 절벽 현상은 모델 자체의 특성이지 KV의 특성이나 가중치 양자화(weight-quantization)로 인한 인위적인 결과가 아닙니다. 솔직하게 재정의하자면: 'Beyond RAG'는 모델의 유효 작업 기억(effective working memory) 안에 들어오는 문서에 대해서만 작동하며, 이 유효 작업 기억은 명목상 컨텍스트 창보다 2~3 자릿수(orders of magnitude) 더 작습니다.

전체 기술 보고서: docs/paper/working-memory-cliff.md

HF 블로그 포스트 초안: docs/paper/hf-blog-draft.md

v3 업데이트 — RLV로 절벽 넘기 (2026-04-14):
만약 이 절벽이 실재한다면, 해결책은 단 한 번의 LLM 호출로 전체 문서를 작업 기억(working memory)에 담으라고 요구하는 것을 멈추는 것입니다. RLV (Read-Locate-Verify)는 gist → locate → lookup → verify → research로 이어지는 5단계 파이프라인으로, 각 단계는 약 1K 토큰의 절벽 아래를 유지하면서도 문서는 임의의 길이까지 다룰 수 있습니다. 12K 토큰의 wikitext(Llama 3.2 3B Q4의 절벽보다 약 10배 긴 길이)에서 RLV는 10/10점을 기록한 반면, verify-only 방식은 8/10점, long-context-only 방식은 1/10점을 기록했습니다. 핵심 비결은 BM25 + Reciprocal Rank Fusion이 위치를 찾아내고(locating), LLM은 오직 동점자 처리(tiebreaker) 역할만 수행한다는 점입니다. 3B 모델과 동일한 16GB Mac에서 실행되며, RAG 인덱스나 임베딩(embeddings)이 필요하지 않습니다.

bench/rlv/ · docs/phase3_rlv_challenge.md

v3.1 처리량(throughput) 업데이트 (2026-04-15):
집중적인 성능 테스트(Q4_K/Q5_K int8 fused dot, ARMv8.2 vdotq_s32, 가중치 행 프리페치(weight-row prefetch), 2-row ILP, P-core 스레드 기본 설정)를 통해 M1 Pro 환경의 모델 라인업 전반에서 CPU 생성 처리량이 +58%에서 +141%까지 향상되었습니다. Phi-3.5-mini Q8_0는 5.4 → 13.0 tok/s로 급증했습니다 (현재 llama.cpp의 순수 CPU 속도의 71% 수준). 우리는 여전히 llama.cpp의 성숙한 Metal 커널(kernels)보다 3~6배 뒤처져 있으며, 이것이 우리가 메워야 할 다음 격차입니다.

전체 수치 및 재현 방법: bench/results/2026-04-15_throughput_vs_llamacpp.md

v3.2 배치 전처리(batched prefill) (2026-04-16): 프롬프트 전처리는 llama.cpp 대비 가장 큰 격차를 보였습니다 (40~50배 느림). 새로운 tq_forward_batch 경로는 Apple AMX를 통해 배치 행렬-행렬 곱셈(batched matrix-matrix matmul)을 사용합니다 (cblas_sgemm-에서 영감을 받아, 1.2 TFLOPS). 이제 모든 지원 아키텍처(Llama 계열, FP32 KV 및 기본 turbo_kv_4b KV 압축 모드 모두)에서 기본으로 활성화됩니다. 약 250 토큰 프롬프트가 있는 Llama-3.2-1B Q8의 경우: 42.7초 → 5.9초로 엔드투엔드(기본 KV 압축을 사용했을 때 총 7.2배 개선). 출력은 토큰별 기준선과 비트 단위로 동일합니다. 커밋 ed4b087, 672fea2, f4934e9에 추가되었으며, 양자화된 K 캐시 쓰기 지원도 포함됩니다.

v3.21 ★★★ Qwen3.6-35B 117 토큰 클리프(cliff) 극복: MoE 소프트맥스 온도 조정 — 이제 qwen35moe에 기본 적용됨 (2026-04-22): 하나의 노브인 TQ_MOE_ROUTE_TEMP=2.0이 Qwen3.6-35B-A3B가 40회 이상의 이전 디버그 라운드에서 117 토큰에 머물며 반복하던

사실 관계 조사(factual probe)가 정확해졌으나, 약 150 토큰 이후의 꼬리 부분 품질(Tail quality)은 여전히 저하됩니다. 급격한 성능 저하(hard cliff) 현상은 해결되었지만, 에세이 전체 길이의 생성(full essay-length generation)에는 여전히 양자화 노이즈 마진(quantization noise margins)이 존재합니다. 선택 사항(Opt-in)이며, 기본값은 변경되지 않았습니다. 권장 설정: TQ_MOE_ROUTE_TEMP=2.0 ./build/quant Qwen3.6-35B-Q5_K_M.gguf -p "..." -n 200 --rep-penalty 1.3

. 전체 보고서: bench/results/2026-04-22_moe_temp_cliff_break.md

. v0.28.0: docs/RELEASE_NOTES.md

.

v3.20 ★★ BPE 인코딩/디코딩 (encode/decode) UTF-8 수정 — 국제 텍스트의 무음 품질 재앙 해결 (2026-04-21): encode_byte_to_bpe_chardecode_bpe_token에서 발생한 두 가지 대칭적인 버그가 모든 Llama-3 / Qwen3 계열 모델에서 비-ASCII 문자(액센트, CJK, 키릴 문자, 바이트 폴백 이모지)를 포함하는 모든 프롬프트와 출력을 조용히 손상시키고 있었습니다.

  • 인코딩(Encode): GPT-2 직접 바이트 코드포인트(direct-byte codepoints)에 대해 0x80 이상의 원시 바이트(raw bytes, 유효하지 않은 UTF-8)를 방출하여 str_lookup이 일치하지 않게 되었고, 문자들이 잘못된 낮은 ID 토큰으로 조용히 폴백(fallback)되었습니다.
  • 디코딩(Decode): 표현하고자 하는 원시 바이트 대신 U+0080-U+00FF 코드포인트의 UTF-8 인코딩을 방출하여, 출력이 이중 인코딩되었습니다 ("café" → "café").

토큰 수준의 HF(Hugging Face) 일치성(parity)을 확인했습니다: café / naïve / 日本語 / привет 모두 이제 Qwen3에서 HF AutoTokenizer와 바이트 단위로 동일하게 토큰화됩니다. 새로운 tools/refparity/ 프레임워크의 A/B 출력 차이(diff)를 통해 발견되었습니다. 또한 quant.h 단일 헤더에도 동기화되었습니다. 향후 리팩토링 시 오류를 명확히 확인할 수 있도록 scripts/test_tokenizer.sh 피스처(fixtures)를 추가했습니다. 범위: GPT-2 스타일의 바이트 수준 BPE (Llama-3.x, Qwen2.5/3.x/3.5/3.6); Gemma/Phi-3의 SentencePiece 경로는 영향을 받지 않았습니다. 회귀 테스트(Regression) 15/15 및 토크나이저 8/8 통과(PASS). v0.27.0.

16GB Mac에서의 실용적인 Qwen3.6-35B 레시피: 최상의 장문 일관성(long-form coherence)을 위해 Qwen3.6-35B-A3B-UD-Q5_K_M.gguf--rep-penalty 1.3과 함께 사용하세요. "Once upon a time in a faraway land" 문구로 측정 시 (-n 200, T=0): 기본 설정은 117 토큰에서 반복 루프에 빠지지만, Q5_K_M + rep-penalty 조합은 끝부분에서만 완만한 저하를 보이며 200 토큰 예산을 모두 소모합니다. 35B DeltaNet 드리프트(drift)는 여전히 미해결된 아키텍처 조사 과제로 남아 있으며, 이것이 현재 사용자에게 제공되는 최선의 설정입니다.

v3.19 ★ DeltaNet L2-norm 공식이 ggml과 일치함 — Qwen3.6 일관성(coherence) +36% (2026-04-21): R26의 "eps fix"는 진단은 정확했으나 공식(formulation)이 틀렸습니다. 우리는 1/sqrt(ss + eps)를 사용했습니다.

하지만 llama.cpp의 ggml_l2_norm1/max(sqrt(ss), eps)를 사용합니다.

— 입력값이 0에 가까울 경우 이 둘은 3자릿수(1e3 vs 1e6)만큼 차이가 납니다. 30개 이상의 DeltaNet 레이어와 위치(position)를 거치면서, 체계적인 K/Q 언더스케일링(under-scaling)이 누적되어 디코드 길이(decode-length) 저하로 이어집니다. 해결책: ggml과 정확히 일치시킴. Qwen3.6-35B IQ4_XS 자동 직렬화(auto-serial) "300단어 에세이 작성" 테스트 측정 결과: 117 → 160 토큰(+36%), 드리프트(drift) 발생 전 일관된 콘텐츠가 45 → 110 토큰으로 증가. 우리의 l2_normalizerefs/llama.cpp/ggml/src/ggml-cpu/ops.cpp::ggml_compute_forward_l2_norm_f32를 직접 비교(diff)하여 발견했습니다. 15/15 회귀 테스트 통과(PASS). v0.26.0.

v3.18 Qwen3.6 자동 직렬화 품질 모드 — 결정론적(determinism) 동작 + 더 긴 일관성 (2026-04-20): 발견 사항: Qwen3.6-35B 멀티스레드 행렬 곱셈(matmul)은 T=0에서 비결정론적(non-deterministic)입니다 (동일한 프롬프트로 두 번 실행 시 결과가 다름). 병렬 FP 리덕션(reduction) 순서의 변동성이 30개의 MoE 레이어와 위치 피드백을 거치며 누적되어 top-1 argmax가 뒤바뀝니다. 해결책: qwen35moe+DeltaNet 하이브리드를 자동 감지하고 -j 1을 강제 적용합니다. 수정 전: 실행 시마다 반복되는 내용이 달라지며 60-70 토큰에서 품질이 저하됨. 수정 후: 결정론적으로 동작하며, 일관된 윈도우(coherent window)가 약 95 토큰까지 확장됨. 비용: 디코드 속도가 약 2-3배 느려짐 (8 t/s 대비 3 t/s). 제외 방법: TQ_NO_AUTO_SERIAL=1

AI 자동 생성 콘텐츠

본 콘텐츠는 GitHub ML Hardware의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0