{"id":54,"date":"2026-05-13T22:00:00","date_gmt":"2026-05-13T20:00:00","guid":{"rendered":"https:\/\/rpi.temporiti.net\/wordpress\/?p=54"},"modified":"2026-05-30T14:06:01","modified_gmt":"2026-05-30T12:06:01","slug":"deepseek-r1-opencode-debian","status":"publish","type":"post","link":"https:\/\/rpi.temporiti.net\/wordpress\/?p=54","title":{"rendered":"Reasoning step-by-step con DeepSeek-R1 7b in locale via opencode"},"content":{"rendered":"<p>DeepSeek-R1 7b lo apro quando devo capire qualcosa che non si risolve con una risposta sbrigativa. Non lo carico per generare codice n\u00e9 per riassunti veloci: lo carico per ragionare. Mi serve un interlocutore che, davanti a un log strano o a una scelta architetturale, espliciti i passaggi del proprio ragionamento dentro blocchi <code><think><\/code> prima di buttare gi\u00f9 una conclusione. Quei blocchi sono spesso pi\u00f9 utili della risposta finale, perch\u00e9 mi mostrano dove il modello sta facendo un&#8217;assunzione che potrei voler contestare prima ancora di leggere la sintesi.<\/p>\n<p>Il modello \u00e8 rilasciato da DeepSeek AI con licenza MIT, quindi \u00e8 libero da vincoli d&#8217;uso. Lo tengo su un server Debian 12 nella mia rete locale, lo stesso che ospita altri modelli Ollama. La 7B in quantizzazione Q4_K_M occupa circa 5 GB di VRAM e gira comoda anche su una scheda di fascia media. La latenza non \u00e8 il punto forte di questa famiglia di modelli, perch\u00e9 generano molti token di pensiero prima della risposta vera, ma per la qualit\u00e0 di ragionamento che restituisce \u00e8 un compromesso che accetto volentieri.<\/p>\n<p>I parametri base sono 7B, contesto nativo 32k che spingo a 16k effettivi via Modelfile per non esagerare con la VRAM, temperature di default a 0.6 (la lascio cos\u00ec, non ho mai trovato motivo di toccarla per come la uso).<\/p>\n<h2>Setup base con Ollama<\/h2>\n<p>Su Debian si installa con lo script ufficiale e si scarica il modello in un solo passaggio.<\/p>\n<pre><code class=\"language-bash\">\ncurl -fsSL https:\/\/ollama.com\/install.sh | sh\nsudo systemctl enable --now ollama\nollama pull deepseek-r1:7b\nollama run deepseek-r1:7b\n<\/code><\/pre>\n<p>Una volta entrato in chat, il modello inizia ogni risposta con un blocco <code><think>...<\/think><\/code> che contiene il ragionamento esplicito. Conviene lasciarlo visibile durante l&#8217;analisi e nasconderlo solo quando si vuole una risposta sintetica da incollare altrove. Per task lunghi alzo <code>num_ctx<\/code>: parto dal Modelfile esistente e ne creo una variante.<\/p>\n<pre><code class=\"language-bash\">\nollama show deepseek-r1:7b --modelfile &gt; \/tmp\/r1.Modelfile\n<\/code><\/pre>\n<p>Dopo aver aggiunto <code>PARAMETER num_ctx 16384<\/code> al file, costruisco la variante con <code>ollama create deepseek-r1-long -f \/tmp\/r1.Modelfile<\/code> e la tengo a parte per le sessioni di analisi pi\u00f9 impegnative, in modo da non sprecare VRAM per tutto il resto della giornata.<\/p>\n<h2>Setup avanzato con opencode<\/h2>\n<p>opencode lo uso come TUI agentica: la finestra di chat \u00e8 pi\u00f9 comoda della shell di <code>ollama run<\/code>, mi permette di dare al modello accesso ai file di un progetto, e mantiene la cronologia. Lo collego al server Ollama locale tramite endpoint OpenAI-compatible, che Ollama espone di default su <code>\/v1<\/code>.<\/p>\n<pre><code class=\"language-json\">\n{\n  \"provider\": {\n    \"ollama-local\": {\n      \"npm\": \"@ai-sdk\/openai-compatible\",\n      \"options\": {\n        \"apiKey\": \"ollama\",\n        \"baseURL\": \"http:\/\/localhost:11434\/v1\"\n      },\n      \"models\": {\n        \"deepseek-r1:7b\": { \"name\": \"DeepSeek R1 7B\" }\n      }\n    }\n  }\n}\n<\/code><\/pre>\n<p>Salvato il file, mi posiziono nella cartella del progetto e apro la sessione.<\/p>\n<pre><code class=\"language-bash\">\ncd ~\/Documenti\/progetti\/analisi-log\nopencode . --model ollama-local\/deepseek-r1:7b\n<\/code><\/pre>\n<p>Dentro la TUI passo i file rilevanti come contesto e il modello li tiene presenti per tutta la sessione, senza che debba riallegare niente a ogni messaggio.<\/p>\n<h2>Un esempio di sessione reale<\/h2>\n<p>Ieri sera alle 23 stavo cercando di capire perch\u00e9 una migration Django in un progetto interno andava in errore solo sul database di staging, mai in locale, sempre con un messaggio criptico su una foreign key che si rifiutava di essere creata. Avevo davanti il dump dello schema, il file della migration generata dal makemigrations, e il traceback intero. Ho aperto opencode nella cartella del progetto, ho dato in contesto i tre file e ho chiesto a DeepSeek-R1 di ragionare ad alta voce su cosa potesse causare quel comportamento solo in staging.<\/p>\n<p>Il blocco <code><think><\/code> ha messo in fila le ipotesi una per una: differenza di engine InnoDB tra le due istanze, charset diverso, una migration precedente non applicata davvero, una constraint dichiarata su una colonna che nel dump aveva tipo BIGINT mentre nella nuova migration era INT. Ha scartato le prime tre con argomenti che potevo verificare e si \u00e8 concentrato sulla quarta, indicandomi esattamente quale tabella e quale colonna controllare. Ho aperto il dump, ho confermato il mismatch di tipo, ho corretto la migration con una operazione esplicita di alter sulla colonna, e in dieci minuti il problema era chiuso. Il valore del ragionamento esplicito sta proprio qui: mi fa risparmiare i giri morti dietro a ipotesi sbagliate.<\/p>\n<h2>Cosa fa bene<\/h2>\n<p>Quando il problema richiede di mettere in fila ipotesi e scartarle con un argomento, DeepSeek-R1 7b d\u00e0 il meglio. Lo trovo utile per debug di errori non ovvi, per decisioni di architettura su scala piccola (scegliere tra due pattern di retry, capire dove mettere un lock), per analisi di log dove serve ricostruire una sequenza causale. Il fatto che il ragionamento sia esplicito e contestabile vale tantissimo.<\/p>\n<h2>Cosa fa meno bene<\/h2>\n<p>Per task brevi \u00e8 sovradimensionato: produce sempre il blocco di pensiero, anche per una domanda da due righe, e il tempo di risposta totale lievita. Su task strettamente di codice \u00e8 meno preciso di un modello specializzato come Qwen2.5-Coder, perch\u00e9 il suo focus \u00e8 il reasoning e non la generazione. Su prompt molto lunghi (oltre 10k token) la qualit\u00e0 del ragionamento cala vistosamente, e conviene spezzare il problema invece di buttargli tutto in pasto.<\/p>\n<h2>Privacy: tutto resta sul mio host<\/h2>\n<p>DeepSeek-R1 gira interamente sul mio server: nessun provider terzo coinvolto, nessun upload, nessuna telemetria. Ollama si lega su 127.0.0.1:11434 e non parla con l&#8217;esterno. I log stanno in <code>~\/.ollama\/logs\/<\/code> e li cancello quando voglio con un <code>rm<\/code>, senza alcuna policy esterna da rileggere. Rispetto ai servizi cloud, dove ogni prompt e ogni risposta passano per server di terzi (e in qualche caso possono finire dentro pipeline di training o retention prolungata), qui l&#8217;analisi resta dentro l&#8217;host: i log che gli passo per ragionare non escono mai dalla mia rete. La licenza MIT di DeepSeek-R1 \u00e8 la pi\u00f9 permissiva possibile, posso integrarlo dove voglio senza altri vincoli.<\/p>\n<h2>In pratica<\/h2>\n<p>DeepSeek-R1 7b \u00e8 il modello che apro per ragionare ad alta voce su un problema poco chiaro. Quando devo invece scrivere o rivedere codice passo a Qwen2.5-Coder, per domande generiche e veloci sul laptop mi appoggio a qwen3:8b, e per risposte brevi sul Mac Mini tengo Gemma3 4B. Tenere a portata modelli con vocazioni diverse cambia parecchio il modo in cui affronto i problemi durante una sessione di lavoro lunga.<\/p>\n<hr>\n<blockquote>\n<p>Immagine generata con Cloudflare Workers AI \/ FLUX.<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>DeepSeek-R1 7b lo apro quando devo capire qualcosa che non si risolve con una risposta sbrigativa. Non lo carico per generare codice n\u00e9 per riassunti veloci: lo carico per ragionare. Mi serve un interlocutore che, davanti a un log strano o a una scelta architetturale, espliciti i passaggi del proprio ragionamento dentro blocchi prima di [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":55,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-54","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-locale"],"_links":{"self":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/54","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=54"}],"version-history":[{"count":6,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/54\/revisions"}],"predecessor-version":[{"id":363,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/54\/revisions\/363"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=\/wp\/v2\/media\/55"}],"wp:attachment":[{"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=54"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=54"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rpi.temporiti.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=54"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}