llm-inference-multimodel: add Qwen2.5-14B shadow instance (port 8002, gated off — VRAM co-residency not yet confirmed)
- New llama-server-qwen systemd unit template, gated by llm_qwen_service_enabled (default false) - Idempotent GGUF download task (bartowski Qwen2.5-14B-Instruct-Q5_K_M, stat-guarded) - Launch flags per local-llm-64k-context-recommendation.md: ctx-size 65536, flash-attn, q8_0 KV cache, batch 2048/ubatch 512, jinja, parallel 1 - verify.yml only starts/verifies the qwen unit when llm_qwen_service_enabled=true - README: documents live VRAM gate finding (nvidia-smi 2026-08-06: Phi-4+Mistral already ~16.6/24GB, ~7.5GB free -- insufficient for Qwen weights concurrently) and options - Does NOT touch llama-server-aux (8000) or llama-server-toolcall (8001) service state
This commit is contained in:
@@ -97,3 +97,28 @@
|
||||
group: "{{ llm_service_user }}"
|
||||
mode: "0644"
|
||||
become: true
|
||||
|
||||
# --- Shadow model (Qwen2.5-14B-Instruct Q5_K_M, port 8002) --------------------
|
||||
# Downloaded unconditionally (so the ~10.5GB file is staged ahead of any VRAM
|
||||
# decision) — only the *service start* is gated by llm_qwen_service_enabled
|
||||
# (see verify.yml / VRAM gate note in defaults/main.yml).
|
||||
|
||||
- name: Check if Qwen shadow model GGUF already exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ llm_qwen_model_path }}"
|
||||
register: llm_qwen_model_stat
|
||||
|
||||
- name: Download Qwen2.5-14B-Instruct-Q5_K_M GGUF (bartowski quant)
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ llm_qwen_model_url }}"
|
||||
dest: "{{ llm_qwen_model_path }}"
|
||||
headers:
|
||||
Authorization: "Bearer {{ llm_hf_token }}"
|
||||
owner: "{{ llm_service_user }}"
|
||||
group: "{{ llm_service_user }}"
|
||||
mode: "0644"
|
||||
timeout: 7200
|
||||
force: false
|
||||
become: true
|
||||
no_log: true
|
||||
when: not llm_qwen_model_stat.stat.exists or (llm_qwen_model_stat.stat.size | int) < (llm_qwen_model_min_bytes | int)
|
||||
|
||||
@@ -41,6 +41,18 @@
|
||||
notify:
|
||||
- reload systemd
|
||||
|
||||
- name: Deploy llama-server-qwen systemd unit (shadow, port 8002)
|
||||
ansible.builtin.template:
|
||||
src: llama-server-qwen.service.j2
|
||||
dest: "/etc/systemd/system/{{ llm_qwen_service_name }}.service"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
become: true
|
||||
register: llm_qwen_unit_deployed
|
||||
notify:
|
||||
- reload systemd
|
||||
|
||||
- name: Flush handlers so daemon-reload lands before any later phase acts on unit state
|
||||
ansible.builtin.meta: flush_handlers
|
||||
|
||||
|
||||
@@ -166,6 +166,51 @@
|
||||
- "Design estimate (plan §1): aux ~{{ llm_aux_expected_vram_gb }}GB + toolcall ~{{ llm_toolcall_expected_vram_gb }}GB = ~{{ llm_combined_expected_vram_gb }}GB / {{ llm_gpu_total_vram_gb }}GB total"
|
||||
- "If measured usage exceeds ~23.5GB or is within ~0.5GB of the 24GB card limit, treat as the OOM-risk trigger condition from plan §6 — do not leave both services running unattended without confirming headroom."
|
||||
|
||||
- name: Enable llama-server-qwen and start/restart (GATED — only if llm_qwen_service_enabled)
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ llm_qwen_service_name }}"
|
||||
state: "{{ 'restarted' if (llm_qwen_unit_deployed.changed | default(false)) else 'started' }}"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
become: true
|
||||
when: llm_qwen_service_enabled | default(false)
|
||||
|
||||
- name: NOTE if Qwen shadow unit was skipped due to VRAM gate
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
llama-server-qwen unit deployed to disk but NOT started
|
||||
(llm_qwen_service_enabled=false). See VRAM gate note in
|
||||
defaults/main.yml / deployment report — Phi-4(8000)+Mistral(8001)
|
||||
already use ~16.6GB/24GB, leaving ~7.5GB free, insufficient for
|
||||
Qwen2.5-14B's ~10-12GB weight footprint concurrently. Resolve before
|
||||
setting llm_qwen_service_enabled: true.
|
||||
when: not (llm_qwen_service_enabled | default(false))
|
||||
|
||||
- name: Wait for Qwen shadow instance API to become available (only if enabled)
|
||||
ansible.builtin.uri:
|
||||
url: "http://{{ llm_bind_address }}:{{ llm_qwen_port }}/health"
|
||||
status_code: 200
|
||||
register: llm_qwen_health
|
||||
retries: 24
|
||||
delay: 10
|
||||
until: llm_qwen_health.status == 200
|
||||
when: llm_qwen_service_enabled | default(false)
|
||||
|
||||
- name: Smoke-test — Qwen shadow instance model listing + n_ctx verification (only if enabled)
|
||||
ansible.builtin.uri:
|
||||
url: "http://{{ llm_bind_address }}:{{ llm_qwen_port }}/v1/models"
|
||||
status_code: 200
|
||||
return_content: true
|
||||
register: llm_qwen_models
|
||||
when: llm_qwen_service_enabled | default(false)
|
||||
|
||||
- name: Report Qwen shadow instance served model + verified n_ctx (only if enabled)
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Qwen shadow (:{{ llm_qwen_port }}) serving: {{ llm_qwen_models.json.data | map(attribute='id') | list }}"
|
||||
- "Verified n_ctx (must be >= 64000, not just requested): {{ llm_qwen_models.json.data | map(attribute='meta') | map(attribute='n_ctx') | list }}"
|
||||
when: llm_qwen_service_enabled | default(false)
|
||||
|
||||
- name: Check for OOM-kill events related to llama-server in dmesg (best-effort, read-only)
|
||||
ansible.builtin.shell:
|
||||
cmd: "dmesg | grep -i 'llama-server' | grep -i -E 'oom|killed' || true"
|
||||
|
||||
Reference in New Issue
Block a user