GGUF에는 가중치 외에 무엇이 들어 있고, 아직 무엇이 빠져 있나?
요약
GGUF는 llama.cpp가 사용하는 언어 모델 파일 포맷으로, 실행에 필요한 메타데이터를 단일 파일로 통합하여 배포와 로딩을 간소화합니다. 이 형식은 특수 토큰, 권장 샘플러 설정, 심지어 샘플러 체인 순서까지 담을 수 있게 되었습니다. 하지만 도구 호출 형식의 표준화나 프로젝션 모델 번들링 등 일부 기능 구현에 여전히 개선할 부분이 남아있습니다.
핵심 포인트
- GGUF는 언어 모델 실행에 필요한 모든 구성요소를 단일 파일로 통합하여 배포 및 로딩을 단순화하는 것이 핵심 장점입니다.
- 채팅 템플릿은 Jinja2와 같은 프로그래밍 언어를 기반으로 하며, 대화 구조, 도구 호출, 멀티미디어 메시지 인코딩 등 복잡한 처리를 담당합니다.
- GGUF는 특수 토큰(예: 종료 토큰)과 권장 샘플러 설정 및 샘플러 체인 순서까지 명시할 수 있도록 업데이트되었습니다.
- 도구 호출 형식은 모델마다 달라 추론 엔진별 하드코딩이 필요하며, 문법 기반 파서 생성이 표준 개선 후보로 남아있습니다.
GGUF는 llama.cpp가 쓰는 언어 모델 파일 형식으로, 실행에 필요한 메타데이터를 단일 파일에 담아 모델 배포와 로딩을 단순하게 만듦
채팅 템플릿은 Jinja2 스크립트로 대화 형식, 도구 호출, 멀티미디어 메시지 인코딩을 처리하지만 구현체별 동작 차이가 있음
- GGUF는 종료 토큰 같은
특수 토큰과 권장 샘플러 설정을 담을 수 있고, 최근에는 샘플러 체인 순서도 명시 가능해짐 - 아직
도구 호출 형식은 모델마다 달라 추론 엔진별 하드코딩이 필요하며, 문법 기반 파서 생성이 표준 개선 후보로 남아 있음
think_token
, 프로젝션 모델 번들링, 기능 플래그가 부족해 생각 구간 분리, 멀티모달 구성, 지원 기능 감지가 여전히 어려움
GGUF가 담는 것
- GGUF는 llama.cpp가 언어 모델에 사용하는 파일 형식
- GGUF의 핵심 장점은 모델 실행에 필요한 여러 구성요소를
단일 파일에 담는다는 데 있음 - GGUF는 이런
부가 정보를 한 파일에 넣어 모델을 더 쉽게 다루게 해줌
채팅 템플릿
- 대화형 언어 모델은 특정 형식의 토큰 시퀀스로 학습되며, 이 형식은 대화 구조처럼 보임
- Gemma4 형식 예시는 다음과 같음
<|turn>user
Hi there!<turn|>
<|turn>model
Hi there, how can I help you today?<turn|>
<s>
<|im_start|>user Hi there!<|im_end|>
<|im_start|>assistant Hi there, how can I help you today?<|im_end|>
-
실제 템플릿은
추론 블록, 도구 설명, 도구 호출과 응답, 이미지·오디오·비디오 같은 멀티미디어 메시지 인코딩까지 포함하면서 훨씬 복잡해짐 -
이런 처리는
채팅 템플릿이 맡으며, Jinja2 템플릿 언어로 작성된 스크립트 -
모델은 여러 개의 채팅 템플릿을 가질 수 있음
-
도구 호출을 지원하는 템플릿과 지원하지 않는 템플릿이 따로 있을 수 있음
-
대부분의 모델은 단일 거대 채팅 템플릿을 제공하고, 도구가 지정된 경우에만 도구 호출 관련 처리를 함
-
일부 모델에서는 도구 전용 채팅 템플릿을 별도로 찾아야 함
-
Jinja2는 루프, 조건문, 할당, 리스트, 딕셔너리 등을 가진
프로그래밍 언어에 가까움 -
대화형 LLM 애플리케이션은 새 메시지가 추가될 때마다 Gemma가 제공하는 약 250줄짜리 Jinja 스크립트 같은 프로그램을 실행할 인터프리터를 포함해야 함
-
구현체별 Jinja 처리 방식도 서로 다름
-
Hugging Face transformers는 Python의 기존 jinja2 라이브러리를 사용함
-
llama.cpp의
llama-server
와 llama-cli
는 자체 Jinja 구현을 사용함
libllama
API에 노출된 llama_chat_apply_template는 소수의 채팅 형식을 C++에 직접 하드코딩한 옛 방식
-
NobodyWho는 Jinja 원작자가 Rust로 다시 구현한 minijinja를 사용함
-
이는 llama.cpp가 한때 사용했던 미니멀 Jinja 라이브러리 minja와는 다름
-
Jinja 구현체 사이에는 상당한 성능 차이가 있음
-
로컬 LLM 애플리케이션에서 채팅 템플릿 처리는 성능 병목이 아니므로 큰 논쟁거리는 아님
특수 토큰
-
언어 모델은 입력된 토큰 시퀀스에 대해 다음 토큰을 계속 출력할 수 있으므로, 생성을 멈출 방법이 필요함
-
일반적인 해법은
종료 토큰을 두고, 모델이 이 토큰을 내보내면 추론 엔진이 생성을 멈추는 방식 -
종료 토큰은
특수 토큰의 한 예 -
특수 토큰은 일반적으로 토큰화된 문자 이상의 의미를 가짐
-
보통 사용자에게 보여주지 않아야 하지만, 텍스트 표현을 갖는 경우가 많아 표시 자체는 가능함
-
Gemma4의 일부 특수 토큰 예시는 다음과 같음
1
/ <eos>
: 시퀀스 종료이며, 모델이 생성을 멈추기 위해 출력함
2
/ <bos>
: 시퀀스 시작이며, 입력 앞에 붙음
46
/ <|tool_call>
: 도구 호출의 시작을 표시함
47
/ <tool_call|>
: 도구 호출의 끝을 표시함
105
/ <|turn>
: 대화 턴의 시작을 표시함
106
/ <turn|>
: 대화 턴의 끝을 표시함
샘플러 설정과 순서
-
언어 모델은 다음 토큰 확률 분포를 출력하며, 이 분포에서 토큰을 고르는 과정을
샘플링이라고 함 -
가장 단순한 방식은 가중치가 적용된 분포에서 무작위로 선택하는 것
-
실제로는 구체적 토큰을 선택하기 전에 확률 분포에 변환을 적용하면 더 나은 결과를 얻을 수 있음
-
연구소가 새 모델을 배포할 때 특정
권장 샘플러 설정을 함께 제공하는 경우가 많음 -
사용자가 더 나은 응답을 얻기 위해 Markdown 파일 등에서 값을 복사해 붙여넣는 일도 잦음
-
NobodyWho는 사용자의 수동 복사를 줄이기 위해 Hugging Face 페이지에 선별 모델을 올리고, 자체 형식으로 권장 샘플러 설정을 묶어 제공했음
-
동작은 했지만, 모델이 유용해지려면 NobodyWho 쪽 변환이 필요했음
-
GGUF 형식에 최근 추가된 기능으로 샘플러 체인을 모델 파일 안에 직접 명시할 수 있게 됨
-
이로 인해 NobodyWho의 자체 형식은 불필요해졌고, 이는 원하던 결과였음
-
llm-sampling 웹앱에서는 서로 다른 샘플러 단계의 역할을 빠르게 확인할 수 있음
-
개별 단계를 드래그 앤드 드롭하면, 샘플링 단계의
순서가 최종 분포에 큰 차이를 만들 수 있음 -
Ollama 이미지의 JSON 파일이나 Hugging Face의
generation_config.json
을 포함한 많은 샘플러 설정 형식은 샘플링 단계의 순서를 명시할 방법이 없음
- GGUF 표준은
general.sampling.sequence
필드로 샘플링 순서를 지정할 수 있음
- 여전히 많은 GGUF 모델은 이 필드를 생략하고 llama.cpp의 기본 동작이라는 암묵적 순서에 의존함
아직 빠진 것들
- 좋은 추론 엔진은 다양한 언어 모델에 대해
통합 인터페이스를 제공하려 함 - GGUF 메타데이터의 부가 정보를 파싱하고 활용하면 모델별 코드 경로를 많이 줄일 수 있음
도구 호출 형식
- 거의 모든 추론 엔진은 서로 다른
도구 호출 형식을 파싱하기 위한 하드코딩 경로를 갖고 있음 - Qwen3의 도구 호출 형식 예시는 다음과 같음
<tool_call>{"name": "get_weather", "arguments": {"location": "Copenhagen"}}</tool_call>
- Qwen3.5의 도구 호출 형식 예시는 다음과 같음
<tool_call>
<function=get_weather>
<parameter=city>
Copenhagen
</parameter>
</function>
</tool_call>
- Gemma4의 도구 호출 형식 예시는 다음과 같음
<|tool_call>call:get_weather{city:<|"|>Copenhagen<|"|>}<tool_call|>
-
새 모델이 나오면 여러 추론 엔진이 각자 파서를 구현해야 하는 상태
-
모델 파일에 문법(grammar)이 포함되고, 그 문법에서 파서를 도출할 수 있다면 GGUF 표준에 훌륭한 추가가 될 수 있음
-
NobodyWho는 전달된 특정 도구에 맞춰
제약 문법을 생성하는 단계를 추가로 수행함 -
이를 통해 도구 호출의 타입 안전성을 보장할 수 있음
-
특히 1B 이하의 작은 모델이 정수가 필요한 곳에 float을 넘기는 식으로 실수할 수 있어 유용함
-
일반 도구 호출 파서를 만들 수 있는 문법이 있더라도, NobodyWho는 전달된 구체적 도구별 문법을 생성하는 함수는 계속 구현해야 함
-
특정 도구에 맞는 구체 문법을 만들고 거기서 파서를 도출할 수 있는
메타 문법 형식은 흥미로운 문제로 남아 있음
Think 토큰
- 빠진 항목 중 가장 쉽게 추가할 수 있는 부분
- 업스트림 Hugging Face 저장소는
think_token
필드를 포함하기 시작했음
think_token
은 생성된 출력의 생각 구간을 분리하는 데 매우 유용함
-
생각 구간은 일반적으로 제거하거나 본문 출력과 다르게 렌더링해야 함
-
다운스트림 GGUF 변환본은 이 필드를 보통 포함하지 않음
-
그 결과 GGUF 기반 추론 엔진은 특정 모델 계열별 코드를 따로 쓰지 않고는 생각 스트림을 본문 출력에서 분리할 수 없음
-
표준 GGUF 변환 파이프라인에
think_token
을 추가하면 이 문제가 해결됨
프로젝션 모델
-
이미지와 오디오를 텍스트가 아니라 LLM이 네이티브로 볼 수 있게 하는
멀티모달 LLM 상호작용에는 비텍스트 입력 처리를 위한 추가 모델이 필요함 -
이 추가 모델은
프로젝션 모델로 불림 -
현재 관례는 두 개의 GGUF 파일을 전달하는 방식
-
하나는 주 언어 모델용 GGUF
-
다른 하나는 이미지와 오디오 처리를 위한 더 작은 모델
-
이 방식은 GGUF의 단일 파일 편의성을 깨뜨림
-
단일 GGUF 파일이 주 파일 안에 프로젝션 모델의 가중치와 설정을 함께 묶을 수 있다면 큰 개선이 됨
-
프로젝션 모델은 종종 약 1GB 크기
-
사용하지 않을 때는 이 오버헤드를 피하고 싶을 만큼 큼
-
프로젝션 가중치가 포함된 GGUF와 포함되지 않은 GGUF 두 가지 변형을 제공하는 방식은 합리적임
-
이렇게 하면 다운로드할 URL 하나, 디스크에 캐시할 파일 하나만 관리하는 상태로 돌아갈 수 있음
지원 기능 목록
-
모델마다 지원하는 기능이 다르며, GGUF 파일만 보고 실제 지원 기능을 쉽게 감지하기 어려움
-
일부 모델은 이미지 입력을 지원하고 일부는 지원하지 않음
-
현재 가장 나은 처리는 프로젝션 모델이 전달되면 이미지 지원이 있다고 가정하는 방식
-
일부 모델은 네이티브 도구 호출을 지원하고 일부는 지원하지 않음
-
현재 가장 나은 처리는 채팅 템플릿에서 도구 JSON 스키마 목록을 렌더링하려는 부분이 있는지 문자열 부분 일치로 확인하는 방식
-
이는 명백히 임시방편
-
일부 모델은 생각 블록을 출력하고 일부는 출력하지 않음
-
생각 태그가 보통 GGUF 메타데이터에 없기 때문에, 모델에서 생각 블록을 기대해도 되는지 확인할 좋은 방법이 불분명함
-
GGUF 커뮤니티가 모델 파일에
기능 플래그를 추가하면 모델 비의존 추론 라이브러리가 더 일관된 오류 메시지와 경고를 제공할 수 있음 -
예를 들어 네이티브 도구 호출을 지원하지 않는 모델에 도구 호출을 시도할 때 더 적절한 안내가 가능해짐
결론
- GGUF는 모델을 올바르게 실행하는 데 필요한 부가 정보를
단일 파일로 담아, 모델별 코드 경로를 많이 추가하지 않아도 되게 함 - GGUF는 개방적이고 확장 가능한 형식이며, 강한 커뮤니티를 갖고 있음
- 표준을 함께 강화하면 좋은 개발자 경험을 유지하면서도 애플리케이션에서 모델을 쉽게 교체할 수 있음
- GGUF 메타데이터는 이미 유용한 부분이 많지만, 도구 호출 문법,
think_token
, 프로젝션 모델 번들링, 기능 플래그 같은 개선 여지가 남아 있음
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기