<?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>Tokenization on Tarragon</title><link>https://tarrragon.github.io/blog/tags/tokenization/</link><description>Recent content in Tokenization on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Thu, 14 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/tokenization/index.xml" rel="self" type="application/rss+xml"/><item><title>Unigram Tokenizer</title><link>https://tarrragon.github.io/blog/llm/knowledge-cards/unigram-tokenizer/</link><pubDate>Thu, 14 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/knowledge-cards/unigram-tokenizer/</guid><description>&lt;p>Unigram tokenizer 的核心概念是「&lt;strong>把 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token&lt;/a> 切分視為從候選子詞集合中選最可能切分的機率問題&lt;/strong>」。它先有一組候選 subword，再用機率模型找出最合理的切分，有別於逐步合併字元對的做法。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Unigram 是 subword tokenizer 家族的一員，常由 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece&lt;/a> 支援。它跟 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE&lt;/a> 的差異在訓練與切分策略：BPE 是貪婪合併，unigram 是機率選擇與剪枝候選。&lt;/p>
&lt;h2 id="可觀察訊號與例子">可觀察訊號與例子&lt;/h2>
&lt;p>讀 tokenizer 文件看到「unigram language model」「subword regularization」「SentencePiece unigram」就是這個概念。它可在訓練時對同一句話採不同合理切分，增加 tokenizer 層的資料多樣性。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>一般應用不會手動選 unigram tokenizer，但理解它能幫助比較模型的多語言支援與 token 效率。判讀時搭配 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/vocabulary-size/" data-link-title="Vocabulary Size" data-link-desc="tokenizer 詞彙表的 token 總數、影響 embedding 大小、tokenization 粒度、多語言友善度">Vocabulary Size&lt;/a> 與 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">Token&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>Unigram tokenizer 的核心概念是「<strong>把 <a href="/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token</a> 切分視為從候選子詞集合中選最可能切分的機率問題</strong>」。它先有一組候選 subword，再用機率模型找出最合理的切分，有別於逐步合併字元對的做法。</p>
<h2 id="概念位置">概念位置</h2>
<p>Unigram 是 subword tokenizer 家族的一員，常由 <a href="/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece</a> 支援。它跟 <a href="/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE</a> 的差異在訓練與切分策略：BPE 是貪婪合併，unigram 是機率選擇與剪枝候選。</p>
<h2 id="可觀察訊號與例子">可觀察訊號與例子</h2>
<p>讀 tokenizer 文件看到「unigram language model」「subword regularization」「SentencePiece unigram」就是這個概念。它可在訓練時對同一句話採不同合理切分，增加 tokenizer 層的資料多樣性。</p>
<h2 id="設計責任">設計責任</h2>
<p>一般應用不會手動選 unigram tokenizer，但理解它能幫助比較模型的多語言支援與 token 效率。判讀時搭配 <a href="/blog/llm/knowledge-cards/vocabulary-size/" data-link-title="Vocabulary Size" data-link-desc="tokenizer 詞彙表的 token 總數、影響 embedding 大小、tokenization 粒度、多語言友善度">Vocabulary Size</a> 與 <a href="/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">Token</a>。</p>
]]></content:encoded></item><item><title>WordPiece</title><link>https://tarrragon.github.io/blog/llm/knowledge-cards/wordpiece/</link><pubDate>Thu, 14 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/knowledge-cards/wordpiece/</guid><description>&lt;p>WordPiece 的核心概念是「&lt;strong>用語料 likelihood 改善量選擇子詞合併的 tokenization 演算法&lt;/strong>」。它跟 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE&lt;/a> 一樣把文字拆成 subword，但選擇 merge 的準則不同。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>WordPiece 屬於 subword tokenizer 家族，BERT 系列是代表。BPE 偏向合併高頻相鄰片段；WordPiece 偏向選擇能最大化語言模型 likelihood 的片段；&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece&lt;/a> 則是 tokenizer framework，可支援 BPE 或 unigram。&lt;/p>
&lt;h2 id="可觀察訊號與例子">可觀察訊號與例子&lt;/h2>
&lt;p>看到 &lt;code>##ing&lt;/code>、&lt;code>##ed&lt;/code> 這類 continuation marker，通常是 WordPiece 風格 vocabulary。它讓模型能處理未見過的詞，因為陌生詞仍可拆成已知 subword。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>比較 tokenizer 時，WordPiece 主要作為 BERT/encoder 系統的背景知識。寫 LLM 推論與本地 serving 時更常遇到 BPE、SentencePiece、vocab size 與 special tokens。&lt;/p></description><content:encoded><![CDATA[<p>WordPiece 的核心概念是「<strong>用語料 likelihood 改善量選擇子詞合併的 tokenization 演算法</strong>」。它跟 <a href="/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE</a> 一樣把文字拆成 subword，但選擇 merge 的準則不同。</p>
<h2 id="概念位置">概念位置</h2>
<p>WordPiece 屬於 subword tokenizer 家族，BERT 系列是代表。BPE 偏向合併高頻相鄰片段；WordPiece 偏向選擇能最大化語言模型 likelihood 的片段；<a href="/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece</a> 則是 tokenizer framework，可支援 BPE 或 unigram。</p>
<h2 id="可觀察訊號與例子">可觀察訊號與例子</h2>
<p>看到 <code>##ing</code>、<code>##ed</code> 這類 continuation marker，通常是 WordPiece 風格 vocabulary。它讓模型能處理未見過的詞，因為陌生詞仍可拆成已知 subword。</p>
<h2 id="設計責任">設計責任</h2>
<p>比較 tokenizer 時，WordPiece 主要作為 BERT/encoder 系統的背景知識。寫 LLM 推論與本地 serving 時更常遇到 BPE、SentencePiece、vocab size 與 special tokens。</p>
]]></content:encoded></item><item><title>BPE（Byte-Pair Encoding）</title><link>https://tarrragon.github.io/blog/llm/knowledge-cards/bpe/</link><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/knowledge-cards/bpe/</guid><description>&lt;p>BPE（Byte-Pair Encoding、Sennrich et al., 2015 引入 NLP）的核心概念是「&lt;strong>從字元開始、反覆找『出現頻率最高的字元對』把它合併成新 token、直到達到目標詞彙表大小&lt;/strong>」。是 GPT、Llama、Mistral 等主流 LLM 的 tokenization 演算法、能在「字元」跟「整詞」之間找平衡。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>BPE 訓練 tokenizer 的流程（簡化）：&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">Step 0：vocab = 所有單一字元（256 個 byte / Unicode 字符）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">迭代：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> Step 1：掃描 corpus、統計所有相鄰 token 對的出現頻率
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl"> Step 2：找出現最多的字元對（如 &amp;#34;l&amp;#34; + &amp;#34;o&amp;#34; 一起出現 1M 次）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl"> Step 3：把它當新 token 加進 vocab、把 corpus 裡所有這個對換成新 token
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl"> Step 4：回到 Step 1、直到 vocab 達到目標大小（如 50K、128K、256K）&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>實際 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token&lt;/a> 化的結果：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>文字&lt;/th>
 &lt;th>BPE token 化結果&lt;/th>
 &lt;th>理由&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>Hello&lt;/code>&lt;/td>
 &lt;td>&lt;code>[&amp;quot;Hello&amp;quot;]&lt;/code>&lt;/td>
 &lt;td>高頻單字、整詞當一個 token&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>Hellobot&lt;/code>&lt;/td>
 &lt;td>&lt;code>[&amp;quot;Hello&amp;quot;, &amp;quot;bot&amp;quot;]&lt;/code>&lt;/td>
 &lt;td>罕見組合、拆成已知 token&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>Antidisestab...&lt;/code>&lt;/td>
 &lt;td>&lt;code>[&amp;quot;Anti&amp;quot;, &amp;quot;dis&amp;quot;, &amp;quot;establish&amp;quot;, ...]&lt;/code>&lt;/td>
 &lt;td>罕見長詞、拆成 sub-word&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>你好&lt;/code>&lt;/td>
 &lt;td>&lt;code>[&amp;quot;你&amp;quot;, &amp;quot;好&amp;quot;]&lt;/code> 或 &lt;code>[&amp;quot;你好&amp;quot;]&lt;/code>&lt;/td>
 &lt;td>視 tokenizer 訓練 corpus 的中文比例&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>BPE 的變體：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Byte-level BPE&lt;/strong>：把每個 byte 當基底（256 個）、所以任何 Unicode / 二進制都能 tokenize、不會有 unknown token。GPT-2 開始的標準。&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece&lt;/a> BPE&lt;/strong>：跟 SentencePiece 框架結合、處理多語言更靈活。&lt;/li>
&lt;/ol>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>讀 model card 看到 &lt;code>tokenizer: BPE&lt;/code> 就是這個演算法。BPE 對英文友好（高頻單詞整個一 token）、中文 / 日韓較不友好（單字符常被當獨立 token）；這就是為什麼同一段中文翻譯成英文後、英文 token 數常常更少、雲端 LLM 用中文 API 比英文貴。但越新的模型（Gemma 4、Qwen3 等）vocab 越大（256K+）、對中文友善度提升中。&lt;/p></description><content:encoded><![CDATA[<p>BPE（Byte-Pair Encoding、Sennrich et al., 2015 引入 NLP）的核心概念是「<strong>從字元開始、反覆找『出現頻率最高的字元對』把它合併成新 token、直到達到目標詞彙表大小</strong>」。是 GPT、Llama、Mistral 等主流 LLM 的 tokenization 演算法、能在「字元」跟「整詞」之間找平衡。</p>
<h2 id="概念位置">概念位置</h2>
<p>BPE 訓練 tokenizer 的流程（簡化）：</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">Step 0：vocab = 所有單一字元（256 個 byte / Unicode 字符）
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</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">  Step 1：掃描 corpus、統計所有相鄰 token 對的出現頻率
</span></span><span class="line"><span class="ln">5</span><span class="cl">  Step 2：找出現最多的字元對（如 &#34;l&#34; + &#34;o&#34; 一起出現 1M 次）
</span></span><span class="line"><span class="ln">6</span><span class="cl">  Step 3：把它當新 token 加進 vocab、把 corpus 裡所有這個對換成新 token
</span></span><span class="line"><span class="ln">7</span><span class="cl">  Step 4：回到 Step 1、直到 vocab 達到目標大小（如 50K、128K、256K）</span></span></code></pre></div><p>實際 <a href="/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token</a> 化的結果：</p>
<table>
  <thead>
      <tr>
          <th>文字</th>
          <th>BPE token 化結果</th>
          <th>理由</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>Hello</code></td>
          <td><code>[&quot;Hello&quot;]</code></td>
          <td>高頻單字、整詞當一個 token</td>
      </tr>
      <tr>
          <td><code>Hellobot</code></td>
          <td><code>[&quot;Hello&quot;, &quot;bot&quot;]</code></td>
          <td>罕見組合、拆成已知 token</td>
      </tr>
      <tr>
          <td><code>Antidisestab...</code></td>
          <td><code>[&quot;Anti&quot;, &quot;dis&quot;, &quot;establish&quot;, ...]</code></td>
          <td>罕見長詞、拆成 sub-word</td>
      </tr>
      <tr>
          <td><code>你好</code></td>
          <td><code>[&quot;你&quot;, &quot;好&quot;]</code> 或 <code>[&quot;你好&quot;]</code></td>
          <td>視 tokenizer 訓練 corpus 的中文比例</td>
      </tr>
  </tbody>
</table>
<p>BPE 的變體：</p>
<ol>
<li><strong>Byte-level BPE</strong>：把每個 byte 當基底（256 個）、所以任何 Unicode / 二進制都能 tokenize、不會有 unknown token。GPT-2 開始的標準。</li>
<li><strong><a href="/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece</a> BPE</strong>：跟 SentencePiece 框架結合、處理多語言更靈活。</li>
</ol>
<h2 id="設計責任">設計責任</h2>
<p>讀 model card 看到 <code>tokenizer: BPE</code> 就是這個演算法。BPE 對英文友好（高頻單詞整個一 token）、中文 / 日韓較不友好（單字符常被當獨立 token）；這就是為什麼同一段中文翻譯成英文後、英文 token 數常常更少、雲端 LLM 用中文 API 比英文貴。但越新的模型（Gemma 4、Qwen3 等）vocab 越大（256K+）、對中文友善度提升中。</p>
]]></content:encoded></item><item><title>SentencePiece</title><link>https://tarrragon.github.io/blog/llm/knowledge-cards/sentencepiece/</link><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/knowledge-cards/sentencepiece/</guid><description>&lt;p>SentencePiece（Kudo &amp;amp; Richardson, 2018）的核心概念是「&lt;strong>Google 開源的 tokenization 框架、把『空白也當一個字元』處理、原生支援 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE&lt;/a> 跟 unigram 兩種演算法&lt;/strong>」。Llama、Gemma、Mistral、T5 等模型用 SentencePiece 作為 tokenizer 實作；它的 multilingual 友善度跟「不依賴語言預處理」是被選擇的主因。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>SentencePiece 跟其他 tokenization 路線的對比：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>框架 / 路線&lt;/th>
 &lt;th>機制&lt;/th>
 &lt;th>處理多語言 / 空白&lt;/th>
 &lt;th>出現在&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>WordPiece&lt;/td>
 &lt;td>類似 BPE、Google 早期方案&lt;/td>
 &lt;td>需語言預處理（如英文 lowercase）&lt;/td>
 &lt;td>BERT、DistilBERT&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>SentencePiece BPE&lt;/strong>&lt;/td>
 &lt;td>BPE 演算法、空白當特殊字符 &lt;code>▁&lt;/code> 處理&lt;/td>
 &lt;td>統一處理、不需語言預設&lt;/td>
 &lt;td>Llama、Gemma、Mistral&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>SentencePiece Unigram&lt;/strong>&lt;/td>
 &lt;td>機率模型、選一組讓 corpus likelihood 最大的子詞&lt;/td>
 &lt;td>同上、機率視角&lt;/td>
 &lt;td>T5、XLNet、ALBERT&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>tiktoken（OpenAI）&lt;/td>
 &lt;td>Byte-level BPE&lt;/td>
 &lt;td>統一處理&lt;/td>
 &lt;td>GPT-3.5、GPT-4、GPT-5&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>關鍵特性：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>&lt;code>▁&lt;/code> 表示空白&lt;/strong>：SentencePiece 把空白編碼成 &lt;code>▁&lt;/code>（Unicode U+2581）、所以「Hello world」會被 tokenize 成 &lt;code>[&amp;quot;Hello&amp;quot;, &amp;quot;▁world&amp;quot;]&lt;/code>、保留空白資訊在 token 內。&lt;/li>
&lt;li>&lt;strong>不依賴語言預處理&lt;/strong>：傳統 NLP 要先做 lowercasing、word segmentation；SentencePiece 直接從 raw bytes 開始學、跨語言通用。&lt;/li>
&lt;li>&lt;strong>原生 multilingual&lt;/strong>：訓練 corpus 包含多語言時、tokenizer 自動學會跨語言的子詞單元、不需要為每種語言設定不同 tokenizer。&lt;/li>
&lt;/ol>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>讀 model card / repo 看到 &lt;code>tokenizer.model&lt;/code> 檔案（不是 &lt;code>tokenizer.json&lt;/code> 或 &lt;code>vocab.txt&lt;/code>）就是 SentencePiece 用的 protobuf 格式。寫 code 場景的意涵：SentencePiece tokenizer 在中文 / 多語言任務上比 WordPiece 友好；換 tokenizer 等於整個 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/embedding-layer/" data-link-title="Embedding Layer" data-link-desc="Transformer 第一層的查表結構、把整數 token ID 轉成可運算的向量">embedding layer&lt;/a> 失效、所以 fine-tune 時不會動 tokenizer。&lt;/p></description><content:encoded><![CDATA[<p>SentencePiece（Kudo &amp; Richardson, 2018）的核心概念是「<strong>Google 開源的 tokenization 框架、把『空白也當一個字元』處理、原生支援 <a href="/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE</a> 跟 unigram 兩種演算法</strong>」。Llama、Gemma、Mistral、T5 等模型用 SentencePiece 作為 tokenizer 實作；它的 multilingual 友善度跟「不依賴語言預處理」是被選擇的主因。</p>
<h2 id="概念位置">概念位置</h2>
<p>SentencePiece 跟其他 tokenization 路線的對比：</p>
<table>
  <thead>
      <tr>
          <th>框架 / 路線</th>
          <th>機制</th>
          <th>處理多語言 / 空白</th>
          <th>出現在</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>WordPiece</td>
          <td>類似 BPE、Google 早期方案</td>
          <td>需語言預處理（如英文 lowercase）</td>
          <td>BERT、DistilBERT</td>
      </tr>
      <tr>
          <td><strong>SentencePiece BPE</strong></td>
          <td>BPE 演算法、空白當特殊字符 <code>▁</code> 處理</td>
          <td>統一處理、不需語言預設</td>
          <td>Llama、Gemma、Mistral</td>
      </tr>
      <tr>
          <td><strong>SentencePiece Unigram</strong></td>
          <td>機率模型、選一組讓 corpus likelihood 最大的子詞</td>
          <td>同上、機率視角</td>
          <td>T5、XLNet、ALBERT</td>
      </tr>
      <tr>
          <td>tiktoken（OpenAI）</td>
          <td>Byte-level BPE</td>
          <td>統一處理</td>
          <td>GPT-3.5、GPT-4、GPT-5</td>
      </tr>
  </tbody>
</table>
<p>關鍵特性：</p>
<ol>
<li><strong><code>▁</code> 表示空白</strong>：SentencePiece 把空白編碼成 <code>▁</code>（Unicode U+2581）、所以「Hello world」會被 tokenize 成 <code>[&quot;Hello&quot;, &quot;▁world&quot;]</code>、保留空白資訊在 token 內。</li>
<li><strong>不依賴語言預處理</strong>：傳統 NLP 要先做 lowercasing、word segmentation；SentencePiece 直接從 raw bytes 開始學、跨語言通用。</li>
<li><strong>原生 multilingual</strong>：訓練 corpus 包含多語言時、tokenizer 自動學會跨語言的子詞單元、不需要為每種語言設定不同 tokenizer。</li>
</ol>
<h2 id="設計責任">設計責任</h2>
<p>讀 model card / repo 看到 <code>tokenizer.model</code> 檔案（不是 <code>tokenizer.json</code> 或 <code>vocab.txt</code>）就是 SentencePiece 用的 protobuf 格式。寫 code 場景的意涵：SentencePiece tokenizer 在中文 / 多語言任務上比 WordPiece 友好；換 tokenizer 等於整個 <a href="/blog/llm/knowledge-cards/embedding-layer/" data-link-title="Embedding Layer" data-link-desc="Transformer 第一層的查表結構、把整數 token ID 轉成可運算的向量">embedding layer</a> 失效、所以 fine-tune 時不會動 tokenizer。</p>
]]></content:encoded></item><item><title>Special Tokens</title><link>https://tarrragon.github.io/blog/llm/knowledge-cards/special-tokens/</link><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/knowledge-cards/special-tokens/</guid><description>&lt;p>Special tokens（特殊 token）的核心概念是「&lt;strong>在 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/vocabulary-size/" data-link-title="Vocabulary Size" data-link-desc="tokenizer 詞彙表的 token 總數、影響 embedding 大小、tokenization 粒度、多語言友善度">vocab&lt;/a> 中保留給控制 / 邊界 / 結構用途的 token&lt;/strong>」、不是正常字面意義的詞。常見如 &lt;code>&amp;lt;bos&amp;gt;&lt;/code>（begin of sequence）、&lt;code>&amp;lt;eos&amp;gt;&lt;/code>（end of sequence）、&lt;code>&amp;lt;pad&amp;gt;&lt;/code>（padding）、&lt;code>&amp;lt;|user|&amp;gt;&lt;/code>、&lt;code>&amp;lt;|assistant|&amp;gt;&lt;/code>、&lt;code>&amp;lt;|tool_call|&amp;gt;&lt;/code> 等。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>LLM 中 special tokens 的常見類型：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Token&lt;/th>
 &lt;th>用途&lt;/th>
 &lt;th>範例&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;bos&amp;gt;&lt;/code> / &lt;code>&amp;lt;s&amp;gt;&lt;/code>&lt;/td>
 &lt;td>序列開頭&lt;/td>
 &lt;td>Llama、Mistral&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;eos&amp;gt;&lt;/code> / &lt;code>&amp;lt;/s&amp;gt;&lt;/code>&lt;/td>
 &lt;td>序列結尾、模型輸出這個就停&lt;/td>
 &lt;td>所有 LLM&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;pad&amp;gt;&lt;/code>&lt;/td>
 &lt;td>把 batch 內不同長度 sequence 填齊&lt;/td>
 &lt;td>訓練 / batched 推論時用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;unk&amp;gt;&lt;/code>&lt;/td>
 &lt;td>遇到 vocab 外的 token（byte-level BPE 已不需要）&lt;/td>
 &lt;td>早期 tokenizer&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;|user|&amp;gt;&lt;/code> / &lt;code>&amp;lt;|assistant|&amp;gt;&lt;/code>&lt;/td>
 &lt;td>Chat template 角色標記&lt;/td>
 &lt;td>Llama 3 chat、Qwen chat&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code> / &lt;code>&amp;lt;|im_end|&amp;gt;&lt;/code>&lt;/td>
 &lt;td>ChatML 格式的對話邊界&lt;/td>
 &lt;td>OpenAI、Qwen 系列&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;|tool_call|&amp;gt;&lt;/code> / &lt;code>&amp;lt;|tool_response|&amp;gt;&lt;/code>&lt;/td>
 &lt;td>Tool use / function calling 訊號&lt;/td>
 &lt;td>Llama 3.1+ 等支援 tool use 的模型&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>&amp;lt;think&amp;gt;&lt;/code> / &lt;code>&amp;lt;/think&amp;gt;&lt;/code>&lt;/td>
 &lt;td>Chain-of-thought 標記&lt;/td>
 &lt;td>DeepSeek-R1、O1 風格模型&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>關鍵特性：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>訓練時用特殊 token ID 標記&lt;/strong>：模型透過大量範例學會「看到 &lt;code>&amp;lt;\|user\|&amp;gt;&lt;/code> 後面是使用者輸入、看到 &lt;code>&amp;lt;\|assistant\|&amp;gt;&lt;/code> 後面要生成回答」。&lt;/li>
&lt;li>&lt;strong>Chat template 把這些組合起來&lt;/strong>：把使用者輸入 + 系統 prompt + 對話歷史依特定格式插入這些 token、組成模型訓練時看過的格式。&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;lt;eos&amp;gt;&lt;/code> 的 sampling 行為&lt;/strong>：模型輸出 &lt;code>&amp;lt;eos&amp;gt;&lt;/code> 後、推論伺服器停止生成、所以「為什麼回答突然停了」很多時候就是模型決定發 EOS。&lt;/li>
&lt;/ol>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>讀 tokenizer config（&lt;code>tokenizer_config.json&lt;/code>）看到 &lt;code>bos_token&lt;/code>、&lt;code>eos_token&lt;/code>、&lt;code>chat_template&lt;/code> 等就是這組設定。寫 code 場景的判讀：用 Continue.dev / Ollama 時、伺服器會自動套用模型的 chat template、把使用者輸入轉成正確的 special tokens 格式；自己寫 inference code 時、要呼叫 &lt;code>tokenizer.apply_chat_template()&lt;/code> 避免格式錯亂導致模型輸出爛。&lt;/p></description><content:encoded><![CDATA[<p>Special tokens（特殊 token）的核心概念是「<strong>在 <a href="/blog/llm/knowledge-cards/vocabulary-size/" data-link-title="Vocabulary Size" data-link-desc="tokenizer 詞彙表的 token 總數、影響 embedding 大小、tokenization 粒度、多語言友善度">vocab</a> 中保留給控制 / 邊界 / 結構用途的 token</strong>」、不是正常字面意義的詞。常見如 <code>&lt;bos&gt;</code>（begin of sequence）、<code>&lt;eos&gt;</code>（end of sequence）、<code>&lt;pad&gt;</code>（padding）、<code>&lt;|user|&gt;</code>、<code>&lt;|assistant|&gt;</code>、<code>&lt;|tool_call|&gt;</code> 等。</p>
<h2 id="概念位置">概念位置</h2>
<p>LLM 中 special tokens 的常見類型：</p>
<table>
  <thead>
      <tr>
          <th>Token</th>
          <th>用途</th>
          <th>範例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>&lt;bos&gt;</code> / <code>&lt;s&gt;</code></td>
          <td>序列開頭</td>
          <td>Llama、Mistral</td>
      </tr>
      <tr>
          <td><code>&lt;eos&gt;</code> / <code>&lt;/s&gt;</code></td>
          <td>序列結尾、模型輸出這個就停</td>
          <td>所有 LLM</td>
      </tr>
      <tr>
          <td><code>&lt;pad&gt;</code></td>
          <td>把 batch 內不同長度 sequence 填齊</td>
          <td>訓練 / batched 推論時用</td>
      </tr>
      <tr>
          <td><code>&lt;unk&gt;</code></td>
          <td>遇到 vocab 外的 token（byte-level BPE 已不需要）</td>
          <td>早期 tokenizer</td>
      </tr>
      <tr>
          <td><code>&lt;|user|&gt;</code> / <code>&lt;|assistant|&gt;</code></td>
          <td>Chat template 角色標記</td>
          <td>Llama 3 chat、Qwen chat</td>
      </tr>
      <tr>
          <td><code>&lt;|im_start|&gt;</code> / <code>&lt;|im_end|&gt;</code></td>
          <td>ChatML 格式的對話邊界</td>
          <td>OpenAI、Qwen 系列</td>
      </tr>
      <tr>
          <td><code>&lt;|tool_call|&gt;</code> / <code>&lt;|tool_response|&gt;</code></td>
          <td>Tool use / function calling 訊號</td>
          <td>Llama 3.1+ 等支援 tool use 的模型</td>
      </tr>
      <tr>
          <td><code>&lt;think&gt;</code> / <code>&lt;/think&gt;</code></td>
          <td>Chain-of-thought 標記</td>
          <td>DeepSeek-R1、O1 風格模型</td>
      </tr>
  </tbody>
</table>
<p>關鍵特性：</p>
<ol>
<li><strong>訓練時用特殊 token ID 標記</strong>：模型透過大量範例學會「看到 <code>&lt;\|user\|&gt;</code> 後面是使用者輸入、看到 <code>&lt;\|assistant\|&gt;</code> 後面要生成回答」。</li>
<li><strong>Chat template 把這些組合起來</strong>：把使用者輸入 + 系統 prompt + 對話歷史依特定格式插入這些 token、組成模型訓練時看過的格式。</li>
<li><strong><code>&lt;eos&gt;</code> 的 sampling 行為</strong>：模型輸出 <code>&lt;eos&gt;</code> 後、推論伺服器停止生成、所以「為什麼回答突然停了」很多時候就是模型決定發 EOS。</li>
</ol>
<h2 id="設計責任">設計責任</h2>
<p>讀 tokenizer config（<code>tokenizer_config.json</code>）看到 <code>bos_token</code>、<code>eos_token</code>、<code>chat_template</code> 等就是這組設定。寫 code 場景的判讀：用 Continue.dev / Ollama 時、伺服器會自動套用模型的 chat template、把使用者輸入轉成正確的 special tokens 格式；自己寫 inference code 時、要呼叫 <code>tokenizer.apply_chat_template()</code> 避免格式錯亂導致模型輸出爛。</p>
]]></content:encoded></item><item><title>Vocabulary Size</title><link>https://tarrragon.github.io/blog/llm/knowledge-cards/vocabulary-size/</link><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/knowledge-cards/vocabulary-size/</guid><description>&lt;p>Vocabulary size（詞彙表大小）的核心概念是「&lt;strong>tokenizer 詞彙表中 token 的總數&lt;/strong>」。是模型訓練時就決定的 hyperparameter、後續不能改。Vocabulary size 影響 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/embedding-layer/" data-link-title="Embedding Layer" data-link-desc="Transformer 第一層的查表結構、把整數 token ID 轉成可運算的向量">embedding layer&lt;/a> 大小、單一文字對應的 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token&lt;/a> 數、多語言處理品質。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>主流 LLM 的 vocab size 演化：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>模型&lt;/th>
 &lt;th>Vocab size&lt;/th>
 &lt;th>設計考量&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>GPT-2&lt;/td>
 &lt;td>50,257&lt;/td>
 &lt;td>早期 byte-level BPE、英文為主&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Llama 1 / 2&lt;/td>
 &lt;td>32,000&lt;/td>
 &lt;td>緊湊、英文 + 部分多語言&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Llama 3&lt;/td>
 &lt;td>128,256&lt;/td>
 &lt;td>大幅擴張、改善多語言（特別是非拉丁語系）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Gemma 4&lt;/td>
 &lt;td>256,000&lt;/td>
 &lt;td>進一步擴大、強化多語言 + code tokenization&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Qwen3&lt;/td>
 &lt;td>151,936&lt;/td>
 &lt;td>中文 + 多語言友善&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>DeepSeek-V3&lt;/td>
 &lt;td>129,280&lt;/td>
 &lt;td>中英 + code、跟 Llama 3 同量級&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Vocabulary size 的取捨：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Vocab 小（如 32K）&lt;/th>
 &lt;th>Vocab 大（如 256K）&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Embedding 矩陣小、模型參數少&lt;/td>
 &lt;td>Embedding 矩陣大、模型參數多&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>罕見字 / 多語言被拆很細、token 數多&lt;/td>
 &lt;td>高頻多語言整詞當一 token、token 數少&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>推論計算每步輸出 softmax 較快&lt;/td>
 &lt;td>每步 softmax 較慢（vocab × hidden 矩陣大）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>API 計費 token 數量較多&lt;/td>
 &lt;td>API 計費 token 數量較少&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>範例：同段中文「你好、世界」、Llama 1 (vocab 32K) 約 6 token、Gemma 4 (vocab 256K) 約 2-3 token、差距不小。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>讀 model card 看到 &lt;code>vocab_size&lt;/code> 就是這個值。寫 code 場景的判讀：跑同個 prompt、不同模型實際處理的 token 數差很多、影響 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/context-window/" data-link-title="Context Window" data-link-desc="模型一次能處理的最大 token 數量：prompt 加生成的總和上限">context window&lt;/a> 利用率跟雲端 API 計費；換 tokenizer = 換 vocab = 整個 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/embedding-layer/" data-link-title="Embedding Layer" data-link-desc="Transformer 第一層的查表結構、把整數 token ID 轉成可運算的向量">embedding layer&lt;/a> 失效、所以 fine-tune 通常不動 tokenizer、想增加新語言的最簡單方式是 extend embedding（加新 row 不動既有 row、再 fine-tune）。&lt;/p></description><content:encoded><![CDATA[<p>Vocabulary size（詞彙表大小）的核心概念是「<strong>tokenizer 詞彙表中 token 的總數</strong>」。是模型訓練時就決定的 hyperparameter、後續不能改。Vocabulary size 影響 <a href="/blog/llm/knowledge-cards/embedding-layer/" data-link-title="Embedding Layer" data-link-desc="Transformer 第一層的查表結構、把整數 token ID 轉成可運算的向量">embedding layer</a> 大小、單一文字對應的 <a href="/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token</a> 數、多語言處理品質。</p>
<h2 id="概念位置">概念位置</h2>
<p>主流 LLM 的 vocab size 演化：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>Vocab size</th>
          <th>設計考量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT-2</td>
          <td>50,257</td>
          <td>早期 byte-level BPE、英文為主</td>
      </tr>
      <tr>
          <td>Llama 1 / 2</td>
          <td>32,000</td>
          <td>緊湊、英文 + 部分多語言</td>
      </tr>
      <tr>
          <td>Llama 3</td>
          <td>128,256</td>
          <td>大幅擴張、改善多語言（特別是非拉丁語系）</td>
      </tr>
      <tr>
          <td>Gemma 4</td>
          <td>256,000</td>
          <td>進一步擴大、強化多語言 + code tokenization</td>
      </tr>
      <tr>
          <td>Qwen3</td>
          <td>151,936</td>
          <td>中文 + 多語言友善</td>
      </tr>
      <tr>
          <td>DeepSeek-V3</td>
          <td>129,280</td>
          <td>中英 + code、跟 Llama 3 同量級</td>
      </tr>
  </tbody>
</table>
<p>Vocabulary size 的取捨：</p>
<table>
  <thead>
      <tr>
          <th>Vocab 小（如 32K）</th>
          <th>Vocab 大（如 256K）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Embedding 矩陣小、模型參數少</td>
          <td>Embedding 矩陣大、模型參數多</td>
      </tr>
      <tr>
          <td>罕見字 / 多語言被拆很細、token 數多</td>
          <td>高頻多語言整詞當一 token、token 數少</td>
      </tr>
      <tr>
          <td>推論計算每步輸出 softmax 較快</td>
          <td>每步 softmax 較慢（vocab × hidden 矩陣大）</td>
      </tr>
      <tr>
          <td>API 計費 token 數量較多</td>
          <td>API 計費 token 數量較少</td>
      </tr>
  </tbody>
</table>
<p>範例：同段中文「你好、世界」、Llama 1 (vocab 32K) 約 6 token、Gemma 4 (vocab 256K) 約 2-3 token、差距不小。</p>
<h2 id="設計責任">設計責任</h2>
<p>讀 model card 看到 <code>vocab_size</code> 就是這個值。寫 code 場景的判讀：跑同個 prompt、不同模型實際處理的 token 數差很多、影響 <a href="/blog/llm/knowledge-cards/context-window/" data-link-title="Context Window" data-link-desc="模型一次能處理的最大 token 數量：prompt 加生成的總和上限">context window</a> 利用率跟雲端 API 計費；換 tokenizer = 換 vocab = 整個 <a href="/blog/llm/knowledge-cards/embedding-layer/" data-link-title="Embedding Layer" data-link-desc="Transformer 第一層的查表結構、把整數 token ID 轉成可運算的向量">embedding layer</a> 失效、所以 fine-tune 通常不動 tokenizer、想增加新語言的最簡單方式是 extend embedding（加新 row 不動既有 row、再 fine-tune）。</p>
]]></content:encoded></item><item><title>3.6 Tokenization：BPE、SentencePiece、Tiktoken</title><link>https://tarrragon.github.io/blog/llm/03-theoretical-foundations/tokenization-algorithms/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/03-theoretical-foundations/tokenization-algorithms/</guid><description>&lt;p>&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">Tokenization&lt;/a> 是把文字切成模型可處理的 token 序列的過程。看似簡單的「切字」實際上有完整算法、且 tokenizer 的選擇深刻影響模型能力、context window 利用率、跨語言表現、跟一些奇怪 bug 的成因（GPT 在某些字串上表現異常的「glitch tokens」就源於 tokenizer 設計）。&lt;/p>
&lt;p>本章拆開四個主流 tokenization 算法（BPE、&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/wordpiece/" data-link-title="WordPiece" data-link-desc="以 likelihood improvement 選擇子詞合併的 tokenizer 演算法，BERT 系列代表性使用">WordPiece&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/unigram-tokenizer/" data-link-title="Unigram Tokenizer" data-link-desc="以機率模型選擇子詞切分的 tokenizer 演算法，常見於 SentencePiece 的 unigram 模式">Unigram&lt;/a>、SentencePiece）、解釋 vocabulary 怎麼學出來、為什麼中文 / 中日韓字幾乎一字一 token、tokenizer 為什麼影響 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/speculative-decoding/" data-link-title="Speculative Decoding" data-link-desc="用小模型猜未來 token、大模型並行驗證的加速技巧">speculative decoding&lt;/a> 的相容性。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>讀完本章後、你應該能：&lt;/p>
&lt;ol>
&lt;li>解釋 BPE（Byte-Pair Encoding）的工作原理。&lt;/li>
&lt;li>看到不同 model 切同段文字得到不同 token 數時、知道原因。&lt;/li>
&lt;li>解釋為什麼 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/drafter-model/" data-link-title="Drafter Model" data-link-desc="speculative decoding 中用來快速猜未來 token 的小模型">drafter&lt;/a> 跟 target 必須共用 tokenizer。&lt;/li>
&lt;li>看到 vocab_size = 256,000 vs 128,256 時、知道差異在哪。&lt;/li>
&lt;/ol>
&lt;h2 id="tokenization-的設計目標">Tokenization 的設計目標&lt;/h2>
&lt;p>理想 tokenizer 要同時滿足：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>覆蓋率高&lt;/strong>：能 encode 任何文字、不會「碰到沒見過的字壞掉」。&lt;/li>
&lt;li>&lt;strong>效率高&lt;/strong>：常見字串切成少數 token、節省 context 與計算。&lt;/li>
&lt;li>&lt;strong>語意保留&lt;/strong>：保留有意義的 sub-word 邊界（「unhappy」切成 &lt;code>un&lt;/code> + &lt;code>happy&lt;/code> 比 &lt;code>unh&lt;/code> + &lt;code>appy&lt;/code> 好）。&lt;/li>
&lt;li>&lt;strong>跨語言公平&lt;/strong>：英文跟中文 / 日文 / 阿拉伯文等都用合理數量的 token。&lt;/li>
&lt;/ol>
&lt;p>不同算法在這四個目標上有不同取捨。&lt;/p>
&lt;h2 id="早期方法word-level-跟-char-level">早期方法：word-level 跟 char-level&lt;/h2>
&lt;h3 id="word-level-tokenization">Word-level Tokenization&lt;/h3>
&lt;p>最簡單的方法是「用空白跟標點切」、每個 word 一個 token。&lt;/p>
&lt;p>優點：直觀。&lt;/p>
&lt;p>缺點：&lt;/p>
&lt;ol>
&lt;li>Vocabulary 爆炸：英文有幾百萬個 word forms（含複數、時態、複合詞等）。&lt;/li>
&lt;li>OOV（out-of-vocabulary）：新詞、typo、URL、混合語言完全壞掉。&lt;/li>
&lt;li>中文 / 日文沒有空白：要先做 word segmentation。&lt;/li>
&lt;/ol>
&lt;p>現代 LLM 已淘汰 word-level、主流改用 subword 系列。&lt;/p>
&lt;h3 id="char-level-tokenization">Char-level Tokenization&lt;/h3>
&lt;p>另一個極端是「每個 character 一個 token」。&lt;/p>
&lt;p>優點：vocabulary 小、無 OOV。&lt;/p>
&lt;p>缺點：序列變很長（一句話幾十到幾百 char、效率低）、模型要從很基礎學起、訓練不效率。&lt;/p>
&lt;p>現代 LLM 也跳過純 char-level、改用 subword 折衷。&lt;/p>
&lt;h3 id="折衷subword-tokenization">折衷：Subword Tokenization&lt;/h3>
&lt;p>主流方案是「subword tokenization」：常見字串當一個 token、罕見字串切成更小單位（甚至到 char 級別）。三個主流算法：&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;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE&lt;/a>&lt;/td>
 &lt;td>GPT-2、GPT-3、GPT-4、Llama 系列&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>WordPiece&lt;/td>
 &lt;td>BERT&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece&lt;/a>&lt;/td>
 &lt;td>Gemma、PaLM、T5&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/vocabulary-size/" data-link-title="Vocabulary Size" data-link-desc="tokenizer 詞彙表的 token 總數、影響 embedding 大小、tokenization 粒度、多語言友善度">Vocabulary size&lt;/a> 跟 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/special-tokens/" data-link-title="Special Tokens" data-link-desc="在 vocab 中保留給特殊用途的 token：sequence 邊界、角色標記、padding、tool call 等">special tokens&lt;/a> 是這幾個算法產出的 tokenizer 共同的概念維度。&lt;/p></description><content:encoded><![CDATA[<p><a href="/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">Tokenization</a> 是把文字切成模型可處理的 token 序列的過程。看似簡單的「切字」實際上有完整算法、且 tokenizer 的選擇深刻影響模型能力、context window 利用率、跨語言表現、跟一些奇怪 bug 的成因（GPT 在某些字串上表現異常的「glitch tokens」就源於 tokenizer 設計）。</p>
<p>本章拆開四個主流 tokenization 算法（BPE、<a href="/blog/llm/knowledge-cards/wordpiece/" data-link-title="WordPiece" data-link-desc="以 likelihood improvement 選擇子詞合併的 tokenizer 演算法，BERT 系列代表性使用">WordPiece</a>、<a href="/blog/llm/knowledge-cards/unigram-tokenizer/" data-link-title="Unigram Tokenizer" data-link-desc="以機率模型選擇子詞切分的 tokenizer 演算法，常見於 SentencePiece 的 unigram 模式">Unigram</a>、SentencePiece）、解釋 vocabulary 怎麼學出來、為什麼中文 / 中日韓字幾乎一字一 token、tokenizer 為什麼影響 <a href="/blog/llm/knowledge-cards/speculative-decoding/" data-link-title="Speculative Decoding" data-link-desc="用小模型猜未來 token、大模型並行驗證的加速技巧">speculative decoding</a> 的相容性。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本章後、你應該能：</p>
<ol>
<li>解釋 BPE（Byte-Pair Encoding）的工作原理。</li>
<li>看到不同 model 切同段文字得到不同 token 數時、知道原因。</li>
<li>解釋為什麼 <a href="/blog/llm/knowledge-cards/drafter-model/" data-link-title="Drafter Model" data-link-desc="speculative decoding 中用來快速猜未來 token 的小模型">drafter</a> 跟 target 必須共用 tokenizer。</li>
<li>看到 vocab_size = 256,000 vs 128,256 時、知道差異在哪。</li>
</ol>
<h2 id="tokenization-的設計目標">Tokenization 的設計目標</h2>
<p>理想 tokenizer 要同時滿足：</p>
<ol>
<li><strong>覆蓋率高</strong>：能 encode 任何文字、不會「碰到沒見過的字壞掉」。</li>
<li><strong>效率高</strong>：常見字串切成少數 token、節省 context 與計算。</li>
<li><strong>語意保留</strong>：保留有意義的 sub-word 邊界（「unhappy」切成 <code>un</code> + <code>happy</code> 比 <code>unh</code> + <code>appy</code> 好）。</li>
<li><strong>跨語言公平</strong>：英文跟中文 / 日文 / 阿拉伯文等都用合理數量的 token。</li>
</ol>
<p>不同算法在這四個目標上有不同取捨。</p>
<h2 id="早期方法word-level-跟-char-level">早期方法：word-level 跟 char-level</h2>
<h3 id="word-level-tokenization">Word-level Tokenization</h3>
<p>最簡單的方法是「用空白跟標點切」、每個 word 一個 token。</p>
<p>優點：直觀。</p>
<p>缺點：</p>
<ol>
<li>Vocabulary 爆炸：英文有幾百萬個 word forms（含複數、時態、複合詞等）。</li>
<li>OOV（out-of-vocabulary）：新詞、typo、URL、混合語言完全壞掉。</li>
<li>中文 / 日文沒有空白：要先做 word segmentation。</li>
</ol>
<p>現代 LLM 已淘汰 word-level、主流改用 subword 系列。</p>
<h3 id="char-level-tokenization">Char-level Tokenization</h3>
<p>另一個極端是「每個 character 一個 token」。</p>
<p>優點：vocabulary 小、無 OOV。</p>
<p>缺點：序列變很長（一句話幾十到幾百 char、效率低）、模型要從很基礎學起、訓練不效率。</p>
<p>現代 LLM 也跳過純 char-level、改用 subword 折衷。</p>
<h3 id="折衷subword-tokenization">折衷：Subword Tokenization</h3>
<p>主流方案是「subword tokenization」：常見字串當一個 token、罕見字串切成更小單位（甚至到 char 級別）。三個主流算法：</p>
<table>
  <thead>
      <tr>
          <th>算法</th>
          <th>模型例子</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE</a></td>
          <td>GPT-2、GPT-3、GPT-4、Llama 系列</td>
      </tr>
      <tr>
          <td>WordPiece</td>
          <td>BERT</td>
      </tr>
      <tr>
          <td><a href="/blog/llm/knowledge-cards/sentencepiece/" data-link-title="SentencePiece" data-link-desc="Google 開源的多語言 tokenization 框架、支援 BPE 跟 unigram 演算法、處理空白統一">SentencePiece</a></td>
          <td>Gemma、PaLM、T5</td>
      </tr>
  </tbody>
</table>
<p><a href="/blog/llm/knowledge-cards/vocabulary-size/" data-link-title="Vocabulary Size" data-link-desc="tokenizer 詞彙表的 token 總數、影響 embedding 大小、tokenization 粒度、多語言友善度">Vocabulary size</a> 跟 <a href="/blog/llm/knowledge-cards/special-tokens/" data-link-title="Special Tokens" data-link-desc="在 vocab 中保留給特殊用途的 token：sequence 邊界、角色標記、padding、tool call 等">special tokens</a> 是這幾個算法產出的 tokenizer 共同的概念維度。</p>
<h2 id="bpebyte-pair-encoding">BPE：Byte-Pair Encoding</h2>
<p><a href="/blog/llm/knowledge-cards/bpe/" data-link-title="BPE（Byte-Pair Encoding）" data-link-desc="用「最常一起出現的字元對」合併建詞彙表的 tokenization 演算法、GPT / Llama 等主流">BPE</a>（Sennrich et al., 2016）的核心想法是「貪婪地合併最常出現的字元對」、迭代到 vocabulary 達到目標大小。</p>
<h3 id="訓練流程">訓練流程</h3>
<ol>
<li>初始 vocabulary：所有 character。</li>
<li>統計訓練語料中、所有相鄰 character pair 的頻率。</li>
<li>把頻率最高的 pair 合併成一個新 token、加進 vocabulary。</li>
<li>用新 vocabulary 重新 tokenize 語料、重複 step 2-3。</li>
<li>直到 vocabulary 達到目標大小（如 50,000、100,000）。</li>
</ol>
<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">初始：l o w e r → 5 個 token
</span></span><span class="line"><span class="ln">2</span><span class="cl">步驟 1：合併 &#39;l&#39; + &#39;o&#39; = &#39;lo&#39;、變成 lo w e r → 4 個 token
</span></span><span class="line"><span class="ln">3</span><span class="cl">步驟 2：合併 &#39;lo&#39; + &#39;w&#39; = &#39;low&#39;、變成 low e r → 3 個 token
</span></span><span class="line"><span class="ln">4</span><span class="cl">步驟 3：合併 &#39;e&#39; + &#39;r&#39; = &#39;er&#39;、變成 low er → 2 個 token</span></span></code></pre></div><p>訓練後、<code>lower</code> 就是 2 個 token。</p>
<h3 id="byte-level-bpe">Byte-level BPE</h3>
<p>原始 BPE 在 character level 運作、但「character」依語言而異（Unicode 字元複雜）。Byte-level BPE 在 byte level 運作、任何文字都可以 encode 成 byte 序列、自然支援多語言。</p>
<p>GPT-2 / GPT-3 / GPT-4 / Llama 系列都用 byte-level BPE。</p>
<h3 id="tiktokenopenai-的高效實作">Tiktoken：OpenAI 的高效實作</h3>
<p>Tiktoken 是 OpenAI 開源的 BPE 高效實作、Python 套件。可以拿來算「這段文字在 GPT-4 上是多少 token」：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">import</span> <span class="nn">tiktoken</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">enc</span> <span class="o">=</span> <span class="n">tiktoken</span><span class="o">.</span><span class="n">encoding_for_model</span><span class="p">(</span><span class="s2">&#34;gpt-4&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">tokens</span> <span class="o">=</span> <span class="n">enc</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&#34;Hello, world!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">tokens</span><span class="p">))</span>   <span class="c1"># 4</span></span></span></code></pre></div><p>Tiktoken 是估算 OpenAI API 費用的標準工具。其他模型有各自的 tokenizer 套件（Llama 的 sentencepiece、Hugging Face 的 transformers.AutoTokenizer）。</p>
<h2 id="wordpiecebert-的選擇">WordPiece：BERT 的選擇</h2>
<p>WordPiece（Schuster &amp; Nakajima, 2012、後來 Google 用在 BERT）跟 BPE 類似、但合併策略不同：</p>
<ul>
<li>BPE：合併「最頻繁出現的 pair」。</li>
<li>WordPiece：合併「合併後 likelihood 最大化的 pair」（更貴的計算、但理論上更好）。</li>
</ul>
<p>實務差異微小。BERT 系列用 WordPiece、現代 LLM 大多回到 BPE 系列。</p>
<h2 id="unigram機率式-subword">Unigram：機率式 subword</h2>
<p>Unigram（Kudo, 2018）是另一條主流 subword 算法、跟 BPE 的「greedy 從下往上合併」相反、它從一個很大的 candidate vocabulary 開始、用機率模型逐步<strong>刪掉</strong> likelihood 貢獻最小的 token：</p>
<ol>
<li>起點：一個包含大量 candidate subword 的初始 vocab（可從訓練資料抓所有 substring）。</li>
<li>用 EM 算法估每個 candidate 的機率、把整段文字 tokenize 成 likelihood 最大的 segmentation。</li>
<li>評估「刪掉某個 candidate 後 total likelihood 損失多少」、刪掉損失最小的一批。</li>
<li>重複到 vocab 達目標大小。</li>
</ol>
<p>跟 BPE 的本質差異：</p>
<ul>
<li><strong>BPE</strong>：每個輸入文字只有一個切法（merge 規則決定）、結果是 deterministic。</li>
<li><strong>Unigram</strong>：每個輸入可能對應多個合法 segmentation、訓練時用機率挑、推論時取 top-1。這個性質讓 Unigram 天然支援 <strong>subword regularization</strong>（訓練時隨機取不同 segmentation、增強 robustness）。</li>
</ul>
<p>Unigram 是 SentencePiece 預設算法、T5、Gemma 系列訓練時用。實務上 Unigram 跟 BPE 的最終 tokenization 接近、選擇看「訓練時要不要做 subword regularization」。</p>
<h2 id="sentencepiecegoogle-的開源實作">SentencePiece：Google 的開源實作</h2>
<p>SentencePiece（Kudo &amp; Richardson, 2018）是 Google 開源的 tokenization 套件、可實作 BPE 或 Unigram 算法、設計上：</p>
<ul>
<li><strong>語言無關</strong>：把輸入當 byte 流處理、不假設「word boundary 是空白」。</li>
<li><strong>無前處理</strong>：不用先切 word、適合中文 / 日文等無空白語言。</li>
<li><strong>可逆</strong>：tokenize → detokenize 完全還原原文。</li>
</ul>
<p>Gemma 系列、PaLM、T5 用 SentencePiece。實務上跟 BPE 表現接近、差異主要在「對中日韓文等無空白語言更友善」。</p>
<h2 id="vocabulary-大小">Vocabulary 大小</h2>
<p>各 LLM 的 vocabulary 大小：</p>
<table>
  <thead>
      <tr>
          <th>模型</th>
          <th>vocab_size</th>
          <th>Tokenizer</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT-2</td>
          <td>50,257</td>
          <td>byte-level BPE</td>
      </tr>
      <tr>
          <td>GPT-3 / GPT-4</td>
          <td>~100K</td>
          <td>byte-level BPE (tiktoken)</td>
      </tr>
      <tr>
          <td>Llama 2</td>
          <td>32,000</td>
          <td>SentencePiece</td>
      </tr>
      <tr>
          <td>Llama 3</td>
          <td>128,256</td>
          <td>tiktoken-style BPE</td>
      </tr>
      <tr>
          <td>Gemma 2</td>
          <td>256,000</td>
          <td>SentencePiece</td>
      </tr>
      <tr>
          <td>Gemma 3</td>
          <td>262,144</td>
          <td>SentencePiece</td>
      </tr>
      <tr>
          <td>Gemma 4</td>
          <td>256,000</td>
          <td>SentencePiece</td>
      </tr>
      <tr>
          <td>Qwen3</td>
          <td>152,064</td>
          <td>byte-level BPE</td>
      </tr>
  </tbody>
</table>
<p>Vocabulary 大小的取捨：</p>
<table>
  <thead>
      <tr>
          <th>大 vocab</th>
          <th>小 vocab</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>同段文字切出 token 數少（context 利用率高）</td>
          <td>同段文字切出 token 數多（context 吃緊）</td>
      </tr>
      <tr>
          <td>Embedding layer 跟 output projection 大</td>
          <td>Embedding 跟 output projection 小</td>
      </tr>
      <tr>
          <td>多語言覆蓋好</td>
          <td>多語言覆蓋差、可能切成 byte 級</td>
      </tr>
      <tr>
          <td>中文 / 日文每字一 token</td>
          <td>中文 / 日文一字可能切 2 ~ 3 個 token</td>
      </tr>
  </tbody>
</table>
<p>Gemma 4 的 256K vocab 是現代 LLM 中較大的、目的之一是多語言支援。</p>
<h2 id="同段文字在不同-tokenizer-上的差異">同段文字在不同 tokenizer 上的差異</h2>
<p>實測「The quick brown fox jumps over the lazy dog」：</p>
<table>
  <thead>
      <tr>
          <th>Tokenizer</th>
          <th>Token 數</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT-4</td>
          <td>9</td>
      </tr>
      <tr>
          <td>Llama 3</td>
          <td>9</td>
      </tr>
      <tr>
          <td>Gemma 4</td>
          <td>11</td>
      </tr>
      <tr>
          <td>Qwen3</td>
          <td>10</td>
      </tr>
  </tbody>
</table>
<p>差異不大。但中文「敏捷的棕色狐狸跳過懶狗」：</p>
<table>
  <thead>
      <tr>
          <th>Tokenizer</th>
          <th>Token 數（估）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT-4</td>
          <td>約 12</td>
      </tr>
      <tr>
          <td>Llama 2</td>
          <td>約 20 (byte 級)</td>
      </tr>
      <tr>
          <td>Llama 3</td>
          <td>約 10</td>
      </tr>
      <tr>
          <td>Gemma 4</td>
          <td>約 9</td>
      </tr>
  </tbody>
</table>
<p>Llama 2 的 32K vocab 對中文支援差、Llama 3 / Gemma 4 改善很多。實務影響：中文 prompt 在 Llama 2 上吃 context 多、Gemma 4 較友善。</p>
<h2 id="tokenizer-跟模型相容性">Tokenizer 跟模型相容性</h2>
<p><a href="/blog/llm/knowledge-cards/speculative-decoding/" data-link-title="Speculative Decoding" data-link-desc="用小模型猜未來 token、大模型並行驗證的加速技巧">Speculative decoding</a> 要 target 跟 <a href="/blog/llm/knowledge-cards/drafter-model/" data-link-title="Drafter Model" data-link-desc="speculative decoding 中用來快速猜未來 token 的小模型">drafter</a> 共用 tokenizer、因為兩者必須對「下個 token」的概念一致：</p>
<ul>
<li>Gemma 4 31B + Gemma 4 E4B：同 tokenizer、可以配對。</li>
<li>Gemma 4 + Llama：不同 tokenizer、配不起來。</li>
</ul>
<p>理解這點、能解釋為什麼 LM Studio 的 draft model UI 自動過濾相容候選、為什麼 Ollama 的 <code>gemma4:31b-coding-mtp-bf16</code> model tag 內含 drafter 而不能自己組合不同家族。</p>
<h2 id="special-tokens">Special Tokens</h2>
<p>除了 vocabulary 中的「正常」token、還有特殊 token：</p>
<ul>
<li><code>&lt;BOS&gt;</code> / <code>&lt;bos&gt;</code>：Beginning of sequence、prompt 起點。</li>
<li><code>&lt;EOS&gt;</code> / <code>&lt;eos&gt;</code>：End of sequence、生成結束。</li>
<li><code>&lt;PAD&gt;</code>：Padding、batch 訓練時補齊長度。</li>
<li><code>&lt;UNK&gt;</code>：Unknown token（現代 BPE 少用、因為 byte-level 覆蓋所有字元）。</li>
<li><code>&lt;|im_start|&gt;</code> / <code>&lt;|im_end|&gt;</code>：ChatML 格式中區隔每段訊息的邊界 token。</li>
<li>ChatML 中的 role 名稱（<code>system</code> / <code>user</code> / <code>assistant</code>）寫在 <code>&lt;|im_start|&gt;</code> 之後當作文字內容、不是獨立 token；模型靠「<code>&lt;|im_start|&gt;</code> + 後接 role 字串」這個 pattern 識別說話者。</li>
</ul>
<p>聊天 LLM 的 prompt 實際長相是用 special tokens 標記 role 跟訊息邊界，而非純文字：</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">&lt;|im_start|&gt;system
</span></span><span class="line"><span class="ln">2</span><span class="cl">You are a helpful assistant.&lt;|im_end|&gt;
</span></span><span class="line"><span class="ln">3</span><span class="cl">&lt;|im_start|&gt;user
</span></span><span class="line"><span class="ln">4</span><span class="cl">Hello!&lt;|im_end|&gt;
</span></span><span class="line"><span class="ln">5</span><span class="cl">&lt;|im_start|&gt;assistant</span></span></code></pre></div><p>不同模型的 chat template 不同、Ollama / Continue.dev 等工具自動處理、但若自己呼叫 API 要注意 template 對不對。</p>
<h2 id="tokenization-引發的-bug">Tokenization 引發的 bug</h2>
<p>Tokenizer 設計的副作用：</p>
<h3 id="glitch-tokens">Glitch Tokens</h3>
<p>某些 token 在訓練資料中很少出現、模型對它們的行為怪異。Reddit 上著名的 <code>SolidGoldMagikarp</code> 就是 GPT-2 / GPT-3 的 glitch token、模型遇到會出現奇怪反應。原因：tokenizer 學了這個 token、但訓練資料中幾乎沒上下文、模型沒學到它的語意。</p>
<h3 id="數字-tokenization">數字 tokenization</h3>
<p>早期 BPE 對數字的處理不一致：<code>1234</code> 可能切成 <code>123</code> + <code>4</code>、<code>1235</code> 可能切成 <code>12</code> + <code>35</code>。模型對「數字加法」表現差跟這個有關。</p>
<p>現代 LLM 多半把每個 digit 各自當一個 token（一致 tokenization）、改善數學能力。</p>
<h3 id="code-的-indentation">Code 的 indentation</h3>
<p>寫 code 場景的 tokenizer 要妥善處理 indentation。早期 LLM 把多個空白合併成一個 token、code 結構壞掉；現代 LLM（特別是 coding-specialized）把 4 空白 / 8 空白等常見 indentation 各自當一個 token。</p>
<h2 id="跟-context-window-的關係">跟 context window 的關係</h2>
<p><a href="/blog/llm/knowledge-cards/context-window/" data-link-title="Context Window" data-link-desc="模型一次能處理的最大 token 數量：prompt 加生成的總和上限">Context window</a> 的單位是 token、不是字。1M token 的 context window 在英文約等於 750K 字、在中文約 1M 字（看 tokenizer）。</p>
<p>實務啟示：</p>
<ul>
<li>「128K context」在不同 tokenizer 上實際容量不同。</li>
<li>計算 API 費用要用該模型的 tokenizer 算 token 數。</li>
<li>中文 prompt 用 Llama 2 比 Llama 3 / Gemma 4 吃 context 多。</li>
</ul>
<h2 id="下一章">下一章</h2>
<p>下一章：<a href="/blog/llm/03-theoretical-foundations/going-deeper-theory/" data-link-title="3.11 想學更深：推薦公開課程" data-link-desc="Karpathy、Stanford CS224N / CS25 / CS336、DeepLearning.AI、Hugging Face：LLM 理論深入學習的完整路線">3.7 想學更深：推薦公開課程</a>。</p>
]]></content:encoded></item><item><title>3.7 跨語言場景的 tokenizer 與訓練分佈原理</title><link>https://tarrragon.github.io/blog/llm/03-theoretical-foundations/cross-language-tokenization/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/llm/03-theoretical-foundations/cross-language-tokenization/</guid><description>&lt;p>模組三 &lt;a href="https://tarrragon.github.io/blog/llm/03-theoretical-foundations/tokenization-algorithms/" data-link-title="3.6 Tokenization：BPE、SentencePiece、Tiktoken" data-link-desc="把文字切成 token 的算法：為什麼不同模型切出不同 token 數、tokenizer 選擇對能力的影響">3.6 tokenization 章節&lt;/a> 提到 Llama 2 對中文支援差、Gemma 4 改善很多——但「為什麼」展開後不只 tokenizer 一層、還涉及訓練資料分佈、模型容量分配、跨語言 reasoning 行為差異。本章把跨語言場景的根本原理走過、讓「該用什麼語言寫 prompt」「commit message 用中文還是英文」這類取捨從直覺變成可推導判斷。&lt;/p>
&lt;p>本章寫的是「跨語言能力為什麼這樣分佈」「該如何依場景選語言」的原理層。具體模型在 2026/5 的中文 / 多語言 benchmark 不在本章——這些隨新模型版本變、用本章的雙因素 framework 重新評估就好。&lt;/p>
&lt;h2 id="本章目標">本章目標&lt;/h2>
&lt;p>讀完本章後、你應該能：&lt;/p>
&lt;ol>
&lt;li>解釋為什麼模型在不同語言上表現不一致、有哪兩個獨立因素。&lt;/li>
&lt;li>看到 tokenizer 對中文「一字切 N token」時、知道對 context cost 跟能力的影響。&lt;/li>
&lt;li>判讀「該翻英寫 prompt 還是維持中文」的取捨。&lt;/li>
&lt;li>解釋為什麼跨語言 reasoning 比 monolingual reasoning 容易失敗。&lt;/li>
&lt;/ol>
&lt;h2 id="為什麼模型對不同語言表現不一致雙因素">為什麼模型對不同語言表現不一致：雙因素&lt;/h2>
&lt;p>模型對不同語言的表現受兩個獨立因素疊加影響：&lt;/p>
&lt;h3 id="因素-1tokenizer-vocab-coverage">因素 1：Tokenizer Vocab Coverage&lt;/h3>
&lt;p>Tokenizer 把文字切成 &lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token&lt;/a>、tokenizer vocab 大小指 tokenizer 認識的 token 種類數（vocab 越大、能切得越細、越能用單一 token 表達常見字）。不同 tokenizer 對不同語言的切割密度不同：&lt;/p>
&lt;ul>
&lt;li>英文中心的 tokenizer（如 Llama 2 的 32K vocab）對 vocab 沒涵蓋的中文字會 fallback 到 byte 級切割（UTF-8 一個中文字常用 3 個 byte、所以變 3 個 token）。&lt;/li>
&lt;li>多語言 tokenizer（如 Gemma 4 的 256K vocab）把常見中文字當獨立 token 收進來、對中文多半一字一 token、跟英文接近。&lt;/li>
&lt;/ul>
&lt;p>完整的 BPE / WordPiece / Unigram / SentencePiece 算法見 &lt;a href="https://tarrragon.github.io/blog/llm/03-theoretical-foundations/tokenization-algorithms/" data-link-title="3.6 Tokenization：BPE、SentencePiece、Tiktoken" data-link-desc="把文字切成 token 的算法：為什麼不同模型切出不同 token 數、tokenizer 選擇對能力的影響">3.6 tokenization 算法&lt;/a>。&lt;/p>
&lt;p>Tokenizer 影響三件事：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Context 成本&lt;/strong>：同樣 prompt 在不同 tokenizer 上吃 token 量級不同、API 費用、&lt;a href="https://tarrragon.github.io/blog/llm/knowledge-cards/context-window/" data-link-title="Context Window" data-link-desc="模型一次能處理的最大 token 數量：prompt 加生成的總和上限">context window&lt;/a> 利用率都跟著差。&lt;/li>
&lt;li>&lt;strong>Token 粒度&lt;/strong>：粗粒度 tokenizer 對某語言的「字」切割不細、影響模型對該語言細微差異的辨識。&lt;/li>
&lt;li>&lt;strong>訓練效率&lt;/strong>：tokenizer 切得好、模型每個 token 學到更多語意、訓練收斂快。&lt;/li>
&lt;/ul>
&lt;h3 id="因素-2訓練資料分佈">因素 2：訓練資料分佈&lt;/h3>
&lt;p>模型預訓練資料的語言佔比決定模型「學了多少」這個語言：&lt;/p>
&lt;ul>
&lt;li>Common Crawl 等主流預訓練資料英文佔 70%+、中文約 1-3%、其他語言更少。&lt;/li>
&lt;li>即使 tokenizer 對某語言支援好、訓練資料少仍會限制模型在該語言上的能力。&lt;/li>
&lt;/ul>
&lt;p>訓練分佈影響三件事：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>事實準確度&lt;/strong>：訓練資料少 → 該語言的事實覆蓋低 → hallucination 多。&lt;/li>
&lt;li>&lt;strong>Reasoning 深度&lt;/strong>：複雜推理需要大量該語言範例支撐、訓練少就退化。&lt;/li>
&lt;li>&lt;strong>風格自然度&lt;/strong>：訓練少的語言、模型輸出語法 OK 但 idiom / 慣用搭配偏直譯。&lt;/li>
&lt;/ul>
&lt;h3 id="雙因素的獨立性">雙因素的獨立性&lt;/h3>
&lt;p>兩個因素獨立、各自影響不同維度：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Tokenizer 好&lt;/th>
 &lt;th>訓練資料多&lt;/th>
 &lt;th>結果&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>是&lt;/td>
 &lt;td>是&lt;/td>
 &lt;td>跨語言能力接近 native（Gemma 4 / Qwen3 在中文上的狀態）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>是&lt;/td>
 &lt;td>否&lt;/td>
 &lt;td>「會讀」但「不熟」、輸出語法 OK 但內容平庸&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>否&lt;/td>
 &lt;td>是&lt;/td>
 &lt;td>能力 OK 但 cost 高、context 利用率差&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>否&lt;/td>
 &lt;td>否&lt;/td>
 &lt;td>該語言基本不可用（Llama 2 對中文的狀態）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>判讀模型某語言能力時、兩個因素都要評估、單看一個會誤判。「Gemma 4 vocab 對中文好」不代表「中文表現一定好」、還要看訓練資料佔比。「OpenAI 訓練資料量大」不代表「對所有語言都好」、還要看 tokenizer 設計。&lt;/p></description><content:encoded><![CDATA[<p>模組三 <a href="/blog/llm/03-theoretical-foundations/tokenization-algorithms/" data-link-title="3.6 Tokenization：BPE、SentencePiece、Tiktoken" data-link-desc="把文字切成 token 的算法：為什麼不同模型切出不同 token 數、tokenizer 選擇對能力的影響">3.6 tokenization 章節</a> 提到 Llama 2 對中文支援差、Gemma 4 改善很多——但「為什麼」展開後不只 tokenizer 一層、還涉及訓練資料分佈、模型容量分配、跨語言 reasoning 行為差異。本章把跨語言場景的根本原理走過、讓「該用什麼語言寫 prompt」「commit message 用中文還是英文」這類取捨從直覺變成可推導判斷。</p>
<p>本章寫的是「跨語言能力為什麼這樣分佈」「該如何依場景選語言」的原理層。具體模型在 2026/5 的中文 / 多語言 benchmark 不在本章——這些隨新模型版本變、用本章的雙因素 framework 重新評估就好。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本章後、你應該能：</p>
<ol>
<li>解釋為什麼模型在不同語言上表現不一致、有哪兩個獨立因素。</li>
<li>看到 tokenizer 對中文「一字切 N token」時、知道對 context cost 跟能力的影響。</li>
<li>判讀「該翻英寫 prompt 還是維持中文」的取捨。</li>
<li>解釋為什麼跨語言 reasoning 比 monolingual reasoning 容易失敗。</li>
</ol>
<h2 id="為什麼模型對不同語言表現不一致雙因素">為什麼模型對不同語言表現不一致：雙因素</h2>
<p>模型對不同語言的表現受兩個獨立因素疊加影響：</p>
<h3 id="因素-1tokenizer-vocab-coverage">因素 1：Tokenizer Vocab Coverage</h3>
<p>Tokenizer 把文字切成 <a href="/blog/llm/knowledge-cards/token/" data-link-title="Token" data-link-desc="LLM 處理文字時的最小單位：介於字元與單字之間">token</a>、tokenizer vocab 大小指 tokenizer 認識的 token 種類數（vocab 越大、能切得越細、越能用單一 token 表達常見字）。不同 tokenizer 對不同語言的切割密度不同：</p>
<ul>
<li>英文中心的 tokenizer（如 Llama 2 的 32K vocab）對 vocab 沒涵蓋的中文字會 fallback 到 byte 級切割（UTF-8 一個中文字常用 3 個 byte、所以變 3 個 token）。</li>
<li>多語言 tokenizer（如 Gemma 4 的 256K vocab）把常見中文字當獨立 token 收進來、對中文多半一字一 token、跟英文接近。</li>
</ul>
<p>完整的 BPE / WordPiece / Unigram / SentencePiece 算法見 <a href="/blog/llm/03-theoretical-foundations/tokenization-algorithms/" data-link-title="3.6 Tokenization：BPE、SentencePiece、Tiktoken" data-link-desc="把文字切成 token 的算法：為什麼不同模型切出不同 token 數、tokenizer 選擇對能力的影響">3.6 tokenization 算法</a>。</p>
<p>Tokenizer 影響三件事：</p>
<ul>
<li><strong>Context 成本</strong>：同樣 prompt 在不同 tokenizer 上吃 token 量級不同、API 費用、<a href="/blog/llm/knowledge-cards/context-window/" data-link-title="Context Window" data-link-desc="模型一次能處理的最大 token 數量：prompt 加生成的總和上限">context window</a> 利用率都跟著差。</li>
<li><strong>Token 粒度</strong>：粗粒度 tokenizer 對某語言的「字」切割不細、影響模型對該語言細微差異的辨識。</li>
<li><strong>訓練效率</strong>：tokenizer 切得好、模型每個 token 學到更多語意、訓練收斂快。</li>
</ul>
<h3 id="因素-2訓練資料分佈">因素 2：訓練資料分佈</h3>
<p>模型預訓練資料的語言佔比決定模型「學了多少」這個語言：</p>
<ul>
<li>Common Crawl 等主流預訓練資料英文佔 70%+、中文約 1-3%、其他語言更少。</li>
<li>即使 tokenizer 對某語言支援好、訓練資料少仍會限制模型在該語言上的能力。</li>
</ul>
<p>訓練分佈影響三件事：</p>
<ul>
<li><strong>事實準確度</strong>：訓練資料少 → 該語言的事實覆蓋低 → hallucination 多。</li>
<li><strong>Reasoning 深度</strong>：複雜推理需要大量該語言範例支撐、訓練少就退化。</li>
<li><strong>風格自然度</strong>：訓練少的語言、模型輸出語法 OK 但 idiom / 慣用搭配偏直譯。</li>
</ul>
<h3 id="雙因素的獨立性">雙因素的獨立性</h3>
<p>兩個因素獨立、各自影響不同維度：</p>
<table>
  <thead>
      <tr>
          <th>Tokenizer 好</th>
          <th>訓練資料多</th>
          <th>結果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>是</td>
          <td>是</td>
          <td>跨語言能力接近 native（Gemma 4 / Qwen3 在中文上的狀態）</td>
      </tr>
      <tr>
          <td>是</td>
          <td>否</td>
          <td>「會讀」但「不熟」、輸出語法 OK 但內容平庸</td>
      </tr>
      <tr>
          <td>否</td>
          <td>是</td>
          <td>能力 OK 但 cost 高、context 利用率差</td>
      </tr>
      <tr>
          <td>否</td>
          <td>否</td>
          <td>該語言基本不可用（Llama 2 對中文的狀態）</td>
      </tr>
  </tbody>
</table>
<p>判讀模型某語言能力時、兩個因素都要評估、單看一個會誤判。「Gemma 4 vocab 對中文好」不代表「中文表現一定好」、還要看訓練資料佔比。「OpenAI 訓練資料量大」不代表「對所有語言都好」、還要看 tokenizer 設計。</p>
<h2 id="tokenizer-vocab-對非英文的影響">Tokenizer Vocab 對非英文的影響</h2>
<p>Tokenizer vocab 設計直接決定中文 context 成本量級、差距可達兩倍以上。具體看 tokenizer 對中文的影響（以下為各 tokenizer 對該句的近似切割、實測會 ±20%、用作量級對照、不含 system prompt / response budget）：</p>
<table>
  <thead>
      <tr>
          <th>Tokenizer</th>
          <th>Vocab</th>
          <th>中文「敏捷的棕色狐狸跳過懶狗」估算 token 數</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Llama 2 BPE</td>
          <td>32K</td>
          <td>約 20（byte 級切割、一字常 2-3 個 token）</td>
      </tr>
      <tr>
          <td>GPT-4 tiktoken</td>
          <td>~100K</td>
          <td>約 12</td>
      </tr>
      <tr>
          <td>Llama 3 BPE</td>
          <td>128,256</td>
          <td>約 10</td>
      </tr>
      <tr>
          <td>Qwen3 BPE</td>
          <td>152,064</td>
          <td>約 10</td>
      </tr>
      <tr>
          <td>Gemma 3</td>
          <td>262,144</td>
          <td>約 9</td>
      </tr>
      <tr>
          <td>Gemma 4</td>
          <td>256,000</td>
          <td>約 9</td>
      </tr>
  </tbody>
</table>
<p>數字差異看似不大、累積起來影響顯著：</p>
<ul>
<li><strong>128K context 的「實際容量」</strong>：以中文每字平均 token 數估算、Llama 2（約 2.2 字 / token 的反比、即一字 ≈ 2-3 token）對中文約 6K 中文字、Gemma 4（接近一字一 token）對中文約 14K 中文字、差兩倍以上（估算未含 system prompt + response budget、實際可用更少）。</li>
<li><strong>API 費用</strong>：同樣中文 prompt、Llama 2 費用是 Gemma 4 的兩倍以上（按 token 收費的話）。</li>
<li><strong>長 prompt 的 <a href="/blog/llm/knowledge-cards/prefill/" data-link-title="Prefill" data-link-desc="Prompt 首次處理時的計算階段：把整段輸入跑過模型、產生 KV cache">prefill</a> 時間</strong>：token 多 prefill 慢、<a href="/blog/llm/knowledge-cards/ttft/" data-link-title="TTFT" data-link-desc="Time To First Token：送出 prompt 到第一個 token 出現的等待時間">TTFT</a> 受影響。</li>
</ul>
<p>但這只是其中一個因素。Tokenizer 改進不會自動讓模型「懂」這個語言——還要訓練資料配合。Llama 3 vocab 比 Llama 2 大很多、但對中文表現的提升不只是 vocab 帶來的、也是訓練資料多語言比例提升的結果。</p>
<h2 id="訓練資料分佈語言佔比決定能力">訓練資料分佈：語言佔比決定能力</h2>
<p>Web 文字的語言分佈嚴重不平衡。Common Crawl 跟同類資料源的語言佔比約：</p>
<ul>
<li>英文：60-70%</li>
<li>中文：2-5%</li>
<li>西班牙文、葡萄牙文、日文、法文、德文：各 1-3%</li>
<li>其他幾百種語言：合計 &lt; 10%</li>
</ul>
<p>模型預訓練多半反映這個分佈。即使「主打多語言」的模型、英文仍是主導。</p>
<p>實務影響：</p>
<ul>
<li><strong>事實準確度</strong>：問模型「台灣某縣市的人口」這類本地化問題、中文回答的準確度通常低於英文回答同個問題（即使翻譯為相同 query）。</li>
<li><strong>Reasoning 深度</strong>：複雜中文推理（如解中文奧數題）、模型可能「翻譯成英文 reasoning、再翻回中文」、中間步驟跳過、答案合理但推理鏈不通。</li>
<li><strong>風格 / 慣用語</strong>：中文輸出可能語法 OK、但 idiom 與慣用搭配偏直譯、詞彙選擇偏「翻譯腔」。</li>
<li><strong>長尾事實</strong>：訓練資料少的語言、長尾事實更容易 hallucinate。</li>
</ul>
<p>判讀模型在某語言上的能力強弱、看訓練資料佔比是主要訊號。Qwen 系列訓練資料大量中文、中文能力強；Llama 系列訓練資料英文為主、即使最新版中文表現仍弱於 Qwen 在中文上的表現。</p>
<h2 id="兩因素的獨立性對實務的影響">兩因素的獨立性對實務的影響</h2>
<p>雙因素獨立、實際模型多半落在某個組合狀態：</p>
<p><strong>Gemma 4 / Qwen3 / Llama 3 主流開源旗艦</strong>：</p>
<ul>
<li>Tokenizer：多語言、vocab 256K 級、中文 token 效率接近英文。</li>
<li>訓練資料：中英都有大量比例、Qwen 中文比例高、Llama 英文比例高。</li>
<li>結果：中文能力接近 native level、跨語言能力差距縮小。</li>
</ul>
<p><strong>OpenAI / Anthropic 雲端旗艦</strong>：</p>
<ul>
<li>Tokenizer：tiktoken 等、中文 token 效率中等。</li>
<li>訓練資料：規模極大、所有語言絕對量都多（即使相對佔比低）。</li>
<li>結果：中英都強、絕對能力受訓練規模支撐。</li>
</ul>
<p><strong>早期 Llama 2 / 純英文模型</strong>：</p>
<ul>
<li>Tokenizer：32K 英文中心、中文切散。</li>
<li>訓練資料：英文主導、其他語言極少。</li>
<li>結果：中文勉強可讀、不建議用於對輸出品質有要求的工作場景。</li>
</ul>
<p>判讀新模型對某語言能力時、先看這兩個因素、再參考實測——比直接看 benchmark 數字準。</p>
<h2 id="中文-prompt-何時該翻英機會成本判讀">中文 Prompt 何時該翻英：機會成本判讀</h2>
<p>寫 code 場景常見問題「該用中文還是英文寫 prompt」、答案取決於三個變數：</p>
<h3 id="變數-1模型在中英的能力差距">變數 1：模型在中英的能力差距</h3>
<p>主流開源旗艦（Gemma 4 / Qwen3 / Llama 3）中英差距已縮小、寫 code 場景中英 prompt 表現接近。早期 / 較小模型差距大、英文 prompt 較穩。</p>
<p>判讀：用較強模型可以維持中文、用較弱模型考慮翻英。</p>
<h3 id="變數-2翻譯成本">變數 2：翻譯成本</h3>
<p>翻譯成本包括：時間、認知負擔、可能的精度損失。</p>
<ul>
<li>簡短 prompt（補完、寫單個 function）：翻英成本低、可考慮。</li>
<li>長 prompt（描述複雜需求、多個檔案 context）：翻英成本高、維持中文較划算。</li>
<li>含技術術語的 prompt：英文是 LLM 訓練的主流、術語維持英文較好（即使句子是中文也保留英文 keyword）。</li>
</ul>
<h3 id="變數-3輸出語言要求">變數 3：輸出語言要求</h3>
<ul>
<li>要中文回答（如寫中文 docs、跟中文團隊溝通）：維持中文 prompt 一致性較好。</li>
<li>要英文回答（如 commit message、open source PR）：英文 prompt 自然引導英文輸出、不需 explicit instruct。</li>
</ul>
<h3 id="綜合判讀">綜合判讀</h3>
<p>寫 code 場景的多數情境（主流模型 + 短 prompt + 維持原語言輸出）：直接用中文寫即可、不必特別翻英。例外：</p>
<ul>
<li>用較弱模型（&lt; 14B）、英文較穩。</li>
<li>特殊領域（法律、醫療、學術）、英文資料豐富、翻英可能更穩。</li>
<li>Domain-specific reasoning（數學、邏輯）、英文訓練資料多、翻英可能改善 reasoning 鏈。</li>
</ul>
<p>「直覺說該翻英」常是過度小心、實測通常發現中文跟英文 prompt 表現接近、翻譯成本浪費。</p>
<h2 id="commit--docstring--註解的語言選擇取捨">Commit / Docstring / 註解的語言選擇取捨</h2>
<p>寫 code 場景的「該用什麼語言」決策多半取決於非模型因素：</p>
<h3 id="commit-message">Commit Message</h3>
<ul>
<li><strong>團隊一致性</strong>：團隊都用英文就英文、都用中文就中文。</li>
<li><strong>長期保留</strong>：commit message 進 git 歷史、長期保留、跨團隊成員 / 外部貢獻者讀。</li>
<li><strong>可讀性受眾</strong>：團隊有非中文 reader 就英文、純中文團隊用中文也 OK。</li>
<li><strong>隱私 / 合規</strong>：commit 進 git、可能進 public repo、敏感資訊不該寫進去（不論語言）。</li>
</ul>
<p>模型對中英 commit message 都能寫、選擇主要看團隊跟 repo 屬性、不是看模型偏好。</p>
<h3 id="docstring">Docstring</h3>
<ul>
<li><strong>語言生態慣例</strong>：Python / JavaScript 開源社群慣例是英文 docstring；JetBrains / 微軟在地化文件多中文。</li>
<li><strong>API consumer</strong>：API 給誰用、用什麼語言。</li>
<li><strong>自動化工具</strong>：docs generator、type checker、IDE hint 對英文 docstring 支援較成熟。</li>
</ul>
<h3 id="程式內註解">程式內註解</h3>
<ul>
<li><strong>團隊母語 vs 國際慣例</strong>：團隊母語寫註解最自然、國際慣例（特別 open source）多英文。</li>
<li><strong>複雜邏輯</strong>：用最能精確表達的語言寫、不一定要英文。</li>
<li><strong>TODO / FIXME</strong>：跟團隊慣例一致。</li>
</ul>
<p>這些決策本質上是團隊跟生態問題、不是 LLM 問題。LLM 對中英都能 handle、選哪個取決於 downstream 讀者。</p>
<h2 id="跨語言-reasoning-的失敗訊號">跨語言 Reasoning 的失敗訊號</h2>
<p>跨語言 reasoning（如中文 prompt 要求模型用中文推理過數學題、或用中文回答需要英文事實 retrieval 的問題）容易出現幾種失敗：</p>
<h3 id="內部翻譯失敗">內部翻譯失敗</h3>
<p>模型「中文 prompt → 內部翻譯成英文 reasoning → 翻回中文輸出」、中間步驟跳過、中文輸出看起來合理但推理鏈不通。</p>
<p>判讀訊號：要求模型「請用中文逐步推理」、模型輸出推理鏈不連貫、步驟跳躍。</p>
<p>緩解：強制 step-by-step prompt、或乾脆翻英 prompt 拿英文輸出、再人工譯回中文。</p>
<h3 id="訓練語言切換">訓練語言切換</h3>
<p>模型在某語言上 reasoning 訓練不足、即使理解 query、輸出推理深度受限。</p>
<p>判讀訊號：中文 query 拿到淺薄答案、同樣 query 翻英拿到深入答案。</p>
<p>緩解：複雜推理任務用英文 prompt + 英文輸出、最後再翻譯。</p>
<h3 id="tokenizer-引發的細節遺失">Tokenizer 引發的細節遺失</h3>
<p>中文一字切多個 token 時、模型可能在 token 邊界誤判語意、輸出細節不準。</p>
<p>判讀訊號：細節錯（罕用字 OOV 被切成 byte / 數字本身切分不一致導致算術出錯）、英文同義問題不會錯。</p>
<p>緩解：對細節敏感的任務（數字、日期、人名）強調確認、或翻英降低 tokenizer 誤判機率。</p>
<h3 id="何時跨語言-reasoning-不會失敗--何時翻英無收益">何時跨語言 reasoning 不會失敗 / 何時翻英無收益</h3>
<p>上述三類失敗模式不會均勻發生在所有跨語言任務上、實際觸發條件是「深度推理 + 語言 specific 事實 retrieval」雙條件命中。以下情境通常翻英沒收益、留在中文 prompt 反而省事：</p>
<ul>
<li><strong>Code 補完、語法重構、加 type annotation</strong>：code 本身就跨語言、模型不需要「翻譯」code、中文 prompt 直接寫即可。</li>
<li><strong>短 QA、context-rich prompt</strong>：問題本身就含完整 context（如「這段程式碼做什麼」+ code）、模型不需要做 retrieval、reasoning 深度需求低。</li>
<li><strong>格式 / 結構轉換</strong>：JSON 轉 YAML、Markdown 重排、tabular 整理 — 任務機械化、跟語言關係小。</li>
<li><strong>單檔 refactor</strong>：選定範圍內的改寫、不需跨檔 retrieval、推理深度受 context 限制而非語言。</li>
<li><strong>commit message / docstring 草稿</strong>：套用 template 性質、模型輸出語言跟 prompt 一致較自然。</li>
</ul>
<p>需要翻英的場景集中在「深度推理（多步邏輯 / 數學）」+「需要 retrieval 語言 specific 事實（如某個 framework 的 API、特定論文細節、英文社群討論）」這兩條都命中時、其他場景翻譯成本是浪費。</p>
<h2 id="code-跟自然語言的不對稱">Code 跟自然語言的不對稱</h2>
<p>Code 本身是「英文偏向」的：keyword（<code>if</code>、<code>for</code>、<code>return</code>）、變數名（多半 ASCII）、API（多半英文）。LLM 對 code 的能力跨語言差距較小——code 本身就跨語言、模型不需要「翻譯」code。</p>
<p>但「code + 自然語言」的混合場景仍受自然語言訓練分佈影響：</p>
<ul>
<li>寫 code + 中文 docstring：模型寫 code 表現一致、寫 docstring 受訓練分佈影響。</li>
<li>解釋 code 給人聽：用哪種語言解釋、受該語言訓練分佈影響。</li>
<li>改寫 code 註解：改 code 行為一致、改自然語言部分受訓練分佈影響。</li>
</ul>
<p>判讀「該不該翻英」時、要區分「code 部分」跟「自然語言部分」。Code 部分中英差距小、自然語言部分中英差距視模型而定。</p>
<h2 id="何時過時--何時不過時">何時過時 / 何時不過時</h2>
<p><strong>不會過時的部分</strong>：</p>
<ul>
<li>Tokenizer + 訓練分佈雙因素 framing。</li>
<li>跨語言能力受結構性限制的本質（不只是「模型不夠強」）。</li>
<li>三個變數判讀（能力差距、翻譯成本、輸出語言要求）。</li>
<li>跨語言 reasoning 失敗模式的分類。</li>
<li>Code 跟自然語言的不對稱觀察。</li>
</ul>
<p><strong>會變的部分</strong>：</p>
<ul>
<li>具體模型在特定語言上的當下能力（會隨新模型版本變、Gemma 5 / Qwen4 等出來會再變）。</li>
<li>各 tokenizer 的 vocab 大小（會調整）。</li>
<li>訓練資料的多語言比例（業界正在改善）。</li>
<li>哪些模型「中文能力好」的具體 ranking。</li>
</ul>
<p>看到新模型時、回到雙因素 framework 評估：tokenizer vocab 多大、中文 token 效率如何、訓練資料中文佔比、實測中文表現是否符合預期——這個 framework 不變、評估結果會隨模型版本更新。</p>
<h2 id="下一章">下一章</h2>
<p>下一章：<a href="/blog/llm/03-theoretical-foundations/reasoning-models/" data-link-title="3.8 Reasoning models：test-time compute paradigm" data-link-desc="Chain-of-thought 從 prompting 技巧演化成訓練 paradigm、reasoning model 的內部運作、本地可跑的選項與適用任務">3.8 Reasoning models</a>、看 2024-2026 的 test-time compute paradigm。完整公開課推薦見 <a href="/blog/llm/03-theoretical-foundations/going-deeper-theory/" data-link-title="3.11 想學更深：推薦公開課程" data-link-desc="Karpathy、Stanford CS224N / CS25 / CS336、DeepLearning.AI、Hugging Face：LLM 理論深入學習的完整路線">3.10 想學更深</a>。</p>
]]></content:encoded></item></channel></rss>