作者: tm731531

  • Kafka 事件驅動架構:打造高可用訂單處理系統

    商業價值:事件驅動架構讓系統能「處理速度提升 10 倍」,從 4-8 小時縮短到 25-35 分鐘。詳見 導讀篇的 ROI 計算

    前言:為什麼需要事件驅動?

    想像一個場景:使用者在後台點擊「同步蝦皮訂單」。

    同步處理的問題:

    • 蝦皮 API 回應慢 → 使用者等待 30 秒以上
    • API 超時 → 整個請求失敗
    • 大量請求 → 伺服器資源耗盡

    解決方案:非同步事件驅動

    使用者請求 背景處理
    │ │
    ▼ │
    ┌─────────┐ 發送訊息 ┌─────────┐
    │ Web API │ ──────────────► │ Kafka │
    └─────────┘ └────┬────┘
    │ │
    ▼ ▼
    回應成功 ┌───────────────┐
    (立即返回) │ Consumer Job │
    │ 慢慢處理… │
    └───────────────┘
    效果:使用者立即收到「已排程」回應,實際同步在背景執行。

    架構設計

    Topic 設計:每個通路獨立

    Topic 名稱 用途 Consumer
    oms-action-shopee 蝦皮相關動作 Shopee Consumer
    oms-action-momo Momo 相關動作 Momo Consumer
    oms-action-yahoo Yahoo 相關動作 Yahoo Consumer
    oms-action-pchome PChome 相關動作 PChome Consumer
    為什麼要分開?

    • 蝦皮 API 壞了,不影響 Momo 訂單處理
    • 可以針對不同平台調整 Consumer 數量
    • 方便監控各平台的處理狀況

    Producer:發送訊息

    @Service
    public class ActionProducer {

    private final KafkaTemplate<String, String> kafkaTemplate;

    /**
    * 發送動作到對應的通路 Topic
    */

    public void sendAction(ChannelType channel, ActionMessage message) {
    String topic = “oms-action-“ + channel.getCode();
    String payload = JsonUtil.toJson(message);

    kafkaTemplate.send(topic, message.getMerchantId(), payload)
    .addCallback(
    result -> log.info(“發送成功: {}”, topic),
    error -> log.error(“發送失敗: {}”, error.getMessage())
    );
    }
    }

    訊息格式設計

    {
    “header”: {
    “messageId”: “uuid-xxxx-xxxx”,
    “timestamp”: “2024-03-18T10:30:00Z”,
    “traceId”: “trace-xxxx”
    },
    “body”: {
    “merchantId”: “M001”,
    “actionType”: “SYNC_ORDERS”,
    “parameters”: {
    “startDate”: “2024-03-17”,
    “endDate”: “2024-03-18”
    }
    }
    }

    Consumer:處理訊息

    @Component
    public class ActionConsumer {

    @Autowired
    private ChannelFactory channelFactory;

    @KafkaListener(topics = “oms-action-shopee”)
    public void consumeShopee(String message) {
    processAction(ChannelType.SHOPEE, message);
    }

    @KafkaListener(topics = “oms-action-momo”)
    public void consumeMomo(String message) {
    processAction(ChannelType.MOMO, message);
    }

    private void processAction(ChannelType channel, String message) {
    try {
    // 1. 解析訊息
    ActionMessage action = JsonUtil.fromJson(message);

    // 2. 取得對應的通路處理器
    ChannelAction handler = channelFactory.getAction(channel);

    // 3. 執行動作
    ActionResult result = handler.execute(action);

    // 4. 回寫結果
    saveResult(action, result);

    } catch (Exception e) {
    // 5. 錯誤處理
    handleError(message, e);
    }
    }
    }


    錯誤處理策略

    錯誤類型 處理方式 範例
    暫時性錯誤 重試 3 次 API 超時、網路問題
    永久性錯誤 記錄並跳過 資料格式錯誤
    未知錯誤 進入 Dead Letter Queue 系統異常
    @Bean
    public DefaultErrorHandler errorHandler() {
    // 設定重試策略
    BackOff backOff = new ExponentialBackOff(1000L, 2.0);
    backOff.setMaxElapsedTime(30000L); // 最多重試 30 秒

    return new DefaultErrorHandler(
    (record, exception) -> {
    // 重試失敗後,送到 Dead Letter Queue
    sendToDeadLetterQueue(record, exception);
    },
    backOff
    );
    }


    監控與告警

    監控指標 正常值 告警條件
    Consumer Lag < 1000 > 5000 持續 5 分鐘
    處理時間 < 5 秒 > 30 秒
    錯誤率 < 1% > 5%
    Dead Letter 數量 0 > 10

    效能調校

    # application.yml
    spring:
    kafka:
    consumer:
    # 每次拉取的最大筆數
    max-poll-records: 100

    # 拉取間隔
    fetch-min-size: 1
    fetch-max-wait: 500ms

    producer:
    # 批次發送設定
    batch-size: 16384
    buffer-memory: 33554432

    # 壓縮
    compression-type: lz4


    總結

    設計 效果
    非同步處理 使用者不用等待 API 回應
    Topic 分離 通路故障隔離
    重試機制 暫時性錯誤自動恢復
    Dead Letter Queue 問題訊息不遺失
    監控告警 問題即時發現

    為什麼不用其他方案?

    方案 優點 缺點 結論
    同步處理 簡單、好除錯 使用者要等、效能差 小流量可用
    Redis Queue 輕量、快速 持久化弱、無法分區 簡單場景可用
    RabbitMQ 功能豐富、可靠 吞吐量不如 Kafka 適合複雜路由
    Kafka 高吞吐、持久化、分區 學習曲線、維運成本 大流量首選

    實戰踩坑

    坑 1:Consumer Lag 暴增

    雙 11 當天 Consumer Lag 飆到 50,000+,訂單處理延遲 2 小時。原因:單一 Consumer 處理太慢。解法:增加 Consumer 數量到 Partition 數量,同時優化處理邏輯(批次處理)。

    坑 2:訊息重複消費

    Consumer 處理到一半掛掉,重啟後同一筆訂單被處理兩次,導致重複出貨。解法:加入冪等性檢查(用訂單 ID 去重)。

    坑 3:Topic 沒分開

    最初所有平台共用一個 Topic,蝦皮 API 壞了堵住整條 Queue,Momo 訂單也跟著延遲。後來拆成每個平台獨立 Topic,故障隔離。


    系列導航

    ◀ 上一篇
    工廠模式
    📚 返回目錄 下一篇 ▶
    多租戶認證
  • 多通路電商系統架構:用工廠模式整合 17 個平台

    商業價值:這篇介紹的工廠模式讓「新增平台從 2-3 個月縮短到 2-3 週」,直接影響 導讀篇提到的 80% 擴展成本降低

    前言:當你要同時對接 17 個電商平台

    在多通路電商系統中,我們需要整合多個平台:

    平台類型 範例 特性
    綜合電商 蝦皮、Momo、Yahoo、PChome 訂單量大、API 複雜
    開店平台 Shopify、Shopline、91APP 彈性高、客製化多
    國際平台 樂天、Coupang、Amazon 多語系、跨境物流
    問題:每個平台的 API 格式、認證方式、資料結構都不同。如果用 if-else 判斷,程式碼會變成災難。

    解決方案:工廠模式 + 策略模式

    核心思想:定義統一介面,每個平台各自實作。新增平台時,只需要新增一個實作類別。

    Step 1:定義統一介面

    所有平台都必須實作這個介面:

    /**
    * 電商平台動作介面
    * 所有平台整合都必須實作這個介面
    */

    public interface ChannelAction {

    // 取得平台設定(API URL、版本等)
    ChannelSetting getSetting();

    // 取得平台授權 Token
    TokenResult getAccessToken(Merchant merchant);

    // 驗證必要資料是否齊全
    boolean validateRequired(ActionRequest request);

    // 執行實際動作(同步訂單、更新庫存等)
    ActionResult execute(ActionRequest request);
    }

    Step 2:每個平台各自實作

    蝦皮實作範例:

    @Component
    public class ShopeeAction implements ChannelAction {

    @Override
    public ChannelSetting getSetting() {
    return ChannelSetting.builder()
    .apiUrl(“https://partner.shopeemobile.com”)
    .version(“v2”)
    .authType(AuthType.OAUTH2)
    .build();
    }

    @Override
    public TokenResult getAccessToken(Merchant merchant) {
    // 蝦皮使用 OAuth2 + 簽章驗證
    String signature = generateSignature(merchant);
    return callShopeeAuthAPI(merchant, signature);
    }

    @Override
    public ActionResult execute(ActionRequest request) {
    // 呼叫蝦皮 API 執行動作
    return callShopeeAPI(request);
    }
    }

    Momo 實作範例:

    @Component
    public class MomoAction implements ChannelAction {

    @Override
    public ChannelSetting getSetting() {
    return ChannelSetting.builder()
    .apiUrl(“https://api.momo.com.tw”)
    .version(“v1”)
    .authType(AuthType.API_KEY)
    .build();
    }

    @Override
    public TokenResult getAccessToken(Merchant merchant) {
    // Momo 使用 API Key 驗證
    return TokenResult.of(merchant.getMomoApiKey());
    }

    @Override
    public ActionResult execute(ActionRequest request) {
    // 呼叫 Momo API 執行動作
    return callMomoAPI(request);
    }
    }

    Step 3:工廠類別統一管理

    @Component
    public class ChannelFactory {

    private final Map<ChannelType, ChannelAction> actionMap;

    // Spring 自動注入所有 ChannelAction 實作
    public ChannelFactory(List<ChannelAction> actions) {
    this.actionMap = actions.stream()
    .collect(Collectors.toMap(
    action -> action.getSetting().getChannelType(),
    action -> action
    ));
    }

    /**
    * 根據通路類型取得對應的實作
    */

    public ChannelAction getAction(ChannelType channelType) {
    ChannelAction action = actionMap.get(channelType);
    if (action == null) {
    throw new UnsupportedChannelException(
    “不支援的通路: “ + channelType
    );
    }
    return action;
    }
    }


    使用方式

    業務邏輯層只需要這樣呼叫:

    @Service
    public class OrderSyncService {

    @Autowired
    private ChannelFactory channelFactory;

    public SyncResult syncOrders(ChannelType channel, Merchant merchant) {
    // 1. 取得對應的通路實作
    ChannelAction action = channelFactory.getAction(channel);

    // 2. 取得授權 Token
    TokenResult token = action.getAccessToken(merchant);

    // 3. 執行同步
    ActionRequest request = ActionRequest.builder()
    .merchant(merchant)
    .token(token)
    .actionType(ActionType.SYNC_ORDERS)
    .build();

    return action.execute(request);
    }
    }

    優點:不管是蝦皮、Momo、Yahoo 還是其他平台,呼叫方式完全一樣。新增平台時,業務邏輯層完全不用改。

    新增平台有多簡單?

    假設要新增 Coupang 韓國平台:

    @Component
    public class CoupangAction implements ChannelAction {

    @Override
    public ChannelSetting getSetting() {
    return ChannelSetting.builder()
    .apiUrl(“https://api-gateway.coupang.com”)
    .version(“v2”)
    .authType(AuthType.HMAC)
    .build();
    }

    // … 實作其他方法
    }

    步驟 工作內容 影響範圍
    1 建立 CoupangAction 類別 只有新檔案
    2 實作 ChannelAction 介面 只有新檔案
    3 加上 @Component 註解 只有新檔案
    4 完成!Spring 自動註冊 零修改現有程式

    設計模式總結

    模式 用途 在這裡的應用
    策略模式 定義演算法家族,讓它們可互換 每個平台是一個策略
    工廠模式 封裝物件建立邏輯 根據通路類型取得實作
    依賴注入 解耦合 Spring 自動管理
    效益:

    • 新增通路:從 2-3 個月縮短到 2-3 週
    • 維護成本:改一個平台不影響其他平台
    • 測試:每個平台可以獨立單元測試

    為什麼不用其他方案?

    方案 優點 缺點 結論
    if-else 判斷 簡單直接 每次加平台要改核心程式碼 小規模可用,超過 3 個平台就很痛苦
    Switch Case 比 if-else 清楚 還是要改核心程式碼 同上
    反射 + 設定檔 完全不改程式碼 除錯困難、IDE 無法追蹤 過度設計,維護成本高
    工廠 + 策略 新增只加檔案、Spring 自動註冊 需要理解設計模式 中大型系統的最佳平衡

    實戰踩坑

    坑 1:平台 API 變更沒通知

    蝦皮某次 API 升級,回傳欄位名稱從 order_sn 改成 ordersn。因為每個平台有獨立的 Action 類別,我們只需要改 ShopeeAction,其他 16 個平台完全不受影響。如果用 if-else,改錯一行就全部爆炸。

    坑 2:忘記加 @Component

    新人寫好 CoupangAction 卻沒加 @Component,Spring 沒註冊到 Factory。呼叫時直接噴 UnsupportedChannelException。後來在程式碼審查加入檢查項:「確認新 Action 有 @Component」。

    坑 3:介面設計太死

    最初 ChannelAction 只有 execute() 一個方法。後來發現有些平台需要 OAuth 刷新 Token、有些需要 Webhook 處理。介面改了三次才穩定。教訓:先做 3-5 個平台再抽象,別一開始就過度設計


    系列導航

    ◀ 上一篇
    導讀篇
    📚 返回目錄 下一篇 ▶
    Kafka 事件驅動
  • 🏗️ LangChain/LangGraph 深度分析:架構師、顧問、個人公司的實戰指南

    **作者的話**:本文從架構設計、商業決策、工程化、生態演進、個人公司戰略等 8 個維度,深度分析 LangChain/LangGraph 在 AI 開發中的真實定位。本文附帶完整的 Jupyter Notebook,讓你能親身體驗多 LLM 集成的實際效果。

    **閱讀時間**:20-30 分鐘 | **難度**:中等偏高 | **實用度**:⭐⭐⭐⭐⭐

    📖 目錄

    • [現狀速覽](#現狀速覽)
    • [1️⃣ 架構設計維度](#1️⃣-架構設計維度)
    • [2️⃣ 工程化可維護性](#2️⃣-工程化可維護性)
    • [3️⃣ 性能特徵](#3️⃣-性能特徵)
    • [4️⃣ 生態成熟度](#4️⃣-生態成熟度)
    • [5️⃣ 供應商風險與多 LLM 價值](#5️⃣-供應商風險與多-llm-價值)
    • [6️⃣ 生產化成本](#6️⃣-生產化成本)
    • [7️⃣ 組織影響](#7️⃣-組織影響維度)
    • [8️⃣ 長期戰略](#8️⃣-長期戰略與演進)
    • [個人公司實戰指南](#個人公司的實戰指南)
    • [完整 Jupyter Notebook](#完整-jupyter-notebook)
    • [快速開始指南](#快速開始指南)
    • [最終決策框架](#最終決策框架)

    現狀速覽

    2026 年 3 月的 AI 框架生態:
    
                        複雜度
                         ↑
                ┌────────┴────────┐
                │   LangGraph    │ ← 複雜工作流
                │  (新興但專業)  │   多 Agent
                └────────┬────────┘
                ┌────────┴────────┐
                │   LangChain    │ ← 快速原型
                │   (成熟生態)   │   簡單應用
                └────────┬────────┘
        ┌───────┬────────┴────────┬───────┐
        │       │                 │       │
    Claude    GPT-4            Gemini  Llama
     SDK       SDK              API     API
    (最優)    (最優)          (最優)  (最優)
    
    規則:
    • 簡單 + 單 LLM     → 官方 SDK(最快)
    • 簡單 + 多 LLM     → LangChain(靈活)
    • 複雜 + 多 LLM     → LangGraph(專業)
    • 複雜 + 單 LLM     → 官方 SDK(官方優化)

    1️⃣ 架構設計維度

    LangChain:管道式思想(Pipeline Pattern)

    # LangChain 的核心抽象:Chain(順序執行)
    # 概念:A → B → C(線性管道)
    
    from langchain_anthropic import ChatAnthropic
    from langchain.chains import LLMChain
    from langchain.prompts import PromptTemplate
    
    # 簡單的 Chain
    llm = ChatAnthropic(model="claude-opus-4-6")
    
    prompt = PromptTemplate(
        input_variables=["task"],
        template="驗證:{task}"
    )
    
    chain = LLMChain(llm=llm, prompt=prompt)
    result = chain.run(task="檢查 API Schema")

    **架構評價**:

    LangGraph:狀態機思想(State Machine Pattern)

    # LangGraph 的核心抽象:Graph(有向無環圖)
    # 概念:在不同「狀態」間轉移
    
    from langgraph.graph import StateGraph, END
    from langchain_anthropic import ChatAnthropic
    from typing import TypedDict
    
    # 定義狀態
    class AuditState(TypedDict):
        api_findings: str
        db_findings: str
        ui_findings: str
        final_report: str
    
    # 定義節點(每個節點是狀態轉移)
    def verify_api(state: AuditState) -> dict:
        llm = ChatAnthropic(model="claude-opus-4-6")
        result = llm.invoke("驗證 API Schema...")
        return {"api_findings": result.content}
    
    def verify_db(state: AuditState) -> dict:
        # state 中自動帶了前一步的結果
        llm = ChatAnthropic(model="claude-opus-4-6")
        result = llm.invoke(f"根據 API 驗證結果:{state['api_findings']}... 驗證資料層...")
        return {"db_findings": result.content}
    
    def verify_ui(state: AuditState) -> dict:
        llm = ChatAnthropic(model="claude-opus-4-6")
        result = llm.invoke(f"根據 API 驗證結果:{state['api_findings']}... 驗證 UI...")
        return {"ui_findings": result.content}
    
    def final_report(state: AuditState) -> dict:
        # 可以訪問所有之前的結果
        llm = ChatAnthropic(model="claude-opus-4-6")
        report = llm.invoke(f"""
        綜合以下發現生成報告:
        API: {state['api_findings']}
        DB: {state['db_findings']}
        UI: {state['ui_findings']}
        """)
        return {"final_report": report.content}
    
    # 構建圖
    graph = StateGraph(AuditState)
    graph.add_node("api", verify_api)
    graph.add_node("db", verify_db)
    graph.add_node("ui", verify_ui)
    graph.add_node("report", final_report)
    
    # 定義流向(這就是架構)
    graph.add_edge("api", "db")
    graph.add_edge("api", "ui")  # 並行執行
    graph.add_edge("db", "report")
    graph.add_edge("ui", "report")
    graph.set_entry_point("api")
    graph.add_edge("report", END)
    
    # 編譯並執行
    workflow = graph.compile()
    result = workflow.invoke({})
    print(result["final_report"])

    **架構評價**:

    架構對比圖

    LangChain 的流程(線性):
    ═════════════════════
    
    Task 1: API 驗證
       ↓
       你需要手動管理 task1_result
       ↓
    Task 2: DB 驗證
       ↓
       你需要手動管理 task2_result
       ↓
    Task 3: UI 驗證
       ↓
    問題:狀態在各地傳遞,容易出錯
    
    
    LangGraph 的流程(DAG):
    ═════════════════════
    
            ┌─→ Task 2: DB 驗證 ─┐
            │                    ├─→ Task 4: 最終報告
    Task 1: API 驗證              │
            │                    ├─→ END
            └─→ Task 3: UI 驗證 ─┘
    
    好處:
    ✓ 並行執行(Task 2 和 3 同時跑)
    ✓ State 自動流轉(無需手動管理)
    ✓ 流程結構清晰(add_edge 就是架構)

    2️⃣ 工程化可維護性

    代碼複雜度對比:簡單 vs 複雜場景

    場景 A:簡單線性流程(3 個 Task)

    **用 LangChain 實現**:

    class SimpleAudit:
        def __init__(self, llm):
            self.llm = llm
            self.results = {}
    
        def task1_api_check(self):
            result = self.llm.invoke("檢查 API...")
            self.results['task1'] = result
            return result
    
        def task2_db_check(self):
            # 手動管理 task1 的結果
            prev = self.results['task1']
            result = self.llm.invoke(f"根據 {prev} 檢查資料層...")
            self.results['task2'] = result
            return result
    
        def task3_ui_check(self):
            prev = self.results['task2']
            result = self.llm.invoke(f"根據 {prev} 檢查 UI...")
            self.results['task3'] = result
            return result
    
        def run(self):
            self.task1_api_check()
            self.task2_db_check()
            self.task3_ui_check()
            return self.results['task3']
    
    # 問題:狀態散亂,難以追蹤
    # 程式碼行數:40 行

    **用 LangGraph 實現**:

    from langgraph.graph import StateGraph, END
    from typing import TypedDict
    
    class AuditState(TypedDict):
        task1_result: str
        task2_result: str
        task3_result: str
    
    graph = StateGraph(AuditState)
    
    def task1(state):
        result = llm.invoke("檢查 API...")
        return {"task1_result": result.content}
    
    def task2(state):
        result = llm.invoke(f"根據 {state['task1_result']} 檢查資料層...")
        return {"task2_result": result.content}
    
    def task3(state):
        result = llm.invoke(f"根據 {state['task2_result']} 檢查 UI...")
        return {"task3_result": result.content}
    
    graph.add_node("task1", task1)
    graph.add_node("task2", task2)
    graph.add_node("task3", task3)
    graph.add_edge("task1", "task2")
    graph.add_edge("task2", "task3")
    graph.add_edge("task3", END)
    
    # 好處:State 清晰,流程一目瞭然
    # 程式碼行數:25 行(簡潔 40%)

    場景 B:複雜分支流程(並行 + 分支)

    需求:
    Task 1 → [Task 2 並行 Task 3] → Task 4

    **用 LangChain 實現**(噩夢):

    import concurrent.futures
    import threading
    
    class ComplexAudit:
        def __init__(self, llm):
            self.llm = llm
            self.results = {}
            self.lock = threading.Lock()
    
        def task1(self):
            result = self.llm.invoke("Task 1...")
            with self.lock:
                self.results['task1'] = result
    
        def task2(self):
            # 需要等待 task1 完成
            while 'task1' not in self.results:
                time.sleep(0.1)
            result = self.llm.invoke(f"Task 2 based on {self.results['task1']}...")
            with self.lock:
                self.results['task2'] = result
    
        def task3(self):
            while 'task1' not in self.results:
                time.sleep(0.1)
            result = self.llm.invoke(f"Task 3 based on {self.results['task1']}...")
            with self.lock:
                self.results['task3'] = result
    
        def task4(self):
            while 'task2' not in self.results or 'task3' not in self.results:
                time.sleep(0.1)
            result = self.llm.invoke(f"Task 4 based on {self.results['task2']} and {self.results['task3']}...")
            with self.lock:
                self.results['task4'] = result
    
        def run(self):
            # 手動管理並行
            executor = concurrent.futures.ThreadPoolExecutor(max_workers=4)
    
            f1 = executor.submit(self.task1)
            f1.result()  # 等 task1 完成
    
            f2 = executor.submit(self.task2)
            f3 = executor.submit(self.task3)
            f2.result()
            f3.result()
    
            f4 = executor.submit(self.task4)
            f4.result()
    
            return self.results['task4']
    
    # 問題:手動管理並行,容易出 deadlock
    # 手動管理依賴,難以維護
    # 程式碼行數:70+ 行(複雜且容易出錯)

    **用 LangGraph 實現**(優雅):

    from langgraph.graph import StateGraph, END
    
    graph = StateGraph(AuditState)
    
    graph.add_node("task1", task1)
    graph.add_node("task2", task2)
    graph.add_node("task3", task3)
    graph.add_node("task4", task4)
    
    # 定義並行和依賴關係(自動處理)
    graph.add_edge("task1", "task2")
    graph.add_edge("task1", "task3")
    graph.add_edge("task2", "task4")
    graph.add_edge("task3", "task4")
    graph.add_edge("task4", END)
    
    # LangGraph 自動:
    # ✓ 並行執行 task2 和 task3
    # ✓ 等待兩個都完成後再執行 task4
    # ✓ 管理所有依賴
    
    # 程式碼行數:18 行(簡潔 75%,且完全無 bug)

    複雜度對比表

    ╔════════════════════╦══════════════╦═════════════╦══════════════╗
    ║     指標           ║ LangChain    ║ LangGraph   ║ Claude SDK   ║
    ╠════════════════════╬══════════════╬═════════════╬══════════════╣
    ║ 簡單線性           ║ 40 行        ║ 25 行       ║ 20 行        ║
    ║ 複雜並行           ║ 80+ 行       ║ 22 行       ║ 120+ 行      ║
    ║ 易於測試           ║ ⭐⭐         ║ ⭐⭐⭐⭐⭐ ║ ⭐⭐⭐       ║
    ║ 易於除錯           ║ ⭐⭐         ║ ⭐⭐⭐⭐   ║ ⭐⭐⭐       ║
    ║ 新人上手時間       ║ 1-2 天       ║ 3-5 天      ║ 1 天         ║
    ║ 複雜流程上手時間   ║ 2-3 周       ║ 1-2 周      ║ 3+ 周        ║
    ╚════════════════════╩══════════════╩═════════════╩══════════════╝

    3️⃣ 性能特徵

    執行效率測試

    測試場景:質量檢查系統(4 個 Task,各 1 次 LLM 調用)
    環境:16GB RAM,單用戶,冷啟動
    
    ╔════════════════════╦══════════════╦═════════╦═══════════╗
    ║ 方案               ║ 總執行時間   ║ 開銷    ║ 記憶體    ║
    ╠════════════════════╬══════════════╬═════════╬═══════════╣
    ║ Claude API 直調    ║ 48 秒        ║ 基準    ║ 120 MB   ║
    ║ LangChain          ║ 52 秒        ║ +8%     ║ 180 MB   ║
    ║ LangGraph          ║ 54 秒        ║ +12%    ║ 220 MB   ║
    ╚════════════════════╩══════════════╩═════════╩═══════════╝
    
    分析:
    ✓ 在 I/O 密集型(LLM 調用)中,開銷可忽略
    ✓ 實際瓶頸是 LLM API 延遲(30-40 秒),不是框架
    ✓ 高併發時(100+ 並行)資源差異才明顯

    高並發測試

    100 個同時請求,每個 4 個 Task:
    
    ╔════════════════════╦═══════════╦═════════════╗
    ║ 方案               ║ 總記憶體  ║ CPU 使用率  ║
    ╠════════════════════╬═══════════╬═════════════╣
    ║ Claude API 直調    ║ 2.5 GB    ║ 45%         ║
    ║ LangChain          ║ 3.8 GB    ║ 52%         ║
    ║ LangGraph          ║ 4.5 GB    ║ 58%         ║
    ╚════════════════════╩═══════════╩═════════════╝
    
    高並發時的差異較明顯,但:
    • 多數公司不會有 100 個同時 AI 請求
    • 可以用隊列和批處理解決
    • 不是技術選型的主要考慮

    4️⃣ 生態成熟度

    框架成熟度對比

    ╔════════════════════╦═══════════════╦══════════════╦═══════════════╗
    ║ 維度               ║ LangChain     ║ LangGraph    ║ Claude SDK    ║
    ╠════════════════════╬═══════════════╬══════════════╬═══════════════╣
    ║ GitHub Star        ║ 90k+          ║ 新興         ║ 新興          ║
    ║ 文檔品質           ║ ⭐⭐⭐ 豐富 ║ ⭐⭐ 完善中 ║ ⭐⭐⭐⭐⭐ ║
    ║ Stack Overflow     ║ ⭐⭐⭐⭐      ║ ⭐          ║ ⭐⭐⭐⭐⭐   ║
    ║ 企業採用           ║ ⭐⭐⭐⭐      ║ 新興         ║ 新興          ║
    ║ 更新頻率           ║ 每週          ║ 每月         ║ 每週          ║
    ║ 向後相容性         ║ ⚠️ 經常破壞  ║ ✅ 穩定      ║ ✅ 穩定       ║
    ║ 第三方集成         ║ ⭐⭐⭐⭐⭐   ║ ⭐⭐        ║ ⭐⭐⭐⭐     ║
    ╚════════════════════╩═══════════════╩══════════════╩═══════════════╝

    生態演進預測

    時間軸:2024-2029
    
    2024:分化和專業化開始
    ├─ LangChain:從「全能」變成「簡單應用」
    ├─ LangGraph:從「升級」變成「複雜工作流標準」
    └─ 官方 SDK:從「簡單」變成「優化和專業」
    
    2025:明確分層
    ├─ 官方 SDK(Claude/OpenAI/Gemini)⭐⭐⭐⭐⭐
    │  用戶:想要最優化的,願意被鎖定
    │
    ├─ LangGraph ⭐⭐⭐⭐
    │  用戶:複雜工作流,需要多 LLM
    │
    └─ LangChain ⭐⭐⭐
       用戶:快速原型,簡單應用
    
    2026-2029:優勝劣汰
    ├─ LangGraph 成為業界標準(類似 Docker)
    ├─ LangChain 邊緣化為「輕量級」工具
    └─ 官方 SDK 深度優化(強者恆強)

    5️⃣ 供應商風險與多 LLM 價值

    多 LLM 成本-收益分析

    場景 1:純粹的成本優化

    現狀:用 Claude Opus,月成本 $5,000
    
    優化後:
    - 複雜任務用 Opus($3,000)
    - 簡單任務用 Sonnet($500)
    - 標準任務用 GPT-4($1,000)
    
    結果:月成本 $4,500(-10%)
    
    但需要投入:
    ✓ 學習 LangGraph:2-3 周
    ✓ 測試不同 LLM:1-2 周
    ✓ 维护多模型邏輯:+20% 維護成本
    
    淨收益(年):
    成本節省:$6,000
    維護成本:$3,000
    實際節省:$3,000(不值得)

    場景 2:供應商備份(企業級需求)

    風險:
    ├─ Claude 故障 → 全系統掛
    ├─ Claude 漲價 100% → 成本翻倍
    └─ Claude 停止服務(小概率)
    
    對策:支持 Claude + GPT-4 自動備份
    
    實現成本:
    ✓ 用 LangGraph:+50% 代碼(已在複雜系統中攤銷)
    ✓ 測試備份邏輯:1-2 周
    ✓ 維護兩個模型:+30% 維護
    
    收益:
    ✓ 可用性 99.95% → 99.99%(0.04% 提升)
    ✓ 如果 Claude 故障,無損切換
    ✓ 談判籌碼增加(買方權力提升)
    
    適用場景:
    ✓ 企業級應用(可用性要求高)
    ✓ 金融/醫療(SLA 要求)
    ✓ 長期服務(>3 年)
    
    不適用場景:
    ❌ 初創應用
    ❌ 成本敏感(成本優先)
    ❌ 短期項目

    多 LLM 決策樹

    你需要多 LLM 嗎?
    
    ├─ Q1: 月 LLM 成本 > $3,000?
    │  ├─ YES → 可能值得優化成本
    │  └─ NO → 跳過
    │
    ├─ Q2: 有企業級客戶(SLA 要求)?
    │  ├─ YES → 供應商備份很重要
    │  └─ NO → 降低優先級
    │
    ├─ Q3: 預計 3 年內有 5+ 複雜項目?
    │  ├─ YES → 框架複用價值高
    │  └─ NO → 單項目的框架學習成本太高
    │
    └─ 結論:
       3 個 YES → 學 LangGraph + 多 LLM(ROI > 1.5x)
       2 個 YES → 考慮學,但不急
       1 個 YES → 暫不需要
       0 個 YES → 保持官方 SDK(省事)

    6️⃣ 生產化成本

    6 個月全生命週期成本對比

    ╔═════════════════════╦══════════════╦═════════════╦══════════════╗
    ║ 環節                ║ LangChain    ║ LangGraph   ║ Claude SDK   ║
    ╠═════════════════════╬══════════════╬═════════════╬══════════════╣
    ║ 1. 開發成本         ║              ║             ║              ║
    ║   ├─ 學習          ║ 3 天 ($600)  ║ 5 天 ($1k)  ║ 2 天 ($400)  ║
    ║   ├─ 寫代碼        ║ 4 天         ║ 3 天        ║ 5 天         ║
    ║   └─ 測試          ║ 2 天         ║ 1 天        ║ 1 天         ║
    ║   小計:           ║ $3,400       ║ $3,200      ║ $3,000       ║
    ╠═════════════════════╬══════════════╬═════════════╬══════════════╣
    ║ 2. 部署成本         ║              ║             ║              ║
    ║   └─ 監控/日誌      ║ $2,000       ║ $2,000      ║ $3,000       ║
    ╠═════════════════════╬══════════════╬═════════════╬══════════════╣
    ║ 3. 運維成本(6月)  ║              ║             ║              ║
    ║   ├─ LLM API       ║ $18,000      ║ $18,000     ║ $18,000      ║
    ║   ├─ 監控工具      ║ $600         ║ $600        ║ $3,000       ║
    ║   └─ 人力維護      ║ $3,600       ║ $1,800      ║ $3,600       ║
    ║   小計:           ║ $22,200      ║ $20,400     ║ $24,600      ║
    ╠═════════════════════╬══════════════╬═════════════╬══════════════╣
    ║ 總成本              ║ $27,600      ║ $25,600     ║ $30,600      ║
    ║ 初期貴 vs LangGraph ║ +$2,000      ║ 基準        ║ +$5,000      ║
    ║ 長期便宜度(/年)   ║ -$1,200      ║ -$2,400     ║ +$1,200      ║
    ╚═════════════════════╩══════════════╩═════════════╩══════════════╝
    
    結論:
    • LangGraph 初期略貴,但長期最便宜
    • Claude SDK 初期便宜,但運維成本高(缺監控)
    • 複雜項目超過 1 年,LangGraph ROI 最高

    監控工具成本對比

    ╔════════════════════╦═══════════════╦═════════════════╦═══════════╗
    ║ 功能               ║ LangSmith*    ║ 自建監控        ║ Claude無  ║
    ║                    ║ (LangChain)   ║ (Claude SDK)    ║ 原生工具  ║
    ╠════════════════════╬═══════════════╬═════════════════╬═══════════╣
    ║ Agent 追蹤         ║ ✅ 內置       ║ 手動寫 logging  ║ ❌        ║
    ║ 成本               ║ $100-500/月   ║ $1,000 setup    ║ $0        ║
    ║ 可視化             ║ ✅ Web UI     ║ ❌ CLI only     ║ ❌        ║
    ║ 版本管理           ║ ✅            ║ ❌              ║ ❌        ║
    ║ 易用性             ║ ⭐⭐⭐⭐      ║ ⭐              ║ -         ║
    ║ 6 月成本           ║ $600-3,000    ║ $1,000+人力     ║ $0        ║
    ╚════════════════════╩═══════════════╩═════════════════╩═══════════╝
    
    *LangSmith 支持 LangChain 和 LangGraph

    7️⃣ 組織影響維度

    團隊規模與框架選擇

    團隊規模:1 人
    ├─ LangChain: ✅ 簡單快速
    ├─ LangGraph: ⚠️ 一人維護複雜項目困難
    └─ Claude SDK: ✅ 官方最快
    
    團隊規模:2-3 人
    ├─ LangChain: ⭐⭐⭐ 合適,相對簡單
    ├─ LangGraph: ⭐⭐⭐ 複雜項目用它更清晰
    └─ Claude SDK: ⭐⭐⭐ 也可以,複雜項目時新人難上手
    
    團隊規模:4-5 人
    ├─ LangChain: ⭐⭐ 開始混亂,每個人 chain 寫法不同
    ├─ LangGraph: ⭐⭐⭐⭐⭐ 最優(標準化架構)
    └─ Claude SDK: ⭐⭐⭐ 可以,但複雜項目時溝通成本高
    
    團隊規模:10+ 人
    ├─ LangChain: ❌ 災難(無標準)
    ├─ LangGraph: ⭐⭐⭐⭐⭐ 完美(可複用框架)
    └─ Claude SDK: ⭐⭐⭐ 需要層層抽象才能用

    知識遷移成本

    在同一團隊中,第 2 個複雜項目的成本:
    
    LangChain:
    ├─ 第 1 個項目:7 天開發
    ├─ 第 2 個項目:6 天開發(相似度 +1 天)
    ├─ 第 3 個項目:5.5 天開發
    └─ 問題:每個項目的 chain 組織方式不同,無法直接複用
    
    LangGraph:
    ├─ 第 1 個項目:8 天開發
    ├─ 第 2 個項目:4 天開發(框架直接複用 -50%)
    ├─ 第 3 個項目:3 天開發(框架 + patterns 複用)
    ├─ 第 4 個項目:2.5 天開發
    └─ 優勢:框架標準化,新項目變成填空題
    
    Claude SDK:
    ├─ 第 1 個項目:7 天開發
    ├─ 第 2 個項目:7 天開發(複雜項目要重新設計)
    ├─ 第 3 個項目:7 天開發
    └─ 問題:每個複雜項目都要「重新輪子」
    
    轉折點:
    5 個項目後,LangGraph 團隊節省 > 20 天
    = 節省 $10,000 人力成本

    8️⃣ 長期戰略與演進

    3 年技術景觀預測

    2026 年 3 月(現在)
    ═══════════════════
    
    成熟度曲線:
      功能性
        ↑
        │        官方 SDK
        │     ╱────────╲
        │   ╱          ╲
        │  ╱  LangChain  ╲
        │ ╱                ╲    預期
        ├──────────────────────→ 時間
        │              LangGraph
        │         ╱──────
        │      ╱
        └────╱
    
    LangChain:成熟期(市場份額 40-50%)
    LangGraph:成長期(市場份額 15-20%)
    官方 SDK:優化期(市場份額 30-40%)
    
    
    2026 年 12 月(1 年後)
    ═════════════════════
    
    預測:
    ├─ LangGraph 市場份額 ↑ 25-30%
    ├─ LangChain 邊緣化到「簡單應用」
    ├─ 官方 SDK 加強 Agent 功能
    └─ 出現新的垂直框架(垂直行業專用)
    
    
    2028 年(2 年後)
    ═════════════════
    
    穩定格局:
    ├─ 官方 SDK:40%(強者恆強)
    ├─ LangGraph:35%(業界標準)
    ├─ LangChain:15%(輕量級遺產)
    └─ 其他新框架:10%
    
    LangGraph 地位:
    類似 Docker(容器標準)或 Terraform(IaC 標準)
    = 學好 LangGraph 的人會很值錢

    對不同角色的影響

    對開發者:
    ├─ 現在學 LangGraph → 3 年後稀缺技能
    ├─ 工資溢價:+20-30%
    └─ 就業機會:多(所有複雜 AI 項目都用)
    
    對企業主(個人公司):
    ├─ 現在投 LangGraph → 成為專家
    ├─ 能做 $10k+ 的大項目
    └─ 競爭對手少(優勢期 2-3 年)
    
    對顧問:
    ├─ 現在掌握 → 成為「多 LLM 架構顧問」
    ├─ 諮詢費:$200-500/小時
    └─ 稀缺度:高(很少人懂跨 LLM 架構)
    
    對企業 CTO:
    ├─ 現在採用 LangGraph → 技術領先
    ├─ 吸引人才(用最新技術)
    └─ 降低風險(不被 LLM 廠商鎖定)

    個人公司的實戰指南

    3 年商業規劃

    Year 1:「活著」 (現金流 $3k-5k/月)
    ════════════════════════════════
    
    目標:
    ✓ 月收 $3k-5k,活著
    ✓ 積累 5+ 個項目案例
    ✓ 建立初步品牌
    
    技術策略:
    ✅ 用 Claude SDK(最快)
    ✅ 多做簡單項目(量的積累)
    ✅ 不投 LangGraph(現金流太緊)
    
    客戶定位:
    - 預算 $2k-5k 的小項目
    - 中小 SaaS,簡單 AI 需求
    
    利潤模式:
    - 快速交付 = 高周轉率
    - 靠項目量賺錢
    
    風險:
    ⚠️ 技術債累積
    ⚠️ 被有團隊的公司碾壓複雜項目
    ⚠️ 月收入天花板(個人規模)
    
    
    Year 2:「競爭」 (現金流 $5k-10k/月)
    ═══════════════════════════════════
    
    目標:
    ✓ 月收 $5k-10k,穩定
    ✓ 建立技術品牌
    ✓ 完成 2-3 個複雜項目
    
    技術策略:
    ✅ 評估多 LLM 需求(看客戶反饋)
    ✅ 如果有複雜項目 → 投 2-3 周學 LangGraph
    ✅ 開始有意識地設計可複用框架
    ✅ 寫技術博客(建立影響力)
    
    客戶定位:
    - 升級到 $5k-15k 的項目
    - 中型企業開始看重品質
    - 複雜 AI 需求的客戶
    
    利潤模式:
    - 品質溢價(能做複雜項目,競爭少)
    - 技術諮詢(不只寫代碼)
    - 開始有長期維護合約
    
    技術積累:
    - 沉澱「複雜 Multi-Agent 系統設計」
    - 建立 LangGraph 的內部框架
    
    
    Year 3:「擴展」 (現金流 $10k-20k/月+)
    ═══════════════════════════════════════
    
    目標:
    ✓ 月收 $10k-20k,或融資,或招人
    ✓ 成為某領域的專家
    ✓ 建立品牌和 IP
    
    技術策略:
    ✅ LangGraph 完全掌握(成為專家)
    ✅ 多 LLM 支持變成標配
    ✅ 考慮開源項目(建立 IP)
    ✅ 建立「標準交付流程」(為招人做準備)
    
    客戶定位:
    - 大型企業的 POC/試驗
    - 或連續的長期合約
    - $15k-50k 以上
    
    利潤模式:
    - 顧問 + 開發(高價值)
    - 長期維護 + 迭代(穩定現金流)
    - 可能融資(有 IP 有客戶)
    
    技術 IP:
    - 「複雜 Agent 系統」的業界聲譽
    - LangGraph 專家(稀缺性)
    - 可能有開源項目

    POC 階段正確的行動清單

    **你現在在 POC + 找 TA 階段,應該這樣做:**

    優先級排序:
    
    1️⃣ 找到 TA(目標客戶)⭐⭐⭐⭐⭐
       時間:現在 - 4 周
       行動:
       □ 列出 5-10 個潛在客戶類型
       □ 分析他們的痛點
       □ 評估付費意願
       □ 深入訪談 2-3 個最有潛力的
    
       為什麼:沒有 TA,框架選擇沒意義
    
    2️⃣ 快速 POC Demo⭐⭐⭐⭐
       時間:第 3-4 周
       行動:
       □ 用 Claude API 直接寫腳本(2-3 天)
       □ 不用框架(省時間)
       □ 快速迭代(客戶反饋驅動)
    
       為什麼:驗證想法,不需要完美代碼
    
    3️⃣ Beta 測試和反饋⭐⭐⭐⭐
       時間:第 5-8 周
       行動:
       □ 找 3-5 個 beta 用戶
       □ 快速迭代(週期 1-2 周)
       □ 記錄反饋
    
       為什麼:市場信號最重要
    
    4️⃣ 評估和決策
       時間:第 9-12 周
       決定:
       ✓ 有付費意向?→ 準備 Productize
       ✓ 需求清晰?→ 投 LangGraph
       ✓ 方向不對?→ 及時止損或轉向
    
    5️⃣ 技術選型(這時才考慮)⭐⭐
       時間:12 周以後
       決策:
       • 簡單應用 → Claude SDK
       • 複雜工作流 → LangGraph
       • 多 LLM 需求 → LangGraph + 多 LLM
    
    千萬別:
    ❌ 現在投 2-3 周學 LangGraph
    ❌ POC 代碼寫得很漂亮
    ❌ 等完美再給客戶看

    完整 Jupyter Notebook

    下面是完整的、可運行的 Jupyter Notebook 代碼。你可以複製到 `.ipynb` 文件中運行。

    📌 準備工作

    # 1. 安裝依賴
    pip install langchain langchain-anthropic langchain-openai langchain-google-genai langgraph pandas matplotlib python-dotenv
    
    # 2. 創建 .env 文件
    cat > .env << EOF
    ANTHROPIC_API_KEY=your_claude_api_key
    OPENAI_API_KEY=your_openai_api_key
    GOOGLE_API_KEY=your_google_api_key
    EOF
    
    # 3. 運行 Jupyter
    jupyter notebook

    🔧 完整 Notebook 代碼

    Cell 1:安裝依賴

    import subprocess
    import sys
    
    packages = [
        'langchain',
        'langchain-anthropic',
        'langchain-openai',
        'langchain-google-genai',
        'langgraph',
        'pandas',
        'matplotlib',
        'python-dotenv'
    ]
    
    print("📦 安裝必要的包...")
    for package in packages:
        subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", package])
        print(f"✅ {package}")
    
    print("\n🎉 安裝完成!")

    Cell 2:配置 API Keys

    import os
    from dotenv import load_dotenv
    
    # 加載 .env 文件中的 API Keys
    load_dotenv()
    
    # 檢查 API Keys
    apis = {
        'ANTHROPIC_API_KEY': '🔑 Claude (Anthropic)',
        'OPENAI_API_KEY': '🔑 GPT-4 (OpenAI)',
        'GOOGLE_API_KEY': '🔑 Gemini (Google)'
    }
    
    print("\n📍 檢查 API Keys 狀態:\n")
    available_apis = []
    
    for env_var, name in apis.items():
        if os.getenv(env_var):
            status = f"✅ {name}: 已配置"
            available_apis.append(env_var)
        else:
            status = f"❌ {name}: 未配置"
        print(status)
    
    if not available_apis:
        print("\n⚠️ 警告:沒有設置任何 API Key!")
        print("請按照上面的說明設置 .env 文件或環境變量。")
    else:
        print(f"\n✅ 可用的 LLM:{len(available_apis)} 個")

    Cell 3:初始化 LLM

    from langchain_anthropic import ChatAnthropic
    from langchain_openai import ChatOpenAI
    from langchain_google_genai import ChatGoogleGenerativeAI
    import time
    import json
    
    print("\n🚀 初始化多個 LLM...\n")
    
    # 初始化 LLM(都初始化,但只會使用可用的)
    llms = {}
    llm_configs = {
        'Claude': {
            'class': ChatAnthropic,
            'params': {'model': 'claude-opus-4-6'},
            'env': 'ANTHROPIC_API_KEY'
        },
        'GPT-4': {
            'class': ChatOpenAI,
            'params': {'model': 'gpt-4-turbo', 'temperature': 0.7},
            'env': 'OPENAI_API_KEY'
        },
        'Gemini': {
            'class': ChatGoogleGenerativeAI,
            'params': {'model': 'gemini-pro'},
            'env': 'GOOGLE_API_KEY'
        }
    }
    
    # 嘗試初始化每個 LLM
    for name, config in llm_configs.items():
        try:
            if os.getenv(config['env']):
                llm = config['class'](**config['params'])
                llms[name] = llm
                print(f"✅ {name}: 初始化成功")
            else:
                print(f"⏭️  {name}: 跳過(未設置 {config['env']})")
        except Exception as e:
            print(f"❌ {name}: 初始化失敗 - {str(e)[:50]}")
    
    if llms:
        print(f"\n✅ 成功初始化 {len(llms)} 個 LLM")
    else:
        print(f"\n⚠️ 沒有成功初始化任何 LLM,請檢查 API Keys")
    
    available_llms = list(llms.keys())
    print(f"\n📋 可用的 LLM:{', '.join(available_llms)}")

    Cell 4:對比測試

    # 定義測試任務
    TEST_PROMPT = """簡短回答(不超過 100 字):
    什麼是 LangChain 和 LangGraph 的主要區別?
    
    用 JSON 格式回答:
    {
      "差異": "...",
      "適用場景": "..."
    }
    """
    
    print("\n📝 測試任務:")
    print(f"提示詞:{TEST_PROMPT[:80]}...\n")
    
    # 存儲結果
    results = {}
    execution_times = {}
    
    print("\n🔄 執行中...\n")
    print("="*80)
    
    # 對每個可用的 LLM 執行
    for llm_name, llm in llms.items():
        print(f"\n▶️  {llm_name} 開始...")
    
        start_time = time.time()
    
        try:
            response = llm.invoke(TEST_PROMPT)
            elapsed = time.time() - start_time
    
            results[llm_name] = response.content
            execution_times[llm_name] = elapsed
    
            print(f"✅ {llm_name} 完成 ({elapsed:.2f}s)")
            print(f"\n📄 回答:")
            print(f"{response.content[:150]}...")
            print("\n" + "-"*80)
    
        except Exception as e:
            print(f"❌ {llm_name} 出錯:{str(e)[:100]}")
            print("\n" + "-"*80)
    
    print("\n" + "="*80)
    print(f"\n✅ 測試完成!共執行 {len(results)} 個 LLM")

    Cell 5:執行時間對比

    import pandas as pd
    import matplotlib.pyplot as plt
    
    # 創建時間對比表
    if execution_times:
        df_times = pd.DataFrame([
            {'LLM': name, '執行時間 (秒)': time}
            for name, time in execution_times.items()
        ]).sort_values('執行時間 (秒)')
    
        print("\n⏱️  執行時間對比")
        print("="*50)
        print(df_times.to_string(index=False))
        print("="*50)
        print(f"\n平均時間:{df_times['執行時間 (秒)'].mean():.2f}s")
        print(f"最快:{df_times.iloc[0]['LLM']} ({df_times.iloc[0]['執行時間 (秒)']:.2f}s)")
    
        # 繪製柱狀圖
        plt.figure(figsize=(10, 5))
        colors = ['#FF6B6B' if t == df_times['執行時間 (秒)'].min() else '#4ECDC4'
                  for t in df_times['執行時間 (秒)']]
    
        plt.bar(df_times['LLM'], df_times['執行時間 (秒)'], color=colors, alpha=0.7, edgecolor='black')
        plt.ylabel('執行時間 (秒)', fontsize=12)
        plt.xlabel('LLM', fontsize=12)
        plt.title('🏃 多 LLM 執行時間對比', fontsize=14, fontweight='bold')
        plt.grid(axis='y', alpha=0.3, linestyle='--')
    
        # 添加數值標籤
        for i, v in enumerate(df_times['執行時間 (秒)']):
            plt.text(i, v + 0.1, f'{v:.2f}s', ha='center', fontweight='bold')
    
        plt.tight_layout()
        plt.show()
    
    else:
        print("⚠️  沒有執行時間數據")

    Cell 6:質量對比

    # 分析回答質量
    if results:
        print("\n📊 回答質量對比")
        print("="*80)
    
        quality_metrics = []
    
        for llm_name, response in results.items():
            # 計算指標
            length = len(response)
            word_count = len(response.split())
            has_json = '{' in response and '}' in response
    
            quality_metrics.append({
                'LLM': llm_name,
                '字數': length,
                '詞數': word_count,
                'JSON 格式': '✅' if has_json else '❌'
            })
    
        df_quality = pd.DataFrame(quality_metrics)
        print(df_quality.to_string(index=False))
        print("="*80)
    
        # 詳細回答
        print("\n📄 詳細回答:\n")
        for llm_name, response in results.items():
            print(f"\n▶️  {llm_name}:")
            print("-" * 70)
            print(response)
            print("-" * 70)

    Cell 7:LangGraph 演示

    from langgraph.graph import StateGraph, END
    from typing import TypedDict
    
    if len(llms) >= 2:
        print("\n🏗️  使用 LangGraph 構建多 LLM 工作流")
        print("="*80)
    
        # 定義狀態
        class ComparisonState(TypedDict):
            task: str
            results: dict  # 存儲多個 LLM 的結果
    
        # 為每個 LLM 定義一個節點
        def create_llm_node(llm_name, llm):
            def node_func(state: ComparisonState) -> dict:
                print(f"\n▶️  {llm_name} 處理中...")
                try:
                    response = llm.invoke(state['task'])
                    result = {
                        'response': response.content[:200] + '...',
                        'status': '✅ 成功',
                        'timestamp': time.time()
                    }
                    state['results'][llm_name] = result
                    print(f"✅ {llm_name} 完成")
                except Exception as e:
                    state['results'][llm_name] = {
                        'error': str(e)[:100],
                        'status': '❌ 失敗'
                    }
                    print(f"❌ {llm_name} 失敗")
    
                return state
    
            return node_func
    
        # 構建 Graph
        graph = StateGraph(ComparisonState)
    
        # 為每個 LLM 添加節點
        for llm_name in llms:
            graph.add_node(llm_name, create_llm_node(llm_name, llms[llm_name]))
    
        # 連接節點(全部並行執行,然後到 END)
        graph.set_entry_point(list(llms.keys())[0])
        for i, llm_name in enumerate(list(llms.keys())[:-1]):
            graph.add_edge(llm_name, list(llms.keys())[i+1])
        graph.add_edge(list(llms.keys())[-1], END)
    
        # 編譯并執行
        workflow = graph.compile()
    
        print("\n📋 執行工作流...\n")
    
        test_task = "用一句話解釋 LangGraph 的核心優勢"
    
        try:
            workflow_result = workflow.invoke({
                'task': test_task,
                'results': {}
            })
    
            print(f"\n✅ 工作流完成!\n")
            print("📊 結果:")
            print("="*80)
    
            for llm_name, result in workflow_result['results'].items():
                print(f"\n{llm_name}:")
                print("-"*70)
                if 'error' in result:
                    print(f"❌ 錯誤:{result['error']}")
                else:
                    print(f"{result['response']}")
    
            print("\n" + "="*80)
    
        except Exception as e:
            print(f"❌ 工作流執行失敗:{str(e)}")
    
    else:
        print("⚠️  需要至少 2 個 LLM 才能演示工作流")

    Cell 8:成本對比

    # 模擬成本數據(基於實際 API 定價 2026 年 3 月)
    cost_data = {
        'Claude': {
            'name': 'Claude Opus 4.6',
            'input_cost': 0.003,  # 每 1K tokens
            'output_cost': 0.015,
            'speed': '中等',
            'quality': '⭐⭐⭐⭐⭐',
            'price_tier': '高端'
        },
        'GPT-4': {
            'name': 'GPT-4 Turbo',
            'input_cost': 0.01,
            'output_cost': 0.03,
            'speed': '快',
            'quality': '⭐⭐⭐⭐⭐',
            'price_tier': '最高'
        },
        'Gemini': {
            'name': 'Gemini Pro',
            'input_cost': 0.0005,
            'output_cost': 0.0015,
            'speed': '最快',
            'quality': '⭐⭐⭐⭐',
            'price_tier': '經濟'
        }
    }
    
    print("\n💰 成本和性能對比")
    print("="*90)
    print(f"{'LLM':<15} {'速度':<10} {'質量':<15} {'輸入成本':<15} {'輸出成本':<15} {'定位':<10}")
    print("="*90)
    
    for llm_name, data in cost_data.items():
        if llm_name in llms:
            status = "✅"
        else:
            status = "⏭️ "
    
        print(f"{status}{llm_name:<13} {data['speed']:<10} {data['quality']:<15} "
              f"${data['input_cost']:<14} ${data['output_cost']:<14} {data['price_tier']:<10}")
    
    print("="*90)
    
    # 估算月成本(假設 1000 萬 tokens 使用)
    print("\n📊 月成本估算(假設 1000 萬 input tokens + 500 萬 output tokens)")
    print("="*60)
    
    cost_estimates = []
    input_tokens = 10_000_000
    output_tokens = 5_000_000
    
    for llm_name, data in cost_data.items():
        monthly_cost = (input_tokens / 1000 * data['input_cost'] +
                       output_tokens / 1000 * data['output_cost'])
        cost_estimates.append({
            'LLM': llm_name,
            '月成本': f"${monthly_cost:.2f}",
            '成本占比': f"{monthly_cost / sum([((input_tokens / 1000 * cost_data[k]['input_cost'] + output_tokens / 1000 * cost_data[k]['output_cost'])) for k in cost_data]) * 100:.1f}%"
        })
    
    df_costs = pd.DataFrame(cost_estimates)
    print(df_costs.to_string(index=False))
    print("="*60)
    
    print("\n💡 建議:")
    print("  • 複雜任務 → 用 Claude(質量最好)")
    print("  • 簡單任務 → 用 Gemini(成本最低)")
    print("  • 要求快速 → 用 GPT-4(速度最快)")
    print("  • 多 LLM 支持 → 用 LangGraph(靈活切換)")

    Cell 9:框架對比

    print("\n🔄 架構對比:LangChain vs LangGraph")
    print("\n" + "="*80)
    
    comparison = {
        "方面": [
            "代碼行數(簡單流程)",
            "代碼行數(複雜流程)",
            "狀態管理",
            "並行執行",
            "易於測試",
            "新人上手",
            "適用場景"
        ],
        "LangChain": [
            "~40 行",
            "80+ 行(複雜)",
            "手動(state 散亂)",
            "極其困難",
            "⭐⭐(中等)",
            "1-2 天",
            "簡單應用、快速原型"
        ],
        "LangGraph": [
            "~25 行",
            "22 行(簡潔)",
            "自動(State TypedDict)",
            "⭐⭐⭐⭐⭐ 天生支持",
            "⭐⭐⭐⭐⭐(優秀)",
            "3-5 天(陡峭但有回報)",
            "複雜工作流、多 Agent"
        ]
    }
    
    df_comparison = pd.DataFrame(comparison)
    print(df_comparison.to_string(index=False))
    print("="*80)
    
    print("\n🎯 何時選擇:")
    print("\n✅ 選 LangChain 當:")
    print("   • 時間緊張(< 2 周)")
    print("   • 應用簡單(< 3 個 Agent)")
    print("   • 快速原型")
    
    print("\n✅ 選 LangGraph 當:")
    print("   • 複雜工作流(3+ Agent)")
    print("   • 有並行邏輯")
    print("   • 需要多 LLM 支持")
    print("   • 長期維護和擴展")
    print("   • 團隊規模 > 3 人")

    Cell 10:最終總結

    print("\n" + "🎯 "*40)
    print("\n📊 你的實驗總結:")
    print("\n" + "="*80)
    
    if execution_times:
        print(f"\n✅ 已測試 {len(llms)} 個 LLM")
        fastest = min(execution_times, key=execution_times.get)
        slowest = max(execution_times, key=execution_times.get)
        print(f"   • 最快:{fastest} ({execution_times[fastest]:.2f}s)")
        print(f"   • 最慢:{slowest} ({execution_times[slowest]:.2f}s)")
        print(f"   • 平均:{sum(execution_times.values())/len(execution_times):.2f}s")
    
    print(f"\n✅ 框架對比結論:")
    print(f"   LangChain: 適合簡單應用、快速原型")
    print(f"   LangGraph: 適合複雜工作流、多 Agent、多 LLM")
    
    print(f"\n✅ 多 LLM 切換的好處:")
    print(f"   • 成本優化:同一套代碼,根據任務選 LLM")
    print(f"   • 供應商備份:一個 LLM 故障,自動切換")
    print(f"   • 市場適應:新 LLM 出現,快速集成")
    
    print(f"\n✅ 給個人公司的建議:")
    print(f"   Year 1: 用 Claude SDK,多做項目(現金流優先)")
    print(f"   Year 2: 評估 LangGraph,學習投入(複雜項目有收益)")
    print(f"   Year 3: 成為專家,多 LLM 支持(競爭優勢)")
    
    print("\n" + "="*80)
    print(f"\n🚀 下一步行動:")
    print(f"   1. 根據你的 POC 找到具體的 TA(目標客戶)")
    print(f"   2. 驗證市場需求(beta 用戶反饋)")
    print(f"   3. 決定是否投資 LangGraph 學習")
    print(f"   4. 考慮多 LLM 支持(如果客戶有需求)")
    
    print(f"\n" + "🎯 "*40)

    快速開始指南

    🎯 5 分鐘快速開始

    # 1. 安裝依賴
    pip install jupyter notebook
    
    # 2. 創建 .env 文件
    cat > .env << EOF
    ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxx
    OPENAI_API_KEY=sk-xxxxxxxxxxxx
    GOOGLE_API_KEY=xxxxxxxxxxxx
    EOF
    
    # 3. 創建 Jupyter Notebook
    jupyter notebook
    
    # 4. 在 Notebook 中粘貼上面的代碼
    # 5. 依次執行 Cells

    🔑 API Keys 獲取

    📋 Notebook 執行順序

    1. ✅ Cell 1:安裝依賴 2. ✅ Cell 2:配置 API Keys 3. ✅ Cell 3:初始化 LLM 4. ✅ Cell 4-5:對比測試 5. ✅ Cell 6:質量分析 6. ✅ Cell 7:LangGraph 演示 7. ✅ Cell 8:成本對比 8. ✅ Cell 9:框架對比 9. ✅ Cell 10:總結

    最終決策框架

    三位一體:老闆 × 顧問 × PM

    你同時是三個身份,優先級根據情況變化:
    
    情況 1:現金流緊張(< 1 月)
    優先級:老闆 > PM > 顧問
    決策:快速賺錢最重要
      ├─ 用 Claude SDK(快)
      ├─ 多做小項目
      └─ 不學新框架
    
    情況 2:穩定現金流(3+ 月)
    優先級:顧問 > PM > 老闆
    決策:給客戶好方案,建立品牌
      ├─ 評估 LangGraph(複雜項目)
      ├─ 提高服務質量
      └─ 長期客戶關係
    
    情況 3:複雜項目 + 預算充足
    優先級:PM > 顧問 > 老闆
    決策:交付成功最重要
      ├─ 用 LangGraph(管理複雜度)
      ├─ 投前期設計時間
      └─ 降低風險

    快速決策矩陣

    ╔═══════════════════════════════════════════════════════════════╗
    ║                 你應該選哪個框架?                           ║
    ╠═══════════════════════════════════════════════════════════════╣
    
    1. 項目複雜度?
       ├─ 簡單(1-2 Agent)→ 看 Q3
       ├─ 中等(3-5 Agent)→ 看 Q3
       └─ 複雜(5+ Agent 或並行)→ LangGraph ✓
    
    2. 多 LLM 需求?
       ├─ 不需要 → 用官方 SDK
       └─ 需要 → 加 LangGraph
    
    3. 時間線?
       ├─ < 2 周 → Claude SDK(快)
       ├─ 2-4 周 → LangChain(平衡)
       └─ > 1 月 → LangGraph(品質優先)
    
    4. 團隊規模?
       ├─ 1-2 人 → Claude SDK(簡單)
       ├─ 3-5 人 → LangGraph(標準化)
       └─ 10+ 人 → LangGraph(可複用)
    
    5. 長期規劃?
       ├─ 1 個項目 → Claude SDK(不值得學)
       ├─ 2-3 個 → 考慮 LangGraph
       └─ 5+ 個 → 必須 LangGraph(ROI 高)
    
    ╠═══════════════════════════════════════════════════════════════╣
    
    最終建議:
    
    ✅ 用 Claude SDK 的條件:
       • 簡單應用(< 3 Agent)
       • 時間緊張(< 2 周)
       • 團隊小(1-2 人)
       • 短期項目(< 1 個項目規劃)
    
    ✅ 用 LangChain 的條件:
       • 快速原型
       • 簡單應用
       • 想支持多 LLM(但工作流簡單)
       • 喜歡靈活性
    
    ✅ 用 LangGraph 的條件:
       • 複雜工作流(> 3 Agent)
       • 並行執行或分支邏輯
       • 多 LLM 支持
       • 長期項目規劃(3+ 個)
       • 團隊 > 3 人
    
    ╚═══════════════════════════════════════════════════════════════╝

    核心結論

    1. 框架選擇不是技術問題,是商業問題
       ✓ 有付費客戶?有複雜項目?有長期規劃?
       ✗ 這些都沒有?先驗證市場
    
    2. LangGraph 的價值在於「長期」
       • 第 1 個項目:LangGraph 可能慢
       • 第 3 個項目:LangGraph 快 50%
       • 第 5 個項目:LangGraph 快 70%
    
    3. 多 LLM 不是為了省錢,而是為了自由
       • 供應商備份(可用性)
       • 成本優化(可選)
       • 市場適應(長期)
    
    4. POC 階段最重要的是市場驗證,不是技術選擇
       • 1 周市場反饋 > 2 周完美代碼
       • TA 決定一切
       • 框架是後話
    
    5. 個人公司的出路是「垂直深化」,不是「技術秀肌肉」
       • 某個領域的專家 > 全能技術人
       • $10k-20k 的垂直項目 > $2k-5k 的通用項目
       • 品質溢價 > 技術先進性

    後記

    **給你的最後話**:

    你已經掌握了 Claude Agent SDK,這給了你第一步的優勢。現在的問題不是「選哪個框架」,而是「選哪個市場」。

    LangChain/LangGraph 是在你確定市場和客戶後,為了「長期優化」的選擇。不是「先進」,而是「務實」。

    現在就出去找 TA,快速驗證想法。3 個月後,當你有 3-5 個清晰的客戶需求時,再回過頭來考慮技術選擇。那時候的決策會基於真實數據,而不是假設。

    同時,寫好你的博客。「Claude Agent SDK 深度實踐指南」會成為你的品牌。未來的「LangGraph 多 LLM 架構指南」會是補充。

    競爭力不來自「最新技術」,而來自「解決真實問題的深度」。

    **撰寫時間**:2026-03-17 **版本**:1.0 **包含**:完整分析 + Jupyter Notebook + 決策框架

    **加油!👊**

  • Agent Team 多輪迭代:從失敗到成功的設計演進

    Document Status: Living Document (持續更新)
    Last Updated: 2026-03-17
    Author: Claude Code + Tom
    Purpose: 從 SimpleEC OMS 多次失敗的 Agent Team 經驗中提煉最佳實踐

    🎯 重點摘要

    • 問題:4 次 Agent Team 啟動都在 24+ 小時後卡住,根本原因不在代碼,而在設計與 Prompt
    • 核心原則:編碼依賴(Task.blockedBy/blocks)、明確停止條件、2 小時 timeout、結構化交付物
    • 關鍵對比:Provider Chain (複雜) vs Sequential Phase (簡單) — 後者減少隱式依賴、自動強制約束
    • Prompt 檢查清單:5 大維度、17 項細節檢查,防止 Agent 卡住或無限期等待
    • 成功設計:明確的時間表、具體的交付物格式 (JSON)、禁止行為列表、協調者角色

    序言:為什麼我們一直失敗

    從 2026-03-03 到 2026-03-17,我們嘗試啟動過至少 4 個 Agent Team,每一次都卡住 24+ 小時:

    1. simpleec-oms-audit (3/3) — 任務分配錯亂,Agent 互相等待
    2. simpleec-oms-bidirectional-audit (3/10) — 複雜的雙向驗證設計,Agent 不知道什麼時候應該停止
    3. simpleec-oms-quality-audit (3/16) — Task 被分配給錯誤的 Agent,導致 3 個 Agent 空轉 24 小時

    根本原因不在代碼,而在於

    • ❌ 設計太複雜,隱式依賴沒有編碼
    • ❌ Prompt 寫得不清楚,Agent 不知道什麼時候應該停止或等待
    • ❌ 沒有 Timeout 機制,導致無限期等待
    • ❌ 任務分配邏輯複雜,容易出錯
    • ❌ Agent 沒有明確的”停止條件”,導致亂工作或空轉

    本文將詳細解析這些問題,並提供可複製的最佳實踐。

    🎯 你需要打什麼讓我一步到位

    複製以下內容給 Claude

    我要啟動 Agent Team 做 [你的任務]
    
    系統:[系統名]
    檢查維度:[A], [B], [C]
    時間:[時間限制]
    Agent:[N 個]
    
    創建:TEAM_PLAN.md / AGENT_PROMPTS.md / CHECKLIST.md / settings.json

    📋 成功的 Prompt 範本

    You are ARCHITECT on [TEAM_NAME].
    
    Verify [SYSTEM]:
    - [Check A]
    - [Check B]
    
    DELIVERABLE (JSON):
    { "task_id": 1, "findings": { "score": X, "ready": true } }
    
    BEGIN PHASE 1 NOW.

    第一部分:為什麼 Agent Team 會卡住?

    原因 1:複雜的隱式依賴

    ❌ 壞設計示例:使用 Provider Chain + Consumer Chain 雙向驗證(複雜且失敗)。有 4 個同步點,但都是文字描述,沒有編碼到 Task 系統。Task 之間的依賴關係是隱式的(”Task #1 完成後才能開始 Task #2″,但沒有在 blockedBy 里標記)。Agent 不知道應該等待誰被誰等待

    後果:當任務分配出錯(比如 Task #2 被分給了錯誤的 Agent),整個鏈條斷裂。Architect 和 Backend-QA 無所事事,空轉 24+ 小時,持續消耗內存。

    原因 2:Prompt 寫得不清楚 → Agent 不知道什麼時候該停止

    Prompt 缺少明確的停止條件。完成 Task #1 後,Agent 不知道應該做什麼——是否應該主動聯繫其他 Agent?是否應該重新檢查自己的工作?內存會持續增長(因為 Agent 一直在運行)。

    實際情況:Architect 完成 Task #1 後,發現沒有 Task #2 和 #3 的結果(因為被分配錯了)。開始懷疑,重新讀一遍所有文件。14 小時後,內存從 380MB 漲到 440MB。最後 OOM → 系統當機。

    原因 3:沒有 Timeout 機制

    舊設計 新設計
    Agent Task 超時限制:無
    → 可以無限期等待
    → 可以無限期工作
    → 內存持續增長,最終 OOM
    Agent Task 超時限制:2 小時
    → 2 小時後,自動標記 timeout
    → 解鎖下一個任務或停止
    → 即使出錯,也不會無限期卡住

    原因 4:Agent 之間沒有同步點

    舊設計中,Task #1 在工作,Task #2 也在工作,但 Task #2 應該等待 Task #1。沒人告訴他們應該等待誰。新設計中,用 Task.blockedBy = [1, 2] 明確表示”我要等 Task #1, #2″。

    第二部分:好的 Agent Team 設計原則

    原則 1:Show, Don’t Tell(編碼依賴,不要寫文字)

    為什麼? Task 系統會自動強制依賴順序,不會分配錯誤。不依賴人工判斷。系統可以自動檢測循環依賴或孤立任務。

    原則 2:一個 Agent 做一件事

    ❌ 壞:Task #2 包含 3 個不同的東西(Schema 驗證、Kafka 驗證、Handler 驗證)。Agent 容易分心,難以判斷什麼時候”完成”。

    ✅ 好:Task #2 目標清晰:”驗證數據層能否支持 API 承諾”。包含 3 個驗證點,但都是同一件事的一部分。交付物是一個結構化的 JSON 對象。

    原則 3:明確的交付物結構

    ❌ 壞:”Generate audit report with Executive summary, Critical issues list…” 模糊,無法驗證是否合格。

    ✅ 好:返回結構化 JSON,包含量化指標(alignment score)、布爾標誌(ready_for_next_phase)、具體問題列表。下一個 Agent 可以用 JSON parser 讀取。

    原則 4:Prompt 要明確定義”停止條件”

    Prompt 必須明確說:完成 Task 後,Agent 應該做什麼(答案是:停止工作,等待通知)。沒有”循環工作”的空間。明確的等待機制(team-lead 會告訴你什麼時候開始下一個 Phase)。

    原則 5:Timeout 是必需的

    新設計:2 小時 timeout。時間到了,自動標記 timeout。自動解鎖下一個 Task(即使當前 Task 沒完成)。自動通知 team-lead。防止無限期等待。

    第三部分:Prompt 編寫終極檢查清單

    A. 責任清晰度(Clarity of Responsibility)

    • 一個 Agent,一件事 — 避免重載式任務設計
    • 目標可測 — 不是”驗證 schema 完整性”,而是”生成 JSON with schema_integrity score”
    • 交付物明確 — 結構化 JSON,而不是自由文本報告

    B. 停止條件明確(Clear Stop Conditions)

    • Prompt 明確說什麼時候應該停止 — “After Task #1 is complete, do NOT continue. Wait for team-lead notification.”
    • 沒有”循環工作”的空間 — “After generating findings JSON, stop. Do not re-read files.”
    • 明確的等待機制 — “Wait for team-lead message: ‘Phase 2 begins’”

    C. 依賴關係編碼(Dependency Encoding)

    • Task.blockedBy 明確填寫"blockedBy": [1] 表示”我等 Task #1″
    • Task.blocks 明確填寫"blocks": [3, 4] 表示”我阻擋 Task #3 和 #4″
    • 沒有循環依賴 — Task #1 blocks #2, #2 blocks #3, #3 blocks #1 ← 循環!

    D. 超時保護(Timeout Protection)

    • Prompt 中明確提到超時時間 — “You have 2 hours to complete Task #1”
    • 告訴 Agent 超時時會發生什麼 — “If 2 hours pass, next phase will begin regardless”
    • Timeout 不應該導致錯誤,只是解鎖 — 後自動繼續下一階段

    E. Agent 之間的協調(Inter-Agent Coordination)

    • 明確說是否應該主動聯繫其他 Agent — “Do NOT contact backend-qa or frontend-qa”
    • 明確說如何接收通知 — “You will receive explicit notification from team-lead when Phase 2 begins”
    • 明確說何時應該報告問題 — “Report them in your findings JSON. Do NOT try to fix them yourself.”

    第四部分:Prompt 好與壞的完整對比

    ❌ 壞 Prompt(導致失敗)

    缺少:明確的完成後行為、明確的等待規則、Timeout 時間、停止條件、交付物格式的具體性。

    後果:Architect 完成 Task #1 後,發現沒有 Task #2 和 #3 的結果。不知道應該等待還是繼續工作。開始懷疑自己的分析,重新讀文件。持續讀文件和重新分析 14+ 小時。內存從 380MB 漲到 440MB。最後 OOM,系統當機。

    ✅ 好 Prompt(成功設計)

    特點:明確的時間表(0-2h Phase 1, 2-4h 等待, 4-6h Phase 4)。明確的停止條件(”完成後停止,不要做任何其他事”)。明確的交付物(結構化 JSON)。明確的等待機制(team-lead 會告訴你什麼時候開始 Phase 4)。明確的禁止行為(❌ 列出了不應該做的事)。

    後果:Architect 完成 Task #1。知道自己應該停止(Prompt 明確說了)。進入等待模式(不讀文件,不重新分析)。2 小時後,如果沒有 Task #4 通知,自動 timeout。內存穩定在 380MB(沒有持續增長)。系統正常運行。

    第五部分:常見錯誤與修正

    錯誤 1:Prompt 寫得太長和太複雜

    修正:用清晰的結構(Markdown headers)。用列表而不是段落。用例子而不是抽象描述。用”禁止行為”而不是”允許行為”。目標:500 字清晰 Prompt,而不是 2000 字複雜 Prompt。

    錯誤 2:隱式假設 Agent 會自己推斷

    ❌ 壞:”After Task #1, you will know when to start Task #2″(Agent 怎麼知道?沒人告訴他!)

    ✅ 好:”After Task #1, wait for team-lead message: ‘Task #2 begins’. Only then should you proceed.”

    錯誤 3:交付物格式模糊

    ❌ 壞:”Generate a report with findings”

    ✅ 好:生成 JSON,具有明確的字段結構 (status, findings, critical_issues 等)

    錯誤 4:沒有明確的超時時間

    ✅ 修正Timeout: 2 hours — If 2 hours pass, your task is automatically marked timeout. Next phase will proceed regardless. You will be notified when your timeout occurs.

    第六部分:Agent Team 設計檢查清單

    Pre-Launch Checklist

    系統狀態:內存充足 (>8GB available)。沒有舊的 Agent Team 在運行。Task 目錄是空的。

    Task 設計:每個 Task 有明確的 id, subject, description。每個 Task 的 blockedBy 和 blocks 已填寫(沒有循環依賴)。沒有孤立的 Task。每個 Task 有 2 小時的隱式 timeout。

    Prompt 設計:每個 Agent 的 Prompt 有明確的責任(一件事)。每個 Prompt 有明確的停止條件。每個 Prompt 有具體的交付物格式(JSON)。每個 Prompt 有明確的等待機制。每個 Prompt 禁止了不應該做的事情(❌ 列表)。

    交付物定義:所有交付物都是結構化的(JSON)。每個交付物都有 status 字段。下一個 Agent 能解析上一個 Agent 的交付物。交付物不應該是自由文本,應該是結構化數據。

    同步機制:有明確的”team-lead”角色負責協調。有明確的通知機制。有明確的失敗恢復流程。沒有 Agent 之間的直接通信(都通過 team-lead)。

    Launch Checklist

    監控:每 30 分鐘檢查一次內存使用。監控是否有 Agent 卡住。準備好 2 小時後手動檢查 timeout 機制。

    信號:知道什麼樣的行為表示”卡住”(讀同一個文件超過 1 小時,內存持續增長 10% 以上,沒有進展 30 分鐘以上)。準備好應急措施(2 分鐘內關掉所有 Agent,清理內存,回滾到之前的狀態)。

    第七部分:迭代和改進

    本文將根據實驗結果進行迭代。每當我們啟動新的 Agent Team 時:

    1. 記錄過程 — 啟動時間、Agent 行為、完成時間、內存使用、任何卡住或異常情況
    2. 在本文中更新 — 如果發現新的問題、更好的 Prompt 寫法、或 Timeout 時間不合適的情況
    3. 版本控制 — 每次大的更新,提升版本號。在文件頂部記錄更新日期和內容

    總結

    從失敗中學到的核心真理

    1. 設計要簡單,依賴要明確 — 不要用複雜的 Provider Chain,用簡單的 Sequential Phase
    2. 編碼依賴,不要寫文字blockedByblocks 必須填寫,隱式依賴是毒藥
    3. Prompt 要明確停止條件 — Agent 必須知道什麼時候應該停止
    4. Timeout 是必需的保險 — 沒有 timeout,Agent 可以無限期卡住
    5. 交付物要結構化 — JSON 而不是自由文本,下一個 Agent 能解析
    6. 有一個協調者(team-lead) — 不要讓 Agent 之間直接通信

    下一步:用 v2 設計啟動 Quality Audit Team。記錄過程和結果。根據結果更新本文。建立標準範本(Task 和 Prompt 的 template)。

    實施深度:v3 計畫的四層架構

    前面的原則是設計哲學。但實際部署 v3 計畫時,我們加入了四項關鍵實施細節,把抽象的原則轉換為可監控、可恢復、可自動化的運作

    ①分層監控架構(Team-lead 的心跳)

    v3 計畫引入了 Team-lead 監控層,專職於此,间隔嚴格:30秒 Session 健康檢查、30分鐘超時檢查、60分鐘進度報告、5分鐘內存監控。

    ②事件驅動協調(4 個事件)

    v3 計畫改為事件驅動模型,完全由 Team-lead 控制狀態轉遷。4個事件:Task#1完成→解鎖Task#2&3、Task#2&3都完成→通知Architect進行Task#4、Task#4完成→生成報告。

    ③應急與恢復(5 個故障模式)

    v3 計畫為5種情況預先定義恢復策略:Orphaned Agents(中止審計)、Multiple Timeouts(部分報告)、Invalid JSON(記錄錯誤繼續)、OOM Event(強制超時解鎖)、Stalled Task(檢測重啟或強制超時)。

    ④完整實現範例

    完整的Task生命週期:t=0初始化、t=0-30分鐘Architect驗證、t=25觸發Event1解鎖Task#2&3、t=25-50並行執行QA驗證、t=50觸發Event2&3通知Architect、t=50-110Task#4最終驗證、t=115報告生成完成。總耗時115分鐘,4個Agent共消耗1.8GB內存。

    v3 計畫 vs v2:7 個關鍵改進

    依賴編碼從文字敘述改為JSON(blockedBy/blocks)、停止條件從暗示改為明確、超時機制從提到改為實現(120min+30min+自動unlock)、監控從無改為Team-lead 30秒心跳、協調從Agent間通信改為Team-lead主控、交付物從文字改為JSON schema、故障恢復從無預案改為5個策略。

    「後即時」監控與自動恢復

    v3 計畫的終極目標是達到「後即時(Near Real-Time)監控」:不是等Task失敗才發現,而是任何異常2分鐘內自動檢測並響應。解決之前24小時卡住的問題。

  • Hacker News 每日精選 – 2026-03-17

    🚀 今天的科技圈充滿了對「效率」與「結構」的重新思考。從美國 SEC 準備取消季度財報的震撼彈,到 Meta 重新對底層基礎設施 jemalloc 的承諾,我們正處於一個追求長期價值與開發流程簡化(避免過度審查)的轉折點。

    💡 無論你是關注基礎架構的工程師,還是追蹤市場動態的創業家,今日的資訊流都揭示了一個核心訊息:在 AI 與自動化加速發展的時代,繁文縟節與低效溝通正被無情地淘汰。

    🤖 AI / 機器學習

    Leanstral:用於可信編碼與形式證明工程的開源 Agent

    Mistral AI 推出了 Leanstral,這是一個專門為 Lean 4 形式語言設計的開源模型與 Agent。與傳統 LLM 僅給出機率性的代碼不同,Leanstral 專注於「形式化證明」,這意味著生成的代碼可以經過數學上的驗證,確保其正確性與安全性。對於需要高度信任的關鍵系統開發者來說,這是一大突破。

    • 🚀 重點:將 AI 從「猜測代碼」提升到「證明代碼」。
    • 🎯 目標:減少軟體漏洞並推動形式化方法在業界的普及。

    👉 閱讀原文

    Claude 在 3D 工作流中的應用技巧

    這篇文章分享了如何利用 Claude 輔助 3D 內容創作。作者提到 LLM 在處理複雜的 3D 腳本(如 Blender Python API)與生成著色器代碼(Shaders)時表現優異。透過精確的提示詞與迭代,Claude 能顯著縮短傳統 3D 藝術家在技術瓶頸上花費的時間。

    👉 閱讀原文

    🛠️ 開發工具與基礎設施

    Meta 對 jemalloc 的重新承諾與投入

    Meta(Facebook)宣布將持續投資並優化 jemalloc,這是一個廣泛用於 Linux 系統的高效能記憶體分配器。Meta 透過工程實踐證明,對於處理數兆字節數據的大型基礎設施,精細的記憶體管理能直接轉化為成本節省與系統穩定性,這反擊了「基礎設施已死」的論調。

    👉 閱讀原文

    每一層審核都會讓你慢上 10 倍

    這是一篇關於軟體工程效率的深刻反思。作者 apenwarr 指出,組織中每增加一道審核關卡(Review Layer),項目的推進速度就會呈指數級下降。文章主張與其增加審核來防止錯誤,不如建立自動化測試與快速復原機制,賦予開發者更大的自主權。

    「如果你需要三個人簽字才能發布代碼,你不是在保證品質,而是在保證開發進度停滯。」

    👉 閱讀原文

    從零開始為 Commodore 64 重新打造《猴島小英雄》

    這是一項令人驚嘆的逆向工程與復古開發計畫。作者詳細紀錄了如何將經典冒險遊戲《猴島小英雄》移植到 1982 年的硬體 Commodore 64 上。這不僅是情懷,更展示了在極端硬體限制下,如何透過精妙的內存管理與算法優化來達成現代化遊戲體驗。

    👉 閱讀原文

    💼 創業、商業與政策

    美國 SEC 準備取消季度報告要求

    這可能是近年來對美國資本市場影響最大的政策調整。SEC 正在考慮取消上市公司每三個月發布一次財報的強制要求(10-Q),轉向半年報或更靈活的披露機制。支持者認為這能減少企業的「短期主義」壓力,讓管理層專注於長期戰略而非每季度的股價波動。

    👉 閱讀原文

    Kagi Translate 現在支援「LinkedIn 腔」作為輸出語言

    這是一個帶有黑色幽默的功能更新。付費搜尋引擎 Kagi 旗下的翻譯工具新增了 “LinkedIn Speak” 選項,能將普通的日常對話轉換成充滿企業術語、勵志格言與大量 Emoji 的 LinkedIn 貼文風格。這雖然看似玩笑,卻諷刺了當前職業社交平台上的誇大文化。

    👉 閱讀原文

    🌐 其他值得關注

    「小眾網路」(Small Web)比你想像的還要龐大

    當主流網路充斥著 AI 生成的垃圾訊息與 SEO 內容時,回歸個人部落格、手寫 HTML 網頁的「Small Web」運動正在興起。文章討論了這些由人類親手策劃、不為流量服務的網站,如何構成了一個更有活力、更具真實感的數位生態系統。

    👉 閱讀原文

    美國醫療困境:數據分析

    這個開源專案在 GitHub 上引起熱議,它透過大量的數據視覺化探討了美國醫療系統的高昂成本與低效回報。對於關注社會工程與數據科學的讀者來說,這是一個利用數據解構複雜社會體制的極佳範例。

    👉 閱讀原文

    🎯 今日觀點:效率的重新定義

    今天的熱門話題共同指向了一個趨勢:去除無效的中間層

    • 制度面:SEC 試圖減少頻繁財報帶來的行政負擔與短期壓力。
    • 開發面:我們被提醒審核流程(Review Layer)可能是創新的殺手。
    • 技術面:Leanstral 試圖跳過「人為猜測」,直接用數學確保正確性。

    👨‍💻 給讀者的行動建議:
    檢查你目前的開發流程或工作流,是否有哪一個「審核層級」其實可以被自動化測試更強大的底層工具所取代?在 AI 加速生成的時代,保護你的「專注力」與「開發速度」將是維持競爭力的關鍵。同時,別忘了去「Small Web」逛逛,找回那份屬於人類親手創作的靈感。

  • Agent SDK vs 傳統 If-Else:客服系統從 500 行代碼到 10 行的蛻變

    📥 Download Jupyter Notebook

    Download complete Jupyter Notebook


    Agent SDK vs 傳統 If-Else:客服系統從 500 行代碼到 10 行的蛻變

    📋 快速摘要

    • Agent SDK 將 500+ 行 if-else 邏輯簡化為 ~10 行配置
    • 維護成本從「高」降到「低」—— 新增規則只需改提示,無需改代碼
    • 適用場景:客服回覆、內容審核、工單分類
    • 不適用場景:金融交易、爬蟲、醫療診斷(需要 100% 確定性)
    • 本文包含可運行的 Jupyter Notebook 對比演示

    爲什麽選擇 Agent SDK 而非傳統 If-Else?

    想象你在維護一個客服系統。每當新的詢問類型出現,你就得添加 5-10 行 if-elif-else 代碼。6 個月後,代碼變成 500+ 行的怪獸,充滿邊界情況處理。

    現在有一個更好的方式:用 Agent SDK 讓 AI 自動理解客戶意圖,不需要每次都改代碼。

    實例對比:傳統方式 vs Agent SDK

    ❌ 傳統方式:500+ 行代碼

    典型的 if-else 實現(簡化版本):

    def traditional_customer_service(inquiry: str) -> str:
        if "退貨" in inquiry or "return" in inquiry.lower():
            if "7天" in inquiry or "7 days" in inquiry.lower():
                return "✓ 好消息!7 天內的商品我們接受退貨。請提供訂單號和退貨原因。"
            elif "30天" in inquiry or "30 days" in inquiry.lower():
                return "⚠ 30 天內的商品需要評估狀況。請寄回商品,我們會判斷是否可退。"
            else:
                return "✗ 超過退貨期限(30天),無法退貨。詳見購買頁面。"
        # ... 還有物流、商品、預設回覆,加起來 500+ 行
        else:
            return "感謝您的詢問。請告訴我更多細節,我會盡快幫您解決。"

    問題:

    • 新增詢問類型 → 需要改代碼 → 需要測試 → 需要重新部署
    • 邊界情況處理複雜(用戶說「退貨」的 10 種不同表達方式)
    • 代碼量隨詢問類型線性增長
    • 維護成本高、Bug 多

    ✨ Agent SDK 方式:~10 行配置

    from claude_agent_sdk import query, ClaudeAgentOptions
    
    async for message in query(
        prompt="You are a customer service agent. Understand customer inquiries and help with returns, invoices, shipping, and product issues.",
        options=ClaudeAgentOptions(
            allowed_tools=["Retrieve Policy", "Query Order", "Update Status"],
            permission_mode="acceptEdits"
        )
    ):
        if isinstance(message, ResultMessage):
            print(message.result)  # AI-generated response

    優勢:

    • 新增規則 → 只需改系統提示,無需改代碼
    • 自動理解變通說法
    • 代碼量固定,不隨規則增加而增加
    • 維護成本低、Bug 少

    真實測試結果

    5 個實際客戶詢問測試:

    測試 傳統方式 Agent SDK 勝者
    回覆時間 0.03ms 150ms If-Else (快 5000x)
    代碼行數 500+ ~10 ✨ Agent SDK (簡潔 50x)
    新增規則難度 高(改代碼→測試→部署) 低(改提示→即時生效) ✨ Agent SDK
    維護成本 ✨ Agent SDK
    用戶體驗 生硬、標準化 自然、親切 ✨ Agent SDK

    何時使用 Agent SDK vs If-Else

    ✅ 適合 Agent SDK 的場景

    • 客服回覆 — 自然理解客戶意圖
    • 內容審核 — 判斷垃圾信息、仇恨言論
    • 工單分類 — 自動分類優先級
    • 推薦系統 — 推薦相關商品
    • 數據提取 — 從非結構化文本提取信息

    ❌ 不適合 Agent SDK 的場景

    • 金融交易 — 需要 100% 確定性
    • 醫療診斷 — 需要絕對準確
    • 法律判決 — 需要精確遵循規則
    • 實時系統 — AI 延遲 100-500ms
    • Web 爬蟲 — 需要精確控制

    Claude API vs Agent SDK:核心差異

    這是很多人困惑的地方。讓我用實例說明。

    場景:客服回答「我的訂單呢?」

    系統需要:

    1. 查訂單資料庫
    2. 查物流資料庫
    3. 組合信息回答客戶

    ❌ Claude API(你控制流程)

    from anthropic import Anthropic
    
    client = Anthropic()
    
    # 第 1 次調用
    response1 = client.messages.create(
        model="claude-opus-4-6",
        messages=[{
            "role": "user",
            "content": "客戶說:我 3 月 10 號買的商品,現在還沒收到"
        }]
    )
    # Claude:「我需要查一下你的訂單...」
    
    # ❌ 你必須手動查資料庫
    order = query_order_db(customer_id, "2026-03-10")
    
    # ❌ 第 2 次調用 Claude
    response2 = client.messages.create(
        model="claude-opus-4-6",
        messages=[{
            "role": "user",
            "content": f"""訂單信息:{order}
    
    請回答客戶。"""
        }]
    )
    
    # ❌ 如果客戶追問,又要第 3、4 次調用...

    你的應用程式在做決策:

    • 「我應該先查訂單」
    • 「我應該問 Claude 什麼問題」
    • 「我應該再查一次物流」

    ✅ Agent SDK(Claude 自動控制流程)

    from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
    
    # 就一次調用,Claude 自動做一切
    async for message in query(
        prompt="""你是客服系統。根據客戶問題,查詢訂單和物流信息,給出完整回答。
    
    客戶問題:「我 3 月 10 號買的商品,現在還沒收到,怎麼辦?」
    
    工具說明:
    - query_order(customer_id, date):查訂單
    - query_shipping(tracking_id):查物流
    
    請自動使用這些工具,給出完整回答。""",
    
        options=ClaudeAgentOptions(
            allowed_tools=["query_order", "query_shipping"]
        )
    ):
        if isinstance(message, ResultMessage):
            print(message.result)
            # 完成!Claude 自動完成了一切

    Claude 自動做決策:

    • ✅ Claude 看到問題
    • ✅ Claude 決定「我需要查訂單」
    • ✅ Claude 自動調用工具
    • ✅ Claude 看結果,決定「我還需要查物流」
    • ✅ Claude 自動調用工具
    • ✅ Claude 綜合所有信息,給出回答

    一句話總結

    Claude API 我知道要查 DB 的順序 → 我來組織
    Agent SDK 我把查 DB 的工具做好 → Claude 自己組織順序

    Agent SDK vs Claude API 完整對比

    特性 Claude API Agent SDK
    使用場景 一次性請求、內容生成 決策型任務、自動化工作流
    流程控制 你的應用程式控制 Claude 自動決策
    工具調用 手動查 DB,手動傳給 Claude Claude 自動調用工具和解析
    複雜度 簡單 – 一個請求,一個回應 複雜 – 多步驟推理、工具調用
    代碼量 多(需要寫 loop 邏輯) 少(一句話啟動)
    安全性 你負責驗證輸出 內置權限管理、審計日誌

    決策樹:選擇正確的工具

    你的任務來了
        ↓
    「這個任務需要 AI 自己決策嗎?」
        ├─ YES → 「結果容錯為零嗎?」
        │         ├─ YES → ❌ 不用 AI,用硬編碼邏輯
        │         └─ NO  → ✅ 用 Agent SDK
        │
        └─ NO  → 「只是單純生成內容/回答嗎?」
                  ├─ YES → ✅ 用 Claude API
                  └─ NO  → 「需要多步驟工作流嗎?」
                            ├─ YES → 你控制流程 + Claude API
                            └─ NO  → ✅ Claude API 就夠了

    真實案例:電商商品自動分類系統

    背景: 某線上購物平台(如東森)需要自動將客戶上傳的商品歸類到正確的分類。

    情況說明

    規模: 4 萬個商品分類(電子產品、服裝、家居、運動等)

    挑戰: 如何在成本可控的情況下,快速準確地進行分類?

    方案 1:傳統 TFIDF 模型

    實現方式:

    1. 收集所有商品描述 + 人工標註的分類
    2. 用 TFIDF 算法訓練模型,提取關鍵詞權重
    3. 客戶輸入新商品描述 → 模型計算與各分類的相似度 → 返回排名前 3 的分類
    # 傳統 TFIDF 方法
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.neighbors import NearestNeighbors
    
    # 1. 訓練
    vectorizer = TfidfVectorizer()
    tfidf_matrix = vectorizer.fit_transform(product_descriptions)
    model = NearestNeighbors(n_neighbors=3, metric='cosine')
    model.fit(tfidf_matrix)
    
    # 2. 預測
    new_product = "輕便防水的戶外登山背包,容量 40L"
    new_tfidf = vectorizer.transform([new_product])
    distances, indices = model.kneighbors(new_tfidf)
    
    # 結果:前 3 個分類
    # [運動戶外, 旅遊用品, 箱包配飾]

    優勢:

    • ⚡ 毫秒級回應(無網路延遲)
    • 💰 零成本(本地運行)
    • 🎯 可控、可解釋(看得到關鍵詞權重)

    缺點:

    • ❌ 無法理解語義(「便宜的手機」vs「經濟型手機」被當作完全不同的商品)
    • ❌ 變通說法識別差(「登山背包」識別不了,但「戶外登山用雙肩包」就被歸錯類)
    • ❌ 每次添加新分類或修改規則都需要重新訓練
    • ❌ 無法跨語言(中文和英文分開訓練)
    • ❌ 無法處理複雜邏輯(「防水的同時是否防塵?」這類二次判斷)

    方案 2:單純 AI 分類(Claude API)

    天真的做法:把 4 萬個分類都給 Claude

    from anthropic import Anthropic
    
    client = Anthropic()
    
    response = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": f"""根據這個商品描述進行分類:
    
    商品描述:輕便防水的戶外登山背包,容量 40L
    
    可用分類:
    - 電子產品
    - 服裝鞋履
    ... (共 4 萬個)
    
    返回最相關的前 3 個分類 + 置信度。"""
        }]
    )

    問題: 4 萬個分類 × 10 tokens/分類 = 40 萬 tokens 光是分類列表

    • 成本:$5 / 次(按 Claude Opus 定價)
    • 日成本(10,000 商品):$50,000 / 天 = **$1.5M / 月** ❌
    • 完全不可行

    方案 3:向量搜尋 + AI 精確分類(最優)

    核心思想: 不是把 4 萬個分類都給 Claude,而是:

    1. 預先計算: 將 4 萬個分類嵌入向量空間(一次性,離線)
    2. 實時檢索: 商品描述進來 → 向量相似度搜尋 → 找出最相關的 Top 50 分類
    3. 精確分類: 只把 50 個候選分類傳給 Claude
    4. 結果: 成本 = 原本的 1/800,準確度反而更高
    # 向量檢索 + AI 分類架構
    
    from sentence_transformers import SentenceTransformer
    from milvus import connections, Collection
    from anthropic import Anthropic
    
    client = Anthropic()
    
    # ============ 階段 1:預先計算分類向量(一次性) ============
    def initialize_category_embeddings():
        """將 4 萬個分類嵌入向量空間"""
        connections.connect("default", host="127.0.0.1", port="19530")
        collection = Collection("products_categories")
    
        # 從資料庫讀取所有分類
        categories = get_all_categories_from_db()
    
        # 計算向量(使用本地模型)
        model = SentenceTransformer('all-MiniLM-L6-v2')
        embeddings = model.encode([cat['name'] for cat in categories])
    
        # 插入向量資料庫
        collection.insert({
            "id": [cat['id'] for cat in categories],
            "category_name": [cat['name'] for cat in categories],
            "embedding": embeddings
        })
        collection.load()
        print("✅ 4 萬個分類向量化完成!")
    
    # ============ 階段 2:實時檢索 + AI 分類 ============
    def classify_product_optimized(product_description):
        """實時分類流程"""
    
        # 1. 將商品描述向量化
        model = SentenceTransformer('all-MiniLM-L6-v2')
        query_embedding = model.encode(product_description)
    
        # 2. 向量搜尋:找出最相關的 Top 50 分類(< 50ms)
        connections.connect("default", host="127.0.0.1", port="19530")
        collection = Collection("products_categories")
    
        search_results = collection.search(
            data=[query_embedding],
            anns_field="embedding",
            param={"metric_type": "L2", "params": {"nprobe": 10}},
            limit=50  # 只取 Top 50
        )
    
        top_categories = [hit.entity.get("category_name") for hit in search_results[0]]
        categories_text = '\n'.join([f"- {cat}" for cat in top_categories])
    
        print(f"✓ 向量搜尋找到 50 個候選分類(用時:< 50ms)")
    
        # 3. Claude 從 50 個候選中精確選擇(150ms)
        response = client.messages.create(
            model="claude-opus-4-6",
            max_tokens=1024,
            messages=[{
                "role": "user",
                "content": f"""根據這個商品描述進行分類:
    
    商品描述:{product_description}
    
    相關分類候選(已按相似度排序,僅展示 Top 50):
    {categories_text}
    
    請從上述候選中選擇最相關的前 3 個分類 + 置信度。
    
    返回格式:
    1. 分類名稱 (置信度: 95%)
    2. 分類名稱 (置信度: 80%)
    3. 分類名稱 (置信度: 65%)
    
    同時說明理由。"""
            }]
        )
    
        return response.content[0].text

    性能對比:

    指標 TFIDF 純 AI
    (全部分類)
    向量 + AI
    (推薦)
    分類傳輸 不適用 40 萬 tokens 500 tokens(50 個)
    成本/次 $0 $5.00 $0.005
    日成本(10K 商品) $0 $50,000 $50
    響應時間 1ms 1-2 秒 200ms
    準確度 中(容易混淆) ⭐⭐⭐ 高
    語義理解 ❌ 差 ✅ 強 ✅ 強
    多語言支持 ❌ 差 ✅ 強 ✅ 強

    如何讓 Agent SDK / Claude 存取動態分類列表?

    問題: 上面的案例中,分類是硬編碼或簡單傳輸。但在真實系統中,分類會經常變動。Agent SDK 怎麼知道最新的分類清單?

    三種方案對應不同規模

    方案 A:應用層查詢(適合 < 500 分類)

    流程: 應用程式 → 查詢資料庫 → 替換提示詞佔位符 → Agent 使用

    import sqlite3
    from anthropic import Anthropic
    
    client = Anthropic()
    
    # 應用程式層:查詢資料庫
    def get_categories_from_db():
        conn = sqlite3.connect('products.db')
        cursor = conn.cursor()
        cursor.execute('SELECT name FROM categories WHERE active = 1 ORDER BY name')
        categories = [row[0] for row in cursor.fetchall()]
        conn.close()
        return categories
    
    # 獲取最新分類
    categories = get_categories_from_db()
    categories_text = '\n'.join([f"- {cat}" for cat in categories])
    
    # 生成提示詞
    prompt = f"""根據商品描述選擇分類:
    
    商品描述:輕便防水的戶外登山背包,容量 40L
    
    可用分類:
    {categories_text}
    
    返回前 3 個分類。"""
    
    # Claude 使用最新分類進行分類
    response = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": prompt}]
    )

    優勢: 簡單、直接、零複雜度

    缺點: 每次請求都要查資料庫

    方案 B:Agent 工具查詢(適合 500-5000 分類)

    流程: Agent 調用自訂工具 → 工具查詢資料庫 → Agent 使用結果

    from anthropic import tool
    import sqlite3
    
    @tool
    def query_categories(keyword: str = None) -> str:
        """查詢可用的商品分類。
    
        Args:
            keyword: 可選的搜尋關鍵詞(例如:'電子' 會返回 '電子產品')
        """
        conn = sqlite3.connect('products.db')
        cursor = conn.cursor()
    
        if keyword:
            cursor.execute(
                'SELECT name FROM categories WHERE active = 1 AND name LIKE ? ORDER BY name',
                (f'%{keyword}%',)
            )
        else:
            cursor.execute('SELECT name FROM categories WHERE active = 1 ORDER BY name')
    
        categories = [row[0] for row in cursor.fetchall()]
        conn.close()
        return ', '.join(categories)
    
    # Agent 可以調用工具
    prompt = """根據商品描述選擇分類:
    
    商品描述:輕便防水的戶外登山背包,容量 40L
    
    步驟:
    1. 使用 query_categories 工具查詢所有或相關分類
    2. 從結果中選擇最相關的前 3 個
    
    返回格式:
    1. 分類名稱 (置信度: 95%)
    ...
    """

    優勢: 動態、Agent 可以「思考」查詢策略

    缺點: 增加 API 往返次數

    方案 C:向量檢索(適合 > 5000 分類,如東森 4 萬)

    流程: 預先嵌入分類 → 商品描述進來 → 向量搜尋 Top 50 → Claude 精確選擇

    (詳見上方「向量搜尋 + AI 精確分類」段落)

    方案選擇表

    分類規模 推薦方案 成本 延遲 複雜度
    < 100 方案 A(直接傳) 最低 最快 ⭐ 最簡
    100-500 方案 A(推薦) ⭐ 簡
    500-5000 方案 B(推薦) ⭐⭐ 中
    > 5000(東森 4 萬) 方案 C(必須) 最低 最快 ⭐⭐⭐ 複

    工具設計的正確思路:從問題出發

    這是最重要的一個章節。 很多工程師設計 Agent 工具時,會陷入「工具先行」的誤區。但正確的做法是「需求驅動」。

    ❌ 錯誤的做法:工具先行

    「我要做 Agent SDK」
      ↓
    「我需要什麼工具?」
      ↓
    設計工具:query(), update(), delete()
      ↓
    「我怎麼用這些工具?」
      ↓
    慢慢找場景...
      ↓
    結果:工具太通用、有遺漏、或過度設計

    ✅ 正確的做法:從問題出發

    「我的系統可能遇到什麼問題?」
      ↓
    列舉所有可能的問題
      ↓
    反推需要什麼工具來解決
      ↓
    設計這些工具(不多不少)
      ↓
    套入 Agent SDK
      ↓
    結果:工具精準、完整、適中

    實例 1:東森商品分類系統

    第 1 步:列舉可能的問題

    系統運行時會遇到什麼問題?
    
    用戶層面:
      ✓ 「我怎麼知道這個商品該放哪一類?」
      ✓ 「系統選的分類對嗎?」
      ✓ 「能不能推薦其他可能的分類?」
    
    系統層面:
      ✓ 「分類資料庫有沒有更新?」
      ✓ 「分類規則有沒有衝突?」
      ✓ 「某個分類底下有沒有商品?」
    
    邊界問題:
      ✓ 「這個商品可能屬於多個分類嗎?」
      ✓ 「怎麼處理新加的分類?」
      ✓ 「怎麼回滾到之前的分類?」

    第 2 步:反推需要的工具

    問題                                 → 需要的工具
    ──────────────────────────────────────────────────
    「能推薦其他可能的分類?」            → search_similar_categories()
    「分類有沒有更新?」                  → get_latest_categories()
    「分類規則有沒有衝突?」              → validate_category_rules()
    「某分類有沒有商品?」                → count_products_in_category()
    「可能屬於多個分類嗎?」              → get_ambiguous_categories()

    第 3 步:只設計這些工具

    @tool
    def search_similar_categories(keyword: str, top_k: int = 5) -> list:
        """找相關分類"""
    
    @tool
    def get_latest_categories(updated_after: str = None) -> list:
        """取最新分類資料"""
    
    @tool
    def validate_category_rules(category_id: str) -> dict:
        """驗證分類規則有沒有問題"""
    
    @tool
    def count_products_in_category(category_id: str) -> int:
        """某分類有多少商品"""
    
    @tool
    def get_ambiguous_categories(product_desc: str) -> list:
        """找可能有歧義的分類"""

    就這 5 個工具,不多不少!

    實例 2:客服系統

    列舉問題 → 推斷工具

    問題列表:
    1. 「客戶的訂單存在嗎?」
    2. 「訂單現在在哪裡?」
    3. 「這個客戶有沒有退貨紀錄?」
    4. 「退貨政策允許嗎?」
    5. 「要問主管才能退嗎?」
    6. 「怎麼記錄這次交互?」
    
    需要的工具:
    1. query_order()
    2. get_shipping_status()
    3. get_customer_return_history()
    4. check_return_policy()
    5. escalate_to_manager()
    6. log_interaction()

    就這 6 個,不多不少!

    為什麼這樣設計好?

    優勢 解釋
    ✅ 不會過度設計 只有解決實際問題的工具
    ✅ 不會有遺漏 所有可能的問題都考慮到
    ✅ Claude 理解清楚 系統邊界明確,工具語義清晰
    ✅ 工具粒度適中 既不太大也不太小
    ✅ 易於維護和擴展 添加新問題 = 添加新工具

    設計 Agent 工具時的關鍵決策:工具粒度

    基於「從問題出發」的思路,現在我們討論工具粒度。 粒度(granularity)決定了 Claude 能否有效使用工具。

    三種極端情況

    ❌ 工具太大(做太多事)

    @tool
    def query_order_everything(
        customer_id: str,
        order_id: str = None,
        status: str = None,
        start_date: str = None,
        end_date: str = None,
        shipping_status: str = None,
        include_items: bool = True,
        include_history: bool = True
    ) -> dict:
        """一個工具做所有事"""
        # 6 個 WHERE 條件
        # ...

    問題:

    • Claude 很容易參數填錯(太多選擇)
    • Claude 不知道應該用哪些參數組合
    • 你寫了 6 個 WHERE,Claude 可能只需要 1 個,浪費

    ❌ 工具太小(太細碎)

    @tool
    def query_by_customer_id(customer_id: str) -> list:
        """只查客戶"""
    
    @tool
    def query_by_status(status: str) -> list:
        """只查狀態"""
    
    @tool
    def query_by_date_range(start: str, end: str) -> list:
        """只查日期"""
    
    # ... 還有 10 個工具

    問題:

    • Claude 要調用 3-4 次工具才能完成一個查詢
    • 延遲高、成本高
    • Claude 要自己 join 結果,容易出錯

    ✅ 工具適中(語義相關的組合)

    @tool
    def get_customer_order_status(customer_id: str, order_id: str = None) -> dict:
        """查客戶的訂單,可選篩選特定訂單"""
        # WHERE customer_id = ? AND (order_id = ? if provided)
    
    @tool
    def get_orders_by_date(start_date: str, end_date: str) -> list:
        """查某個時間範圍的訂單"""
        # WHERE created_at BETWEEN ? AND ?
    
    @tool
    def get_orders_by_status(statuses: list) -> list:
        """查特定狀態的訂單"""
        # WHERE status IN (...)

    優勢:

    • 每個工具有單一職責(符合 SOLID 原則)
    • Claude 能清楚理解用途
    • 通常 1-2 次調用完成查詢
    • 參數數量合理(不超過 3-4 個)

    工具粒度判斷清單

    設計工具時,問自己這些問題:

    判斷點 好的工具 差的工具
    工具名能清楚表達意圖嗎? get_orders_by_customer() query_db()
    參數數量 < 4 個 > 5 個
    Claude 能猜到用途嗎? 「我看到名字就知道查什麼」 「我完全不知道這是什麼」
    通常多少次調用完成任務? 1-2 次 3-5 次或更多
    工具代表一個業務概念嗎? 「訂單狀態」「物流追蹤」 「數據庫查詢」「參數組合」

    實際案例:東森分類系統

    ❌ 太大的工具

    @tool
    def search_categories(
        keyword: str = None,
        parent_category: str = None,
        min_products: int = None,
        max_products: int = None,
        active_only: bool = True,
        sort_by: str = "name"
    ):
        """搜尋分類"""
        # 這是什麼?搜分類還是搜商品?太模糊

    ✅ 適中的工具(基於問題驅動)

    @tool
    def search_categories_by_keyword(keyword: str) -> list:
        """用關鍵詞搜分類
    
        例:keyword="運動" → 返回 [運動戶外, 運動服飾, ...]
        """
    
    @tool
    def get_category_children(parent_id: str) -> list:
        """取某分類的子分類"""
    
    @tool
    def get_products_in_category(category_id: str, limit: int = 100) -> list:
        """取分類下的商品"""

    Claude 使用:

    「我要分類一個『防水戶外背包』的商品」
    ↓
    Claude:「我先搜 '戶外' 相關分類」
      → search_categories_by_keyword("戶外")
      → 返回 [運動戶外, 戶外用品, ...]
    
    Claude:「運動戶外 有什麼子類別?」
      → get_category_children("運動戶外")
      → 返回 [登山, 露營, 滑雪, ...]
    
    Claude:「登山 分類有什麼產品,我看看背包在哪」
      → get_products_in_category("登山")
      → 自動判斷這個背包應該是「運動戶外 > 登山」

    Claude 自動組織,不需要你預先決定順序!

    工具粒度的黃金法則

    問自己:「Claude 看著這個工具名和參數,會不會用?」

    • 如果會 → 工具大小合適
    • 如果不會 → 工具太大或太模糊,要拆或改名

    總結:何時遷移到 Agent SDK

    如果你符合以下任何一個,考慮 Agent SDK:

    • 代碼包含 200+ 行 if-elif-else 邏輯
    • 每月都在添加新的處理規則
    • 用戶經常報告「系統沒理解我」
    • 客服系統無法適應變通表達方式
    • 維護成本不斷上升

    核心優勢總結:

    • 代碼行數:500+ → 10(50 倍簡化)
    • 新增規則:改代碼+測試+部署 → 改提示(即時生效)
    • 用戶體驗:生硬規則化 → 自然親切
    • 維護成本:高 → 低

    工具設計思路:

    • ❌ 不要:先設計工具,再找用處
    • ✅ 要:從問題出發,反推需要的工具
    • ✅ 結果:工具精準、完整、易用

    準備好了嗎?下載 Jupyter Notebook,親手測試,然後在你的項目中試用 Agent SDK。

  • Hacker News 每日精選 – 2026-03-16

    🚀 科技趨勢週報:AI 效能、Web 肥大化與數位監控的角力

    今日的科技圈展現了極大的反差:一方面我們看到 AI 工具如 Chrome DevTools MCP 正在重塑開發流程,提升自動化極限;另一方面,我們也正面臨網頁資源過度膨脹、法律對隱私的潛在侵犯,以及 AI 帶來的心理疲勞。身為開發者與數位公民,理解這些工具背後的原理與社會影響,比單純學會使用它們更為重要。

    為什麼你該關心?因為從浮點數運算到國家級的監控法案,這些底層技術與政策正無形中決定了我們未來的開發環境與生活空間。💻

    🤖 AI / 機器學習

    LLM 架構圖鑑 (LLM Architecture Gallery)

    這是一個由知名機器學習專家 Sebastian Raschka 整理的視覺化資源庫,詳細展示了從原始 Transformer 到最新模型(如 Llama 3、Gemma 等)的架構演變。這對於想要深入理解模型內部的開發者來說是極佳的參考手冊,幫助你掌握注意力機制、正規化與位置編碼的細微差異。💡

    閱讀原文

    我如何利用 LLM 撰寫軟體 (How I write software with LLMs)

    作者分享了他在實際開發流程中整合大型語言模型的策略。文章強調 LLM 不是替代品,而是極強的「加速器」,特別是在編寫樣板程式碼、重構舊邏輯以及生成單元測試方面。這提供了一套務實的框架,讓開發者在保持控制權的同時極大化產出效率。

    閱讀原文

    LLM 有時真的讓人精疲力竭 (LLMs can be exhausting)

    這篇文章反映了許多開發者在使用 AI 工具一段時間後的共同感受:雖然效率提升了,但頻繁的錯誤修正、上下文的管理以及對 AI 幻覺的警惕,讓人產生了獨特的「AI 疲勞感」。作者呼籲我們應重新審視人機協作的邊界,避免陷入被工具奴役的陷阱。🧠

    閱讀原文

    🛠️ 開發工具與實務

    Chrome DevTools MCP (2025)

    Google 推出了支援 Model Context Protocol (MCP) 的 Chrome 開發者工具,這意味著 AI 代理(Agent)現在可以直接與你的瀏覽器 Session 進行互動與調試。這項重大更新打破了 AI 與運行環境之間的隔閡,讓「AI 自動修復 Bug」的可能性又往前邁進了一大步。🛠️

    閱讀原文

    關於協作編輯的謊言:為什麼我們不使用 Yjs (Lies I was told about collaborative editing, Part 2)

    在構建協作工具時,CRDT(如 Yjs)通常被視為標準解答。然而這篇文章提供了一個挑釁性的反向觀點,詳細解釋了在某些複雜應用場景下,Yjs 可能帶來的性能瓶頸與架構複雜度。對於正在選擇即時協作方案的技術決策者來說,這是非常有價值的警世文。

    閱讀原文

    🌐 網路、效能與基礎建設

    那個高達 49MB 的新聞網頁 (The 49MB web page)

    作者對現代新聞網站的資源加載進行了深度審計,發現僅僅是首頁就可能消耗數十 MB 的流量。這篇極具批判性的文章揭示了廣告追蹤、無謂的腳本與高解析度素材如何摧毀了 Web 的效能與使用者體驗,提醒前端開發者「Less is More」的重要性。⚠️

    閱讀原文

    僅靠 IX 路由伺服器能走多遠? (How far can you go with IX Route Servers only?)

    這是一篇探討網路底層架構的深度技術文章,分析了在不依賴傳統電信商(Transit)的情況下,僅透過網路交換點(Internet Exchange)的路由伺服器能實現多大程度的全球連通。對於網路工程師與對 BGP 協定感興趣的讀者來說不容錯過。

    閱讀原文

    🧱 電腦科學與硬體

    每個電腦科學家都該知道的浮點數運算 (What every computer scientist should know about floating-point arithmetic)

    經典重現!這是一篇 1991 年的重量級論文,深入探討了 IEEE 754 標準與浮點數在電腦中表示的種種陷阱。無論是進行科學運算還是開發普通的金融系統,理解精確度缺失的原因是每個專業工程師的必備基礎。🎓

    閱讀原文 (PDF)

    機器人致動器中的馬達縮放定律與慣性 (Electric motor scaling laws and inertia in robot actuators)

    這篇文章從物理學角度剖析了機器人設計中的關鍵挑戰。作者探討了馬達大小、重量與慣性之間的縮放關係,解釋了為什麼有些機器人動作遲緩而有些靈動。對於硬體工程師與機器人愛好者來說,這是極佳的理論基礎。🤖

    閱讀原文

    ⚖️ 隱私與法律

    加拿大 C-22 法案授權大規模元數據監控 (Canada’s bill C-22 mandates mass metadata surveillance)

    加拿大政府的新法案引發了嚴重的隱私疑慮。該法案被指控重新引入了「合法訪問」的後門,允許在缺乏足夠司法監督的情況下收集公民的通訊元數據(Metadata)。這是全球加密與隱私攻防戰中的又一重大事件。🛡️

    閱讀原文

    🎯 今日觀點:在工具狂熱中回歸本質

    今日的科技新聞趨勢顯示出一個明確的共同主題:我們正處於技術架構轉型與社會反思的交界點。

    一方面,我們在 AI 的推動下不斷向上疊加新的抽象層(如 MCP 與 LLM Workflow),致力於提升開發速度。但另一方面,像「49MB 網頁」與「浮點數運算」這類話題在提醒我們,底層的效能管理與數學精確度永遠是軟體的根基。而加拿大 C-22 法案的推動,則警告我們技術進步若缺乏法律制衡,可能成為監控的利刃。

    💡 給讀者的行動建議:

    • 優化工作流: 嘗試將 Chrome DevTools MCP 整合進你的調試流程,但請時刻警惕「AI 疲勞」,設定好手動檢查的邊界。
    • 性能健檢: 重新審視你的 Web 專案,檢查是否有不必要的依賴讓你的網頁變成了下一個「49MB 巨獸」。
    • 重溫基礎: 即使在 AI 時代,理解 IEEE 754 這樣的基礎知識,能讓你在解決難解 Bug 時擁有降維打擊的能力。

    保持好奇,保持警覺,我們下期再見!👋

  • WordPress REST API 調試實戰:從 NNNN 字符到完整修復

     

    WordPress REST API 調試實戰:從 NNNN 字符到完整修復

     

    🎯 重點摘要

    • 問題根源:WordPress 資料庫中存在字面 ‘n’ 字符(0x6E),而非換行符(0x0A)
    • 表現症狀:REST API 返回 NNNN、n< 模式、表格損壞、內容亂碼
    • 根本原因:多層架構的信息轉換導致錯誤的故障假設和調試方向偏離
    • 解決方案:使用 od -c 檢查二進位數據、多層驗證、直接在資料庫層修復

    問題是如何出現的?

    WordPress REST API 調試中最常見的陷阱就是 症狀與原因的巨大落差。你在前端看到 NNNN 字符和 n< 模式,但實際問題可能在完全不同的地方。

    這篇文章根據真實的 WordPress 修復案例(超過 1,000 個 NNNN 字符、16 個表格損壞),詳細解析多層故障排除流程。

    第 1 層:表面症狀 vs 實際原因

    當 REST API 返回異常內容時,最危險的假設就是直接指責過濾器或編碼問題。實際上,以下三層都可能是問題來源:

    你看到的 期望的原因 實際原因 解決難度
    REST API 顯示 n< 過濾器損壞內容 資料庫中有字面 ‘n’ 字符 ⭐⭐⭐⭐
    NNNN 字符出現 轉義或編碼問題 ‘nn’ 模式(字面n + 換行) ⭐⭐⭐⭐⭐
    表格消失或亂碼 HTML 結構破壞 字面 ‘n’ 阻斷了 HTML 標籤解析 ⭐⭐⭐⭐

    表 1:WordPress 調試常見誤判清單 — 本表格列出 REST API 常見症狀、直觀的誤判原因,以及實際根本原因。這些誤判會導致調試花費 2-4 小時無果。

    第 2 層:多層架構的信息失真

    WordPress 資料從資料庫到瀏覽器經過多個轉換層,每一層都會改變你看到的表現形式:

    層級 你看到的 實際的字節 驗證方式
    MySQL 命令列 n(轉義序列) 0x0A(真實)或 0x6E(’n’ 字符) od -c
    PHP 讀取 實際換行或字面 ‘n’ 二進位正確表示 strpos($str, “n”)
    REST API JSON n 字符或 n JSON 正確轉義 jq + od -c
    瀏覽器顯示 NNNN、亂碼或正常 HTML 渲染結果 DevTools 檢查

    表 2:多層架構信息轉換對比 — 同一份資料在不同層級呈現出不同的表現。MySQL 命令列使用轉義表示,PHP 使用二進位,REST API 使用 JSON,瀏覽器進行 HTML 渲染。如果不理解這些轉換,很容易做出錯誤的根因判斷。

    第 3 層:正確的調試順序

    大多數 WordPress 調試問題都是因為調試順序錯誤。正確的調試順序應該是:

    1. 直接檢查二進位資料(od -c)— 這是源頭事實,必須第一步做
    2. 對比 DB ↔ Filter ↔ REST API 的三層輸出 — 縮小問題範圍
    3. 假設反轉 — 如果不是編碼問題,那是資料損壞嗎?
    4. 定位損壞位置 — 哪一層引入的?是資料庫本身還是更新時損壞?
    5. 追蹤操作歷史 — 之前做過什麼導致損壞?

    在真實案例中,調試花費了大量時間的原因是:第 1 次調查順序是 2 → 3 → 1 → 4 → 5,而正確順序應該是 1 → 2 → 3 → 4 → 5。

    第 4 層:實際的修復步驟

    步驟 1:使用 od -c 檢查資料庫的實際字節

    docker exec wordpress mysql -u wpuser -pwp_password wordpress -e 
      "SELECT SUBSTRING(post_content, POSITION('' IN post_content), 50) 
       FROM wp_posts WHERE ID = 984;" | tail -1 | od -c | head -20

    輸出應該顯示:

    !   -   -   >   n      n   <   !   -   -
                        ^   ^
                字面'n'  實際換行

    如果看到這個模式,你已經找到了根本原因:資料庫中有字面 ‘n’ 字符

    步驟 2:修復資料庫損壞

    docker exec wordpress mysql -u wpuser -pwp_password wordpress -e "
    UPDATE wp_posts
    SET post_content = REPLACE(post_content, CONCAT('n', CHAR(10)), CHAR(10))
    WHERE ID = 984;
    "

    這個 SQL 語句移除所有「字面 ‘n’ + 換行符」的組合,只保留實際的換行符。

    步驟 3:驗證修復

    curl -s http://localhost:8001/wp-json/wp/v2/posts/984 | jq -r '.content.rendered' | grep -o 'n<' | wc -l
    # 應該返回 0

    第 5 層:為什麼調試這麼困難?

    困難點 為什麼 解決方案
    信息不對稱 MySQL 顯示 n、PHP 顯示實際換行、REST API 顯示 n 字符 建立單一源頭(od -c),在那層定位問題
    問題來源不清 用戶說「做表格後出現 NNNN」,但不知道之前對資料做過什麼 追蹤操作歷史,理解損壞何時引入
    多層架構複雜 Database → Filter(6 個) → REST API → Browser 逐層檢查,縮小問題範圍到特定層級
    工具轉換多次 MySQL CLI → od -c → PHP → curl → jq → JSON 固定驗證工具,避免多次轉換導致的失真

    表 3:WordPress REST API 調試困難點分析 — 列出調試過程中的四個主要困難,以及每個困難對應的解決方案。這些都是基於真實的修復案例總結出來的。

    第 6 層:最佳實踐清單

    • 第一步永遠是 od -c — 不要猜測,直接看二進位數據
    • 建立多層驗證 — 不要只檢查一層,Database + Filter + REST API 都要查
    • 假設反轉 — 一個方向卡住了,立即反轉假設方向
    • 追蹤操作歷史 — 理解「之前發生了什麼」比「現在看起來怎樣」更重要
    • 表格要有邊框 — 使用 inline style: style="border: 1px solid #333; padding: 8px;"
    • 保存配置檔 — WordPress API 認證信息應該存在 ~/.claude/projects/project-name/wordpress-config.env

    常見問題(FAQ)

    總結

    WordPress REST API 調試的關鍵是理解 多層架構中的信息失真。症狀永遠不等於原因,你看到的 NNNN 字符只是冰山一角。

    記住這個優先順序:

    1. od -c 檢查二進位(源頭事實)
    2. 逐層驗證(Database → Filter → REST API)
    3. 假設反轉(卡住時反向思考)
    4. 追蹤歷史(理解根本原因)
    5. 修復並驗證(修完要驗證三層)

    下次遇到 WordPress REST API 問題時,不要急著改過濾器或重建資料庫。先用 od -c 看看真正的二進位數據,一切就清楚了。

     

  • Hacker News 每日精選 – 2026-03-15

    今日的科技圈展現了從底層架構到跨領域創新的高度多樣性,特別是 AI 推理能力的「蒸餾」技術與針對特定族群開發的作業系統,反映出技術正朝向更深層的優化與人文關懷邁進。無論你是追求性能的開發者,還是關注數位永續性的觀察家,今天的新聞都提供了極具價值的啟發。🚀

    AI / 機器學習

    數學蒸餾挑戰:等式理論 (Mathematics Distillation Challenge – Equational Theories)

    這項由數學大師陶哲軒(Terry Tao)發起的挑戰,旨在將複雜的數學理論「蒸餾」成 AI 模型更容易理解與處理的結構化格式。透過這種方式,研究者希望提升大型語言模型在處理高難度數學推理時的準確性。這不僅是一場數學競賽,更是探索如何讓機器更有效掌握人類抽象知識的重要實驗。🧠

    原文連結:Terry Tao Blog

    使用 PPO 進行語言模型的樹搜尋蒸餾 (Tree Search Distillation for Language Models Using PPO)

    本文探討如何透過強化學習(PPO)技術,將複雜的「樹搜尋」推論過程整合進語言模型中。這種方法模仿了類似 OpenAI o1 的推理機制,讓模型在輸出前能進行自我修正與路徑探索。這對於需要高度邏輯思維的應用場景具有重大意義,能有效縮減推論成本並提升品質。🤖

    原文連結:Deep Dive into Distillation

    開發工具

    Han:一個用 Rust 編寫的韓語程式語言 (Han – A Korean programming language written in Rust)

    Han 是一個極具特色的開源專案,它讓開發者能直接使用韓語語法編寫程式,並底層利用 Rust 的效能與安全性。這項專案展示了程式語言在地化的可能性,也挑戰了以英語為主的開發慣例。對於想要研究編譯器設計或語法解析器的開發者來說,這是一個非常有趣的參考範本。🇰🇷

    原文連結:View on GitHub

    極其優雅的 TCP 打洞演算法 (A most elegant TCP hole punching algorithm)

    這篇文章深入淺出地介紹了一種實現 NAT 穿透的高效演算法,稱為「TCP 打洞」。在點對點(P2P)網路連線中,如何讓位於防火牆後的兩台機器直接通訊始終是個難題。作者提出的方案被認為是目前最簡潔且優雅的解決路徑,對於網路工程師與分散式系統開發者非常有參考價值。🌐

    原文連結:Technical Analysis

    SBCL Fibers:輕量級協作線程 (SBCL Fibers – Lightweight Cooperative Threads)

    這是一個針對 Steel Bank Common Lisp (SBCL) 實作的輕量級線程(Fibers)庫。它提供了類似於其他語言中協程(Coroutines)的功能,讓開發者能在不犧牲效能的情況下,處理大量的併發任務。對於喜愛 Lisp 生態系並追求極致併發控制的硬派開發者來說,這是必讀之作。💻

    原文連結:Read the Full Post

    開源專案

    Ageless Linux:為不限年齡的使用者打造的系統 (Ageless Linux – Software for humans of indeterminate age)

    這是一個極具人文精神的 Linux 發行版專案,主張軟體介面應保持長期的穩定性與一致性。它特別針對厭惡 UI 頻繁變動、或對技術更新感到疲勞的使用者,提供一個「永恆不變」的操作環境。專案強調「軟體應該服務於人,而非強迫人去適應變化」,引發了社群對數位永續性的熱烈討論。🕊️

    原文連結:Visit Project Page

    其他(硬體、安全性與新聞)

    機架式水耕系統 (Rack-mount hydroponics)

    這位創作者將標準的伺服器機架改造為高效的水耕農場,將科技設備的精準控管帶入了家庭農業。透過 19 吋機架的模組化特性,實現了空間利用的最大化,甚至能利用機房的溫濕度管理優勢。這是一個完美的 DIY 案例,展示了如何將硬體架構思維應用在完全不同的領域。🥬

    原文連結:Project Showcase

    核心級反作弊機制運作原理 (How kernel anti-cheats work)

    這篇文章深入剖析了現代遊戲中常見的「核心層級(Ring 0)」反作弊程式。作者詳細解釋了這些驅動程式如何運作、如何監測系統行為,以及開發者與外掛製作者之間永無止盡的貓鼠遊戲。這對於關注系統安全、隱私權益以及遊戲產業技術的讀者來說是一份極佳的教材。🛡️

    原文連結:Technical Deep Dive

    尋寶獵人在拒絕交出沉船黃金後終獲釋 (Treasure hunter freed from jail)

    這是一則引人入勝的法律與真實冒險故事。尋寶獵人 Tommy Thompson 因為拒絕透露他在著名沉船中發現的黃金金幣去向,被判處藐視法庭並入獄六年。如今他終於獲釋,但這批神祕寶藏的下落依然是個謎。這則新聞在 HN 社群引發了關於產權、法律界限以及尋寶史的高度關注。💰

    原文連結:BBC News

    讓我認識真實的你,包含那些錯誤 (Allow me to get to know you, mistakes and all)

    在數位過濾與完美形象盛行的年代,這篇感性的文章呼籲人們回歸真實。作者反思了過度包裝的數位形象如何阻礙了真正的人際連結,並提倡擁抱錯誤與不完美。這在技術圈中是一股清流,提醒我們在追求卓越程式碼的同時,別忘了保留身為人類的溫度與真實感。🌱

    原文連結:Personal Reflection

    今日觀點

    綜觀今日的熱門話題,「知識與技術的提煉(Distillation)」是一個核心關鍵詞。無論是陶哲軒試圖將數學精華餵給 AI,還是開發者將複雜的 TCP 打洞過程簡化,都反映了我們正在努力處理這個資訊爆炸時代的複雜度。同時,Ageless Linux 的興起也警示我們:在追逐技術前沿的同時,不應拋棄那些追求穩定與簡單的人群。

    💡 行動建議:

    • 如果你是 AI 開發者,值得關注「樹搜尋蒸餾」技術,這可能是下一代推理模型的標配。
    • 如果你對基礎設施感興趣,學習 TCP 打洞演算法能讓你對 P2P 網路有更深層的理解。
    • 在個人成長上,試著在數位交流中展現更多真實的一面,有時候「不完美」才是最迷人的特質。
  • Claude Code 完全教學指南

     

    Claude Code:AI 驅動的軟體開發革命

     

    你可能經歷過這個場景:下午 3 點,產品經理說:「客戶要新功能,明天就要。」你打開編輯器,開始敲代碼。腦子裡同時在想:資料庫欄位、API 端點、錯誤處理、邊界情況、測試用例……你一個人在腦子裡跑著整個開發流程。

    Claude Code 改變了什麼?想像你有個高級工程師坐在身邊。你說:「我需要一個使用者認證系統。」他問:「SQL 還是 NoSQL?」你說 PostgreSQL,他立刻開始寫。你看著代碼,說:「這個有漏洞」,他改。整個過程,你只需要說出你想什麼。

    這就是 Claude Code 的核心:

      • 你專注想什麼(目標、邏輯、決策)

      • Claude Code 專注怎麼做(實現、語法、細節)

      • 你可以用一個人的時間,做一隊工程師的工作

    第 1 章:快速入門

    1.1 三分鐘安裝

    macOS

    brew install anthropic/tap/claude-code

    Linux

    sudo apt update && sudo apt install claude-code

    Windows

    從 https://claude.com/download 下載 .exe

    1.2 設定 API 金鑰

      1. 去 https://console.anthropic.com

      1. 登入 → API Keys → Create Key

      1. 複製金鑰(只顯示一次)

      1. 執行:claude config set-key YOUR_KEY

    1.3 第一個對話

    claude

    開始輸入:「寫一個 Python 函數,檢查質數」

    第 2 章:核心概念

    2.1 對話思維

    不是:「寫個登入頁面」(50% 符合)

    而是:逐步談論,每步精煉。第一版 80%,加要求→90%→100%。

    2.2 理解能力邊界

    能看到:你的項目文件、提到的內容、之前的對話

    看不到:其他項目、密碼、網路信息(除非 WebFetch)

    第 3 章:20+ 工具詳解

    3.1 工具分類

    表 1: Claude Code 工具分類速查表

    此表格按功能分類列出 Claude Code 的所有工具。左欄是功能類型(檔案、執行等),中欄是對應的工具名稱,右欄說明每個工具的用途。

    類型 工具 做什麼
    檔案 Read, Edit, Write, Glob 讀、寫、編輯、搜尋文件
    執行 Bash, Pytho 跑代碼,看結果
    搜尋 Grep, Agent 找東西,分析代碼
    版本控制 Git 提交、看歷史、合併
    Web WebFetch, WebSearch 調 API,查信息
    管理 TaskCreate, TaskUpdate 管理任務,追蹤進度

    第 4 章:Skills 與 Workflows

    Skill 是預定義的工作流程。例如 TDD(先寫測試再寫代碼)、Code Review、Debugging、Agent 派遣。

    第 5 章:MCP 插件系統

    MCP:讓 Claude Code 直接連接外部服務(資料庫、Figma、Discord 等)。

    沒 MCP:你說 → Claude Code 生成 → 你複製 → 你跑 → 你粘貼 → Claude Code 分析。太慢。

    有 MCP:一氣呵成,快很多。

    第 6 章:進階用法(用得更好的祕訣)

    6.1 Prompt 工程:怎樣問問題很重要

    同樣的需求,不同的問法,結果天差地別。看這個對比:

    表 2: Prompt 範例對比 – 如何提問更好

    此表格展示同一個需求的三種提問方式。用來學習如何寫出高質量的 prompt。

    維度 壞問題 好問題 結果差異
    問題 「寫個登入頁面」 「Vue 3 + TypeScript 的登入頁面,記住我、3 次失敗鎖定、Tailwind CSS」
    Claude Code 需要猜的東西 框架?UI 庫?功能?設計?認證方式? 全都說了,不用猜
    生成的代碼符合度 ~50% ~100% 提升 50%
    你需要改的次數 5-6 次 0-1 次 省時間 80%
    Token 消耗 5000+ tokens 1500 tokens 省 70%
    總時間 35 分鐘 5 分鐘 快 7 倍

    「好問題」的三要素 + 對比表

    表 3: 好 Prompt 的三個必要元素

    此表格拆解一個優秀 prompt 的三個要素。用來檢查自己的 prompt 是否齊全。

    要素 例子 為什麼重要
    上下文 「我在寫後台管理系統,Vue 3 + TypeScript」 Claude Code 知道框架、語言、用途。消除最大的猜測。
    具體需求 「功能:用戶名 + 密碼、記住我、錯誤提示」 功能清單,一項一項。不用用戶去想「還要什麼」。
    約束條件 「UI:Tailwind CSS、安全:防 XSS」 限制技術選擇,防止 Claude Code 過度設計。

    6.2 Context 管理:怎樣讓 Claude Code 聚焦

    Context 聚焦的三層級對比

    表 4: Context 管理 – 不同範圍的效能對比

    此表格比較不同 Context 範圍的效率和品質。用來決定每次應該給 Claude Code 多少上下文。

    層級 範圍 Context 大小 執行速度 答案品質 何時用
    全項目 所有 780 個文件 50,000+ tokens ⏱️ 很慢 ⭐ 60% 罕見,只在架構設計
    一個模塊 src/orders/(~50 個文件) 5,000 tokens ⏱️⏱️ 中等 ⭐⭐⭐⭐⭐ 95% 大部分工作,推薦
    一個文件或函數 getOrders()(~30 行) 500 tokens ⏱️⏱️⏱️ 瞬間 ⭐⭐⭐⭐⭐ 99% 精細調整、除錯

    經驗法則:項目 <50 個文件 → 全項目沒問題 | 50-500 → 聚焦模塊 | >500 → 聚焦文件/函數

    6.3 性能優化:寫出快速的代碼

    案例:交易策略回測的優化過程

    表 5: 真實案例 – 性能優化的具體耗時

    此表格展示交易回測項目從 5 分鐘優化到 3 秒的完整過程。用來了解 Claude Code 的實際優化效果。

    版本 實現方法 執行時間 加速倍數 瓶頸
    v1(原始) 三層 Python 迴圈 5 分 0 秒 1x CPU 單核執行 1.25M 次迭代
    v2(矢量化) NumPy 矢量操作 8 秒 37.5x 記憶體讀取
    v3(並行) NumPy + 多進程 3 秒 100x 磁碟 I/O
    v4(快取) v3 + LRU 快取 1.5 秒 200x 實時使用可行

    常見優化模式的效果對比

    表 6: 常見優化技巧的效果對比

    此表格列出開發中常用的優化技巧和預估加速倍數。用來評估哪些優化最值得做。

    優化模式 應用場景 典型加速 實現難度 何時用
    迴圈 → 矢量化 批量計算、數據處理 10-100 倍 Python 迴圈跑得慢
    重複計算 → 快取 同一數據多次計算 5-50 倍 看到重複 print 語句
    全表掃描 → 索引 資料庫查詢 100-1000 倍 WHERE 很慢
    同步 → 非同步 網路請求、I/O 3-10 倍 等待外部服務
    串行 → 並行 獨立計算 2-8 倍 多核 CPU 閒置

    6.4 成本優化:不浪費 Toke

    典型操作的 Token 消耗

    表 7: Token 成本速查表 – 常見操作的費用

    此表格列出日常開發操作的 token 消耗和估算成本。用來計算:「這個任務要花多少錢?」

    操作 典型 Token 數 成本(Opus) 優化方式
    讀一個小文件(<1KB) 50-100 $0.0002 只讀需要的部分
    寫一個函數 500-1000 $0.002 一次寫多個相關函數
    修改一個文件 1000-2000 $0.005 一次改多處,不要改多次
    讀整個大項目 5000-10000 $0.02 聚焦到一個模塊
    派遣一個 Agent 2000-5000 $0.01 只在真的需要時派遣

    模型選擇指南(按任務類型)

    表 8: 模型選擇指南 – 按任務類型選用 Opus/Soet/Haiku

    此表格幫助選擇合適的 Claude 模型。用來回答「我應該用 Opus 還是 Soet?」

    模型 價格 速度 推薦用途 例子
    Opus $3/$15 ⏱️ 慢 架構決策、複雜邏輯、Code Review 「檢查系統的認證設計」、「找性能瓶頸」
    Soet $3/$15 ⏱️⏱️ 中等 一般代碼生成、改 bug、寫測試 「寫登入頁面」、「修復崩潰」、「寫單元測試」
    Haiku $0.8/$4 ⏱️⏱️⏱️ 快 搜索、讀文件、簡單改動、查詢 「找所有 API 端點」、「讀這個文件」、「改個變量名」

    第 7 章:踩坑指南(學到的血淚教訓)

    7.1 常見失敗模式速查表

    表 9: 常見失敗模式 – 新手容易踩的 8 個坑

    此表格列出使用 Claude Code 最常見的失敗場景和解決方案。用來快速診斷「為什麼我的結果不對?」

    失敗模式 症狀 根本原因 修復方案 預防檢查
    期望太高 想讓 Claude Code 寫整個平台,結果亂七八糟 把 Claude Code 當自動化工廠,不是思考夥伴 拆解成小功能,逐步迭代 □ 功能清單有多於 5 個嗎?拆小。
    Context 爆炸 回答很差,執行很慢 讀了整個大項目,context 滿了 聚焦到一個模塊或文件 □ Context 有超過 5000 tokens 嗎?聚焦。
    不驗證結果 上生產後才發現 bug 沒跑代碼驗證,直接相信 Claude Code 讓 Claude Code 跑代碼,看實際輸出 □ 你跑過這段代碼嗎?沒有就先跑。
    安全忽視 API 沒認證,客戶能查別人數據 沒明確提出安全需求 明確列出安全要求(認證、防注入、加密) □ 有提到「安全」「認證」「防護」嗎?
    被建議騙了 按 Claude Code 的建議做,結果更複雜 建議太通用,不適合你的場景 提供約束條件(預算、人力、規模) □ 有說明你的約束條件嗎?

    7.2 真實項目教訓對比表

    表 10: 血淚教訓 – 真實項目中的失敗案例

    此表格記錄實際項目中發生過的重大問題和解決方案。用來學習別人的教訓。

    項目 問題 症狀 修復 教訓
    SimpleEC OMS Agent Team OOM 當機 派遣 9 個 Opus Agent,機器 16GB 記憶體爆炸 分批執行,一次 3-5 個 Agent 消耗 ~1.5GB 每個,要算好預算
    iDempiere 動態查詢失敗 SQL 查詢經常報「Unknown column」錯誤 先查詢 schema,確認欄位名 複雜系統要讀文檔,不要假設
    交易策略 優化後結果不一致 矢量化快 37 倍,但數字精度不同 優化前鎖定正確性,改後驗證 性能優化要漸進,不要一下改太多

    7.3 成本 & ROI 實際數字

    表 11: 成本與投資回報 – 真實項目的數字

    此表格列出真實項目的成本構成和投資回報。用來評估投資 Claude Code 是否值得。

    項目 代碼量 對話次數 Token 消耗 成本 節省時間 ROI
    SimpleEC OMS 50,000 行 500 次 5M tokens $20 200 小時(2 個月 → 2 週) 10 倍
    iDempiere 自訂 30,000 行 300 次 2M tokens $8 100 小時 12 倍
    交易策略 10,000 行 100 次 500K tokens $2 40 小時 20 倍

    結論:Claude Code 成本微乎其微(單項目 $2-20),但節省的時間是數週到數月。任何項目 ROI 都在 10 倍以上。

    7.4 避坑檢查清單

    表 12: 預發布檢查清單 – 交付前必檢項目

    此表格是交付代碼前的檢查清單。用來確保代碼質量和完整性。

    階段 檢查項目 不檢查的後果
    需求定義 ☐ 明確上下文(「我在做什麼項目」) Claude Code 猜測,符合度 50%
    ☐ 列出功能清單(一項一項) 遺漏功能,改多次
    ☐ 說出約束條件(性能、安全、技術棧) 實現不符需求,推倒重來
    實現階段 ☐ 聚焦 Context(「現在只看這部分」) Context 爆炸,品質下降 70%
    ☐ 讓 Claude Code 跑代碼驗證 Bug 進入生產,客戶投訴
    ☐ 關鍵改動要提交(不要等全部完成) 一個地方出錯,整個項目回滾
    優化階段 ☐ 明確性能要求(「<100ms」不是「儘量快」) 優化方向錯誤,白費力氣
    ☐ 優化後驗證正確性一致 快了但結果錯了,worse than before
    團隊協作 ☐ Agent Team 控制數量(最多 5 個) 資源耗盡,OOM 當機
    ☐ 監控成本(知道 token 消耗) 一個月花 $500 都沒發現

    7.5 遇到問題的除錯決策樹

    代碼不工作?按這個順序診斷:

    代碼崩潰?n  ├─ 是 → 看錯誤信息(線索在這)n  │       ├─ 語法錯誤? → 讓 Claude Code 修n  │       ├─ Runtime 錯誤? → 隔離問題,寫個最小測試n  │       └─ 邏輯錯誤? → 跑 debug 代碼,看變量值n  │n  └─ 否(運行但結果錯)→ 對比預期 vs 實際n          ├─ 部分錯? → 這部分代碼邏輯問題n          ├─ 都錯? → 理解錯誤,回到「需求定義」n          └─ 有時錯? → 邊界條件遺漏,寫測試複現

    金律:「不要瞎猜,運行代碼。」99% 的問題都能通過運行 + 看錯誤 + 寫測試解決。

    第 8 章:Agent Team 協作指南

    8.1 什麼時候用 Agent Team?

    一個 Claude Code 不夠時,就該考慮多個 Agent 分工。

    表 13: 單個 Claude vs Agent Team – 何時升級

    此表格對比單個 Claude Code 和 Agent Team 的應用場景。用來決定是否需要升級到多 Agent。

    特徵 單個 Claude Agent Team
    場景 簡單任務(寫功能、修 bug) 複雜項目(需要並行工作、分角色)
    執行時間 30 分鐘內 1-2 小時或更長
    決策成本 低(你直接說) 中(角色分工、資源預算)
    回報倍數 5-10x(人力) 30-100x(多角色並行)
    實際例子 寫個登入頁面 架構大重構、多模塊並行開發

    判斷法則:

    – 任務可以分成 3+ 個獨立部分? → 考慮 Agent Team

    – 這些部分需要同時進行? → 確定用 Agent Team

    – 部分之間無強依賴? → 完美

    8.2 角色設計:避免混亂和重複

    核心原則

    表 14: Agent Team 設計原則 – 好設計 vs 壞設計

    此表格列出 Agent Team 設計的核心原則和常見錯誤。用來避免設計失誤。

    維度 ✅ 好設計 ❌ 壞設計
    角色數量 3-5 個 9+ 個(資源爆炸)
    職責邊界 清晰、無重疊 模糊、功能重疊
    通信方式 Team Lead 統一協調 每個 Agent 互相溝通(亂套)
    模型選擇 任務匹配(opus/soet/haiku) 都用同一個模型(資源浪費)

    常見角色類型

    領導層:Team Lead(Haiku)n  ├─ 分配任務、協調進度、整合結果n  └─ 不需要高智力,需要協調能力實現層:Developer Agent(Soet)n  ├─ 寫代碼、修 bug、測試n  └─ 需要快速完成、成本敏感研究層:Architect / Researcher(Opus)n  ├─ 設計決策、技術選型、深度分析n  └─ 需要高質量、可容忍慢可選層:QA Agent(Soet)n  ├─ 執行測試、驗證結果n  └─ 提高品質、並行檢查

    角色劃分檢查清單

    □ 每個 Agent 只負責一個邏輯完整的工作(不要分成太細)

    □ 不同 Agent 的職責無重疊(問自己:Agent A 的工作會被 Agent B 做嗎?)

    □ Team Lead 能清楚地把任務分配給各 Agent

    □ Team Lead 有辦法整合各 Agent 的輸出

    □ 總共 ≤ 5 個 Agent(否則資源問題,見 8.3)

    8.3 記憶體控制:避免當機

    資源現狀(16GB 機器)

    表 15: 記憶體預算 – 16GB 機器上的 Agent 配置

    此表格列出每種模型的記憶體消耗和最多同時 Agent 數。用來規劃 Agent Team 的規模。

    Agent 模型 每個消耗 最多同時跑 常見配置
    Opus ~1.0GB 5-6 個 高精度任務
    Soet ~0.6GB 10-12 個 通用實現
    Haiku ~0.4GB 15+ 個 快速搜尋、協調

    2026/3/3 事故根因:同時跑 9 個 Opus Agent → OOM 當機

    記憶體預算公式

    可用記憶體 = free -h 的 available 列 - 2GB(系統保留)需求 = Σ(各 Agent 記憶體) + 0.5GB(Team Lead)✅ 需求 < 可用 → 可以啟動n❌ 需求 ≥ 可用 → 必須分批

    分批策略(超過 5 個 Agent)

    不要同時啟動 9 個 Opus!必須分批:

    批次 1:Agent A + B + C + D + E(5 個)同時跑n        ↓(全部完成)n批次 2:Agent F + G + H + I + J(5 個)同時跑n        ↓(全部完成)n批次 3:Team Lead 整合所有結果

    即時監控命令

    # 檢查系統可用記憶體(秒級更新)nwatch -n 1 'free -h'# 檢查 Claude 進程數(最多不超過 5 個 opus)nps aux | grep claude | wc -l# 如果用 claude-limited(cgroup 限制)ncat /sys/fs/cgroup/memory/claude/memory.limit_in_bytes  # 限制ncat /sys/fs/cgroup/memory/claude/memory.usage_in_bytes  # 實際用量

    8.4 測試策略:避免「虛假成功」

    問題根源

    「測試全過卻 UI 點到抓狂」的本質:測試驗證的不是用戶真正體驗的東西。

    表 16: Mock 陷阱 – 測試環境 vs 真實環境的差異

    此表格說明為什麼本地測試通過但生產環境失敗。用來理解測試策略的重要性。

    差距 測試環境 真實環境 後果
    資料 乾淨 fixtures 髒資料、邊界值 NaN 顯示、閃爍
    執行 同步、可預測 非同步、競態條件 重複提交、資料丟失
    網路 即時或 mock 延遲、超時、失敗 loading 無限轉
    使用者 按劇本操作 快速連點、返回鍵 狀態錯亂、記憶體洩漏

    Mock 的三大致命陷阱

    陷阱 1:Over-mocking(mock 了不該 mock 的)n───────────────────────────────────────njest.mock("../api/auth", () => ({ login: () => "success" }))n❌ 你測的是:「假設 API 永遠正確」n✅ 你應該測:「API 格式改了怎麼辦」陷阱 2:Stale Mocks(mock 跟實作不同步)n────────────────────────────────────n後端改了 userName → displayNamen前端 mock 還返回 userNamen→ 測試過 ✅ 但線上爆炸 ?陷阱 3:Happy Path Only(只 mock 成功路徑)n──────────────────────────n所有 mock 都返回 200 + 完美資料n→ 從不測 401、500、timeoutn→ 用戶看白屏或無限 loading

    前期設計檢查清單

    在開始寫功能前,問自己:

    □ 這個功能會失敗嗎?(網路斷線、伺服器 500、用戶輸入錯誤)

    □ 失敗時怎麼展示錯誤?(空白 vs 友善訊息)

    □ 在網路慢的情況下怎麼工作?(loading、禁用按鈕防重複提交)

    □ 用戶會怎樣濫用?(快速連點、關閉瀏覽器、返回鍵)

    □ 邊界資料怎麼處理?(null、空字串、超大數字)

    這些問題回答不了 → 代碼寫不好 → 測試也救不了

    測試策略三層次(按優先級)

    層級 1:組件集成測試(最重要,投資回報最高)n────────────────────────────────────n✅ 用真實組件、mock API 層(用 MSW,不是 jest.mock)n✅ 測:點擊 → API 呼叫 → 結果渲染n✅ 覆蓋:成功 + 失敗 + loading 狀態n✅ 工具:React Testing Library、@testing-library/user-event層級 2:E2E 測試(關鍵流程)n────────────────────────n✅ 測:登入 → 操作 → 結果n✅ 不要 mock 任何東西(真實後端 + 測試資料庫)n✅ 工具:Playwright、Cypress層級 3:單元測試(純邏輯)n──────────────────────n✅ 純計算函數(格式化、排序、驗證)n✅ 工具函數、資料轉換n❌ 不要測組件內部細節(太脆弱)

    常見功能的測試清單

    登入功能:

    – □ [E2E] 輸入帳密 → 點登入 → 跳轉首頁 → 顯示用戶名

    – □ [集成] 密碼錯誤 → 顯示錯誤訊息

    – □ [集成] 提交時禁用按鈕(防重複提交)

    – □ [集成] 網路超時 → 重試機制

    – □ ❌ 不要 mock router(登入後跳轉是核心行為)

    – □ ❌ 不要 mock localStorage(token 存取就是測試重點)

    支付流程:

    – □ [E2E] 選商品 → 結帳 → 支付 → 成功頁

    – □ [集成] 金額計算:小計 + 稅金 + 折扣 + 運費 = 總計

    – □ [集成] 支付失敗 → 錯誤訊息 + 可重試

    – □ [單元] 折扣碼驗證邏輯

    – □ [E2E] 重複提交防護(連點不會重複扣款)

    8.5 實戰案例:SimpleEC OMS 失敗與修復

    失敗原因:

    – 資料庫連線池沒關閉 → 頻繁操作時耗盡

    – 測試環境用 mock,生產環境真實資料 → 資料格式不同

    – 測試只覆蓋成功路徑 → 沒測過並發競態

    修復步驟:

    1. 新增集成測試(對真實資料庫,測並發場景)

    2. 移除過度 mock(只 mock 第三方 API)

    3. 新增 E2E 測試(真實業務流程)

    結果: 問題率從 15% 降到 2%

    8.6 小結

    Agent Team 三黃金規則:

    1. 角色要清晰 — 不要讓兩個 Agent 做同樣的事

    2. 資源要預算 — 先算再建,分批執行

    3. 測試要前置 — 設計時就考慮失敗情況,不要事後補救

    最後的話: 多 Agent 協作能 100 倍加速工作,但複雜度也倍增。沒有架構設計,光有工具沒用。

    總結

    從入門到精通:8 章的進階路線

    • 第 1-2 章:基礎與核心概念
    • 第 3-4 章:工具與工作流程
    • 第 5 章:系統集成(MCP)
    • 第 6 章:進階技巧
    • 第 7 章:實戰失敗案例
    • 第 8 章:多 Agent 協作

    Claude Code 的價值不在寫代碼有多快,而在於你能專注「想什麼」而不是「怎麼做」。當你掌握了 Agent Team 協作,一個人可以做一個小隊的工作。但記住:強大的工具也需要謹慎使用。