AI 互動教室 ‹ 生成式 AI 導論
下載 .py 單獨開啟實驗場 ↗ 留言回報
GENAI BASICS · 01 · 基礎概念

Token、Embedding
與上下文窗

所有關於 LLM 的名詞——計費、上下文、RAG、加速——追到最底,都站在四個地基上。 第一個地基是:模型看到的不是字,是 token。 點下面四句話,看真實的 tokenizer(GPT-4o 系列的 o200k_base) 怎麼下刀:

右邊的實驗場是真的 Python(在你的瀏覽器裡跑,不用安裝任何東西)。 首次載入約需 30–60 秒,正好夠你讀完第 1 節。每一格程式碼都能改、能重跑, 改壞了重新整理就復原——這是你的沙盒,盡量玩。

01 · TOKEN / TOKENIZER

Token:模型處理文字的最小單位

一句話重點:token 是模型的最小文字單位,計費照它算、上下文照它數—— 跟 LLM 有關的錢和容量,單位都是 token。

Tokenizer 把文字切成 token 的規則叫 BPE(Byte Pair Encoding), 訓練方式簡單得驚人:從單一字元開始,反覆把「語料裡最常相鄰的兩塊」黏成一塊, 黏個幾十萬次。於是常見字串(international)變成一整塊, 罕見字串被切成碎塊。你可以在右邊親手訓練一個迷你 BPE,十次合併就看得到這個過程。

開場那個實驗值得再看一眼數字:同樣意思的一句話, 英文 44 個字元只切成 10 個 token(平均 4.4 字元一塊), 中文 15 個字卻切成 17 個 token——平均一個字被切成 1.1 塊, 有的字甚至被剖成兩三塊 byte。實測(o200k_base,2026-08): 同樣內容,中文大約要多花 70% 的 token。API 按 token 計價、 上下文按 token 計量,所以這不是冷知識,是成本結構。

想自己數,真實工具長這樣(tiktoken 是 OpenAI 的官方 tokenizer 套件):

import tiktoken enc = tiktoken.get_encoding("o200k_base") # GPT-4o/o 系列用的編碼 ids = enc.encode("敏捷的棕色狐狸跳過了那隻懶狗。") print(len(ids)) # 17(同義英文句只要 10)

開源模型各有各的 tokenizer,用 Hugging Face 的 transformers 載:

from transformers import AutoTokenizer tok = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B-Instruct") tok.tokenize("生成式人工智慧") # 每家模型的刀工都不一樣
02 · EMBEDDING

Embedding:把語意變成座標

一句話重點:embedding 把文字轉成語意向量——意思越近、向量越近, 是語意搜尋與 RAG 的地基。

Token 編號本身沒有意義(編號 3421 和 3422 毫無關係), embedding 模型負責把一段文字變成一串浮點數(常見 768~4096 維), 讓「意思相近」的文字在這個高維空間裡距離相近。 相似度用 cosine(夾角)量:1.0 是同方向、0 是無關。

右邊 2️⃣ 有 16 個短句的真向量(embedding 模型事先算好、打包進課程)。 你會看到情緒句自成一國;也會看到一個反直覺的事實—— 「熱拿鐵咖啡」的最近鄰不是別的食物,是「熱騰騰的拉麵」(cosine 0.423), 而同屬食物的「草莓蛋糕」只有 0.143:embedding 量的是語意組合, 不是你心裡的目錄分類

真實工具的用法(各家 API 大同小異,都是「文字進、向量出」):

from openai import OpenAI client = OpenAI() resp = client.embeddings.create( model="text-embedding-3-small", input=["一隻可愛的貓", "一隻忠心的狗"], ) vec = resp.data[0].embedding # 1536 維的浮點數清單 # 相似度=cosine:夾角越小、語意越近 import numpy as np a, b = np.array(resp.data[0].embedding), np.array(resp.data[1].embedding) cos = a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
03 · CONTEXT WINDOW

Context Window:模型的工作記憶

一句話重點:模型一次能看的 token 上限。超過的部分不是記性差, 是根本沒被送進去;窗越長,推理時的 KV cache 也越大。

System prompt + 對話歷史 + 你貼的文件 + 模型的回答,全部擠同一個窗。 塞不下的時候會發生兩種事之一:API 直接回錯誤(後面驗收那題你會親眼看到真實的錯誤訊息), 或者應用程式默默把最舊的對話裁掉——這就是「聊久了它忘記開頭」的真相。

模型(公開規格)上下文窗大約等於
Llama 38K一篇長文
Llama 3.1 / GPT-4o128K一本薄薄的書
Claude Haiku 4.5200K一本小說
Claude Opus 51M整套文件庫

但「裝得下」不等於「該全塞」:塞一堆無關內容會稀釋重點、拉高成本, 上下文越長推理要維護的 KV cache 記憶體也暴增——「怎麼塞得聰明」是 第 6 課的 context engineering, 「為什麼變貴變慢」是第 3 課的主線。

04 · AUTOREGRESSIVE

Autoregressive:一次吐一個 token

一句話重點:LLM 是串行生成——看著前文算「下一個 token 的機率分布」、 抽一個、接上、再算下一個。這是所有推理加速技術要解的瓶頸。

你看到 ChatGPT 的回答一個字一個字蹦出來,不是打字動畫, 是模型真的一次只算一個 token。每一步都是一次完整的前向計算, 所以:輸出越長越慢(串行,沒法平行)、每一步都要重看整段前文 (所以要 KV cache 來省重算)、同一題每次答案不完全一樣(因為是**抽樣**, 不是查表)。右邊 4️⃣ 用一個迷你模型把這個迴圈拆給你看, 連 temperature 在調什麼都一目瞭然。

串流輸出(邊生成邊顯示)就是把這個迴圈的每一步直接推到你眼前:

from openai import OpenAI client = OpenAI(base_url="http://localhost:11434/v1", # Ollama 的本機端點 api_key="ollama") stream = client.chat.completions.create( model="llama3.1", messages=[{"role": "user", "content": "介紹一下台北"}], stream=True, # 一個 token 一個 token 送回來 ) for chunk in stream: print(chunk.choices[0].delta.content or "", end="")
05 · 速查

本課名詞速查卡

發講義用的濃縮版——一個名詞一句話:

Token / Tokenizer 模型處理文字的最小單位,直接影響計費上下文長度;中文比英文吃 token(實測同義句 +70%)。
Embedding 把文字轉成語意向量,意思近=距離近——RAG 與語意搜尋的地基。
Context Window 一次能看的 token 上限;超過的內容根本沒進模型,而且窗越長 KV cache 越大。
Autoregressive 一次吐一個 token 的串行生成——輸出慢的根源,也是所有加速技術要解的瓶頸。
06 · 實戰

換你動手

LEVEL 1

在右邊 1️⃣ 把「要切的詞」改成 wider(語料裡沒有的字),合併次數拉到 10——它會被切成幾塊?為什麼不會「不認識就炸掉」?

LEVEL 2

在 4️⃣ 把 temperature 壓到 0.1、再拉到 2.0,各重抽五次。觀察:哪個設定下句子幾乎不變?「天」後面為什麼老是接「氣」?(提示:實驗區印得出計數。)

LEVEL 3

在 2️⃣ 挑「一杯熱拿鐵咖啡」看最近鄰。先猜:最近的會是誰?再想:為什麼跟它同組的「草莓蛋糕」輸給不同組的句子?這件事對 RAG 檢索意味著什麼?

卡住了?三題在 notebook 最後一格都有折疊解答——先自己做,再打開對照。

07 · 驗收

情境測驗

離開前試試看:下面的情境都真的會遇到。每題選一個你認為的最佳做法,選了馬上看得到解釋。

Q1 情境題

你的客服機器人每月 API 帳單暴增。你發現 system prompt 是一段 3,000 字的中文規範,每一次對話的每一輪都會原封不動送一次。想先降成本,最該做的是?

成本問題先換算成 token 帳:中文約 1 字 1.1 token(實測 o200k_base),3,000 字的 system prompt 每輪重送就是每輪多付 ~3,400 個 input token。正解是先讓要送的東西變少(精簡內容),再用快取讓重複的部分變便宜。A 方向存在但代價是改變行為與維護成本,而且省的是 30–40%,不如直接精簡;B 搞混了兩件事——窗多大跟「每輪要重送整段歷史」無關,API 是無狀態的,換大窗一樣重送;D 管的是輸出端,帳單暴增的主因在每輪重複的輸入端。

Q2 情境題

你要幫公司的內部文件做搜尋。同事說:「用關鍵字比對就好,何必搞 embedding?」什麼情況下他是對的、什麼情況下你該堅持用 embedding?

Embedding 的價值在「換個說法也找得到」:它把語意變成向量,「怎麼退錢」跟「退款政策」向量距離近,關鍵字比對卻一個字都對不上。反過來,查工單編號、精確料號這種一字不差的查詢,關鍵字(或倒排索引)又快又準,embedding 反而可能被語意相近的雜訊干擾——所以成熟的檢索系統常常兩路並用(hybrid search)。A 是把工具當信仰;C 語言跟該不該用向量無關;D 說反了,embedding 是文字檢索的主流地基(也有多模態版本,那是第 7 課的延伸)。

Q3 錯誤診斷

同事把一整份長文件貼進 prompt 要模型摘要,API 回了下面的錯誤。他說「這模型壞了,昨天問答都正常」。最可能的原因是?

HTTP 400 This model's maximum context length is 16384 tokens. However, you requested 64 output tokens and your prompt contains at least 16321 input tokens, for a total of at least 16385 tokens. Please reduce the length of the input prompt or the number of requested output tokens.

錯誤訊息其實把帳算給你看了:輸入 16,321 + 要求的輸出 64 = 16,385,超過 16,384 的窗,一個 token 都不通融——這正是「上下文窗是硬上限」的具體長相(訊息為實測,2026-08)。昨天正常是因為昨天的輸入短。A 認錯症狀,400 是請求本身不合法,重試一萬次都一樣;B 方向剛好相反——調大 max_tokens 是把總帳加得更大,只會錯得更多;D 無中生有,訊息裡寫得清清楚楚是長度問題。正解就是訊息最後一句:減少輸入(分段、先裁剪無關段落),或換更大的窗。

Python 環境載入中(首次約 30–60 秒)…讀完第 1 節它就好了