大型語言模型 LLM
Transformer 架構簡介
💡 比喻:翻譯團隊的注意力機制 想像一個專業翻譯團隊在翻譯一本書:
- 每個翻譯員(Attention Head)負責注意不同的面向
- 有人專注「文法結構」,有人專注「情感語氣」,有人專注「專有名詞」
- 他們同時工作(平行處理),然後把結果合在一起
- 這就是 Multi-Head Attention(多頭注意力機制) 的概念
之前的 RNN 像是一個翻譯員從頭到尾一個字一個字翻,很慢。 Transformer 像是一群翻譯員同時看完整本書,然後各自負責不同面向,超快。
Transformer 的核心組件
Transformer 架構(簡化版)
┌─────────────────────────────┐
│ Output │ // 最終輸出的文字
├─────────────────────────────┤
│ Linear + Softmax │ // 把向量轉換成機率分布
├─────────────────────────────┤
│ ┌───────────────────────┐ │
│ │ Decoder Block × N │ │ // 解碼器,負責生成文字
│ │ ┌─────────────────┐ │ │
│ │ │ Masked Self-Attn │ │ │ // 只能看到前面的文字(防作弊)
│ │ │ Cross Attention │ │ │ // 參考編碼器的結果
│ │ │ Feed Forward │ │ │ // 全連接層,做進一步處理
│ │ └─────────────────┘ │ │
│ └───────────────────────┘ │
├─────────────────────────────┤
│ ┌───────────────────────┐ │
│ │ Encoder Block × N │ │ // 編碼器,負責理解輸入
│ │ ┌─────────────────┐ │ │
│ │ │ Self-Attention │ │ │ // 每個字都看其他所有字
│ │ │ Feed Forward │ │ │ // 全連接層
│ │ └─────────────────┘ │ │
│ └───────────────────────┘ │
├─────────────────────────────┤
│ Positional Encoding │ // 告訴模型每個字的位置
├─────────────────────────────┤
│ Input Embedding │ // 把文字轉成向量
├─────────────────────────────┤
│ Input │ // 輸入的文字
└─────────────────────────────┘
Self-Attention 自注意力機制
// Self-Attention 的直覺理解
// 句子:「小明把蘋果給了小華,因為他很餓」
// 問題:「他」指的是誰?
// Self-Attention 會計算「他」和每個字的關聯度
var attentionScores = new Dictionary<string, double> // 注意力分數
{
["小明"] = 0.15, // 「他」跟「小明」有一些關聯
["蘋果"] = 0.02, // 「他」跟「蘋果」關聯很低
["小華"] = 0.75, // 「他」跟「小華」關聯最高(因為餓→收到蘋果的人)
["餓"] = 0.08, // 「他」跟「餓」有一點關聯
};
// 模型學會了「他」最可能指「小華」
// 這就是 Attention 的威力:理解上下文關係
Q、K、V 的直覺解釋
// Query(查詢)、Key(鍵)、Value(值)
// 比喻:圖書館找書
// Query = 你想找什麼?「我想找關於 C# 的書」
// Key = 每本書的標籤:「C# 入門」「Python 教學」「C# 進階」
// Value = 書的實際內容
// Attention(Q, K, V) = softmax(Q × K^T / √d) × V
var query = "我想找 C# 的書"; // 你的需求(Query)
var books = new Dictionary<string, string> // Key → Value 的對應
{
["C# 入門"] = "第一章:變數...", // Key 匹配度高 → 取出 Value
["Python 教學"] = "import 語法", // Key 匹配度低 → 忽略
["C# 進階"] = "泛型與反射...", // Key 匹配度高 → 取出 Value
};
// 最終結果是根據匹配度加權混合所有 Value
GPT vs Claude vs LLaMA 比較
模型 開發公司 特色 開源?
──────────────────────────────────────────────────────────
GPT-4o OpenAI 最廣泛使用的 LLM 否
Claude Anthropic 注重安全性和誠實 否
LLaMA 3 Meta 開源社群最活躍 是
Gemini Google 多模態能力強 否
Mistral Mistral AI 歐洲開源模型,效能好 部分
// 在 C# 中呼叫不同的 LLM API
// 雖然每家 API 格式不同,但概念相似
// OpenAI GPT
var openaiClient = new OpenAIClient(apiKey); // 建立 OpenAI 客戶端
var gptResponse = await openaiClient // 發送請求
.GetChatCompletionsAsync( // 聊天補全 API
"gpt-4o", // 指定模型名稱
new ChatCompletionsOptions // 設定選項
{
Messages = { new ChatMessage( // 加入訊息
ChatRole.User, "你好") } // 使用者角色的訊息
});
// Anthropic Claude
var claudeClient = new AnthropicClient(apiKey); // 建立 Claude 客戶端
var claudeResponse = await claudeClient // 發送請求
.CreateMessageAsync(new() // 建立訊息 API
{
Model = "claude-sonnet-4-20250514", // 指定模型名稱
MaxTokens = 1024, // 最大回應 token 數
Messages = new[] { // 訊息陣列
new("user", "你好") } // 使用者訊息
});
// 選擇模型的考量
// 1. 任務類型:程式碼生成、文字分析、多語言翻譯
// 2. 成本:API 計價方式不同
// 3. 回應品質:不同模型各有擅長
// 4. 隱私需求:開源模型可以自己架設
Token 與 Tokenization
💡 比喻:樂高積木 把文字想像成樂高,Token 就是一塊一塊的積木:
- 常見的字就是一塊大積木(例如 "the" = 1 token)
- 少見的字會被拆成小積木(例如 "tokenization" = "token" + "ization")
- 中文通常一個字 = 1-2 個 token
// Token 的概念
var text = "Hello, how are you?"; // 這句英文大約 6 個 token
// 英文 Tokenization 示例
// "Hello" → token_1 // 常見字,一個 token
// "," → token_2 // 標點符號,一個 token
// " how" → token_3 // 含前面空格,一個 token
// " are" → token_4 // 含前面空格,一個 token
// " you" → token_5 // 含前面空格,一個 token
// "?" → token_6 // 標點符號,一個 token
// 中文 Tokenization 示例
var chineseText = "今天天氣很好"; // 中文的 token 切法不同
// "今天" → token_1 // 兩個字可能合成一個 token
// "天氣" → token_2 // 常見詞彙一個 token
// "很好" → token_3 // 常見詞彙一個 token
// 為什麼 Token 很重要?
// 1. API 計費是按 token 數計算 // 用越多 token 越貴
// 2. 模型有 token 上限 // 超過上限就無法處理
// 3. 中文比英文花更多 token // 同樣內容,中文成本稍高
// 4. 程式碼的 token 消耗量很大 // 因為有很多特殊符號
// 估算 token 數量的經驗法則
int EstimateTokens(string text) // 粗略估算 token 數
{
var englishWords = text.Split(' ').Length; // 英文大約 1 字 = 1.3 token
var chineseChars = text.Count( // 中文大約 1 字 = 1.5 token
c => c >= 0x4E00 && c <= 0x9FFF); // 偵測中文字元的 Unicode 範圍
return (int)(englishWords * 1.3 // 英文的估算
+ chineseChars * 1.5); // 中文的估算
}
Temperature, Top-P 參數意義
💡 比喻:點餐的隨機程度
- Temperature = 0:每次都點一樣的(最愛的那道菜)
- Temperature = 0.7:通常點喜歡的,偶爾嘗鮮
- Temperature = 1.5:隨便亂點,可能點到奇怪的東西
// Temperature 控制回答的「隨機性」
var stableRequest = new ChatRequest // 穩定的回答設定
{
Temperature = 0.0f, // 溫度 = 0,每次回答都一樣
// 適合:寫程式、翻譯、事實性問答 // 需要精確答案的場景
};
var creativeRequest = new ChatRequest // 有創意的回答設定
{
Temperature = 0.9f, // 溫度 = 0.9,回答更多樣化
// 適合:寫故事、腦力激盪、創意發想 // 需要多樣性的場景
};
// Top-P (Nucleus Sampling) 控制詞彙選擇的範圍
var request = new ChatRequest // Top-P 設定
{
TopP = 0.9f, // 只從機率最高的 90% 詞彙中選
// TopP = 1.0 → 所有詞彙都有機會被選到
// TopP = 0.1 → 只從最可能的少數詞彙中選
};
// 實際應用中的參數設定建議
var codeGeneration = new ChatRequest // 程式碼生成
{
Temperature = 0.0f, // 低溫度,確保程式碼正確
TopP = 1.0f, // Top-P 保持預設
};
var creativeWriting = new ChatRequest // 創意寫作
{
Temperature = 0.8f, // 高溫度,增加創意
TopP = 0.95f, // 稍微限制太離譜的選擇
};
var chatbot = new ChatRequest // 一般聊天
{
Temperature = 0.5f, // 中等溫度,平衡準確和自然
TopP = 0.9f, // 適當範圍的詞彙選擇
};
Context Window 限制
💡 比喻:工作桌面的大小 Context Window 就像你的工作桌面:
- 桌子越大,能同時看的文件越多
- GPT-4o 的桌子能放 128K token(約一本小說)
- Claude 的桌子能放 200K token(約兩本小說)
- 但桌子再大,放太多東西找起來也慢
// Context Window 的概念
var contextLimits = new Dictionary<string, int> // 各模型的上下文窗口
{
["GPT-4o"] = 128_000, // 128K tokens
["Claude 3.5"] = 200_000, // 200K tokens
["LLaMA 3"] = 128_000, // 128K tokens
["Gemini 1.5 Pro"] = 2_000_000, // 2M tokens(超大!)
};
// Context Window 包含什麼?
// Input tokens(你說的話) + Output tokens(AI 的回答)= 總 token 數
// 如果對話太長,超過 Context Window,就要截斷或摘要
// 管理 Context Window 的策略
public class ConversationManager // 對話管理器
{
private List<Message> _messages = new(); // 所有訊息歷史
private int _maxTokens = 128000; // 模型的 token 上限
private int _currentTokens = 0; // 目前已使用的 token 數
public void AddMessage(Message msg) // 加入新訊息
{
_currentTokens += msg.TokenCount; // 累計 token 數
_messages.Add(msg); // 加入訊息列表
while (_currentTokens > _maxTokens * 0.8) // 超過 80% 就開始清理
{
var oldest = _messages[1]; // 保留系統訊息,移除最舊的
_currentTokens -= oldest.TokenCount; // 減少 token 計數
_messages.RemoveAt(1); // 移除最舊的使用者訊息
}
}
}
Fine-tuning vs RAG vs Prompt Engineering
💡 比喻:三種讓 AI 變聰明的方式
- Prompt Engineering:問對問題(不改變 AI,改變你問問題的方式)
- RAG:開卷考試(給 AI 一本參考書讓它查)
- Fine-tuning:送 AI 去補習班(修改 AI 本身的知識)
// 1. Prompt Engineering(提示工程)
// 成本:最低 | 速度:最快 | 效果:中等
var prompt = @"你是一個專業的 C# 程式教師。 // 設定角色
請用繁體中文回答。 // 設定語言
回答時請附上程式碼範例。 // 設定格式
如果不確定,請說「我不確定」。"; // 設定行為準則
// 2. RAG(檢索增強生成)
// 成本:中等 | 速度:中等 | 效果:高(特定領域)
// 不修改模型,而是給模型額外的參考資料
var context = SearchVectorDB(userQuestion); // 從向量資料庫搜尋相關資料
var ragPrompt = $"根據以下資料回答:\n{context}\n問題:{userQuestion}";
// 優點:資料可以即時更新,不需要重新訓練模型
// 3. Fine-tuning(微調)
// 成本:最高 | 速度:需要訓練時間 | 效果:高(風格和格式)
// 修改模型的權重,讓它學習新的知識或風格
var trainingData = new List<FineTuneExample> // 準備微調資料
{
new("如何宣告變數?", // 輸入
"在 C# 中使用 var 或型別名稱..."), // 期望的輸出格式
};
await client.CreateFineTuneJob(trainingData); // 送出微調訓練任務
// 如何選擇?
// ┌──────────────────┬─────────────┬────────┬──────────┐
// │ 方法 │ 成本 │ 難度 │ 適用場景 │
// ├──────────────────┼─────────────┼────────┼──────────┤
// │ Prompt Eng. │ 幾乎免費 │ 低 │ 一般任務 │
// │ RAG │ 中(需DB) │ 中 │ 知識問答 │
// │ Fine-tuning │ 高(需GPU) │ 高 │ 特殊風格 │
// └──────────────────┴─────────────┴────────┴──────────┘
🤔 我這樣寫為什麼會錯?
❌ 錯誤 1:Temperature 設太高導致程式碼出錯
// ❌ 用高 Temperature 生成程式碼
var request = new ChatRequest // 錯誤的設定
{
Prompt = "寫一個排序演算法", // 需要精確的程式碼
Temperature = 1.5f, // 溫度太高,回答太隨機
};
// 結果:可能生成語法錯誤或邏輯錯誤的程式碼
// ✅ 程式碼生成應該用低 Temperature
var betterRequest = new ChatRequest // 正確的設定
{
Prompt = "寫一個排序演算法", // 同樣的需求
Temperature = 0.0f, // 低溫度確保準確性
};
// 結果:穩定、正確的程式碼
❌ 錯誤 2:把所有資料都塞進 Prompt
// ❌ 嘗試把整個資料庫放進 prompt
var hugePrompt = $@" // 超大的 prompt
以下是我們公司的所有資料:
{entireDatabase} // 可能有幾百萬筆資料
請回答:{question}"; // 一定會超過 Context Window
// ✅ 應該用 RAG 只取相關的資料
var relevantDocs = await vectorDb // 向量資料庫搜尋
.SearchAsync(question, top: 5); // 只取最相關的 5 筆
var smartPrompt = $@" // 精簡的 prompt
參考資料:{string.Join("\n", relevantDocs)} // 只放相關資料
請回答:{question}"; // 不會超過 Context Window
❌ 錯誤 3:以為 Fine-tuning 能讓模型學新知識
// ❌ 錯誤觀念:Fine-tuning 是教模型新知識
// 很多人以為 fine-tuning 可以讓 GPT 學會你的產品文件
// 實際上 fine-tuning 更適合調整「回答的風格和格式」
// ✅ 正確用法
// 學新知識 → 用 RAG(檢索增強生成) // 把文件放向量資料庫
// 調整風格 → 用 Fine-tuning // 例如讓模型用特定語氣回答
// 簡單指引 → 用 Prompt Engineering // 在 prompt 中給明確指示