分類: LLM 應用

  • LangGraph 多模型實戰:從零到 Production 的完整教學

    重點摘要

    • LangGraph 讓你把不同 AI 模型串成自動化流水線:Claude 負責「想」,Groq Llama 負責「寫」,各司其職
    • 本文從零開始,帶你走完四個階段:基本流水線 → 智慧路由 → Streaming + 容錯 → FastAPI 部署
    • 每個階段都有完整可執行的程式碼,跟著做就能跑
    • 核心區別:Claude Code / Cursor 是「你的工具」,LangGraph 是「你造工具的材料」——當你要造產品給別人用時才需要它
    • 實測結果:比全用 Claude Sonnet 省 75% 成本,同時保留深度分析的品質

    這篇文章是給誰看的?

    如果你符合以下任一情況,這篇文章就是為你寫的:

    • 你想做一個 AI chatbot(客服、內部助手、產品功能),但不知道怎麼開始
    • 你已經在用 Claude / GPT,但覺得全部用最貴的模型太浪費錢
    • 你聽過「多模型協作」但不確定具體怎麼實作
    • 你想知道 LangGraph 跟你平常用的 Claude Code / Cursor / Copilot 到底差在哪

    本文從零開始,帶你走完四個階段,每個階段都有完整可執行的程式碼。你可以在任何一個階段停下來——不是每個人都需要走到 production。

    先搞清楚:這跟 Claude Code / Cursor / Copilot 完全不同

    在往下讀之前,先釐清最容易搞混的一件事:

    面向 Claude Code / Cursor / Copilot LangGraph
    本質 開發者工具 — 你用它寫 code 開發框架 — 你用它造產品
    使用者是誰 你自己(開發者) 你的客戶 / 你的系統 / 你的團隊
    使用場景 日常寫程式、debug、重構 建 chatbot、自動化流程、API 服務
    互動方式 人 ↔ AI 即時對話 程式碼自動跑,可以無人值守
    模型選擇 工具幫你選好(通常固定一個) 你自己決定哪個步驟用哪個模型
    計費方式 月費訂閱(工具包了) 純 API 按量計費,你自己控制成本

    用一個比喻:Claude Code 是你請了一個很強的工程師坐在旁邊幫你寫 code;LangGraph 是你在蓋一條自動化產線,產線上有不同的機器人各司其職

    如果你只是日常寫程式,用 Claude Code 就好,不需要 LangGraph。往下讀之前,確認你的需求是「造一個東西給別人用」,而不是「讓自己寫 code 更快」。

    為什麼不同的 AI 模型要分工合作?

    沒有一個模型什麼都最好。每個模型有不同的強項和定價:

    能力 Claude Sonnet Groq Llama 70B Groq Llama 8B
    架構設計 / Code Review ⭐ 最強 普通
    程式碼生成 ⭐ 強且快 普通
    簡單問答 大材小用 大材小用 ⭐ 夠用且極便宜
    生成速度 ~50 tok/s ~300 tok/s ~800 tok/s
    費用 (Output/1M tokens) $15.00 $0.79 $0.08

    核心邏輯:讓擅長「想」的模型去想,讓擅長「做」的模型去做,讓便宜的模型處理瑣事。就像軟體團隊裡,架構師出規格、工程師寫程式、實習生回答簡單問題一樣。

    LangGraph 是什麼?一分鐘看懂

    LangGraph 是 LangChain 團隊開發的有狀態流程編排框架。三個核心概念:

    1. Node(節點)— 一個步驟,比如「用 Sonnet 設計」或「用 Llama 實作」
    2. Edge(邊)— 步驟之間的連線,決定「做完 A 接著做 B」
    3. State(狀態)— 所有節點共享的資料,比如設計規格、程式碼、審查結果

    把這三個組合起來,就是一個可以自動跑的流水線。你定義「什麼步驟做什麼、什麼條件走什麼路」,框架負責執行。

    環境準備(所有階段共用)

    開始之前,你需要準備兩個 API key 和安裝套件。這一步做完,後面四個階段都不用再設定。

    1. 取得 API Key(兩個都有免費額度)

    ⚠️ 注意:這是 API key,跟 Claude.ai 的月費訂閱、GitHub Copilot 的訂閱完全無關。API 是按用量計費的。

    2. 建立專案

    mkdir langgraph-duo && cd langgraph-duo
    
    # 安裝套件
    pip install langgraph langchain-anthropic langchain-groq python-dotenv
    
    # 建立 .env 檔案(填入你的 key)
    cat > .env << 'EOF'
    ANTHROPIC_API_KEY=sk-ant-xxxx
    GROQ_API_KEY=gsk_xxxx
    EOF

    3. 驗證連線

    python3 -c "
    from dotenv import load_dotenv; load_dotenv()
    from langchain_anthropic import ChatAnthropic
    from langchain_groq import ChatGroq
    
    sonnet = ChatAnthropic(model='claude-sonnet-4-6', max_tokens=50)
    llama = ChatGroq(model='llama-3.3-70b-versatile', max_tokens=50)
    
    print('Sonnet:', sonnet.invoke('Say OK').content)
    print('Llama:', llama.invoke('Say OK').content)
    "

    兩行都印出 OK,就可以開始了。

    第一階段:Duo 流水線(設計 → 實作 → 審查)

    目標:讓 Claude Sonnet 設計規格,Groq Llama 寫程式碼,Sonnet 再審查品質。審查不通過自動重做,最多 3 次。

    適合場景:批量生成程式碼、自動化 code review、需要品質把關的程式碼生成。

    Task → [Sonnet 設計] → [Llama 實作] → [Sonnet 審查]
                                ↑               |
                                └── 未通過 ──────┘  (最多 3 次)
                                      ↓ 通過
                                     END

    完整程式碼:duo.py

    from typing import TypedDict
    from dotenv import load_dotenv
    from langgraph.graph import StateGraph, END
    from langchain_anthropic import ChatAnthropic
    from langchain_groq import ChatGroq
    from langchain_core.messages import HumanMessage, SystemMessage
    
    load_dotenv()
    
    # 模型分工:Sonnet 想,Llama 做
    sonnet = ChatAnthropic(model="claude-sonnet-4-6", max_tokens=4096)
    llama = ChatGroq(model="llama-3.3-70b-versatile", max_tokens=4096)
    
    # 所有節點共享的狀態
    class AgentState(TypedDict):
        task: str             # 原始需求
        design: str           # Sonnet 的設計規格
        code: str             # Llama 的實作
        review: str           # Sonnet 的審查結果
        revision_notes: str   # 修改指示(給重試用)
        approved: bool        # 是否通過
        attempt: int          # 重試次數
    
    MAX_ATTEMPTS = 3
    
    # Node 1: Sonnet 設計
    def design_node(state):
        response = sonnet.invoke([
            SystemMessage(content="You are a senior architect. Produce a precise technical spec with function signatures, edge cases, and pseudocode."),
            HumanMessage(content=f"Request: {state['task']}")
        ])
        return {"design": response.content}
    
    # Node 2: Llama 實作
    def implement_node(state):
        prompt = f"Spec:\n{state['design']}"
        if state.get("revision_notes"):
            prompt += f"\n\nFix these issues:\n{state['revision_notes']}"
        response = llama.invoke([
            SystemMessage(content="Implement per spec. Output only Python code."),
            HumanMessage(content=prompt)
        ])
        return {"code": response.content, "attempt": state.get("attempt", 0) + 1}
    
    # Node 3: Sonnet 審查
    def review_node(state):
        response = sonnet.invoke([
            SystemMessage(content="Review code vs spec. Reply VERDICT: APPROVED or REJECTED with details."),
            HumanMessage(content=f"Spec:\n{state['design']}\n\nCode:\n{state['code']}")
        ])
        review = response.content
        approved = "APPROVED" in review.upper()
        return {"review": review, "approved": approved,
                "revision_notes": "" if approved else review}
    
    # 條件路由:通過 → 結束,未通過 → 回去重做
    def should_continue(state):
        if state["approved"] or state["attempt"] >= MAX_ATTEMPTS:
            return "end"
        return "revise"
    
    # 組裝 Graph
    workflow = StateGraph(AgentState)
    workflow.add_node("design", design_node)
    workflow.add_node("implement", implement_node)
    workflow.add_node("review", review_node)
    workflow.set_entry_point("design")
    workflow.add_edge("design", "implement")
    workflow.add_edge("implement", "review")
    workflow.add_conditional_edges("review", should_continue,
                                   {"end": END, "revise": "implement"})
    app = workflow.compile()
    
    # 跑!
    result = app.invoke({
        "task": "Write a Python function that reads a CSV and returns column averages as a dict",
        "design": "", "code": "", "review": "",
        "revision_notes": "", "approved": False, "attempt": 0,
    })
    
    print("=== CODE ===")
    print(result["code"])
    print(f"\n{'✅ APPROVED' if result['approved'] else '⚠️ BEST EFFORT'} after {result['attempt']} attempt(s)")

    實測結果

    階段 模型 結果
    🧠 Design Claude Sonnet 4.6 產出 4 個參數、10 個 edge case、9 步 pseudocode 的完整規格
    ⚡ Implement Groq Llama 70B 完整 Python 函數,含 type hints、docstring、error handling
    🔍 Review Claude Sonnet 4.6 VERDICT: APPROVED — 第一次就通過,沒有重試

    到這裡你已經有一個能跑的多模型流水線了。如果你的需求是「批量生成程式碼 + 自動品質把關」,可以停在這個階段。

    第二階段:Smart Router(自動選模型的聊天機器人)

    目標:做一個像 ChatGPT 一樣的對話介面,但底下不是固定一個模型,而是自動根據問題類型選最適合的模型。

    適合場景:客服 chatbot、團隊內部 AI 助手、需要控制 API 成本的聊天服務。

    你的問題 → [Llama 8B 分類器] → 判斷類型
                                      |
                      ┌────────────────┼────────────────┐
                      ↓                ↓                ↓
                [Claude Sonnet]  [Llama 70B]      [Llama 8B]
                 深度分析          寫程式            簡單問答
                      ↓                ↓                ↓
                      └────────────────┼────────────────┘
                                       ↓
                                    回答你

    分類器怎麼運作?

    分類器用最便宜的 Llama 8B(每次呼叫不到 $0.0001)讀取問題,輸出一個 JSON 判斷結果。分類規則:

    分類 路由到 觸發條件 費用 (Output/1M)
    🧠 深度思考 Claude Sonnet 架構分析、比較權衡、code review、規劃 $15.00
    ⚡ 寫程式 Llama 70B 實作函數、生成腳本、重構、修 bug $0.79
    💨 快速回答 Llama 8B 打招呼、簡單問答、定義、基礎算數 $0.08

    核心程式碼

    import json
    from langgraph.graph import StateGraph, END
    
    # 分類器:Llama 8B 讀問題,判斷該走哪條路
    def router_node(state):
        response = llama_8b.invoke([
            SystemMessage(content="""Classify into one category:
    - "sonnet": complex reasoning, analysis, architecture
    - "llama_70b": write code, implement, fix bugs
    - "llama_8b": greetings, simple facts, casual chat
    Reply ONLY JSON: {"route": "...", "reason": "..."}"""),
            HumanMessage(content=state["question"])
        ])
        parsed = json.loads(response.content)
        return {"route": parsed["route"]}
    
    # 條件路由:根據分類結果,走不同的回答節點
    workflow = StateGraph(RouterState)
    workflow.add_node("router", router_node)
    workflow.add_node("sonnet", answer_sonnet)
    workflow.add_node("llama_70b", answer_llama_70b)
    workflow.add_node("llama_8b", answer_llama_8b)
    
    workflow.set_entry_point("router")
    workflow.add_conditional_edges("router", lambda s: s["route"], {
        "sonnet": "sonnet",
        "llama_70b": "llama_70b",
        "llama_8b": "llama_8b",
    })
    app = workflow.compile()

    實測分類準確度:7/7

    問題 路由結果 正確?
    Hi! 💨 Llama 8B
    1+1=? 💨 Llama 8B
    Write a Python quicksort ⚡ Llama 70B
    Compare microservices vs monolith 🧠 Sonnet
    What is Docker? 💨 Llama 8B
    幫我寫一個 REST API ⚡ Llama 70B
    分析 Redis cache vs CDN 優缺點 🧠 Sonnet

    到這裡你有一個能自動選模型的聊天機器人了。但它還缺兩個東西:回答會一次全部吐出(不是逐字顯示),而且 Groq 掛了就整個壞掉。第三階段解決這兩個問題。

    第三階段:Streaming + Fallback(讓它不會掛)

    目標:回答逐字出現(像 ChatGPT 一樣流暢),而且模型掛了自動切換備用模型。

    為什麼這一步很重要:沒有 Streaming 的 chatbot,使用者體驗像 2010 年的網頁——按下送出,等 5 秒,突然一大段文字出現。沒有 Fallback 的服務,Groq 一限速(免費版每分鐘 30 次),你的整個服務就掛了。

    Streaming:體感延遲降 25 倍

    方式 使用者體驗 程式碼差別
    invoke()(非串流) 等 5 秒 → 突然出現整段文字 response = model.invoke(messages)
    stream()(串流) 0.2 秒開始出字 → 像打字一樣流暢 for chunk in model.stream(messages)
    # 只需要把 .invoke() 改成 .stream()
    # 然後迭代每個 chunk 即時輸出
    
    for chunk in model.stream(messages):
        print(chunk.content, end="", flush=True)  # flush=True 強制即時顯示

    Fallback:模型掛了自動切換

    主要模型 Fallback 模型 切換代價
    🧠 Sonnet ⚡ Llama 70B 分析品質略降,速度更快
    ⚡ Llama 70B 🧠 Sonnet 速度略慢,品質更高
    💨 Llama 8B ⚡ Llama 70B 稍慢稍貴,但一定能回答
    # Fallback 模式:try 主要模型,失敗自動切備用
    try:
        for chunk in primary_model.stream(messages):
            print(chunk.content, end="", flush=True)
    except Exception:
        print("⚠️ Primary failed, switching to fallback...")
        for chunk in fallback_model.stream(messages):
            print(chunk.content, end="", flush=True)

    完整的 router_stream.py 把 Streaming + Fallback + 對話歷史 + 使用統計整合在一起,不到 200 行。跑起來就是一個帶有自動模型切換的 terminal 聊天機器人。

    到這裡你有一個穩定的、體驗流暢的聊天機器人了。但它還是跑在你的 terminal 裡,只有你能用。第四階段讓它變成任何人都能呼叫的 API 服務。

    第四階段:FastAPI 部署(讓別人能用)

    目標:把 chatbot 包成 HTTP API,讓網頁、App、Line bot、Slack bot 都能呼叫。

    為什麼是 FastAPI:Python 生態最主流的 API 框架,原生支援 async、自動生成 API 文件、社群龐大。

    API 端點設計

    端點 方式 適合場景
    POST /chat 非串流,回傳完整 JSON Slack/Line bot、後端呼叫、批次處理
    POST /chat/stream SSE 串流,逐 token 推送 網頁聊天窗、需要即時體感的 UI
    GET /health 健康檢查 負載平衡器、監控系統
    GET /sessions/{id} 取得對話歷史 Debug、對話紀錄查詢
    DELETE /sessions/{id} 清除對話 使用者開始新對話

    啟動與測試

    # 安裝額外套件
    pip install fastapi uvicorn sse-starlette
    
    # 啟動 server
    python server.py
    # → 🤖 Smart Router API running on http://localhost:8900
    
    # 測試非串流
    curl -X POST http://localhost:8900/chat \
      -H "Content-Type: application/json" \
      -d '{"message": "什麼是 Docker?", "session_id": "test-user"}'
    
    # 回應範例:
    # {
    #   "answer": "Docker 是一個容器化平台...",
    #   "model_used": "llama_8b",
    #   "route_reason": "simple definition question",
    #   "session_id": "test-user",
    #   "fallback_used": false,
    #   "elapsed_seconds": 0.85
    # }

    前端怎麼接 SSE 串流?

    如果你要做網頁聊天窗,前端只需要幾行 JavaScript:

    // 瀏覽器原生 EventSource API
    const response = await fetch('/chat/stream', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({message: '寫一個排序函數', session_id: 'user-1'})
    });
    
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    
    while (true) {
      const {done, value} = await reader.read();
      if (done) break;
      const text = decoder.decode(value);
      // 每個 chunk 到了就即時顯示在畫面上
      document.getElementById('chat').innerHTML += text;
    }

    為什麼用 SSE 而不是 WebSocket?

    聊天場景是「使用者送一次訊息、AI 回一次」的單向推送。SSE 比 WebSocket 更適合:

    • 更簡單 — 單向傳輸,不需要管雙向連線
    • 瀏覽器原生 — EventSource API 內建自動重連
    • 穿透力好 — 走標準 HTTP,能通過代理和 CDN
    • 夠用 — 使用者的訊息用 POST 送,AI 的回應用 SSE 推

    四個階段的完整對照

    階段 檔案 新增能力 適合誰 可以停在這嗎?
    1. Duo 流水線 duo.py 設計→實作→審查 批量生成程式碼
    2. Smart Router router.py 自動選模型 個人實驗、學習
    3. Streaming + Fallback router_stream.py 逐字輸出 + 自動容錯 團隊內部使用
    4. FastAPI 部署 server.py HTTP API + SSE + Session 對外服務、產品整合

    費用比較:到底能省多少?

    假設一天 100 個問題,其中 20% 深度分析、30% 寫程式、50% 簡單問答:

    方案 月成本估算 品質
    全部用 Claude Sonnet ~$54 最高,但簡單題大材小用
    Smart Router(自動切換) ~$13.50 深度題用 Sonnet,其餘用 Llama
    全部用 Groq Llama 70B ~$4.20 最便宜,但分析品質弱

    Smart Router 方案比全用 Sonnet 省 75%,同時保留了深度分析任務的 Sonnet 品質。規模越大差距越明顯——1000 個使用者的 SaaS 產品,月省 $3000+。

    什麼場景適合?什麼場景不適合?

    ✅ 適合的場景

    1. 客服 Chatbot — 70% 簡單題用 Llama 8B 秒回,複雜題自動升級到 Sonnet
    2. 團隊 AI 助手 — 接 Slack,PM 問策略用 Sonnet,工程師要 code 用 Llama 70B
    3. 自動化 Pipeline — CI/CD 中的 AI code review,PR 提交自動跑
    4. SaaS 產品 — 加 AI 功能但要控成本,簡單摘要用 Llama,深度分析用 Sonnet
    5. 批量內容生成 — 50 篇產品描述:Sonnet 定規範 → Llama 批量寫 → Sonnet 抽檢

    ❌ 不適合的場景

    • 日常寫程式 — 用 Claude Code 或 Cursor 就好,不需要 LangGraph
    • 一次性分析 — 直接貼給 Claude 問就好,不需要搭 pipeline
    • 不需要控成本 — 個人使用月花不到 $10,Smart Router 省下的錢不值得建置成本

    三個問題判斷法

    在決定要不要用之前,問自己:

    1. 使用者是誰? — 你自己 → 不需要。別人(客戶/團隊/系統)→ 繼續看
    2. 會跑多少次? — 幾次 → 直接呼叫 API。幾百幾千次 → LangGraph 有意義
    3. 需要品質分級嗎? — 所有問題都要最高品質 → 用最強模型。不同問題可以不同品質 → Smart Router

    三個都答「後者」才值得用 LangGraph。

    走完四個階段之後,還有什麼?

    如果你的服務要上正式商業環境,還有幾個面向需要處理:

    面向 做什麼 不做的後果
    RAG(檢索增強) 接向量資料庫,讓 AI 查你的文件回答 AI 只能回答通用知識,不懂你的業務
    評估(LangSmith) 追蹤每次呼叫的路由、延遲、成本 不知道 Router 分類準不準,成本失控
    Session 持久化 用 Redis 存對話歷史(目前在記憶體) Server 重啟,所有對話消失
    認證 API key 或 JWT 驗證 任何人都能呼叫你的 API,幫你花錢
    Prompt Injection 防護 驗證使用者輸入,防止惡意 prompt 使用者讓 AI 做不該做的事
    Docker 容器化 打包成 Docker image 部署 環境不一致,部署困難
    Subgraph 嵌套 Router 判斷「寫程式」→ 啟動整個 Duo 流水線 只能單步回答,沒有品質把關

    完整專案結構

    langgraph-duo/
    ├── .env                  # API keys(不要 commit)
    ├── .gitignore            # 排除 .env
    ├── requirements.txt      # 所有套件
    ├── duo.py                # 階段 1:設計→實作→審查 流水線
    ├── duo_notebook.ipynb    # 階段 1 的 Jupyter 版
    ├── router.py             # 階段 2:Smart Router 基本版
    ├── router_stream.py      # 階段 3:+ Streaming + Fallback
    └── server.py             # 階段 4:FastAPI HTTP API

    所有程式碼都有詳細的中英文註解,說明每個模型的選用原因和適用場景。從哪個階段開始都可以,每個檔案都是獨立可執行的。

    總結

    LangGraph 多模型流水線的核心價值不是「用 AI 寫程式更快」——如果只是速度,直接用一個模型最快。它的價值在於把 AI 當成團隊來管理:讓擅長設計的去設計、擅長實作的去實作、擅長審查的去審查。

    從 Duo 流水線到 Smart Router,再到帶有 Streaming、Fallback、API 部署的生產版本,每一步都是從「能跑」走向「能上線」的必經之路。你不需要一次走完四個階段——先跑通第一階段,確認這個架構對你有用,再往下走。

    相關閱讀:LangChain/LangGraph 深度分析:架構師、顧問、個人公司的實戰指南 | Claude Code Agent Teams:從穩定執行到自動化代碼審查的完整指南 | 舊系統整合場景下,會用 vs 不會用 Claude Code 的差距

  • Claude Code Agent Teams:從穩定執行到自動化代碼審查的完整指南

    Claude Code Agent Teams:從穩定執行到自動化代碼審查的完整指南

    本文整合三部分內容:(1) Agent Teams 的穩定執行框架;(2) 全局代碼審查規則系統的設計與實施;(3) 自動化雙 Agent 審查機制(架構師 + PM)的完整實現方案。這是一份實踐導向的指南,涵蓋從資源評估、權限配置、到自動觸發流程的所有細節。

    第一部分:Agent Teams 的三層穩定執行框架

    1.1 評估層(Assessment)— 前置資源檢查

    每次建立 Agent Team 前,必須執行三個評估動作:

    1. 記憶體現狀:執行 free -h 或查看 Docker stats,確認可用容量
    2. 計算容量:根據模型選擇計算最大並行 agent 數(opus ~1GB、sonnet ~600MB、haiku ~400MB)
    3. 決策與確認:列出 agent 角色、模型、預估記憶體,取得用戶確認後才建立

    模型選擇口訣

    • 需要「想」 → Opus(架構決策、安全設計、業務邏輯、複雜 SQL、Code Review)
    • 需要「做」 → Sonnet(CRUD 實作、API 對接、測試撰寫、文件撰寫)
    • 需要「找」 → Haiku(檔案掃描、配置對比、API 整合)

    1.2 確認層(Confirmation)— 用戶決策前置

    建立 Team 前,必須向用戶列出清晰的角色定義和資源計劃,包括:

    • 各 agent 的角色名稱與職責
    • 指定的 AI 模型及其預估記憶體
    • 總計容量和系統可用容量
    • 並行數量和預期執行順序

    只有在用戶明確確認後,才啟動 TeamCreate 和後續任務建立。這一步防止了資源耗盡、權限誤配、以及 agent 之間通訊不暢的根本原因。

    1.3 執行層(Staged Execution)— 分階段序列化

    即使資源充足,也不應讓所有 agent 同時轟炸執行。分階段策略包括:

    1. 第 1 階段:啟動基礎設施 agent(如資源管理、環境配置)
    2. 第 2 階段:啟動 researcher agent,進行資訊搜集與分析
    3. 第 3 階段:啟動 architect agent,設計方案
    4. 第 4 階段:啟動 developer agent,進行實作
    5. 第 5 階段:啟動驗證 agent,進行測試與審查

    各階段 agent 完成任務後,主動進入「空閒」狀態並通知團隊。不進行「拉取」操作,而是由前置 agent 完成後才推進下一階段。這種設計確保:

    • 前置依賴滿足後才啟動
    • 消息傳遞清晰,無需輪詢
    • 系統記憶體壓力均勻分散
    • 故障範圍可控,易於除錯

    第二部分:全局代碼審查規則系統架構

    2.1 雙層規則設計

    代碼審查規則分為兩層,確保通用性和專案適應性的平衡:

    • 全局層~/.claude/memory/):所有項目共享的代碼品質標準(SOLID 原則、Design Pattern、代碼異味、測試規範、語言特定規範)
    • 項目層項目/.claude/code-review-rules.md):專案特定的業務邏輯規則、設計稿映射、外部驗證清單

    2.2 全局規則內容結構

    code-review-global-rules.md(SOLID、Pattern、Code Smell、Testing)

    • SOLID 五項原則的定義和違反示例
    • Design Pattern 反面示例(God Object、Feature Envy 等)
    • 代碼異味檢查清單(N+1、Magic Number、過長方法、過多參數、重複代碼、複雜邏輯)
    • 單元測試最低標準(80%+ 覆蓋、邊界情況、Mock vs Real Dependency)

    code-review-languages.md(Java、Python、JavaScript/TypeScript、SQL)

    • 命名規範(類名、方法名、變數名、常數、包名)
    • 包結構約定(分層架構:domain/service/repository/validator 等)
    • 異常處理規範
    • 語言特定工具規範(Lombok、OSGi、Type Hint、Docstring 等)

    code-review-feedback.md(架構師與 PM Agent 職責和對焦框架)

    • 架構師 Agent:SOLID 遵循度(1-5 分)、Design Pattern、Code Smell、測試覆蓋、異常處理、語言規範
    • PM Agent:功能 vs 設計稿對齐、API 返回值、邊界情況、業務邏輯、用戶體驗、外部驗證需求
    • 雙方對焦框架:架構師問「代碼設計能支持你檢查的功能嗎?」,PM 反問「這些功能需求會造成架構問題嗎?」

    code-review-process.md(自動觸發、Agent 角色、聯合報告格式)

    • 觸發點:Task marked as completed
    • Agent 角色 Prompt(初版):架構師評估、PM 評估、聯合對話
    • 聯合報告格式:分離的評估 + 統一優先級排序 (P0/P1/P2)
    • 最終判定:Pass / Needs Work / Fail

    2.3 項目層規則(台灣發票系統範例)

    項目規則分為三類:

    A. 業務邏輯規則(優先級最高)
    • 進項稅計算公式(進項稅金額 = 發票金額 × 5%,DECIMAL(19,2) 向下取整)
    • 三聯式(不含稅)vs 二聯式(含稅)的會計處理邏輯
    • 進項稅折讓的強制申報期限(當期內必須申報,無延後例外)
    • 兼營營業人的比例扣抵公式(可扣抵進項稅 = 總進項稅 × (應稅銷售額 / 總銷售額))
    • 發票號碼連續性檢查和遺失空白發票記錄
    • 發票開立日期 → 申報期間的映射(1-2月→第1期、3-4月→第2期 等,共六期)
    B. 設計稿對齐規則(優先級次之)
    • API 端點的返回格式和欄位定義
    • 邊界情況的預期響應(零金額、負數、超大金額)
    • 數據型態和範圍檢查
    C. 外部驗證清單(優先級最低,但定期更新)
    • 進項稅可扣抵期限是否仍為 10 年
    • 電子發票強制規定的生效狀態
    • 設計稿版本確認
    • 技術規範(iDempiere PO 模型、OSGi Bundle)

    第三部分:自動化雙 Agent 審查機制的實現

    3.1 TaskCompleted Hook 配置

    .claude/settings.local.json 中配置 TaskCompleted Hook,每當任務標記完成時,自動觸發架構師和 PM 兩個 agent 進行深度審查:

    {
      "hooks": {
        "TaskCompleted": [
          {
            "hooks": [
              {
                "type": "agent",
                "prompt": "Conduct comprehensive code review: (1) Architecture: SOLID principles (1-5), design patterns, code smells (P0/P1/P2), testing, exceptions. (2) Functional: spec alignment, API contracts, boundary cases, business logic (Taiwan tax rules). Provide unified P0/P1/P2 priority with Pass/Needs Work/Fail decision and file:line recommendations.",
                "model": "opus",
                "statusMessage": "Running code review on completed task...",
                "timeout": 300
              }
            ]
          }
        ]
      }
    }

    3.2 架構師 Agent 職責細節

    架構師 Agent 按以下維度進行評估,每項 1-5 分自評:

    1. SOLID 原則遵循度:檢查 S(單一職責)、O(開閉)、L(里氏替換)、I(接口隔離)、D(依賴倒轉)五項是否遵循
    2. Design Pattern 應用恰當性:是否應用了合適的設計模式,是否存在過度設計
    3. 代碼異味程度:N+1 查詢、Magic Number、過長方法(>20 行)、過多參數(>3 個)、重複代碼、複雜邏輯(圈複雜度 > 10)
    4. 測試覆蓋度:目標 80%+,是否涵蓋邊界情況(null、empty、max/min)
    5. 異常處理完整性:是否避免過寬泛的異常捕捉,異常信息是否有意義,是否吞掉異常
    6. 語言特定規範遵循度:根據 code-review-languages.md 檢查命名、包結構、工具使用規範

    輸出:各維度評分 + 具體改進建議(標記優先級 P0/P1/P2 和代碼位置)

    3.3 PM Agent 職責細節(含 QA)

    PM Agent 進行務實檢查,確保功能實現和業務邏輯正確性:

    1. 功能 vs 設計稿對齐:設計稿的所有功能點是否實現,是否有範圍蠕動
    2. API 返回值對齐:返回欄位是否與文檔一致,資料型態是否正確,必需欄位是否都有
    3. 邊界情況涵蓋:null 輸入、空集合、最大值/最小值、負數、零值是否處理
    4. 業務邏輯正確性:根據項目規則(進項稅計算、發票號碼、申報期間映射等)是否正確
    5. 用戶體驗:錯誤提示是否清楚,用戶流程是否順暢,是否有令人困惑的行為
    6. 外部驗證需求:是否需要查證業務規定(優先 C)、設計稿(優先 A)、技術規範(優先 B)

    輸出:功能層缺陷清單、QA 項目、待驗證項(註明 C/A/B 優先級)

    3.4 聯合報告與優先級統一排序

    架構師和 PM 分別完成評估後,進行深度對話:

    • 架構師問 PM:「代碼結構能支持你檢查的功能嗎?」
    • PM 反問架構師:「這些功能需求會造成架構問題嗎?」

    基於對話結果,生成聯合報告:

    • P0(Critical):N+1 查詢、安全漏洞、死鎖風險、未處理的邊界情況、違反台灣稅務規則
    • P1(Important):過長方法、重複代碼、Magic Number、缺失測試、不清晰的錯誤提示
    • P2(Nice to Have):輔助方法提取、考慮設計模式、日誌增強

    最終判定

    • Pass:P0 問題 0 個,P1 問題可接受(≤2 個或不影響核心功能)
    • ⚠️ Needs Work:P0 問題 1-3 個,或 P1 問題 >3 個,或測試覆蓋度 <70%
    • Fail:P0 問題 ≥3 個,或安全漏洞,或違反重要法規

    第四部分:審查流程與反覆迭代

    4.1 外部驗證流程

    當 PM Agent 提出待驗證項時,按優先級啟動查詢:

    優先級 C(業務邏輯)— 需人工驗證
    • 用戶透過稅務官網或法規文件進行人工查證(AI 查詢易出錯)
    • 驗證結果更新到項目規則
    • 重新審查涉及的代碼
    優先級 A(設計稿)— 查閱項目文檔
    • 查閱設計文件、API 文檔
    • 如無對應文件,提示用戶補充
    • 確認後更新 code-review-rules.md
    優先級 B(技術規範)— 查詢官方文檔
    • 查詢 iDempiere、OSGi 官方文檔
    • 標記為參考(變動機會低)

    4.2 修改與重審流程

    當報告判定為 Needs Work 或 Fail 時:

    1. 開發者查看報告,收到 P0/P1/P2 改進清單
    2. 開發者修改代碼並完成新測試
    3. 重新標記 Task 為 completed(或手動觸發 /code-review-force)
    4. 自動重審(流程回到架構師 + PM 評估)
    5. 迴圈進行,直到最終判定 Pass

    第五部分:系統集成與迭代計劃

    5.1 全局記憶結構

    所有規則和流程信息保存在用戶的全局記憶庫中:

    • ~/.claude/memory/code-review-global-rules.md — SOLID、Pattern、Code Smell、Testing
    • ~/.claude/memory/code-review-languages.md — Java、Python、JS、SQL 規範
    • ~/.claude/memory/code-review-feedback.md — 架構師/PM 職責與對焦框架
    • ~/.claude/memory/code-review-process.md — 自動觸發、報告格式、判定標準

    5.2 項目級別記憶結構

    • 項目/.claude/code-review-rules.md — 業務邏輯規則 + 設計稿映射 + 外部驗證清單
    • 項目/.claude/settings.local.json — TaskCompleted Hook 配置

    5.3 三個迭代階段

    Phase 1(現在)
    • 建立全局規則知識庫(4 個記憶文件)
    • 編寫項目層規則(code-review-rules.md)
    • 配置 TaskCompleted Hook
    • 在項目中試用審查機制
    Phase 2(2-4 週後)
    • 根據實際審查結果優化規則(哪些規則發現了 bug、哪些規則太寬泛)
    • 改進 Agent Prompt(增加上下文、更清晰的指導)
    • 補充項目層規則細節(特別是邊界情況和特殊規則)
    Phase 3(1-2 月後)
    • 考慮集成到 CI/CD(每次 PR 自動審查)
    • 累積審查報告,形成項目代碼品質歷史
    • 調整 Hook 超時和 Agent 模型選擇

    第六部分:常見問題與實踐建議

    Q1:如果審查花太長時間怎麼辦?

    A:初版 timeout 設為 300 秒。如果超時,可調整為 600 秒,或簡化 Agent Prompt 去掉某些維度。對大型代碼改動,可分成多個小 Task,每個分別審查。

    Q2:外部驗證項目誰負責查證?

    A:初版由用戶或 PM 手動查證(特別是業務邏輯 C 項)。後續可考慮集成更多自動化(如 WebSearch for C 項、文檔連接 for A 項)。

    Q3:PM Agent 如何知道設計稿的內容?

    A:初版需在 code-review-rules.md 的 B 項中維護設計稿摘要(API 返回格式、欄位定義、邊界情況)。後續可考慮直接連接設計文件或 API 文檔鏈接。

    Q4:審查報告輸出到哪裡?

    A:初版直接輸出到對話(用戶可複製保存或導出)。後續可考慮存到 Task comment、Markdown 文件或項目文檔。

    Q5:如何確保 Agent Teams 穩定運行?

    A:遵循三層框架:

    • 評估層:前置資源檢查和確認,不盲目建立 Team
    • 確認層:列出角色、模型、容量,取得用戶確認
    • 執行層:分階段序列化,避免並行轟炸,讓 agent 主動進入空閒狀態而不是被拉取

    以及定期檢查記憶體、監控 agent 通訊、設置合理的超時時間。

    結論

    穩定可信的 Agent Teams 不是靠運氣,而是靠紮實的前置規劃、清晰的資源評估、以及精心設計的執行流程。本文提供的三層框架(評估→確認→分階段執行)確保了 Team 運行的穩定性。配合全局規則庫 + 項目規則 + 自動審查機制,可以建立一套完整的代碼品質保證體系,既有通用性,也有靈活性。

    從 Phase 1 的試用開始,逐步優化規則和 Agent Prompt,經過 2-4 週的實踐,可以達到穩定的審查效果。最終目標是讓代碼審查成為自動化流程的一部分,開發者無需手動申請審查,系統自動評估和反饋,確保每個 Task 完成時都經過架構師和 PM 的雙重把關。

  • 【實戰指南】如何為 AI 代理準備資料?Agent Spec 設計指南 — 從 SDD 到代理規格書的完整轉化

    在上兩篇文章中,我們解析了《2026 Agentic Coding Trends Report》的 8 大趨勢,也實際跑了一次雙代理流水線。但實戰中最常被問到的問題是:「我到底要準備什麼資料給 AI 代理?」

    答案不是傳統的 SDD(Software Design Document)。50 頁的 Word 文件會讓代理 timeout。你需要的是一種為 AI 代理設計的輕量規格書——Agent Spec


    一、為什麼 SDD 不適合代理?

    傳統 SDD(給人看的) Agent Spec(給 AI 看的)
    長度 50+ 頁 200 行以內
    包含 背景、歷史、會議記錄、UML 圖 只有「做什麼」「不做什麼」「怎樣算完成」
    表達方式 文字描述 + 圖表 程式碼範例 + 簽名契約
    閱讀方式 多人在不同時間反覆閱讀 一個代理在一次 context 中完整消化
    設計原則 越詳細越好 越精準越好(長度是敵人)

    核心差異:SDD 追求完整性,Agent Spec 追求精準性。代理不需要知道「為什麼要做這個功能」的三頁背景故事,它需要知道「輸入什麼、輸出什麼、邊界怎麼處理」。


    二、Agent Spec 的五個區塊

    一份文件,五個區塊,控制在 200 行以內。以下用「訂單處理功能」為例完整示範:

    區塊一:WHAT — 做什麼(必要)

    這是最核心的區塊。不要寫散文,直接給輸入輸出契約

    ## 功能規格
    
    ### 輸入輸出契約(最重要的部分)
    - 函數簽名:`def process_order(order: Order) -> Receipt`
    - 輸入範例:
      {"item_id": "A001", "qty": 3, "user_id": "U100"}
    - 輸出範例:
      {"receipt_id": "R001", "total": 150.0, "status": "confirmed"}
    - 錯誤回傳:
      raises InsufficientStockError when qty > available
      raises DuplicateOrderError when same order within 1 second
    
    ### 行為規則
    1. 庫存不足時拒絕訂單,不要部分出貨
    2. 同一用戶同一秒內的重複訂單要去重
    3. 金額計算精度到小數點後 2 位
    

    為什麼這樣寫有效?因為代理最擅長的是「根據契約實作」。函數簽名 + 輸入輸出範例 + 邊界條件 = 代理需要的全部資訊。業務背景、產品需求文件、PM 的原始 ticket——這些人類需要,代理不需要。

    區塊二:HOW — 技術約束(必要)

    告訴代理已經有什麼可以直接用。這是最容易被忽略、但最能提升品質的資訊:

    ## 技術約束
    
    ### 必須使用
    - 語言:Python 3.11
    - 框架:FastAPI
    - 資料庫:已有的 PostgreSQL,用 SQLAlchemy ORM
    - 現有模組:from app.models import Order, Product(已存在,直接用)
    
    ### 現有介面(可以直接呼叫的)
    - db.session.get(Product, product_id) -> 查商品
    - db.session.add(receipt) -> 寫入收據
    - redis_client.get(f"order:{user_id}:{hash}") -> 去重檢查
    - from app.services.product_service import get_price -> 取得商品價格
    
    ### 專案結構(讓代理知道檔案放哪裡)
    src/
      models/order.py       -- 資料模型(已存在)
      services/             -- 業務邏輯放這裡
      routes/orders.py      -- API 路由(要在這裡加 endpoint)
    

    為什麼這麼重要?沒有這個區塊,代理會自己發明資料庫連接方式、自己建立 model class、自己設計專案結構——然後跟你的現有程式碼完全不相容。告訴它「已經有什麼」,它就會「用已經有的」。

    區塊三:DON’T — 禁止事項(必要)

    從我們的雙代理實驗中學到的最重要教訓:禁止比允許更重要。AI 的創造空間是無限的,你無法列舉所有「應該做」的事,但你可以明確劃定「絕對不能做」的紅線。

    ## 禁止
    
    ### 絕對不可(違反 = 程式碼作廢)
    - 不可直接寫 SQL(必須用 ORM)
    - 不可在 API handler 裡寫業務邏輯(必須放 service 層)
    - 不可 catch 所有 Exception(必須指定具體類型)
    - 不可新增資料表(只能用現有的 schema)
    - 不可使用 global 變數
    
    ### 不要(違反 = 需要修改)
    - 不要新增依賴套件
    - 不要修改現有的 model 定義
    - 不要寫 print debug(用 logging)
    - 不要硬編碼設定值(用 config)
    

    分層禁止的好處:「絕對不可」是紅線——審查代理看到這些違規應該直接判 FAIL。「不要」是黃線——可以在審查中要求修改。這種分層讓自動化審查變得可行。

    區塊四:DONE — 怎樣算完成(必要)

    這個區塊定義了機器可以驗證的完成標準。如果完成標準只有人能判斷(「程式碼要寫得漂亮」),那自動化流水線永遠跑不完。

    ## 完成標準
    
    ### 代理自檢清單
    - [ ] 所有公開函數都有 type hint 和 docstring
    - [ ] 沒有用到禁止清單中的任何項目
    - [ ] 能處理:正常訂單、庫存不足、重複訂單、無效商品 ID
    
    ### 測試要求
    - [ ] pytest 測試覆蓋率 > 85%
    - [ ] 包含正常路徑、邊界條件、錯誤處理測試
    - [ ] 併發測試(至少 5 個 thread 同時下單)
    
    ### 驗證指令(代理或流水線可以直接執行的)
      pytest tests/ -v --tb=short
      flake8 src/ --max-line-length=120
      mypy src/ --strict
    

    關鍵:給出可以直接跑的驗證指令。這讓流水線可以自動驗證——不需要人來判斷「完成了沒有」,直接跑指令看 return code。

    區塊五:CONTEXT — 最小必要上下文(選用)

    只有當代理需要理解「這個功能在系統中的位置」時才加這個區塊。注意:只放代理需要知道的,不放背景故事。

    ## 上下文
    
    ### 相關檔案(給路徑,不要描述內容)
    - 資料模型:src/models/order.py
    - 現有服務層:src/services/product_service.py(參考這個的寫法)
    - API 路由:src/routes/orders.py(要在這裡加 endpoint)
    
    ### 資料流
    用戶 -> POST /orders -> OrderService.process() -> DB write -> return Receipt
    
    ### 注意事項
    - 這個功能是 v2 重構,舊的 process_order_legacy() 已廢棄但還在程式碼中
    - 資料庫連線用 app.db.get_session(),不要自己建連線
    

    三、不同任務複雜度對應的準備量

    任務複雜度 範例 需要的區塊 Spec 行數 代理配置
    簡單 加一個 API endpoint WHAT + DON’T ~50 行 單代理
    中等 實作一個演算法模組 WHAT + HOW + DON’T + DONE ~100 行 雙代理(寫+審)
    複雜 跨模組的功能開發 全部五個區塊 ~150 行 三代理(寫+審+測)
    大型 多服務協作的功能 拆成多份子任務 Spec 每份 ~80 行 Agent Team + Orchestrator

    大型任務的關鍵:不是寫一份更大的 Spec,而是拆成多份小 Spec。


    四、Agent Team 的致命問題:為什麼會卡死?

    在我們的雙代理實驗中,跑了 5 次才成功。多代理場景下問題更嚴重。以下是常見的卡死模式和解法:

    卡死模式 1:連鎖 Timeout

    # 串聯 3 個代理,每個 300s timeout = 最壞 900s
    Orchestrator -> Agent A (300s) -> Agent B (300s) -> Agent C (300s)
    
    # 如果 Agent A timeout 了,B 和 C 都在空等
    

    解法:每個代理獨立 timeout + 能平行的就平行

    # 架構代理串行(後面都依賴它)
    design = call_agent("architect", spec, timeout=120)
    
    # 實作和測試平行(互不依賴)
    with ThreadPoolExecutor(max_workers=2) as pool:
        impl = pool.submit(call_agent, "implementer", design, timeout=120)
        test = pool.submit(call_agent, "tester", design, timeout=120)
    

    卡死模式 2:髒輸出污染下游

    # Agent A 輸出中文說明而非程式碼
    # Agent B 拿到垃圾 -> 產出垃圾 -> Agent C 也跟著壞
    Agent A: "我建議三種方案..." -> Agent B: "這不是程式碼?" -> Agent C: timeout
    

    解法:每個代理之間加「驗證閘門」

    # 不要直接傳遞
    output_b = call_agent(agent_b, output_a)  # 危險!
    
    # 加驗證閘門
    code = extract_code(output_a)
    if not code:
        raise PipelineError("Agent A did not produce valid code")
    if not code.startswith(("import ", "from ", "class ", "def ")):
        raise PipelineError("Agent A output is not valid Python")
    output_b = call_agent(agent_b, code)  # 只傳驗證過的內容
    

    卡死模式 3:Spec 太長導致代理失焦

    # 500 行的大 Spec -> 代理只看前 100 行,後面的禁止事項被忽略
    call_agent(agent, massive_500_line_spec)  # -> 產出違規程式碼
    

    解法:拆分子任務,每份 Spec 控制在 50-100 行

    # 拆成多份獨立的小 Spec
    subtasks = [
        {"agent": "backend",  "spec": order_service_spec},    # 50 行
        {"agent": "backend",  "spec": order_endpoint_spec},    # 30 行
        {"agent": "tester",   "spec": order_test_spec},        # 40 行
    ]
    
    # 逐個執行,每個都有獨立的驗證
    for task in subtasks:
        output = call_agent(task["agent"], task["spec"], timeout=120)
        validate(output)
    

    五、正確的擴展路徑

    不要一步跳到 5 個代理的複雜系統。正確的路徑是:

    Level 0 -> Level 1:加一個 Reviewer

    # 你現在就可以做的最小改變
    code = call_agent("implementer", spec)
    review = call_agent("reviewer", code)  # 就這一步
    if "FAIL" in review:
        code = call_agent("implementer", f"Fix:\n{review}\n\n{code}")
    

    Level 1 -> Level 2:加自動測試

    # 在審查後加 Tester + 實際執行
    tests = call_agent("tester", code)
    result = run_pytest(code, tests)  # 機器驗證,不靠 AI 判斷
    

    Level 2 -> Level 3:平行化

    # 找出可以平行的步驟
    # 實作和測試可以同時進行(都只依賴 spec,不互相依賴)
    impl_future = pool.submit(call_agent, "implementer", spec)
    test_future = pool.submit(call_agent, "tester", spec)
    

    Level 3 -> Level 4:Agent Team

    # 用 Python Orchestrator(不是 AI)管理流程
    # AI 做思考,Python 做控制
    class Orchestrator:
        def run(self, spec):
            design = self.call_agent("architect", spec)
            self.validate(design)           # 驗證閘門
    
            impl, tests = self.parallel(    # 平行執行
                ("implementer", design),
                ("tester", design)
            )
            self.validate(impl)             # 驗證閘門
    
            review = self.call_agent("reviewer", impl)
            if "FAIL" in review:
                impl = self.call_agent("implementer", fix_prompt)
    
            self.run_tests(impl, tests)     # 機器驗證
    

    六、Agent Spec 模板(直接複用)

    以下是可以直接複製使用的模板,填入你的內容即可:

    # Agent Spec: [功能名稱]
    
    ## WHAT - 做什麼
    ### 輸入輸出契約
    - 函數/API 簽名:
    - 輸入範例:
    - 輸出範例:
    - 錯誤情況:
    
    ### 行為規則
    1. ...
    2. ...
    
    ## HOW - 技術約束
    ### 必須使用
    - 語言/框架:
    - 現有模組(直接 import):
    
    ### 現有介面(可以直接呼叫的)
    - ...
    
    ## DON'T - 禁止
    ### 絕對不可
    - ...
    
    ### 不要
    - ...
    
    ## DONE - 完成標準
    ### 自檢清單
    - [ ] ...
    
    ### 驗證指令
      pytest ...
      lint ...
    
    ## CONTEXT - 上下文(選用)
    ### 相關檔案
    - ...
    
    ### 資料流
    A -> B -> C -> D
    

    七、一句話總結

    SDD 是給人在不同時間反覆閱讀的。
    Agent Spec 是給 AI 在一次 context 中完整消化的。
    精準 > 詳細,200 行 > 2000 行。

    本文是《2026 Agentic Coding Trends Report》深度解析系列的第三篇。系列文章: