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:
Hermes Agent service account
2026-08-06 09:08:33 -05:00
parent 79edb8f4e1
commit d10255297c
6 changed files with 181 additions and 8 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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"