Docker Model Runner
Docker Model Runner (DMR)
Docker Model Runner(DMR)로 오픈소스 AI 모델을 내 컴퓨터에서 직접 실행하는 방법을 설명해요. 모델이 Docker 안에서 돌아가서 API 키도 필요 없고 데이터도 PC 밖으로 나가지 않아요.
출처: 문서
본문
Docker Model Runner(DMR)를 쓰면 오픈소스 AI 모델을 내 컴퓨터에서 직접 실행할 수 있어요. 모델이 Docker에서 돌기 때문에 API 키가 필요 없고, 데이터가 기기를 벗어나지 않아요.
Docker Agent는 DMR에서 이미 내려받은 모델을 자동으로 발견해요. 명시적으로 모델을 설정하지 않으면 자동 선택이 로컬에 설치된 모델을 우선해요(에이전트 YAML의 model: 키로 지정된 모델이 로컬에 이미 있다면 그것을, 아니면 사용 가능한 첫 번째 비-임베딩 모델을 선택). 항상 ai/qwen3:latest로 기본 설정되고 pull 프롬프트를 띄우지는 않아요.
팁 API 키가 필요 없어요 DMR은 로컬에서 모델을 실행해요 — 데이터가 기기를 벗어나지 않죠. 개발, 민감 데이터, 오프라인 사용에 좋아요.
사전 준비
- Model Runner 기능이 활성화된 Docker Desktop
- 확인:
docker model status --json
구성
인라인
agents:
root:
model: dmr/ai/qwen3
네임드 모델
models:
local:
provider: dmr
model: ai/qwen3
max_tokens: 8192
사용 가능한 모델
Docker Model Runner로 사용할 수 있는 모델은 모두 쓸 수 있어요. 흔한 선택지:
| 모델 | 설명 |
|---|---|
ai/qwen3 |
Qwen 3 — 다재다능, 코딩과 일반 작업에 좋음 |
ai/llama3.2 |
Llama 3.2 — Meta의 오픈소스 모델 |
런타임 플래그
provider_opts.runtime_flags로 기반 추론 런타임(예: llama.cpp)에 플래그를 전달해요:
models:
local:
provider: dmr
model: ai/qwen3
max_tokens: 8192
provider_opts:
runtime_flags: ["--threads", "8"]
런타임 플래그는 단일 문자열도 받아요:
provider_opts:
runtime_flags: "--threads 8"
Model Runner 백엔드가 허용하는 플래그만 사용하세요(docker model configure --help와 백엔드 문서 참고). 샘플링 파라미터(temperature, top_p, 페널티)는 runtime_flags에 넣지 말고 모델(temperature, top_p 등)에 설정하세요. 그것들은 OpenAI 호환 채팅 API로 요청마다 전송돼요.
컨텍스트 크기
max_tokens는 채팅 완성 요청당 최대 출력 토큰 수를 제어해요. 엔진의 전체 컨텍스트 윈도우를 설정하려면 provider_opts.context_size를 사용하세요:
models:
local:
provider: dmr
model: ai/qwen3
max_tokens: 4096 # 최대 출력 토큰 (요청당)
provider_opts:
context_size: 32768 # 전체 컨텍스트 윈도우 (_configure로 전송)
context_size를 생략하면 Model Runner가 자체 기본값을 사용해요. max_tokens는 컨텍스트 윈도우로 쓰이지 않아요.
Docker Agent의 자동 압축은 요약 및 유지 꼬리 토큰 예산을 context_size에 비례해 조정해요. 이렇게 해서 작은 컨텍스트 윈도우에서도 압축이 올바르게 동작해요 — 예를 들어 8k 토큰 로컬 모델도 압축 중에 세션 기록이 지워지지 않아요.
Thinking / 추론 예산
llama.cpp 백엔드를 쓸 때 thinking_budget은 _configure에서 구조화된 llamacpp.reasoning-budget으로 전송돼요(--reasoning-budget에 매핑). 문자열 노력 값은 다른 프로바이더와 같은 토큰 매핑을 쓰고, adaptive는 무제한(-1)에 매핑돼요.
vLLM 백엔드를 쓸 때 thinking_budget은 각 채팅 완성 요청에서 thinking_token_budget으로 전송돼요. 노력 레벨은 다른 프로바이더와 같은 척도로 토큰 수에 매핑되고, adaptive는 무제한(-1)에 매핑돼요.
models:
local:
provider: dmr
model: ai/qwen3
thinking_budget: medium # llama.cpp: reasoning-budget=8192; vLLM: thinking_token_budget=8192
MLX와 SGLang 백엔드에서는 thinking_budget이 조용히 무시돼요 — 그 엔진들은 현재 요청별 추론 토큰 예산 손잡이를 노출하지 않아요.
vLLM 전용 구성
vLLM 백엔드에서 모델을 실행할 때 추가 엔진 레벨 설정을 provider_opts로 전달하면 model-runner의 _configure 엔드포인트로 전달돼요:
- gpu_memory_utilization — vLLM이 사용할 GPU 메모리 비율(0.0–1.0). 이 범위 밖의 값은 거부돼요.
models:
vllm-local:
provider: dmr
model: ai/some-model-safetensors
provider_opts:
gpu_memory_utilization: 0.9
hf_overrides:
max_model_len: 8192
dtype: bfloat16
hf_overrides 키(중첩 포함)는 ^[a-zA-Z_][a-zA-Z0-9_]*$와 일치해야 해요 — model-runner가 서버 측에서 플래그 주입을 막기 위해 적용하는 것과 같은 규칙이에요. 잘못된 키는 클라이언트 생성 시점에 거부돼서 왕복을 기다리지 않고 즉시 실패하게 해요.
이 옵션들은 vLLM이 아닌 백엔드에서는 무시돼요.
모델을 메모리에 유지하기 (keep_alive)
기본적으로 model-runner는 몇 분 사용하지 않으면 유휴 모델을 언로드해요. provider_opts.keep_alive로 유휴 제한 시간을 바꾸세요:
models:
sticky:
provider: dmr
model: ai/qwen3
provider_opts:
keep_alive: "30m" # 기간 문자열
# keep_alive: "0" # 각 요청 후 즉시 언로드
# keep_alive: "-1" # 계속 로드 유지
허용 값: 모든 Go 기간 문자열("30s", "5m", "1h", "2h30m"), "0"(즉시 언로드), "-1"(절대 언로드 안 함). 잘못된 값은 configure 요청이 보내지기 전에 거부돼요.
에이전트 전환 시 모델 언로드
두 DMR 모델을 GPU 메모리에 동시에 못 넣는 멀티 에이전트 구성이라면, 각 에이전트의 on_agent_switch 체인에 unload 내장 훅을 연결하세요. 활성 에이전트가 제어권을 넘길 때마다, 런타임이 엔진의 _unload 엔드포인트로 POST해서 다음 모델이 로드되기 전에 이전 모델의 리소스를 해제해요:
agents:
coder:
model: qwen3-large
handoffs: [reviewer]
hooks:
on_agent_switch:
- type: builtin
command: unload
reviewer:
model: qwen3-coder
handoffs: [coder]
hooks:
on_agent_switch:
- type: builtin
command: unload
unload URL은 base_url에서 끝의 /v1 세그먼트를 바꿔서 파생돼요(예: http://127.0.0.1:12434/engines/llama.cpp/v1/ → http://127.0.0.1:12434/engines/llama.cpp/_unload). 비표준 model-runner 배포를 상대할 때는 프로바이더 레벨 unload_api 필드로 명시적으로 덮어쓰세요:
providers:
my_dmr:
provider: dmr
base_url: http://model-runner.docker.internal/engines/v1
unload_api: /engines/_unload # 기본값; 절대 URL도 동작
models:
big:
provider: my_dmr
model: ai/qwen3
unload 오류는 로그에 남기고 삼켜져요 — 막히거나 도달 불가능한 엔진이 에이전트 전환을 막지 않아요(각 호출은 10초로 제한). 이걸 keep_alive와 함께 쓰는 건 단일 에이전트 실행 내 유휴 시간에도 모델이 살아남길 원할 때만 하세요. 훅은 에이전트 사이 언로드를 독립적으로 제어해요.
경고 단일 테넌트 가정
_unload엔드포인트는 엔진 레벨이에요: 누가 쓰는지와 무관하게 DMR 메모리에서 모델을 내보내요. 같은 런타임에서 동시 세션 두 개(여러 사용자를 서빙하는 API 서버 등)가 같은 에이전트를 건드리면, 세션 A에서 전환할 때 세션 B의 진행 중 요청 아래에서 모델이 뽑혀서 재로드를 기다려야 해요. 이 모델을 쓰는 에이전트를 동시에 실행하지 않을 때만unload를 연결하세요 — 보통 단일 TUI/CLI 세션에서요.
전체 예시는 examples/unload_on_switch.yaml을 참고하세요.
운영 모드 (mode)
model-runner은 보통 요청 경로에서 백엔드 모드를 추론해요. provider_opts.mode로 명시적으로 고정할 수 있어요:
provider_opts:
mode: embedding # 값 중 하나: completion, embedding, reranking, image-generation
대부분의 에이전트는 이게 필요 없어요. 꼭 필요할 때만 설정하세요.
원시 런타임 플래그 (raw_runtime_flags)
runtime_flags(리스트)가 플래그를 전달하는 선호 방식이에요. 이미 만들어진 커맨드라인 문자열을 그대로 보내고 싶다면 raw_runtime_flags를 대신 쓰세요:
provider_opts:
raw_runtime_flags: "--threads 8 --batch-size 512"
Model-runner는 그 문자열을 셸 방식 단어 분리로 파싱해요. runtime_flags와 raw_runtime_flags는 상호 배타적이에요 — 둘 다 설정하면 오류예요.
추측 디코딩 (Speculative Decoding)
작은 드래프트 모델로 토큰을 미리 예측해 추론을 빠르게:
models:
fast-local:
provider: dmr
model: ai/qwen3:14B
max_tokens: 8192
provider_opts:
speculative_draft_model: ai/qwen3:0.6B-F16
speculative_num_tokens: 16
speculative_acceptance_rate: 0.8
커스텀 엔드포인트
base_url을 생략하면 Docker Agent가 DMR 엔드포인트를 자동 발견해요. 수동으로 설정하려면:
models:
local:
provider: dmr
model: ai/qwen3
base_url: http://127.0.0.1:12434/engines/llama.cpp/v1
문제 해결
- 플러그인을 찾을 수 없음: Docker Desktop에서 Docker Model Runner가 활성화되어 있는지 확인하세요. Docker Agent는 기본 URL로 폴백해요.
- 엔드포인트가 비어 있음:
docker model status --json으로 Model Runner가 실행 중인지 확인하세요. - 성능:
runtime_flags로 GPU 레이어(--ngl)와 스레드 수(--threads)를 조정해 보세요.
더 알아보기 (Learn more)
- Provider 정의 문서에서 커스텀 프로바이더 설정 자세히 보기
- Model Providers 개요에서 다른 프로바이더 살펴보기