<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Gemma on Tarragon</title><link>https://tarrragon.github.io/blog/tags/gemma/</link><description>Recent content in Gemma on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Tue, 12 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/gemma/index.xml" rel="self" type="application/rss+xml"/><item><title>Hands-on：跨資料夾風格 follow 任務的模型對比</title><link>https://tarrragon.github.io/blog/llm/01-local-llm-services/hands-on/instruction-following-test/</link><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/01-local-llm-services/hands-on/instruction-following-test/</guid><description>&lt;p>本篇是個讓本地 LLM 在「&lt;strong>讀兩個資料夾、學風格、寫新章節&lt;/strong>」任務上自我評估的實驗。任務本身內容無關緊要（隨便挑了一份私人創作資料夾）、要看的是&lt;strong>不同模型在 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/instruction-following/" data-link-title="Instruction Following" data-link-desc="模型遵守任務範圍、格式、限制與停止條件的能力，是評估 instruction-tuned 模型能否落地的核心訊號">instruction following&lt;/a> / format consistency / 篇幅控制三個維度的差距&lt;/strong>。&lt;/p>
&lt;p>實驗跑了四個本地模型對比：&lt;/p>
&lt;ul>
&lt;li>&lt;code>gemma3:1b&lt;/code>（815 MB、舊代 / 小）&lt;/li>
&lt;li>&lt;code>gemma3:4b&lt;/code>（3.3 GB、舊代 / 中）&lt;/li>
&lt;li>&lt;code>qwen3:8b&lt;/code>（5.2 GB、跨家族 / 大）&lt;/li>
&lt;li>&lt;code>gemma4:e4b&lt;/code>（9.6 GB、新代 / 中、bf16）&lt;/li>
&lt;/ul>
&lt;p>對應 &lt;a href="https://tarrragon.github.io/blog/llm/04-applications/agent-architecture/" data-link-title="4.4 Agent 架構原理" data-link-desc="Agent loop 結構、失敗模式、什麼任務適合 vs 不適合、跟人類審查的協作模型">4.4 Agent 架構&lt;/a> 「規劃能力是雲端旗艦的明顯強項、本地小模型的明顯弱項」這條觀察、用具體 structural metrics 驗證、並揭示**「最新世代 + 較大 size」未必比「跨家族 / 較強訓練」勝出**。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>驗證日期&lt;/strong>：2026-05-12
&lt;strong>環境&lt;/strong>：Ollama 0.23.2、Apple Silicon、&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/gpu-compute-backend/" data-link-title="GPU Compute Backend" data-link-desc="GPU 加速計算的底層 API 介面（CUDA / ROCm / Vulkan / Metal / SYCL）、決定推論軟體能否用 GPU 跑得快">MPS backend&lt;/a>
&lt;strong>任務&lt;/strong>：讀資料夾 A（風格參考、5 章已寫完）+ 資料夾 B（同類型、5 章已寫完、需寫 v06）→ 為 B 生成 v06
&lt;strong>評估方式&lt;/strong>：純 structural metrics、不評論內容品質&lt;/p>&lt;/blockquote>
&lt;h2 id="任務設計">任務設計&lt;/h2>
&lt;p>兩個資料夾結構：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">A/ B/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">├── README.md ├── README.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">├── v01_XXX.md ├── v01_XXX.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">├── v02_XXX.md ├── v02_XXX.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">├── v03_XXX.md ├── v03_XXX.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">├── v04_XXX.md ├── v04_XXX.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">└── v05_XXX.md └── v05_XXX.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl"> └── v06_XXX.md ← 要生成&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>兩個資料夾用&lt;strong>不同 markdown 格式&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>A 風格：&lt;code># 標題&lt;/code>（H1）+ &lt;code>## 場景設定&lt;/code> 段 + 結尾 &lt;code>**【本章結束】**&lt;/code>&lt;/li>
&lt;li>B 風格：&lt;code>## v0X｜&amp;lt;主題&amp;gt;（&amp;lt;角色1&amp;gt;×&amp;lt;角色2&amp;gt;）&lt;/code>（H2）+ 直接敘事、無結尾 marker&lt;/li>
&lt;/ul>
&lt;p>LLM 看完 A + B 後、要寫 B 的 v06——&lt;strong>必須 follow B 的格式、不是 A 的&lt;/strong>。是個 format discrimination 測試。&lt;/p>
&lt;h2 id="評估維度">評估維度&lt;/h2>
&lt;p>純 structural、不涉內容：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>測法&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>篇幅控制&lt;/td>
 &lt;td>char count、跟 B 既有 v01-v05 平均比&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>段落結構&lt;/td>
 &lt;td>paragraph count、avg paragraph char&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Markdown heading&lt;/td>
 &lt;td>H1 / H2 count、是否寫對 v06 title 格式&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>結尾 marker&lt;/td>
 &lt;td>是否誤加 A 風格的「&lt;strong>【本章結束】&lt;/strong>」&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>角色 fidelity&lt;/td>
 &lt;td>提到 B 兩個主角名次數（太少 = 內容偏離）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>跨資料夾串戲&lt;/td>
 &lt;td>提到 A 資料夾角色名次數（contamination）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>對話 follow&lt;/td>
 &lt;td>「對話行」（行首是 &lt;code>「&lt;/code>）數量、跟 baseline 比&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>生成時間&lt;/td>
 &lt;td>從送 prompt 到收完整 response&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>不評估的：&lt;/p></description><content:encoded><![CDATA[<p>本篇是個讓本地 LLM 在「<strong>讀兩個資料夾、學風格、寫新章節</strong>」任務上自我評估的實驗。任務本身內容無關緊要（隨便挑了一份私人創作資料夾）、要看的是<strong>不同模型在 <a href="/blog/llm/knowledge-cards/instruction-following/" data-link-title="Instruction Following" data-link-desc="模型遵守任務範圍、格式、限制與停止條件的能力，是評估 instruction-tuned 模型能否落地的核心訊號">instruction following</a> / format consistency / 篇幅控制三個維度的差距</strong>。</p>
<p>實驗跑了四個本地模型對比：</p>
<ul>
<li><code>gemma3:1b</code>（815 MB、舊代 / 小）</li>
<li><code>gemma3:4b</code>（3.3 GB、舊代 / 中）</li>
<li><code>qwen3:8b</code>（5.2 GB、跨家族 / 大）</li>
<li><code>gemma4:e4b</code>（9.6 GB、新代 / 中、bf16）</li>
</ul>
<p>對應 <a href="/blog/llm/04-applications/agent-architecture/" data-link-title="4.4 Agent 架構原理" data-link-desc="Agent loop 結構、失敗模式、什麼任務適合 vs 不適合、跟人類審查的協作模型">4.4 Agent 架構</a> 「規劃能力是雲端旗艦的明顯強項、本地小模型的明顯弱項」這條觀察、用具體 structural metrics 驗證、並揭示**「最新世代 + 較大 size」未必比「跨家族 / 較強訓練」勝出**。</p>
<blockquote>
<p><strong>驗證日期</strong>：2026-05-12
<strong>環境</strong>：Ollama 0.23.2、Apple Silicon、<a href="/blog/llm/knowledge-cards/gpu-compute-backend/" data-link-title="GPU Compute Backend" data-link-desc="GPU 加速計算的底層 API 介面（CUDA / ROCm / Vulkan / Metal / SYCL）、決定推論軟體能否用 GPU 跑得快">MPS backend</a>
<strong>任務</strong>：讀資料夾 A（風格參考、5 章已寫完）+ 資料夾 B（同類型、5 章已寫完、需寫 v06）→ 為 B 生成 v06
<strong>評估方式</strong>：純 structural metrics、不評論內容品質</p></blockquote>
<h2 id="任務設計">任務設計</h2>
<p>兩個資料夾結構：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">A/                          B/
</span></span><span class="line"><span class="ln">2</span><span class="cl">├── README.md               ├── README.md
</span></span><span class="line"><span class="ln">3</span><span class="cl">├── v01_XXX.md              ├── v01_XXX.md
</span></span><span class="line"><span class="ln">4</span><span class="cl">├── v02_XXX.md              ├── v02_XXX.md
</span></span><span class="line"><span class="ln">5</span><span class="cl">├── v03_XXX.md              ├── v03_XXX.md
</span></span><span class="line"><span class="ln">6</span><span class="cl">├── v04_XXX.md              ├── v04_XXX.md
</span></span><span class="line"><span class="ln">7</span><span class="cl">└── v05_XXX.md              └── v05_XXX.md
</span></span><span class="line"><span class="ln">8</span><span class="cl">                            └── v06_XXX.md  ← 要生成</span></span></code></pre></div><p>兩個資料夾用<strong>不同 markdown 格式</strong>：</p>
<ul>
<li>A 風格：<code># 標題</code>（H1）+ <code>## 場景設定</code> 段 + 結尾 <code>**【本章結束】**</code></li>
<li>B 風格：<code>## v0X｜&lt;主題&gt;（&lt;角色1&gt;×&lt;角色2&gt;）</code>（H2）+ 直接敘事、無結尾 marker</li>
</ul>
<p>LLM 看完 A + B 後、要寫 B 的 v06——<strong>必須 follow B 的格式、不是 A 的</strong>。是個 format discrimination 測試。</p>
<h2 id="評估維度">評估維度</h2>
<p>純 structural、不涉內容：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>測法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>篇幅控制</td>
          <td>char count、跟 B 既有 v01-v05 平均比</td>
      </tr>
      <tr>
          <td>段落結構</td>
          <td>paragraph count、avg paragraph char</td>
      </tr>
      <tr>
          <td>Markdown heading</td>
          <td>H1 / H2 count、是否寫對 v06 title 格式</td>
      </tr>
      <tr>
          <td>結尾 marker</td>
          <td>是否誤加 A 風格的「<strong>【本章結束】</strong>」</td>
      </tr>
      <tr>
          <td>角色 fidelity</td>
          <td>提到 B 兩個主角名次數（太少 = 內容偏離）</td>
      </tr>
      <tr>
          <td>跨資料夾串戲</td>
          <td>提到 A 資料夾角色名次數（contamination）</td>
      </tr>
      <tr>
          <td>對話 follow</td>
          <td>「對話行」（行首是 <code>「</code>）數量、跟 baseline 比</td>
      </tr>
      <tr>
          <td>生成時間</td>
          <td>從送 prompt 到收完整 response</td>
      </tr>
  </tbody>
</table>
<p>不評估的：</p>
<ul>
<li>內容品質、文筆好壞</li>
<li>敘事邏輯是否合理</li>
<li>角色塑造是否生動</li>
</ul>
<p>純 structural 評估的好處是 reproducible、不需 reviewer 主觀判斷、可自動跑。</p>
<h2 id="baselineb-既有-v01-v05-的-metrics">Baseline：B 既有 v01-v05 的 metrics</h2>
<p>B 資料夾 5 個既有章節的平均：</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th>Average</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>char count</td>
          <td>~933</td>
      </tr>
      <tr>
          <td>paragraph count</td>
          <td>~32</td>
      </tr>
      <tr>
          <td>avg paragraph chars</td>
          <td>~29</td>
      </tr>
      <tr>
          <td>dialogue lines</td>
          <td>~7</td>
      </tr>
      <tr>
          <td>H1 used</td>
          <td>0（全部用 H2）</td>
      </tr>
      <tr>
          <td>H2 used</td>
          <td>1</td>
      </tr>
      <tr>
          <td>結尾「<strong>【本章結束】</strong>」</td>
          <td>全部 False</td>
      </tr>
      <tr>
          <td>Cross leak</td>
          <td>全部 0</td>
      </tr>
      <tr>
          <td>主角名提及（合計）</td>
          <td>~60</td>
      </tr>
  </tbody>
</table>
<p>這是 LLM 該模仿的目標。</p>
<h2 id="四個模型的結果">四個模型的結果</h2>
<p>四個 model 跑同樣 prompt、同樣輸入內容。</p>
<h3 id="對比表">對比表</h3>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Baseline</th>
          <th><code>gemma3:1b</code></th>
          <th><code>gemma3:4b</code></th>
          <th><code>qwen3:8b</code></th>
          <th><code>gemma4:e4b</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>模型大小</strong></td>
          <td>—</td>
          <td>815 MB</td>
          <td>3.3 GB</td>
          <td>5.2 GB</td>
          <td>9.6 GB（bf16）</td>
      </tr>
      <tr>
          <td><strong>發布世代</strong></td>
          <td>—</td>
          <td>Gemma 3</td>
          <td>Gemma 3</td>
          <td>Qwen 3</td>
          <td><strong>Gemma 4（2026/4）</strong></td>
      </tr>
      <tr>
          <td>char count</td>
          <td>~933</td>
          <td>4324（4.6×）</td>
          <td>1330</td>
          <td><strong>951（1.02×）</strong></td>
          <td>679</td>
      </tr>
      <tr>
          <td>paragraph count</td>
          <td>~32</td>
          <td>145</td>
          <td>29</td>
          <td><strong>36</strong></td>
          <td>11</td>
      </tr>
      <tr>
          <td>avg paragraph chars</td>
          <td>~29</td>
          <td>30</td>
          <td>46</td>
          <td><strong>26</strong></td>
          <td>62</td>
      </tr>
      <tr>
          <td>H1 = 0</td>
          <td>符合</td>
          <td>不符（1）</td>
          <td>符合</td>
          <td>符合</td>
          <td>不符（1）</td>
      </tr>
      <tr>
          <td>H2 = 1</td>
          <td>符合</td>
          <td>不符（0）</td>
          <td>符合</td>
          <td>符合</td>
          <td>不符（3）</td>
      </tr>
      <tr>
          <td>v06 title 格式</td>
          <td>—</td>
          <td>不符</td>
          <td>符合</td>
          <td>符合</td>
          <td>不符</td>
      </tr>
      <tr>
          <td>結尾 marker</td>
          <td>False</td>
          <td>符合</td>
          <td>符合</td>
          <td>符合</td>
          <td>符合</td>
      </tr>
      <tr>
          <td>Cross leak</td>
          <td>0</td>
          <td>無（0）</td>
          <td>無（0）</td>
          <td>無（0）</td>
          <td>無（0）</td>
      </tr>
      <tr>
          <td>dialogue lines</td>
          <td>~7</td>
          <td>4</td>
          <td><strong>0</strong></td>
          <td><strong>7</strong></td>
          <td>0</td>
      </tr>
      <tr>
          <td>主角名提及（合計）</td>
          <td>~60</td>
          <td>286</td>
          <td>24</td>
          <td><strong>27</strong></td>
          <td><strong>0</strong></td>
      </tr>
      <tr>
          <td><strong>通過項目</strong></td>
          <td>—</td>
          <td><strong>2 / 7</strong></td>
          <td><strong>6 / 7</strong></td>
          <td><strong>7 / 7</strong></td>
          <td><strong>1 / 7</strong></td>
      </tr>
      <tr>
          <td>生成時間</td>
          <td>—</td>
          <td>41.8s</td>
          <td>36.5s</td>
          <td>97.5s</td>
          <td>43.5s</td>
      </tr>
  </tbody>
</table>
<h3 id="各模型觀察">各模型觀察</h3>
<p><strong><code>gemma3:1b</code>（815 MB）</strong>：</p>
<ul>
<li>篇幅 4.6× 失控、段落數 4.5× 超標、用 H1 而不是 H2。</li>
<li>顯示 1B 模型對「2000-3000 字」這種 numeric instruction 沒有有效執行能力、會一直生成到 context 限制。</li>
<li>但 cross leak 0、結尾 marker 也沒誤加——「不要 X」這類 negative instruction follow 較成功。</li>
</ul>
<p><strong><code>gemma3:4b</code>（3.3 GB）</strong>：</p>
<ul>
<li>篇幅 / 段落 / heading 結構全 OK、明顯比 1B 大幅改善。</li>
<li><strong>dialogue lines = 0</strong>：完全沒寫對話、整篇純敘事。表示 4B 抓到字面 structural feature、但沒抓到「對話 driven 敘事」這個 stylistic feature。</li>
<li>主角名提及 24 次（baseline ~60）—內容偏短、提及次數偏低、但比例合理。</li>
</ul>
<p><strong><code>qwen3:8b</code>（5.2 GB、跨家族）</strong>：</p>
<ul>
<li><strong>唯一 7/7 全 pass 的模型</strong>——篇幅完美匹配（951 vs ~933）、段落數合理（36 vs ~32）、heading 對、對話 7 行完全等於 baseline。</li>
<li>跨家族 + 大一級的組合表現質變，比同家族下一級的 4B 模型大幅提升。</li>
<li>代價：生成時間 97.5s、約是 4B 模型的 2.7×。</li>
</ul>
<p><strong><code>gemma4:e4b</code>（9.6 GB、新代）</strong>：</p>
<ul>
<li><strong>驚人的 1/7、最差表現</strong>——比 1B 還少通過項目。</li>
<li><strong>主角名提及 0</strong>：完全沒寫角色名、純抽象敘述「某一方」「另一方」。</li>
<li><strong>dialogue 0</strong>：沒對話。</li>
<li><strong>生成內容是「劇情大綱建議」而非實際章節</strong>：含「劇情核心思路」「預計情緒強度」「寫作切入點建議」等 meta-text。</li>
<li>輸出末尾「<strong>（此為結構化建議、等待具體的指令後、將會生成與風格一致的劇情內容。）</strong>」——明示它把 prompt 理解成「給建議框架、等下一步」。</li>
</ul>
<h3 id="strict-prompt-retest揭示-internal-alignment">Strict prompt retest：揭示 internal alignment</h3>
<p>懷疑 1/7 可能是「prompt 不夠強硬」、用 strict prompt 重跑 <code>gemma4:e4b</code>。Strict 加了八條規則、明示：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">- 直接從 `## v06｜...` 開頭、不寫前言
</span></span><span class="line"><span class="ln">2</span><span class="cl">- 絕對不可寫「劇情核心思路」「預計情緒強度」「寫作切入點」等 meta-text
</span></span><span class="line"><span class="ln">3</span><span class="cl">- 必須直接寫敘事內容、含對話、動作、感受描寫
</span></span><span class="line"><span class="ln">4</span><span class="cl">- 強制提到角色名多次、不要用「某一方」「另一人」抽象稱呼
</span></span><span class="line"><span class="ln">5</span><span class="cl">- ...</span></span></code></pre></div><p>Strict prompt 結果：</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th>原 prompt</th>
          <th>strict prompt</th>
          <th>變化</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>char count</td>
          <td>679</td>
          <td>660</td>
          <td>相同量級</td>
      </tr>
      <tr>
          <td>H1 = 0</td>
          <td>不符（1）</td>
          <td>符合</td>
          <td><strong>改善</strong></td>
      </tr>
      <tr>
          <td>H2 = 1</td>
          <td>不符（3）</td>
          <td>符合</td>
          <td><strong>改善</strong></td>
      </tr>
      <tr>
          <td>v06 title 格式</td>
          <td>不符</td>
          <td>符合</td>
          <td><strong>改善</strong></td>
      </tr>
      <tr>
          <td>meta-text 出現</td>
          <td>有</td>
          <td>無</td>
          <td><strong>改善</strong></td>
      </tr>
      <tr>
          <td>dialogue lines</td>
          <td>0</td>
          <td>3</td>
          <td><strong>改善</strong></td>
      </tr>
      <tr>
          <td><strong>主角名提及</strong></td>
          <td><strong>0</strong></td>
          <td><strong>0</strong></td>
          <td><strong>未改善</strong></td>
      </tr>
      <tr>
          <td><strong>通過項目</strong></td>
          <td><strong>1 / 7</strong></td>
          <td><strong>4 / 7</strong></td>
          <td><strong>+3</strong></td>
      </tr>
  </tbody>
</table>
<p>從 1/7 → 4/7、prompt 強化明顯有用。但<strong>主角名提及兩次都 0</strong>、即使 strict prompt 明示「強制提到角色名」、模型仍用「兩人」「彼此」「對方」抽象稱呼。</p>
<p>這比「模型不會 follow」更精確、是兩個層次的 follow 差別：</p>
<ul>
<li><strong>Surface level instruction</strong>（heading 格式、不要 meta-text、要對話）：model 願意 follow strict prompt。</li>
<li><strong>Semantic level instruction</strong>（在這個情境用具名角色）：model 有 <strong>internal alignment 抗拒</strong>、即使 prompt 明示也不 follow。</li>
</ul>
<p>Gemma 4 e4b 是 device-deployable edge variant、RLHF 可能特別針對「敏感情境下的人物識別」做 alignment。這個 alignment 比 prompt-level instruction follow 更深、是 hard line、不能用 prompt engineering 繞過。</p>
<h2 id="關鍵觀察">關鍵觀察</h2>
<h3 id="model-size-不是唯一因素訓練-alignment-更重要">Model size 不是唯一因素、訓練 alignment 更重要</h3>
<p>最反直覺的結果：</p>
<ul>
<li><code>gemma4:e4b</code>（9.6 GB、最新世代）原 prompt 通過 <strong>1/7</strong>、strict prompt 通過 <strong>4/7</strong>。</li>
<li><code>gemma3:4b</code>（3.3 GB、舊一代）通過 <strong>6/7</strong>。</li>
<li><code>qwen3:8b</code>（5.2 GB、跨家族）通過 <strong>7/7</strong>。</li>
</ul>
<p>「最大 + 最新」不等於「最好 follow instruction」。在這個任務上、ranking 是：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">qwen3:8b &gt; gemma3:4b &gt; gemma3:1b ≈ gemma4:e4b (strict) &gt; gemma4:e4b (default)</span></span></code></pre></div><p>可能因素：</p>
<ol>
<li><strong>訓練資料分佈差異</strong>：Qwen 系列訓練資料含大量中文、對中文 instruction follow 更穩。</li>
<li><strong>Edge variant 的 alignment 設計</strong>：<code>gemma4:e4b</code> 是 device-deployable edge variant、RLHF 可能特別在敏感情境用 conservative output。Strict prompt 能改善 surface-level（heading、meta-text、對話）、但 semantic-level（具名角色）有 hard line 不能繞過。</li>
<li><strong>跨家族效應 &gt; 跨代效應</strong>：Qwen vs Gemma（不同家族）比 Gemma 3 vs Gemma 4（同家族跨代）影響更大。</li>
</ol>
<h3 id="兩層-instruction-follow">兩層 instruction follow</h3>
<p><code>gemma4:e4b</code> 的 strict prompt retest 揭示一個重要區分：</p>
<ul>
<li><strong>Surface-level instruction</strong>（heading 格式、不要 meta-text、要對話）：可以用 strict prompt 改善、prompt engineering 有效。</li>
<li><strong>Semantic-level alignment</strong>（特定情境的角色處理、敏感主題的表述方式）：是 RLHF 階段建立的 hard line、prompt engineering 繞不過。</li>
</ul>
<p>設計應用時要意識：<strong>「LLM follow 不了 instruction」可能不是能力問題、是 alignment 問題</strong>。模型訓練時被刻意 align 不做某些事、即使 prompt 明示也不會做。發現這種情況、改換 model（或 less-aligned variant）會比繼續調 prompt 更省時間。</p>
<h3 id="最新世代的標籤可能誤導">「最新世代」的標籤可能誤導</h3>
<p>Gemma 4 是 2026/4/2 才發布的最新代、size 也夠大、但在這個 instruction following 任務上<strong>輸給 6 個月前發布的 Gemma 3 4b</strong>。</p>
<p>設計應用 / 選模型時、實測對自己 task 的表現比「最新 / 最大」標籤可靠。Benchmark ranking（如 LMSYS Chatbot Arena）反映平均表現、未必 reflect 你的 narrow 任務。本實驗示範了「自己跑一次」比「看 benchmark」更可靠的判讀方法。</p>
<h3 id="structural-feature-跟-stylistic-feature-兩層">Structural feature 跟 stylistic feature 兩層</h3>
<p>跨四個模型一致觀察：</p>
<ul>
<li><strong>Structural feature</strong>（heading level、結尾 marker、不要 cross leak）：所有模型多少都抓到。</li>
<li><strong>Stylistic feature</strong>（對話 driven 敘事、篇幅精準）：差異極大、Qwen3 8B 完美、其他三個都有明顯失分。</li>
</ul>
<p>這對應 <a href="/blog/llm/04-applications/agent-architecture/" data-link-title="4.4 Agent 架構原理" data-link-desc="Agent loop 結構、失敗模式、什麼任務適合 vs 不適合、跟人類審查的協作模型">4.4 Agent</a> 的「規劃 vs 字面 follow」差距——字面 instruction 容易、stylistic mimic 困難。寫應用時、預期 follow「形式約束」（output JSON、結尾 signature）跟 follow「風格約束」（用簡潔口吻、bullet 而非段落）兩種 instruction 的成功率不同。</p>
<h3 id="cross-pairing-leak全-0">Cross-pairing leak：全 0</h3>
<p>四個模型 cross leak 都 0——表示「不要混角色」這個 instruction 兩個都 follow 成功。可能因素：</p>
<ul>
<li>角色名是名詞、模型 generation 時容易 constrain。</li>
<li>Prompt 已明示「為 B 寫」、模型沒被 A 角色名干擾。</li>
</ul>
<p>如果改成模糊 instruction（「混合 A、B 風格」）、leak 可能會出現——本實驗沒涵蓋這個 case。</p>
<h3 id="生成時間size--時間">生成時間：size ≠ 時間</h3>
<p>四個模型的生成時間：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>size</th>
          <th>時間</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>gemma3:1b</td>
          <td>815 MB</td>
          <td>41.8s</td>
      </tr>
      <tr>
          <td>gemma3:4b</td>
          <td>3.3 GB</td>
          <td>36.5s</td>
      </tr>
      <tr>
          <td>qwen3:8b</td>
          <td>5.2 GB</td>
          <td><strong>97.5s</strong></td>
      </tr>
      <tr>
          <td>gemma4:e4b</td>
          <td>9.6 GB</td>
          <td>43.5s</td>
      </tr>
  </tbody>
</table>
<p>意外發現：</p>
<ol>
<li><strong>1B 比 4B 慢</strong>：因為 1B 生成 4324 字、4B 生成 1330 字、總 token 量決定總時間、不是 model size。</li>
<li><strong>qwen3:8b 慢 2.7×</strong>：8B 的 forward pass 較慢、加上 generation 量級正常、總時間最長。</li>
<li><strong>gemma4:e4b 跟 1B 相近</strong>：generation 短（679 字）、抵消 model 較大的開銷。</li>
</ol>
<p><a href="/blog/llm/knowledge-cards/tokens-per-second/" data-link-title="Tokens Per Second" data-link-desc="LLM 每秒能生成幾個 token：生字速度的標準量化指標">tokens per second</a> 跟 total latency 是兩件事——decode 速度快但生成太多 token、未必更快完成任務。</p>
<h2 id="對寫應用的啟示">對寫應用的啟示</h2>
<ol>
<li><strong>「最新最大」≠ 「最好 follow」</strong>：選模型實測自己 task、benchmark / size 只是輔助訊號。</li>
<li><strong>本地小模型（&lt; 3B）做需要 follow 結構規則的任務、要嚴格驗證</strong>：用 structural metrics 自動 check、目視判斷模型「看起來有做到」的可靠度低。</li>
<li><strong>Edge variant 可能有 special behavior</strong>：device-deployable variant 可能 RLHF 偏向 conservative、不一定適合所有任務。</li>
<li><strong>跨家族對比比同家族升 size 收益大</strong>：Qwen3 8B vs Gemma3 4B 比 Gemma3 4B vs Gemma3 1B 改善更明顯。</li>
<li><strong>「形式跟風格」分開驗證</strong>：應用層的 validation 分維度 score、比一次評全部更可解讀。</li>
</ol>
<h2 id="跑這個實驗的-framework">跑這個實驗的 framework</h2>
<p>通用流程（不放具體 script、會綁定 corpus 內容）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">1. 準備兩個資料夾、A 是風格參考、B 是 work-in-progress
</span></span><span class="line"><span class="ln">2</span><span class="cl">2. 寫 helper script 把兩個資料夾完整內容 + 任務說明做成 prompt
</span></span><span class="line"><span class="ln">3</span><span class="cl">3. 跑多個 model 各一次（同 prompt、不同 model）
</span></span><span class="line"><span class="ln">4</span><span class="cl">4. 對輸出計算 structural metrics（char count、paragraph、heading、dialogue lines）
</span></span><span class="line"><span class="ln">5</span><span class="cl">5. 跟 B 既有章節的 baseline metrics 對比
</span></span><span class="line"><span class="ln">6</span><span class="cl">6. 列通過 / 失敗矩陣</span></span></code></pre></div><p>關鍵設計選擇：</p>
<ul>
<li><strong>A 跟 B 風格故意不一樣</strong>：才能驗證 LLM 是否分辨「該 follow 哪個」。</li>
<li><strong>不評估內容品質</strong>：純 structural 評估 reproducible、不需 reviewer 主觀判斷。</li>
<li><strong>baseline 用既有章節算</strong>：B 自己的 v01-v05 是「正確答案」的 reference。</li>
<li><strong>跑多個跨家族 / 跨世代 / 跨 size 模型</strong>：避免「只測一個就下結論」的偏差。</li>
</ul>
<h2 id="何時這份對比會過時">何時這份對比會過時</h2>
<ul>
<li><strong>具體模型 ranking</strong>：新模型發布後 ranking 會變、特別是新版 Gemma 4 / Qwen 4 / Llama 4 等推出時。</li>
<li><strong>「Gemma 4 edge 表現差」這個觀察</strong>：可能隨後續 fine-tune 或新版改善。</li>
</ul>
<p><strong>不會過時的部分</strong>：</p>
<ul>
<li>Model size 不是 instruction following 的唯一因素——這個現象在所有 LLM 都存在。</li>
<li>Structural vs stylistic 兩層 follow 難度不同。</li>
<li>跨家族對比比同家族升 size 收益大、這個現象可能持續。</li>
<li>純 metrics-based 評估比主觀判斷可重現。</li>
<li>「自己跑一次」比「看 benchmark」更可靠的判讀邏輯。</li>
</ul>
<p>未來想擴展、可以加入更多維度（如反向 retrieval：把生成內容當 query、看能不能找回原資料夾；或 perplexity-based 評估）。</p>
<p>跟其他 hands-on 章節的關係：完整 hands-on 系列見 <a href="/blog/llm/01-local-llm-services/hands-on/" data-link-title="Hands-on：本地 AI 工具實作筆記" data-link-desc="Ollama / ComfyUI / Whisper / Piper TTS：實際安裝、驗證、跑通的紀錄。隨工具版本演化、跟 1.x 原理章節互補。">Hands-on 章節索引</a>、選模型的優先序策略見 <a href="/blog/llm/01-local-llm-services/model-selection-priority/" data-link-title="1.4 寫 code 場景的模型選型優先順序" data-link-desc="Gemma 4 31B MTP → Qwen3-Coder 30B → Qwen3 14B → gpt-oss 20B 的取捨與適用情境">Model selection priority</a>、模型 tag 命名規則見 <a href="/blog/llm/knowledge-cards/model-tag/" data-link-title="Model Tag" data-link-desc="Ollama 等推論伺服器用來定位特定模型版本的命名規則">Model tag</a>、跑多模型的記憶體預算見 <a href="/blog/llm/01-local-llm-services/hands-on/resource-management/" data-link-title="Hands-on：LLM 運行中 &#43; 結束的資源管理" data-link-desc="RAM / 磁碟 / port 三個 dimension 的觀察跟釋放、Ollama keep_alive 跟 ComfyUI 兩種 lifecycle 對比、實測釋放數字">Resource management</a>。</p>
]]></content:encoded></item><item><title>Hands-on：安裝 Ollama + 拉第一個 Gemma 模型</title><link>https://tarrragon.github.io/blog/llm/01-local-llm-services/hands-on/ollama-setup/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/01-local-llm-services/hands-on/ollama-setup/</guid><description>&lt;p>本篇紀錄在 Apple Silicon Mac 上裝 Ollama 並拉一個小模型驗證的完整流程。指令在 macOS 14 (Sonoma) / Homebrew 提供的環境下驗證。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>驗證日期&lt;/strong>：2026-05-11
&lt;strong>Ollama 版本&lt;/strong>：0.23.2
&lt;strong>示範模型&lt;/strong>：&lt;code>gemma3:1b&lt;/code>（約 815 MB、選最小可運行的 Gemma 變體當驗證對象）&lt;/p>&lt;/blockquote>
&lt;h2 id="前置設定">前置設定&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>項目&lt;/th>
 &lt;th>檢查指令&lt;/th>
 &lt;th>預期&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>macOS 版本&lt;/td>
 &lt;td>&lt;code>sw_vers -productVersion&lt;/code>&lt;/td>
 &lt;td>14.x 或更新&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Apple Silicon&lt;/td>
 &lt;td>&lt;code>uname -m&lt;/code>&lt;/td>
 &lt;td>&lt;code>arm64&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Homebrew&lt;/td>
 &lt;td>&lt;code>brew --version&lt;/code>&lt;/td>
 &lt;td>4.x（任何近期版）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>磁碟空間&lt;/td>
 &lt;td>&lt;code>df -h ~&lt;/code>&lt;/td>
 &lt;td>至少 3 GB 剩餘給 runtime + 1B 模型&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>port 11434&lt;/td>
 &lt;td>&lt;code>lsof -i :11434&lt;/code>&lt;/td>
 &lt;td>無輸出（port 沒被佔）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>表中 &lt;code>brew --version&lt;/code> 這關若還沒過、代表 Homebrew 沒裝。新機從零的安裝順序（Homebrew、PATH、bash）見 &lt;a href="https://tarrragon.github.io/blog/other/macos-%E6%96%B0%E6%A9%9F%E5%9F%BA%E7%A4%8E%E5%BB%BA%E8%A8%AD%E5%A5%97%E4%BB%B6%E7%AE%A1%E7%90%86%E8%88%87%E5%80%8B%E4%BA%BA-bin-%E7%9A%84%E8%A8%AD%E5%AE%9A%E9%A0%86%E5%BA%8F/" data-link-title="macOS 新機基礎建設：套件管理與個人 bin 的設定順序" data-link-desc="重灌或換機後底層基礎建設的依賴順序，免得後面工具裝不起來或路徑互相找不到。">macOS 新機基礎建設&lt;/a>。&lt;/p>
&lt;p>選 1B 模型只是為了驗證流程、能力很弱、實際寫 code 場景請用 14B / 31B 級。模型大小跟記憶體 / 磁碟對應關係見 &lt;a href="https://tarrragon.github.io/blog/llm/00-foundations/hardware-memory-budget/" data-link-title="0.5 Apple Silicon 記憶體預算" data-link-desc="記憶體決定能跑什麼，Q4 量化下的可運作模型對照與系統保留">0.5 Apple Silicon 記憶體預算&lt;/a>。&lt;/p>
&lt;h2 id="安裝-ollama">安裝 Ollama&lt;/h2>
&lt;p>用 Homebrew 安裝、是 macOS 上最直接的路徑：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">brew install ollama&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>執行時間在 broadband 大約 30 秒到 2 分鐘、視 dependency cache 是否已有（Ollama 依賴 mlx-c 等 Apple Silicon 加速函式庫、首次裝較久）。&lt;/p>
&lt;p>裝完看到的 caveat 訊息：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">To start ollama now and restart at login:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> brew services start ollama
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">Or, if you don&amp;#39;t want/need a background service you can just run:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> OLLAMA_FLASH_ATTENTION=&amp;#34;1&amp;#34; OLLAMA_KV_CACHE_TYPE=&amp;#34;q8_0&amp;#34; /opt/homebrew/opt/ollama/bin/ollama serve&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>兩種啟動模式：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>launchd service&lt;/strong>（推薦日常用）：開機自動啟動、跑在背景。&lt;/li>
&lt;li>&lt;strong>前景手動跑&lt;/strong>：terminal 開著、關掉就停。&lt;/li>
&lt;/ul>
&lt;p>驗證 binary 路徑：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">which ollama
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c1"># 應該回 /opt/homebrew/bin/ollama&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="啟動-ollama-service">啟動 Ollama Service&lt;/h2>
&lt;p>選 launchd service 模式：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">brew services start ollama&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>預期輸出：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">==&amp;gt; Successfully started `ollama` (label: homebrew.mxcl.ollama)&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這個動作做兩件事：&lt;/p>
&lt;ol>
&lt;li>註冊一個 launchd plist（macOS 開機自啟動 / 背景服務的設定檔、見 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/launchd-service/" data-link-title="launchd Service" data-link-desc="macOS 原生的服務管理機制、把 process 註冊成自動啟動的 daemon 或 agent">launchd-service 卡片&lt;/a>）到 &lt;code>~/Library/LaunchAgents/homebrew.mxcl.ollama.plist&lt;/code>。&lt;/li>
&lt;li>立刻啟動 ollama serve、之後重開機自動啟動。&lt;/li>
&lt;/ol>
&lt;p>驗證 server 真的在跑：&lt;/p></description><content:encoded><![CDATA[<p>本篇紀錄在 Apple Silicon Mac 上裝 Ollama 並拉一個小模型驗證的完整流程。指令在 macOS 14 (Sonoma) / Homebrew 提供的環境下驗證。</p>
<blockquote>
<p><strong>驗證日期</strong>：2026-05-11
<strong>Ollama 版本</strong>：0.23.2
<strong>示範模型</strong>：<code>gemma3:1b</code>（約 815 MB、選最小可運行的 Gemma 變體當驗證對象）</p></blockquote>
<h2 id="前置設定">前置設定</h2>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>檢查指令</th>
          <th>預期</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>macOS 版本</td>
          <td><code>sw_vers -productVersion</code></td>
          <td>14.x 或更新</td>
      </tr>
      <tr>
          <td>Apple Silicon</td>
          <td><code>uname -m</code></td>
          <td><code>arm64</code></td>
      </tr>
      <tr>
          <td>Homebrew</td>
          <td><code>brew --version</code></td>
          <td>4.x（任何近期版）</td>
      </tr>
      <tr>
          <td>磁碟空間</td>
          <td><code>df -h ~</code></td>
          <td>至少 3 GB 剩餘給 runtime + 1B 模型</td>
      </tr>
      <tr>
          <td>port 11434</td>
          <td><code>lsof -i :11434</code></td>
          <td>無輸出（port 沒被佔）</td>
      </tr>
  </tbody>
</table>
<p>表中 <code>brew --version</code> 這關若還沒過、代表 Homebrew 沒裝。新機從零的安裝順序（Homebrew、PATH、bash）見 <a href="/blog/other/macos-%E6%96%B0%E6%A9%9F%E5%9F%BA%E7%A4%8E%E5%BB%BA%E8%A8%AD%E5%A5%97%E4%BB%B6%E7%AE%A1%E7%90%86%E8%88%87%E5%80%8B%E4%BA%BA-bin-%E7%9A%84%E8%A8%AD%E5%AE%9A%E9%A0%86%E5%BA%8F/" data-link-title="macOS 新機基礎建設：套件管理與個人 bin 的設定順序" data-link-desc="重灌或換機後底層基礎建設的依賴順序，免得後面工具裝不起來或路徑互相找不到。">macOS 新機基礎建設</a>。</p>
<p>選 1B 模型只是為了驗證流程、能力很弱、實際寫 code 場景請用 14B / 31B 級。模型大小跟記憶體 / 磁碟對應關係見 <a href="/blog/llm/00-foundations/hardware-memory-budget/" data-link-title="0.5 Apple Silicon 記憶體預算" data-link-desc="記憶體決定能跑什麼，Q4 量化下的可運作模型對照與系統保留">0.5 Apple Silicon 記憶體預算</a>。</p>
<h2 id="安裝-ollama">安裝 Ollama</h2>
<p>用 Homebrew 安裝、是 macOS 上最直接的路徑：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">brew install ollama</span></span></code></pre></div><p>執行時間在 broadband 大約 30 秒到 2 分鐘、視 dependency cache 是否已有（Ollama 依賴 mlx-c 等 Apple Silicon 加速函式庫、首次裝較久）。</p>
<p>裝完看到的 caveat 訊息：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">To start ollama now and restart at login:
</span></span><span class="line"><span class="ln">2</span><span class="cl">  brew services start ollama
</span></span><span class="line"><span class="ln">3</span><span class="cl">Or, if you don&#39;t want/need a background service you can just run:
</span></span><span class="line"><span class="ln">4</span><span class="cl">  OLLAMA_FLASH_ATTENTION=&#34;1&#34; OLLAMA_KV_CACHE_TYPE=&#34;q8_0&#34; /opt/homebrew/opt/ollama/bin/ollama serve</span></span></code></pre></div><p>兩種啟動模式：</p>
<ul>
<li><strong>launchd service</strong>（推薦日常用）：開機自動啟動、跑在背景。</li>
<li><strong>前景手動跑</strong>：terminal 開著、關掉就停。</li>
</ul>
<p>驗證 binary 路徑：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">which ollama
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># 應該回 /opt/homebrew/bin/ollama</span></span></span></code></pre></div><h2 id="啟動-ollama-service">啟動 Ollama Service</h2>
<p>選 launchd service 模式：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">brew services start ollama</span></span></code></pre></div><p>預期輸出：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">==&gt; Successfully started `ollama` (label: homebrew.mxcl.ollama)</span></span></code></pre></div><p>這個動作做兩件事：</p>
<ol>
<li>註冊一個 launchd plist（macOS 開機自啟動 / 背景服務的設定檔、見 <a href="/blog/llm/knowledge-cards/launchd-service/" data-link-title="launchd Service" data-link-desc="macOS 原生的服務管理機制、把 process 註冊成自動啟動的 daemon 或 agent">launchd-service 卡片</a>）到 <code>~/Library/LaunchAgents/homebrew.mxcl.ollama.plist</code>。</li>
<li>立刻啟動 ollama serve、之後重開機自動啟動。</li>
</ol>
<p>驗證 server 真的在跑：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">curl -s http://localhost:11434/api/version</span></span></code></pre></div><p>預期回：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">{</span><span class="nt">&#34;version&#34;</span><span class="p">:</span><span class="s2">&#34;0.23.2&#34;</span><span class="p">}</span></span></span></code></pre></div><p>看到這個 JSON 就證明三件事：Ollama daemon 跑了、port 11434 通了、API 結構正確。</p>
<h2 id="拉第一個模型">拉第一個模型</h2>
<p>Ollama 用 <code>ollama pull</code> 從官方 registry 下載模型：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">ollama pull gemma3:1b</span></span></code></pre></div><p>Gemma 3 1B 約 815 MB、broadband 約 1-2 分鐘下載。下載過程顯示多階段：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">pulling 7cd4618c1faf: 100% ▕██████████████████▏ 815 MB
</span></span><span class="line"><span class="ln">2</span><span class="cl">pulling e0a42594d802: 100% ▕██████████████████▏  358 B
</span></span><span class="line"><span class="ln">3</span><span class="cl">pulling dd084c7d92a3: 100% ▕██████████████████▏  8.4 KB
</span></span><span class="line"><span class="ln">4</span><span class="cl">pulling 3116c5225075: 100% ▕██████████████████▏   77 B
</span></span><span class="line"><span class="ln">5</span><span class="cl">pulling 120007c81bf8: 100% ▕██████████████████▏  492 B
</span></span><span class="line"><span class="ln">6</span><span class="cl">verifying sha256 digest
</span></span><span class="line"><span class="ln">7</span><span class="cl">writing manifest
</span></span><span class="line"><span class="ln">8</span><span class="cl">success</span></span></code></pre></div><p>幾個 hash blob 分別是：模型權重（最大那個）、tokenizer、template、license metadata 等。Ollama 把這些統一管理、放在 <code>~/.ollama/models/</code>。</p>
<p>驗證模型已下載：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">ollama list</span></span></code></pre></div><p>預期：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">NAME         ID              SIZE      MODIFIED
</span></span><span class="line"><span class="ln">2</span><span class="cl">gemma3:1b    8648f39daa8f    815 MB    35 seconds ago</span></span></code></pre></div><h2 id="驗證-openai-相容-api">驗證 OpenAI 相容 API</h2>
<p>OpenAI 相容 API 是下游所有工具（IDE plugin、RAG pipeline、MCP server、<a href="/blog/llm/01-local-llm-services/vscode-continue-integration/" data-link-title="1.3 VS Code &#43; Continue.dev 整合" data-link-desc="安裝 Continue 擴充套件、config.json 設定、Cmd&#43;L 對話 / Cmd&#43;I 行內編輯快捷鍵">Continue.dev</a> 等）依賴的介面 contract、驗證它能正常回應、整個 stack 才走得通：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">curl -s http://localhost:11434/v1/chat/completions <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  -H <span class="s2">&#34;Content-Type: application/json&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  -d <span class="s1">&#39;{
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="s1">    &#34;model&#34;: &#34;gemma3:1b&#34;,
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="s1">    &#34;messages&#34;: [{&#34;role&#34;:&#34;user&#34;,&#34;content&#34;:&#34;Reply in one short sentence: what is 2+2?&#34;}],
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="s1">    &#34;stream&#34;: false
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="s1">  }&#39;</span></span></span></code></pre></div><p>預期回 JSON、<code>choices[0].message.content</code> 是模型回答（如 <code>&quot;2 + 2 = 4&quot;</code>）。看到合理回答就證明：</p>
<ol>
<li>Ollama 跟模型權重對接好。</li>
<li>OpenAI 相容 API 格式正常（IDE plugin 可以接）。</li>
<li>推論流程整條通。</li>
</ol>
<p>常見的失敗回應跟下一步：</p>
<ul>
<li><strong><code>{&quot;error&quot;:&quot;model 'gemma3:1b' not found, try pulling it first&quot;}</code></strong>：先跑 <code>ollama pull gemma3:1b</code>、確認 <code>ollama list</code> 看到該 tag。</li>
<li><strong><code>curl: (7) Failed to connect to localhost port 11434: Connection refused</code></strong>：server 沒在跑、回 <code>brew services list</code> 看 status、若是 stopped 跑 <code>brew services start ollama</code>。</li>
<li><strong><code>{&quot;error&quot;:&quot;json: cannot unmarshal ...&quot;}</code></strong>：請求格式錯（例如 messages 寫成 string 不是 array）、檢查 JSON body。</li>
<li><strong>連得上但長時間沒回應</strong>：第一次載入大 model 需要 30 ~ 60 秒、看 <code>~/.ollama/logs/server.log</code> 確認是否還在 loading。</li>
</ul>
<p>用內建 CLI 互動模式也行：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">ollama run gemma3:1b</span></span></code></pre></div><p>進入 REPL、可以打字對話。<code>/bye</code> 離開。</p>
<p>第一次跑 <code>ollama run</code> 會把模型載入記憶體（1B 模型大約 1-2 秒）、之後對話延遲低。如果幾分鐘沒用、模型會被 unload 釋放記憶體、下次 run 又要等載入。控制行為的環境變數是 <code>OLLAMA_KEEP_ALIVE</code>（預設 5 分鐘）。</p>
<h2 id="常見前置設定問題">常見前置設定問題</h2>
<h3 id="port-11434-被佔用">Port 11434 被佔用</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">lsof -i :11434</span></span></code></pre></div><p>若已有 process 占用、可能是先前手動跑過 <code>ollama serve</code> 沒關。kill 後再 start service：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">pkill -f <span class="s2">&#34;ollama serve&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">brew services restart ollama</span></span></code></pre></div><h3 id="ollama-command-not-found裝完還是找不到"><code>ollama: command not found</code>（裝完還是找不到）</h3>
<p>Homebrew 在 Apple Silicon 預設裝到 <code>/opt/homebrew/bin</code>、shell PATH 應該已含。若沒含：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="nv">$PATH</span> <span class="p">|</span> tr <span class="s1">&#39;:&#39;</span> <span class="s1">&#39;\n&#39;</span> <span class="p">|</span> grep homebrew
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># 若沒看到 /opt/homebrew/bin、要加進 ~/.zshrc：</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;export PATH=&#34;/opt/homebrew/bin:$PATH&#34;&#39;</span> &gt;&gt; ~/.zshrc
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">source</span> ~/.zshrc</span></span></code></pre></div><h3 id="server-啟動但-curl-失敗">Server 啟動但 curl 失敗</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">brew services list <span class="p">|</span> grep ollama</span></span></code></pre></div><p>若 status 不是 <code>started</code>、看 log：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">tail -50 /opt/homebrew/var/log/ollama.log</span></span></code></pre></div><p>常見原因：port 衝突、權限問題、上次 crash 沒清乾淨。</p>
<p>完整排錯流程見 <a href="/blog/llm/01-local-llm-services/troubleshooting/" data-link-title="1.7 排錯方法論：用三層架構做故障定位" data-link-desc="故障定位的分層思考、症狀到層級的對應反射、log 在三層的角色差異、最小可重現的縮減策略">1.7 排錯方法論</a>。</p>
<h2 id="之後想做的事">之後想做的事</h2>
<ul>
<li><strong>接 VS Code</strong>：見 <a href="/blog/llm/01-local-llm-services/vscode-continue-integration/" data-link-title="1.3 VS Code &#43; Continue.dev 整合" data-link-desc="安裝 Continue 擴充套件、config.json 設定、Cmd&#43;L 對話 / Cmd&#43;I 行內編輯快捷鍵">1.3 VS Code + Continue.dev 整合</a>。設定 <code>apiBase: http://localhost:11434</code> 就能用。</li>
<li><strong>跑更大模型</strong>：32GB+ Mac 推薦 <code>gemma4:31b-coding-mtp-bf16</code>（18 GB）。模型選擇見 <a href="/blog/llm/01-local-llm-services/model-selection-priority/" data-link-title="1.4 寫 code 場景的模型選型優先順序" data-link-desc="Gemma 4 31B MTP → Qwen3-Coder 30B → Qwen3 14B → gpt-oss 20B 的取捨與適用情境">1.4 模型選型優先順序</a>。</li>
<li><strong>加 embedding</strong>：codebase 索引要 embedding 模型：<code>ollama pull nomic-embed-text</code>（274 MB）、見 <a href="/blog/llm/04-applications/rag-principles/" data-link-title="4.1 RAG 原理：retrieval &#43; augmentation 模式" data-link-desc="為什麼模型需要外掛知識、語意相似 vs 字面相似、chunking 的本質取捨、retrieval 失敗的根本原因">4.1 RAG 原理</a>。</li>
</ul>
<h2 id="升級--移除">升級 / 移除</h2>
<p>升級：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">brew upgrade ollama
</span></span><span class="line"><span class="ln">2</span><span class="cl">brew services restart ollama</span></span></code></pre></div><p>完整移除：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">brew services stop ollama
</span></span><span class="line"><span class="ln">2</span><span class="cl">brew uninstall ollama
</span></span><span class="line"><span class="ln">3</span><span class="cl">rm -rf ~/.ollama  <span class="c1"># 清模型 cache（可選）</span></span></span></code></pre></div><h2 id="何時這篇會過時">何時這篇會過時</h2>
<ul>
<li><code>brew install ollama</code> 安裝方式跟 OpenAI 相容 API 形狀短期內不會變（生態都依賴）。</li>
<li><code>gemma3:1b</code> 這個具體 tag 預期會被新模型取代、但「拉一個小模型驗證流程」的方法不變。</li>
<li>launchd service 機制是 macOS 系統 API、不會 deprecate。</li>
</ul>
<p>讀的時候若 <code>brew install</code> 跑失敗、查 Ollama GitHub release notes；其餘驗證步驟結構通用。</p>
]]></content:encoded></item></channel></rss>