{"id":601,"date":"2026-03-01T15:29:32","date_gmt":"2026-03-01T14:29:32","guid":{"rendered":"https:\/\/blog.sguazz.it\/?p=601"},"modified":"2026-03-30T08:56:06","modified_gmt":"2026-03-30T07:56:06","slug":"la-ia-in-cantina","status":"publish","type":"post","link":"https:\/\/blog.sguazz.it\/index.php\/archives\/601","title":{"rendered":"La IA in cantina"},"content":{"rendered":"\n<p>Sto cercando di capire come funzioni una IA. Non mi riferisco alla matematica o agli algoritmi che ci sono dietro, ma alla composizione di un qualcosa da interrogare, possibilmente <em>open source<\/em> e possibilmente che sfrutti la scheda grafica Intel B580 del server in cantina.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Un po&#8217; di terminologia<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>ollama<\/strong>, \u00e8 una specie di frontend che espone in maniera semplificata (ma non ancora semplice) le potenzialit\u00e0 di una IA, in particolare di quella che si chiama llama.cpp. ollama offre funzionalit\u00e0 per scaricare e gestire i vari modelli, offre una interfaccia REST per l&#8217;accesso alla IA, e cose simii;<\/li>\n\n\n\n<li><strong>llama.cpp<\/strong>, \u00e8 un motore di inferenza scritto in C++ che utilizza i modelli GGUF e che ha la possibilit\u00e0 di accelerare grazie all&#8217;hardware delle schede video. Una caratteristica di llama.cpp \u00e8 che se il modello in uso utilizza pi\u00f9 RAM di quanta ne abbia la scheda video, allora viene usata anche la memoria RAM del computer;<\/li>\n\n\n\n<li><strong>Open-WebUI<\/strong>, \u00e8 una interfaccia web che permette l&#8217;interazione con un motore di inferenza tramite i protocolli di ollama oppure di OpenAI;<\/li>\n\n\n\n<li><strong>quantizzazione<\/strong>, indicata con sigle tipo Q4_K_M, Q5_K_M, \u00e8 una modalit\u00e0 di memorizzazione del modello in formato ridotto: anzich\u00e9 contenere i pesi interi da 16 e 32 bit in virgola mobile, si memorizzano valori approssimati usando meno bit. Il metodo per approssimare prevede di usare fattori di scala e altri stratagemmi, che valgono spesso per pi\u00f9 quanti successivi, da cui l&#8217;opzione del raggruppamento. La lettera <strong>Q<\/strong> indica appunto che parliamo di quantizzazione, il numero successivo indica il numero di bit occupati da ogni quanto, la lettera <strong>K<\/strong> indica che la quantizzazione \u00e8 fatta a gruppi ed \u00e8 contrapposta al numero <strong>0<\/strong> che indica una quantizzazione non raggruppata, la lettera <strong>M<\/strong> indica una precisione media contrapposta alle lettere <strong>S<\/strong> (precisione piccola, maggiore velocit\u00e0) e <strong>L<\/strong> (grande precisione, maggiore lentezza);<\/li>\n\n\n\n<li><strong>perplexity<\/strong>, se si utilizza la quantizzazione si va incontro ad una approssimazione, quindi ad un errore. Per misurare questo errore si fa riferimento ad un valore chiamato perplexity: minore \u00e8 il valore, migliore \u00e8 l&#8217;approssimazione;<\/li>\n\n\n\n<li><strong>GGUF<\/strong>, \u00e8 un formato di file binari che descrivono un modello. Si tratta di una sigla inglese che vuol dire \u00abFormato unificato generato da GPT\u00bb. Questo formato \u00e8 l&#8217;evoluzione del precedente, chiamato GGML \u00abLinguaggio modello generato da GPT\u00bb. Il formato GGUF \u00e8 adottato da vari motori di inferenza;<\/li>\n\n\n\n<li><strong>SYCL<\/strong>: \u00e8 uno dei backend che permettono di sfruttare la scheda video, in particolare \u00e8 quello utilizzato fino a gennaio 2026 da pkix-llm per utilizzare le schede Intel;<\/li>\n\n\n\n<li><strong>vulkan<\/strong>, \u00e8 un backend per utilizzare le schede video, ma pi\u00f9 generico del SYCL, difatti gestisce schede video Intel, AMD e nVidia e funziona su Linux, MacOS e Windows,<\/li>\n\n\n\n<li><strong>ROCm<\/strong>, \u00e8 un backend per utilizzare le schede video AMD.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Proviamo!<\/h2>\n\n\n\n<p>Partiamo dal compilare llama.cpp per farne una immagine da usare con docker. Il progetto llama.cpp ha gi\u00e0 un dockerfile che prepara un immagine con il compilatore (attualmente basata su Ubuntu 26.04) e che viene lanciata per compilare il tutto e creare una immagine docker finale. La compilazione dura pochi minuti e genera l&#8217;immagine <strong>llama-cpp-vulkan<\/strong> gi\u00e0 pronta tra quelle di docker.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># git clone https:\/\/github.com\/ggml-org\/llama.cpp.git\n# cd llama.cpp.git\n# docker build -t llama-cpp-vulkan -f .devops\/vulkan.Dockerfile .\n&#91;...]\n# docker image ls llama-cpp-vulkan\nREPOSITORY         TAG       IMAGE ID       CREATED         SIZE\nllama-cpp-vulkan   latest    83854865d087   5 minutes ago   501MB<\/code><\/pre>\n\n\n\n<p>Facciamo un primo test, che attiva il container, controlla e riconosce l&#8217;hardware e scarica un piccolo modello. Per dare dello spazio disco nel quale scaricare il modello, uso la mia directory \/srv\/nfs\/docker\/modelli_ollama\/models:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># docker run -it --rm -v \"\/srv\/nfs\/docker\/modelli_ollama\/models:\/root\/.cache\/llama.cpp:Z\" --device \/dev\/dri\/renderD128:\/dev\/dri\/renderD128 --device \/dev\/dri\/card0:\/dev\/dri\/card0 llama-cpp-vulkan -hf ggml-org\/gemma-3-1b-it-GGUF\n&#91;...]\n<strong>ggml_vulkan: 0<\/strong> = Intel(R) Arc(tm) B580 Graphics (BMG G21) (Intel open-source Mesa driver) | uma: 0 | fp16: 1 | bf16: 1 | warp size: 32 | shared memory: 49152 | int dot: 1 | matrix cores: KHR_coopmat\nload_backend: loaded Vulkan backend from \/app\/libggml-vulkan.so\nload_backend: loaded CPU backend from \/app\/libggml-cpu-haswell.so\ncommon_download_file_single_online: <strong>no previous model file found<\/strong> \/root\/.cache\/llama.cpp\/ggml-org_gemma-3-1b-it-GGUF_preset.ini\n&#91;...]\nllama_model_load_from_file_impl: <strong>using device Vulkan0<\/strong> (Intel(R) Arc(tm) B580 Graphics (BMG G21)) (0000:0a:00.0) - 3366 MiB free\n&#91;...]<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Usiamo le immagini gi\u00e0 pronte<\/h2>\n\n\n\n<p>Al di l\u00e0 di compilare la propria immagine e poi creare l&#8217;immagine docker, \u00e8 anche possibile utilizzare l&#8217;immagine standard, quella fatta e tenuta aggiornata direttamente dagli sviluppatori di ollama, la quale all&#8217;interno ha i vari backend. Per farlo io ho utilizzato questo file docker che definisce due container, uno  per ollama e uno per l&#8217;interfaccia web:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  ollama-vk:\n    image: ollama\/ollama\n    container_name: ollama-vk\n    restart: always\n    networks: &#91; ml_shared ]\n    ports:\n      - \"11434:11434\"\n    devices:\n      - \/dev\/dri:\/dev\/dri\n    environment:\n      OLLAMA_HOST: \"0.0.0.0\"\n      OLLAMA_VULKAN: 1\n    volumes:\n      - \/srv\/nfs\/docker\/modelli_ollama:\/root\/.ollama\n\n  openwebui:\n    image: ghcr.io\/open-webui\/open-webui:main\n    container_name: openwebui\n    restart: always\n    networks: &#91; ml_shared ]\n    depends_on:\n      - ollama-vk\n    ports:\n      - \"3000:8080\"\n    environment:\n      OLLAMA_BASE_URL: \"http:\/\/ollama-vk:11434\"\n\nnetworks:\n  ml_shared:\n\nvolumes:\n  ollama_models:<\/code><\/pre>\n\n\n\n<p>Questo testo, se copiato in un file chiamato docker-compose.yml, permette di attivare tutto ci\u00f2 che serve. Notare che nella sezione \u00abdevices\u00bb ho fatto in modo da far vedere nel container il device \/dev\/dri che da accesso alla scheda video, mentre nella sezione \u00abvolumes\u00bb ho fatto s\u00ec che i modelli non finiscano dentro l&#8217;immagine del container, ma su un file system esterno, persistente. In questo modo quando l&#8217;immagine verr\u00e0 aggiornata, non perder\u00f2 i modelli scaricati.<\/p>\n\n\n\n<p>Una volta attivato questi container di docker, posso controllare se siano veramente attivi in questo modo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># docker ps\nCONTAINER ID   IMAGE                                COMMAND               CREATED          STATUS                    PORTS                                           NAMES\n9382e06bb799   ghcr.io\/open-webui\/open-webui:main   \"bash start.sh\"       27 minutes ago   Up 27 minutes (healthy)   0.0.0.0:3000->8080\/tcp, :::3000->8080\/tcp       openwebui\n66487bef49b8   ollama\/ollama                        \"\/bin\/ollama serve\"   27 minutes ago   Up 27 minutes             0.0.0.0:11434->11434\/tcp, :::11434->11434\/tcp   ollama-vk\n<\/code><\/pre>\n\n\n\n<p>e poi collegarmi al Open-WebUi con un browser all&#8217;indirizzo <a href=\"http:\/\/localhost:3000\/\">http:\/\/localhost:3000\/<\/a> , ma posso collegarmici anche da altri computer sostituendo \u00ablocalhost\u00bb con il nome o l&#8217;indirizzo IP del server.<\/p>\n\n\n\n<p>Alla prima connessione sar\u00e0 necessario creare un account amministratore indicando un nome utente, un indirizzo email e una password. Non ho ancora capito dove queste informazioni vadano a finire, ma se lo scoprissi sarebbe utile impostare, anche per il container dell&#8217;interfaccia web, un volume esterno all&#8217;immagine, in modo che questi account siano persistenti.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sto cercando di capire come funzioni una IA. Non mi riferisco alla matematica o agli algoritmi che ci sono dietro, ma alla composizione di un qualcosa da interrogare, possibilmente open source e possibilmente che sfrutti la scheda grafica Intel B580 del server in cantina. Un po&#8217; di terminologia Proviamo! Partiamo dal compilare llama.cpp per farne [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,3,11,10],"tags":[],"class_list":["post-601","post","type-post","status-publish","format-standard","hentry","category-sysadmin","category-computer","category-debian","category-open-source"],"_links":{"self":[{"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/posts\/601","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/comments?post=601"}],"version-history":[{"count":13,"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/posts\/601\/revisions"}],"predecessor-version":[{"id":615,"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/posts\/601\/revisions\/615"}],"wp:attachment":[{"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/media?parent=601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/categories?post=601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.sguazz.it\/index.php\/wp-json\/wp\/v2\/tags?post=601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}