04_models.yml 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. ---
  2. # playbooks/04_models.yml
  3. # Pull and register Ollama models based on benchmark selection
  4. - name: "Models | Pull and register Ollama models"
  5. hosts: ai_server
  6. become: true
  7. gather_facts: true
  8. tags:
  9. - models
  10. vars:
  11. model_selection_file: "{{ playbook_dir }}/../benchmarks/results/model_selection.json"
  12. modelfiles_dir: /mnt/ai_data/ollama_models/modelfiles
  13. slot4_model: ""
  14. tasks:
  15. # ── Load benchmark results ───────────────────────────────────────
  16. - name: "Models | Read model_selection.json from control node"
  17. ansible.builtin.slurp:
  18. src: "{{ model_selection_file }}"
  19. delegate_to: localhost
  20. become: false
  21. register: model_selection_raw
  22. tags:
  23. - models-load
  24. - name: "Models | Parse model selection data"
  25. ansible.builtin.set_fact:
  26. model_selection: "{{ model_selection_raw.content | b64decode | from_json }}"
  27. tags:
  28. - models-load
  29. - name: "Models | Apply slot4 override if provided"
  30. ansible.builtin.set_fact:
  31. model_selection: "{{ model_selection | combine({'slot4_coding': slot4_model}) }}"
  32. when: slot4_model | length > 0
  33. tags:
  34. - models-load
  35. - name: "Models | Display selected models"
  36. ansible.builtin.debug:
  37. msg:
  38. - "Slot 1 (General Primary): {{ model_selection.slot1_general }}"
  39. - "Slot 2 (General Secondary): {{ model_selection.slot2_general }}"
  40. - "Slot 3 (Coding Primary): {{ model_selection.slot3_coding }}"
  41. - "Slot 4 (Coding Secondary): {{ model_selection.slot4_coding }}"
  42. tags:
  43. - models-load
  44. # ── Pull models ──────────────────────────────────────────────────
  45. - name: "Models | Get currently installed models"
  46. ansible.builtin.command: ollama list
  47. changed_when: false
  48. register: current_models
  49. tags:
  50. - models-pull
  51. - name: "Models | Set installed models list"
  52. ansible.builtin.set_fact:
  53. installed_model_names: >-
  54. {{ current_models.stdout_lines[1:] |
  55. default([]) |
  56. map('split') |
  57. map('first') |
  58. list }}
  59. tags:
  60. - models-pull
  61. - name: "Models | Pull slot models if not already present"
  62. ansible.builtin.command: "ollama pull {{ item }}"
  63. loop:
  64. - "{{ model_selection.slot1_general }}"
  65. - "{{ model_selection.slot2_general }}"
  66. - "{{ model_selection.slot3_coding }}"
  67. - "{{ model_selection.slot4_coding }}"
  68. when:
  69. - item | length > 0
  70. - item != 'none'
  71. - item not in installed_model_names
  72. changed_when: true
  73. loop_control:
  74. label: "Pulling {{ item }}"
  75. tags:
  76. - models-pull
  77. - name: "Models | Pull fixed models if not already present"
  78. ansible.builtin.command: "ollama pull {{ item }}"
  79. loop:
  80. - "llama3.2:3b"
  81. - "gemma3:12b-it-q4_K_M"
  82. when: item not in installed_model_names
  83. changed_when: true
  84. loop_control:
  85. label: "Pulling {{ item }}"
  86. tags:
  87. - models-pull
  88. # ── Create Modelfiles ────────────────────────────────────────────
  89. - name: "Models | Create modelfiles directory"
  90. ansible.builtin.file:
  91. path: "{{ modelfiles_dir }}"
  92. state: directory
  93. mode: "0755"
  94. owner: root
  95. group: root
  96. tags:
  97. - models-modelfile
  98. - name: "Models | Template coder-128k Modelfile"
  99. ansible.builtin.copy:
  100. content: |
  101. FROM {{ model_selection.slot3_coding }}
  102. PARAMETER num_ctx 131072
  103. SYSTEM You are an expert coding assistant. You write clean, efficient, well-documented code. Always include type hints and follow best practices.
  104. dest: "{{ modelfiles_dir }}/Modelfile.coder-128k"
  105. mode: "0644"
  106. tags:
  107. - models-modelfile
  108. - name: "Models | Template coder-32k Modelfile"
  109. ansible.builtin.copy:
  110. content: |
  111. FROM {{ model_selection.slot4_coding }}
  112. PARAMETER num_ctx 32768
  113. SYSTEM You are an expert coding assistant. You write clean, efficient, well-documented code. Always include type hints and follow best practices.
  114. dest: "{{ modelfiles_dir }}/Modelfile.coder-32k"
  115. mode: "0644"
  116. when:
  117. - model_selection.slot4_coding | length > 0
  118. - model_selection.slot4_coding != 'none'
  119. tags:
  120. - models-modelfile
  121. - name: "Models | Template llama-family Modelfile"
  122. ansible.builtin.copy:
  123. content: |
  124. FROM llama3.2:3b
  125. PARAMETER num_ctx 8192
  126. SYSTEM You are a helpful, friendly family assistant. Provide safe, age-appropriate responses suitable for all family members.
  127. dest: "{{ modelfiles_dir }}/Modelfile.llama-family"
  128. mode: "0644"
  129. tags:
  130. - models-modelfile
  131. - name: "Models | Template gemma-family Modelfile"
  132. ansible.builtin.copy:
  133. content: |
  134. FROM gemma3:12b-it-q4_K_M
  135. PARAMETER num_ctx 32768
  136. SYSTEM You are a helpful, friendly family assistant. Provide safe, age-appropriate responses suitable for all family members.
  137. dest: "{{ modelfiles_dir }}/Modelfile.gemma-family"
  138. mode: "0644"
  139. tags:
  140. - models-modelfile
  141. # ── Register models ──────────────────────────────────────────────
  142. - name: "Models | Register custom models with Ollama"
  143. ansible.builtin.command: "ollama create {{ item.name }} -f {{ modelfiles_dir }}/{{ item.file }}"
  144. loop:
  145. - { name: "coder-128k", file: "Modelfile.coder-128k" }
  146. - { name: "coder-32k", file: "Modelfile.coder-32k", slot: "{{ model_selection.slot4_coding }}" }
  147. - { name: "llama-family", file: "Modelfile.llama-family" }
  148. - { name: "gemma-family", file: "Modelfile.gemma-family" }
  149. when: item.slot is not defined or (item.slot | length > 0 and item.slot != 'none')
  150. changed_when: true
  151. loop_control:
  152. label: "Creating {{ item.name }}"
  153. tags:
  154. - models-register
  155. # ── Warmup service ───────────────────────────────────────────────
  156. - name: "Models | Template warmup script"
  157. ansible.builtin.template:
  158. src: "{{ playbook_dir }}/../templates/ollama/warmup.sh.j2"
  159. dest: /usr/local/bin/ollama-warmup.sh
  160. mode: "0755"
  161. owner: root
  162. group: root
  163. tags:
  164. - models-warmup
  165. - name: "Models | Template warmup systemd service"
  166. ansible.builtin.template:
  167. src: "{{ playbook_dir }}/../templates/ollama/ollama-warmup.service.j2"
  168. dest: /etc/systemd/system/ollama-warmup.service
  169. mode: "0644"
  170. owner: root
  171. group: root
  172. tags:
  173. - models-warmup
  174. - name: "Models | Reload systemd daemon"
  175. ansible.builtin.systemd:
  176. daemon_reload: true
  177. tags:
  178. - models-warmup
  179. - name: "Models | Enable and start warmup service"
  180. ansible.builtin.systemd:
  181. name: ollama-warmup
  182. enabled: true
  183. state: started
  184. tags:
  185. - models-warmup