標籤: 多代理系統

  • 用 Claude+n8n 打造會自己跑的 AI 工作流

    用 Claude+n8n 打造會自己跑的 AI 工作流

    📌 本文重點

    • 用 Claude /goal/loop 自動化長流程任務
    • 用 n8n 串 API、Email、DB 打造完整工作流
    • 一定要保留「人工審核閘」避免 AI 誤發內容

    用 Claude 搭配 n8n,你可以把「每週拉數據、寫報告、發信或更新網站」這種例行公事交給 AI 自動跑完,只在最後一關人工點頭即可。


    核心功能:這套組合幫你做什麼?

    1. Claude 長任務指令:/goal/loop 讓 AI 自己把事做完

    先理解 Claude 的幾個關鍵指令(在 Claude Code 或支援指令的環境使用):

    • /goal:一次講清楚最終目標,讓 AI 自己拆步驟、規劃流程、按順序執行。
    • /loop:針對一批項目重複跑同一種處理,例如對 50 個關鍵字依序寫摘要、產出標題。
    • /batch:一次處理多筆輸入,適合批次內容生成或批次分析。

    可參考這篇詳細說明:Claude Code: The Autonomous Commands…

    你可以馬上做的事:

    • 在 Claude 裡建一個新專案,貼上你常做的流程(例如「每週 SEO 報表」),試著用這個提示:

    /goal
    目標:我想把「每週 SEO 報表」變成一個自動流程。
    請你:
    1. 問我目前是怎麼做(包含用到哪些工具、檔案格式)
    2. 拆成清楚步驟,分出「AI 可以做」和「一定要人工做」
    3. 用適合 /loop 或 /batch 的地方標註出來


    2. n8n:把 API、Email、資料庫都接在一起

    n8n 是一個開源自動化工具(像是開源版 Zapier),負責把「資料源 → Claude → 發送結果」串起來。

    常用節點大概就是:

    • Trigger:時間觸發(Cron),例如每週一早上 9 點跑一次。
    • HTTP Request / API 節點:去叫 Google Search Console、SEO 工具、你的內部系統。
    • Claude / OpenAI 類節點:把資料丟給 Claude 分析或生成內容。
    • Email / Slack / Notion 節點:把結果送到你或客戶手上。

    你可以馬上做的事:

    • 註冊 n8n(雲端版)或用 Docker 在本機跑:https://n8n.io
    • 開一個最簡單 workflow:
    • Cron → HTTP Request → Email
    • HTTP Request 隨便先叫一個公開 API(例如 Github trending),收回結果後,用 Email 節點寄給自己,確認「API → 自己」這條管線沒問題。

    3. 人工審核閘:一定要保留的「最後一關」

    這一步是整篇文章最重要的重點。

    在一篇實戰分享裡,作者用 Claude + n8n + SE Ranking API 自動產出客戶 SEO 週報,為了省 token 做了一個「優化」:當某些欄位沒資料時,讓 Claude 自己補。結果 Claude 開始用其他客戶的品牌數據去補空缺,還一臉正常,差點寄給一整串客戶,最後是靠人工審核節點擋住了災難(原文連結)。

    💡 關鍵: 再「聰明」的自動化流程也可能補錯資料,最後一關一定要由人審核才能避免嚴重誤發。

    結論:千萬不要把最後的人審自動化掉。

    你可以馬上做的事:

    • 在 n8n 裡加一個「人審」節點(可以是):
    • 把報告先丟到 Slack 私訊給你,附兩個按鈕:Approve / Reject
    • 或者寄到你 Email,只有你手動轉寄給客戶才算「送出」。
    • 規則很簡單:
    • AI 可以草擬與整理
    • 你來決定要不要「正式送出」

    實戰案例:自動 SEO 週報(含人審)

    參考 Reddit 上「Claude is my entire SEO team」的做法(原文),我們做一個最小可行版本:

    流程圖(文字版)

    1. Cron 觸發:每週一 09:00。
    2. 抓數據:n8n 呼叫 Google Search Console / SE Ranking / GA4 API。
    3. 整理成 JSON/CSV:在 n8n 做基本清洗、欄位統一。
    4. 丟給 Claude
    5. 提示大意:

      “`
      你是一位 SEO 分析師。請根據以下資料:
      – 找出本週與上週的主要變化(曝光、點擊、CTR、排名)
      – 標記前三個值得關注的關鍵字或頁面
      – 用「給客戶看的語氣」寫一份 300-500 字報告
      – 最後用 bullet points 給出下週三個具體行動建議

      資料如下(JSON):
      {{data}}
      “`

    6. 產出報告草稿:Claude 回傳 Markdown 或 HTML。

    7. 人工審核閘
    8. n8n 把草稿丟到 Slack 或 Email。
    9. 你檢查內容、改幾句,手動按「OK」。
    10. 正式發送
    11. n8n 把最終版本寄給客戶,存一份到 Notion/GDrive。

    你可以馬上做的事:

    • 不接 API,把第 2 步改成「從 Google Search Console 下載 CSV,手動上傳到 n8n」:
    • n8n workflow:Manual Trigger → Upload(Webhook / Form)→ Claude → Email to yourself
    • 等流程穩定,再把手動上傳改成 API 自動抓。

    多代理與 MCP:什麼時候要用,什麼時候別急著上

    當你開始想:

    • 一個 Agent 負責抓資料
    • 一個 Agent 負責分析
    • 一個 Agent 負責 QA / 測試

    就會踩到「多代理系統」與 MCP(Model Context Protocol)的世界。

    有人已經用 Claude Agent SDK + MCP 做出:

    • 看板(Kanban)每張卡片就是一個開發任務
    • Cron 定時啟動 Claude,為每張卡開一個隔離環境,
    • 拉 repo → 寫 code → Git 提交 → Vercel 建預覽 → 第二個 Claude 做 QA 測試 → 不過就自動重試(案例影片)。

    但實務上,多代理+多個 MCP server 很容易變成:

    • 工具太多、描述太長,模型不斷選錯工具。
    • 每次調用都把全部工具 schema 塞進 context,token 成本暴漲(有研究與實務案例顯示,長 agent run 可能是一般聊天的 1000 倍 token)。

    💡 關鍵: 多代理與 MCP 雖強大,但會大幅拉高複雜度與 token 成本,先把單一流程跑穩再擴充效益最高。

    建議:先把單一流程 + 人審做好,再考慮多代理。

    你可以馬上做的事:

    • 若你不是工程背景,目前只要記得兩件事:
    • MCP = 讓 AI 直接操作一堆內部工具的「插座規格」
    • 「工具越多越好」是錯誤想像,實務上要刻意減少工具數量,讓 AI 比較不會選錯。

    適合誰用:三種典型場景

    角色 / 團隊類型 痛點 可以先做的第一條工作流
    個人創業者 / 獨立站長 每週 SEO 數據、內容企劃很花時間 自動 SEO 週報 + 下週內容建議(保留人審)
    接案顧問 / 行銷代理商 多個客戶週報、月報內容高度重複 客戶週報模板 + 客製評論區,由 Claude 先填、你負責最後一段「專業觀點」
    內容團隊主編 多篇文章排程、更新 meta、內鏈整理 /loop 對多篇文章產出標題、描述,n8n 更新到 CMS 草稿,人工再審核發佈

    工具比較:Claude、n8n 以及類似選項

    名稱 核心功能 免費方案 適合誰
    Claude (Claude Code) 長任務指令(/goal/loop)、多代理、強文字與程式處理 有免費網頁版與有限額度 需要寫報告、寫程式、設計長流程的人
    n8n 視覺化工作流、自動化各種 API/Email/DB 有自架免費版,雲端有免費層 想用「拖拉方式」把不同工具串起來的人
    Zapier/Make SaaS 自動化平台,介面更友善,內建大量整合 有免費層但步數較少 不想部署系統,只想快點測試概念的人

    💡 關鍵: Claude 負責「想與寫」,n8n 和 Zapier/Make 負責「串與送」,搭配起來才能形成真正的自動化流水線。


    怎麼開始:從「一個安全的流程」練起

    按照這個順序,你可以在半天內完成第一條「會自己跑,但有你把關」的 AI 工作流:

    1. 開通帳號
    2. 註冊 Claude 帳號:https://claude.ai
    3. 註冊 n8n(雲端或自架):https://n8n.io

    4. 在 Claude 裡寫清楚你的「流程說明書」

    5. 建一個專屬專案,新增檔案 WORKFLOW.md,內容包含:

      • 你每週報告的步驟
      • 用到資料來源
      • 哪些步驟你不想讓 AI 自動做(例如「最後寄給客戶」)
    6. 做第一個最小工作流(本機測試版)

    7. n8n:Manual Trigger → 手動貼 CSV → Claude → Email 給自己。
    8. 實際跑一次,看 Claude 生成的報告是否接近你平常寫的內容。

    9. 加上人工審核閘

    10. 把收件人改成你的 Slack / 私人 Email。
    11. 只有你手動確認後,才另外轉寄給客戶或上線。

    12. 再考慮進階:API、自動抓數據、多客戶分流

    13. 等你對這條流量和錯誤模式有感覺後,再把手動步驟替換成 API。

    只要守住「AI 做草稿,人做決定」這一條線,你就可以放心把「會自己跑」的工作流丟給 Claude 和 n8n,真正把時間留給需要判斷與創意的事情。

    🚀 你現在可以做的事

    • 在 Claude 建一個專案,照文中範例貼上你的「每週報表流程」並用 /goal 讓它幫你拆步驟
    • 在 n8n 建立「Cron → HTTP Request → Email」或「Manual Trigger → Claude → Email」的最小工作流
    • 為現有任一例行報告加上一個「人工審核閘」,先從「AI 草擬、人來定稿」開始運行
  • AI Middleware 控制層實戰指南

    AI Middleware 控制層實戰指南

    📌 本文重點

    • 直接在業務程式碼呼叫 LLM API 是反模式
    • 需要獨立 AI Middleware 控制層集中治理
    • 控制層是從 demo 到 production 的關鍵分水嶺
    • 多代理與記憶治理必須納入審計與安全設計

    先講結論:直接在產品程式碼裡 fetch('https://api.llm.com') 是一種反模式。當功能從「問答」長成「多工具、多代理、多租戶」時,你會需要一層專門的 AI Middleware 控制層,把:

    • 模型路由與選型
    • Tool / Agent 協調
    • log / trace / metrics
    • 成本與速率限制
    • cache / 重試策略
    • 合規與安全策略注入

    從業務程式碼中抽出來,集中治理。這一層就是 LLM 應用從 demo 到 production 的分水嶺

    💡 關鍵: 把所有 LLM / Tool / Agent 呼叫收斂到單一控制層,是從玩具 demo 變成可維運產品的必要條件


    重點說明:為什麼要獨立 AI Middleware 控制層?

    1. 從「直接 call 模型」到「控制層」

    傳統 Web 三層:UI 層 → Service 層 → DB 層

    LLM 應用如果是:UI → 直接呼叫模型 API,你會發現:

    • 想加 多模型路由(如 GPT + Claude + 本地模型)時,只能四處找出 openai.chat.completions.create 逐一改。
    • 想統一 重試 / 超時 / 灰階 / rollback,根本沒有共同入口可以掛。
    • 想做 成本統計、用戶配額,只剩 trace log 回頭瞎猜。

    控制層的做法是:

    Product Code → AI Middleware(控制層)→ 各家模型 / 工具 / Agent

    所有模型呼叫先經過這一層,才能實作像 API Gateway + Service Mesh 那種集中治理能力。

    2. 控制層的核心職責拆解

    實務上,控制層至少要負責這幾件事(建議直接當 checklist):

    1. 路由與模型選擇
    2. 任務類型、租戶、成本上限、延遲預算 選擇具體模型。
    3. 範例策略:summary 走便宜模型;寫 SQL 走更準確模型;UGC 敏感類先加安全模型前置審查。

    4. Tool / Agent 協調

    5. 統一管理 工具 registry、Tool 調用權限、Agent orchestration。
    6. 在多代理系統中,把「誰能叫什麼工具」和「記憶寫入策略」集中配置,而不是散落在各 Agent 類別裡。

    7. 觀測與追蹤(logs / traces / metrics)

    8. 每個 LLM 請求、工具呼叫、記憶讀寫 都要有 trace id。
    9. 對接 OpenTelemetry 或 APM:把 token 數量、延遲、錯誤碼、cache 命中等變成可查詢的 metrics。

    10. 成本與速率限制

    11. user / org / feature 做 token 配額與 qps 限制。
    12. 將成本計算邏輯(model 單價、權重)集中在控制層。

    13. cache 與重試策略

    14. 根據 prompt 指紋 + 入參 做 deterministic 回答的 cache。
    15. 定義 哪些錯誤可重試、最大重試次數、退避策略,避免在業務層各自實作。

    16. 合規與安全策略注入

    17. 對接 DLP、敏感詞檢測、角色權限,把 prompt / tool call / output 走同一條審查管線。
    18. 企業內部可在這裡插入 審批流(human-in-the-loop)

    💡 關鍵: 成本、風險與合規控制若不集中在控制層,很難在日後擴展時補強而不「大重構」

    3. 審計追蹤與記憶治理:多代理系統必備

    多代理系統與企業場景最常見的兩個雷:

    • 沒有審計 trail:agent 到處點擊、下單、寫 ticket,最後出了事誰也說不清「是第幾步決定下單」?
      → 參考 Reddit 討論:AI agents 比起更多自主性,更需要完整 audit trail。控制層就是自然的落點。

    • 記憶污染嚴重:所有 agent 都能隨意寫向量庫,久了之後充滿過期決策、敏感資料。
      → 引入 Memory Curator 概念:worker agent 只能發出 記憶事件,由專門的記憶治理層決定要不要寫入、寫到哪個 scope(個人 / 團隊 / 專案 / 會話)。

    這兩件事如果不在控制層規範好,就會像 Reddit 上那位開發者形容的:「前三週一切正常,之後 retrieval 變成噪音地獄」。


    實作範例:用 Genkit 與 Vercel AI Gateway 搭 Node / Python 控制層

    下面用兩個路線示範:

    • Node:Google Genkit + Vercel AI Gateway
    • Python:簡易自製 Middleware(搭配 OpenTelemetry

    範例一:Node + Genkit Middleware(含 model 路由與 observability)

    安裝與基礎設定(簡化示意):

    npm install @genkit-ai/core @genkit-ai/openai @genkit-ai/firebase
    npm install @opentelemetry/api @opentelemetry/sdk-node
    

    建立 aiClient.ts 當控制層入口:

    // aiClient.ts
    import { genkit, z } from "@genkit-ai/core";
    import { openai } from "@genkit-ai/openai";
    
    const ai = genkit({
      plugins: [openai()],
    });
    
    // 定義模型路由策略
    const pickModel = (task: string) => {
      if (task === "summary") return "gpt-4.1-mini";
      if (task === "sql") return "gpt-4.1";
      return "gpt-4o";
    };
    
    // 中央統一的生成函數
    export async function generateText(req: {
      task: "summary" | "sql" | "general";
      input: string;
      userId: string;
    }) {
      const model = pickModel(req.task);
    
      // observability: 附上 trace metadata
      const traceMeta = {
        userId: req.userId,
        task: req.task,
        model,
      };
    
      return ai.generate(
        {
          model,
          prompt: req.input,
        },
        {
          // middleware hooks: 可插 retry / cache / logging
          trace: traceMeta,
        }
      );
    }
    

    在 Genkit middleware hooks 中加入 cache / retry / 安全策略(概念程式):

    // middleware.ts
    import { registerMiddleware } from "@genkit-ai/core";
    
    registerMiddleware(async (ctx, next) => {
      const key = hashPrompt(ctx.request);
    
      // 1. Cache 命中
      const cached = await cacheGet(key);
      if (cached) {
        ctx.log.info("cache-hit", { key });
        return cached;
      }
    
      // 2. 成本與速率限制
      await enforceQuota(ctx.trace.userId, ctx.request.model);
    
      // 3. 安全策略:例如 DLP 檢查
      await checkPromptPolicy(ctx.request.prompt);
    
      // 4. 重試包一層
      return retry(async () => {
        const res = await next();
        await cacheSet(key, res);
        return res;
      }, { retries: 2, backoffMs: 200 });
    });
    

    前端 / 服務層就只呼叫 generateText,完全不碰 openai.chat 類 API。未來換模型、加灰階、接別家供應商,只要改控制層即可。

    範例二:Node + Vercel AI Gateway 作為集中入口

    Vercel AI Gateway 提供 統一 endpoint + 多模型路由 + 速率限制 + 規則引擎,很適合當外部控制層。

    基本設定(vercel.json 或 UI 設定):

    • 建立一個 Gateway route,例如:https://ai.yourdomain.com/v1/chat
    • 配置 providersOpenAI / Anthropic / 自建模型。
    • 寫 routing rule:
    • if (task == 'summary') -> openai:gpt-4.1-mini
    • if (tenant == 'premium') -> anthropic:claude-3.7

    前端程式碼(Next.js 伺服器端)只需要呼叫單一 gateway:

    // app/api/ai/route.ts
    import { NextRequest, NextResponse } from "next/server";
    
    export async function POST(req: NextRequest) {
      const body = await req.json();
    
      const res = await fetch(process.env.AI_GATEWAY_URL!, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Tenant": body.tenantId,
          "X-Task": body.task,
        },
        body: JSON.stringify({
          messages: body.messages,
          stream: body.stream ?? false,
        }),
      });
    
      // 這裡可以加 audit log / trace id
      return new NextResponse(res.body, { status: res.status });
    }
    

    優點:

    • 速率限制、成本統計、提供者 failover 直接用 Vercel 的 console 配。
    • 灰階與回滾:改 routing rule 即可,比如 10% 流量導到新模型。

    💡 關鍵: 把流量管理與模型路由交給 gateway,可用設定檔與後台調整,而不必每次動到應用程式碼

    範例三:Python 控制層 + 記憶治理(Memory Curator)

    假設你在做多代理系統,希望 worker agent 不能直接寫入向量庫

    # ai_control_layer.py
    from dataclasses import dataclass
    from typing import Literal, Dict, Any
    
    Scope = Literal["agent", "team", "project", "session"]
    
    @dataclass
    class MemoryEvent:
      scope: Scope
      content: str
      evidence: Dict[str, Any]
      actor: str  # 哪個 agent
    
    class MemoryCurator:
      def __init__(self, store):
        self.store = store
    
      def decide(self, event: MemoryEvent):
        # 簡單篩選:過長、含敏感資訊則拒絕
        if len(event.content) > 2000:
          return "discard"
        if "password" in event.content.lower():
          return "discard"
    
        # 不同 scope 寫不同 index
        index_name = {
          "agent": f"agent-{event.actor}",
          "team": "team-shared",
          "project": "project-global",
          "session": None,  # 只放在 runtime context
        }[event.scope]
    
        if index_name:
          self.store.write(index_name, event.content, event.evidence)
          return f"written:{index_name}"
        else:
          # session-only: 不寫 durable store
          return "session-only"
    
    # worker agent 不直接調 store
    curator = MemoryCurator(store=vectordb)
    
    async def worker_store_memory(proposed_content: str, actor: str):
      event = MemoryEvent(
        scope="project",
        content=proposed_content,
        evidence={"source": "task_result"},
        actor=actor,
      )
      result = curator.decide(event)
      return result
    

    在這個架構下:

    • 所有記憶寫入 都經過 MemoryCurator,可審計、可控。
    • 之後要加 審計 log / OpenTelemetry span 也只改這一處。

    建議與注意事項:常見踩坑與實戰指引

    1. 不要把控制層寫成巨大 God Service

    常見錯誤:

    把所有邏輯(模型路由、prompt 模板、tool orchestration、記憶管理、審批流)塞進同一個 ai_service.ts

    結果:

    • 難以測試、難以灰階、任何小改都要全 redeploy。
    • 無法對特定職責做獨立 scaling(例如工具呼叫爆量時)。

    建議:依職責拆模組,例如:

    • ModelRouter
    • ToolRegistry
    • RetryPolicy
    • QuotaManager
    • MemoryCurator

    控制層本身只是一個 薄 orchestration 層,組裝這些模組,不要變成 monolith。

    2. 一開始就設計可觀測性 schema

    很多團隊是到事故發生後才加 log,結果 schema 雜亂無章,完全無法統計。

    最低限度,請在控制層統一定義以下欄位

    • trace_id / span_id:串起同一個 user request 下的所有模型與工具呼叫。
    • user_id / tenant_id / feature_name:方便做成本報表與配額控制。
    • model_name / provider / tokens_in / tokens_out / latency_ms:跑出模型性能與成本比較。
    • cache_hit / retry_count / policy_blocked (bool):分析策略的實際效果。

    搭配 OpenTelemetry

    • 在 control layer 的入口建立 root span
    • 每個 model_calltool_callmemory_write 建子 span。
    • 把上述欄位當 attributes 寫入。

    3. 灰階與回滾機制不要事後補

    Anthropic 的觀察顯示:非程式碼型 agent 在 production 常常因為資料與流程難控而失敗。這不是模型問題,而是缺乏 安全試錯機制

    在控制層預先設計:

    • 灰階發布:例如新增模型時,只讓 5% 的流量使用;表現不好立即切回。
    • 可以在 Vercel AI Gateway 或內部 router 實作簡單的百分比路由。
    • 策略回滾:策略(例如更嚴格的 DLP、不同記憶寫入規則)要抽成 可配置,而不是寫死在程式裡。
    • 配合 feature flag 平台(LaunchDarkly 等)效果更佳。

    4. 把 audit trail 當成產品需求,不是附加功能

    對多步 agent 流程,請明確要求:

    • 每一步 「想做什麼 → 實際做了什麼 → 結果如何」 都寫 audit log。
    • 在 UI(或 admin console)內提供「代理執行歷史」頁面,讓使用者能依 trace id 看到整條鏈。

    這件事最好放在控制層完成:

    • 所有 tool_call 都經過控制層。
    • 控制層負責序列化成統一格式:

    json
    {
    "trace_id": "...",
    "step": 3,
    "actor": "billing_agent",
    "tool": "update_invoice",
    "input": {"invoice_id": 123},
    "output": {"status": "ok"},
    "started_at": "...",
    "duration_ms": 532
    }

    這直接提升企業客戶的信任度,也方便日後做合規稽核。


    總結: 如果你的專案準備從「demo 給老闆看」變成「真的要上線給客戶用」,請先停下來,把所有 LLM / Tool / Agent 呼叫集中收斂到一個 AI Middleware 控制層。路由、觀測、策略、記憶治理都放在這裡,才能控制成本、降低事故、加快迭代速度。

    🚀 你現在可以做的事

    • 整理專案中所有 openai.chat / fetch('llm') 呼叫點,設計一個統一的控制層介面(如 generateText()
    • 在控制層導入基本的 trace_iduser_idmodel_name log schema,並串接 OpenTelemetry 或現有 APM
    • 為現有的多代理或 RAG 系統設計一個 MemoryCurator 類別,強制所有記憶寫入都經過同一治理入口
  • 把 Claude 變成你的主力工作代理人

    把 Claude 變成你的主力工作代理人

    📌 本文重點

    • 把 Claude 當「可配置代理人」,而非一次性問答工具
    • 善用 Claude.md、Skills、Subagents、Plugins 建立工作流程
    • 針對身份配置專屬 workflow,讓重複工作自動化

    一句話定位:不是再多寫一個 prompt,而是把 Claude 配好「記憶+流程+工具」,變成每天幫你跑任務的主力工作代理人。


    核心功能:先理解這 4 個積木

    目標:看完這一節,你要能說出「Claude 現在在哪裡記東西、怎麼做事、怎麼叫外部工具」。


    1. Claude.md:給代理人一個「長期腦袋」

    • 角色:你的私人知識庫與工作說明書(system prompt 的升級版)。
    • 放什麼:
    • 你的背景(職位、產業、常用技術棧)
    • 任務偏好(寫作語氣、程式碼風格、專案管理習慣)
    • 長期專案的關鍵資訊、慣用模板
    • 使用效果:每次新對話,Claude 自動帶著這份設定,不用再重複解釋自己。

    💡 關鍵: 善用 Claude.md,可以一次設定、長期沿用,省去每次從零解釋背景與偏好的時間成本。

    可以馬上做的事:

    1. claude.ai 登入。
    2. 在設定或 Workspace 設定裡找到 Claude.md 或類似「AI 配置檔」。
    3. 寫第一版內容(建議結構):

    “`markdown
    # 關於我
    – 角色:B2B SaaS 產品經理
    – 常用語言:繁體中文 + 英文技術文件

    # 工作偏好
    – 寫作:偏實用教學,少形容詞,多步驟
    – 文件格式:盡量用 Markdown,標題層級清楚

    # 長期專案
    – 專案 A:AI 產品內部知識庫
    – 專案 B:每週技術選型評估報告
    “`

    1. 日後只要養成習慣:有長期沿用的規則/資訊,就補進 Claude.md,而不是每次對話再講一次。

    2. Skills:可重用的「任務模板」

    • 角色:把你常做的工作,變成一顆一鍵呼叫的小程式。
    • 適合類型:
    • 每週重複的報告(例:每週產品更新摘要)
    • 固定格式的輸出(例:Code review 指南、文章大綱格式)
    • 需要多步驟的任務(例:先讀文件 → 列出問題 → 提出修改建議)

    一個簡單 Skill 範例:專案讀書筆記器

    邏輯:給 Claude 一篇文章連結或貼上內容,Skill 幫你產出固定結構的筆記。

    Skill 內容可以長這樣(概念示意):

    # 技能名稱:research_note
    
    ## 功能
    將一篇文章整理成結構化研究筆記。
    
    ## 輸入
    - `content`: 文章全文或重點摘錄
    
    ## 任務步驟
    1. 先用 3 句話摘要內容。
    2. 條列:關鍵概念、重要數據、引用來源。
    3. 給出:
       - 對我目前專案的啟發
       - 後續可以延伸研究的 3 個問題
    
    ## 輸出格式
    使用 Markdown:
    - 概覽
    - 關鍵概念
    - 數據與引用
    - 對專案的啟發
    - 後續問題
    

    可以馬上做的事:

    1. 在 Claude 介面中找到 Skills(通常在左邊或設定的 Skills / Tools 區)。
    2. 新增一個 Skill,把上面範例貼進去並調整成你的語氣與領域。
    3. 之後看到文章,直接對 Claude 說:

    research_note 幫我整理這篇,內容在下面:


    3. Subagents:把大任務拆給專職小幫手

    • 角色:一個大代理人(你平常在聊的 Claude),底下可以派出「專職分身」。
    • 適合情境:
    • 寫作:資料研究 agent、結構調整 agent、潤稿 agent 各司其職
    • 工程:debug agent、測試覆蓋率 agent、文件撰寫 agent
    • 專案管理:需求整理 agent、風險盤點 agent、會議紀錄 agent

    參考 多代理系統實作文章 的做法,你可以這樣配置:

    • ResearchAgent:只負責找資料、整理重點,不下結論。
    • WriterAgent:只根據整理好的重點寫初稿。
    • EditorAgent:只負責風格、語氣、構優化。

    可以馬上做的事:

    1. 在 Skills 區先各自為 researchwriteedit 建立對應 Skill。
    2. 建一個「總控 Skill」,流程像這樣:

    markdown
    1. 呼叫 ResearchAgent Skill,輸入主題。
    2. 將輸出傳給 WriterAgent Skill,生成草稿。
    3. 將草稿丟給 EditorAgent Skill,優化文稿。

    1. 你對 Claude 下命令就只剩一句:

    用你的寫作工作流幫我處理這個主題:XXX

    這呼應了「Plan 模式比一次搞定更重要」的思路(可參考 這篇 Plan mode 深入解析)。


    4. Plugins / MCP:把 Notion、GitHub、日曆接進來

    • Plugins(或 MCP 伺服器):讓 Claude 能「去別的服務做事」,而不是只在聊天室輸出文字。
    • 常見接法:
    • Notion:讀寫頁面、幫你整理研究筆記
    • GitHub:查 issue、看 PR、寫 review 建議
    • 日曆:生成待辦、排會議時間

    可以馬上做的事:

    1. 在 Claude 設定中找到「Plugins」或「MCP」管理頁面。
    2. 授權你常用的工具(例如 Notion / GitHub)。
    3. 測試一個實用指令:
    4. Notion:

      幫我把這篇研究筆記整理成 Notion 新頁面,放在資料庫「AI Research」底下。

    5. GitHub:

      幫我看這個 PR,先列出潛在風險,再寫一段給同事看的 review。連結在這裡:XXX


    適合誰用:3 種典型配置範例

    目標:對照自己的身份,直接抄一套設定起來。


    1. 個人工作者:寫作 / 研究 / 專案管理

    建議配置:

    • Claude.md
    • 明確定義你的寫作風格、常用結構(例如所有教學文都用「背景 → 步驟 → 範例 → 常見錯誤」)。
    • Skills:
    • research_note:文章/論文筆記
    • outline_builder:輸入主題,自動給 2–3 個不同角度的大綱
    • meeting_minute:貼原始會議筆記,輸出「決策/待辦/風險」三欄
    • MCP / Plugins:
    • Notion 或 Obsidian 相關工具,讓筆記自動進入你的知識庫。

    日常 workflow 範例:

    1. 丟 3–5 篇相關資料給 Claude,用 research_note 各自整理。
    2. outline_builder 產出文章大綱,選一版改一改。
    3. 完稿後請 Claude 依指定格式,寫成 Notion 新頁面並歸檔。

    2. 工程師:Code Review + 多 repo 協作

    建議配置:

    • Claude.md
    • 寫清楚專案技術棧、程式碼風格規範、測試原則。
    • Skills:
    • code_review:給 PR 連結或 patch,輸出:問題清單、風險點、建議 commit 清單。
    • test_case_generator:根據函式/API,幫你列出缺的測試案例。
    • Subagents:
    • ArchitectureAgent:只看架構與邏輯。
    • StyleAgent:只看命名、風格、一致性。
    • MCP / Plugins:
    • GitHub / GitLab 工具,直接讀 PR diff、issue 歷史。

    日常 workflow 範例:

    1. 對 Claude 說:

    幫我用你的 code_review 工作流檢查這個 PR:XXX

    1. Claude 讀 GitHub diff,先由 ArchitectureAgent 看設計,再由 StyleAgent 補充風格問題,最後合併成一份可直接貼回 PR 的 review。

    3. 小團隊:共用一組技能與工作流

    建議配置:

    • 共用 Workspace 的 Claude.md
    • 放團隊寫作規範、技術決策原則、產品定位。
    • 共用 Skills:
    • weekly_update:所有人都用同一個模板輸出週報。
    • spec_template:PRD / 技術規格文件的標準結構。
    • MCP / Plugins:
    • 共用的 Notion、Jira、GitHub 專案權限。

    操作方式:

    1. 由一人負責整理團隊的 Claude.md 和 Skills。
    2. 其他成員只需要:
    3. 在週報時輸入:

      weekly_update 幫我整理這週的進度,重點在 XXX。

    4. 寫新功能時:

      spec_template 幫我產生這個功能的 PRD 初稿,功能說明如下:XXX。


    一小時內用起來:實戰 workflow 示範

    目標:照這段做完,你就有「從資料收集 → 產出大綱 → 自動整理到知識庫」的一套日常代理人流程。


    Step 1:開啟並寫好第一版 Claude.md(10 分鐘)

    1. 打開 claude.ai → 設定 → Claude.md
    2. 貼入這個模板再依需求修改:

    “`markdown
    # 關於我
    – 角色:__
    – 主要領域:
    ____

    # 工作偏好
    – 回覆語言:繁體中文
    – 文件格式:預設使用 Markdown
    – 風格:先給結論,再拆解步驟

    # 長期專案
    – 專案 1:__(簡述目的與目前進度)
    – 專案 2:
    ____
    “`


    Step 2:建立第一個 Skill:研究筆記(10 分鐘)

    1. 到 Skills 管理頁,新增 Skill research_note
    2. 使用前面提供的 research_note 範本,改成你的領域語氣。
    3. 找一篇你最近在看的文章,把內容貼給 Claude,指定使用 research_note

    Step 3:讓 Subagent 接手子任務:大綱生成(15 分鐘)

    1. 新增 Skill outline_builder,內容類似:

    “`markdown
    # 技能名稱:outline_builder

    ## 功能
    針對一個主題,產生 2–3 個不同角度的大綱,每個大綱最多 5 個主標。

    ## 步驟
    1. 簡要理解主題與目標讀者。
    2. 提出 2–3 種切入角度。
    3. 針對每種角度,列出主標與一句說明。
    “`

    1. 建立一個「寫作工作流 Skill」,流程:
    2. 先呼叫 research_note 消化資料。
    3. 再把研究結果摘要丟給 outline_builder
    4. 你只要給主題 + 資料清單,就能一次拿到整理後的研究+多版本大綱。

    💡 關鍵:research_note + outline_builder 串成 workflow,一次輸入主題就能從資料整理到多版本大綱,大幅降低起稿門檻。


    Step 4:接上 Notion,自動寫入知識庫(15–25 分鐘)

    1. 在 Plugins / MCP 介面中,啟用 Notion 並完成授權。
    2. 建一個 Notion 資料庫,叫做「AI 研究庫」。
    3. 對 Claude 下指令:

    從現在開始,所有用 research_note 產出的內容,幫我整理成 Notion 新頁面,放在「AI 研究庫」,標題用日期+主題。

    1. 測試一次完整流程:
    2. 丢一篇文章 → 用 research_note 整理。
    3. 要求 Claude 寫入 Notion。
    4. 打開 Notion 確認格式與欄位是否符合期待,必要時微調規則。

    延伸工具:如果想把多個 AI 輸出集中管理

    如果你平常 Claude / ChatGPT / Gemini 都會用,可以考慮配合像 Coffer 這類工具,把所有 AI 回覆存進一個可搜尋的 vault(原作者分享在 Reddit)。

    名稱 核心功能 免費方案 適合誰
    Claude 主力工作代理人:Claude.md + Skills + MCP 想把 AI 當長期工作夥伴的人
    Coffer 儲存多家 AI 回應到本地可搜尋知識庫 重度問 AI、怕內容散佈的人

    💡 關鍵: 把多家 AI 的回應集中到同一個可搜尋知識庫,可以避免資訊分散在不同聊天裡,長期累積成真正可用的資產。


    只要先把 Claude 當成「可以配置的代理人」,而不只是「一次性的問答工具」,從 Claude.md、Skills 到 Subagents、Plugins 一步步搭起來,你就會開始感受到:每天重複的工作,有越來越多可以丟給它接手。

    🚀 你現在可以做的事

    • 登入 claude.ai,建立並填好你的第一版 Claude.md
    • 新增一個 research_note Skill,實際拿一篇文章讓 Claude 幫你整理研究筆記
    • 啟用 Notion 或 GitHub Plugin,測試一次「從 Skill 輸出到外部工具」的完整工作流
  • 96 個 Gemini Agent 幫你寫系統?

    96 個 Gemini Agent 幫你寫系統?

    📌 本文重點

    • 多 Agent 可複製「多人分工」開發流程
    • Runtime 設計比單純換更大模型更關鍵
    • 用開源工具就能打造迷你版 Antigravity

    用一群 Agent 代替「一個工程師慢慢寫」,解決的是:複雜專案要靠多人分工,AI 也可以用 Runtime + 多代理系統做到同樣的協作和自動化

    核心觀念先講白:模型戰爭差不多打完了,現在比的是誰的 Agent Runtime 能把「模型能力」變成可落地的、多步驟的自動化工作流。

    Google 在 I/O 上展示的 Antigravity 2.0 + Gemini 3.5 Flash 是一個很極端的例子:

    • 96 個子代理分工
    • 12 小時寫完一套從零開始的作業系統
    • Token 成本不到 1,000 美金
    • OS 還能跑《Doom》

    💡 關鍵: 多代理 + 強 Runtime 已經能在「12 小時、不到 1,000 美金」內完成從零開發 OS,顯示關鍵瓶頸不再是模型本身,而是協作與流程設計。

    這不是叫你明天也去做一個 OS,而是提供一個「如何設計多 Agent 開發流程」的範本。下面我們拆成三件你可以直接抄的事:

    1. 多代理分工設計:任務 → 子任務 → Agent 編隊
    2. 強健 Runtime:重試、檢查點、錯誤恢復
    3. 平價版本實作:在你自己的專案做一個「迷你 Antigravity」

    核心功能:Antigravity 2.0 給開發者的三個啟示

    1. 多代理分工:任務 → 子任務 → Agent 編隊

    Antigravity 的做法,其實很像你帶一個遠端工程團隊:

    • 架構師 Agent:決定 OS 的模組切分(檔案系統、排程、驅動、UI…)
    • 模組作者 Agent:各自負責某一個模組的程式碼生成
    • 測試員 Agent:寫測試、跑測試、收斂錯誤
    • 整合者 Agent:把各模組組合、處理相依性、打包成可啟動的系統

    對你來說,可直接套用成一個通用流程:

    1. 寫一個頂層任務描述
      例:建立一個 RESTful CRUD 服務,管理任務(待辦事項),含 API、DB schema、簡單前端。

    2. 讓「架構師 Agent」自動拆解

    3. API 設計與 OpenAPI spec

    4. 後端框架與資料庫層
    5. 前端 UI
    6. 測試與 CI script

    7. 為每個子任務設計 Agent 角色

    8. api-architect-agent:只產出 API spec

    9. backend-agent:根據 spec 產生程式碼
    10. frontend-agent:負責 UI
    11. tester-agent:生成並執行測試
    12. integrator-agent:檢查專案結構、跑 build / lint

    13. 在 Runtime 中定義工作流

    14. 任務圖(DAG):架構師 → 模組作者 → 測試員 → 整合者

    15. 每個節點定義輸入/輸出檔案、工具(Git、DB、HTTP client)

    可行動步驟:

    • 選一個你熟的框架(例如 FastAPI / Next.js
    • 用自然語言寫清楚「最終可交付物」
    • 為這個專案定義 3–5 個 Agent 角色,明確限制各自輸入輸出

    2. Runtime 比模型重要:90% 成功率在多步任務會變災難

    多步任務有一個殘酷數學:

    • 假設每一步成功率 90%
    • 要跑 20 步,整體成功率 ≈ 0.9^20 ≈ 12%

    💡 關鍵: 即使單步有 90% 成功率,20 步工作流成功率只剩約 12%,所以不加 Runtime 管控,多步任務幾乎註定失敗。

    這就是為什麼像 Forge 這種開源 guardrails 會被重視:作者實測,一個 8B 模型在多步代理任務上,從 53% 提到 99% 成功率,完全不改模型,只改 Runtime。

    你在自己的「迷你 Antigravity」裡,要做三件事:

    1. 重試與 nudging

    2. 為每個步驟設 max_retries(例如 3 次)

    3. 失敗時自動加上「修正提示」,例如:上一步測試失敗,錯誤訊息如下,請修正而不是重寫整檔。

    4. 檢查點(checkpoint)

    5. 每完成一個重要子任務,就把中間產出存到 Git / DB

    6. 失敗時從最近的檢查點重跑,而不是重頭來

    7. 錯誤恢復流程

    8. 專門的 debug-agent:只看錯誤訊息 & log,產出修復建議

    9. Runtime 層做:自動建立 bug report、開 issue、指派給對應 Agent

    如果你用 Forge,它已內建:

    • Tool-agnostic 重試策略
    • 步驟執行強制與錯誤恢復
    • VRAM-aware context 管理(對本地模型很重要)
    • 評估套件與 Dashboard,可量化成功率

    可行動步驟:

    • 先把現有「單 Agent 自動流程」改成有重試與 checkpoint
    • 對每個任務記錄:總步數、失敗點、重試次數,在 Dashboard 裡看瓶頸

    3. 平價版本:你也能做一個「迷你 Antigravity」

    你不需要 Gemini 3.5 Flash + Google 內部 Runtime 才能玩多 Agent。下面這些工具可以在自家專案做一個縮小版:

    名稱 核心功能 免費方案 適合誰
    Forge 多步代理 guardrails、重試、Dashboard 開源 想提升本地 / 自架 LLM 可靠性的工程師
    llama.cpp + Qwen 本地 Agent 在個人電腦跑本地模型 + 簡易工具調用 開源 想省雲端費用、在內網跑 Agent 的團隊
    MCP 生態(如 OpenAI MCP、各種 server) 統一的工具協議,讓 Agent 調用資料庫、API 等 多數開源 / 免費 想把既有系統暴露為 Agent 工具的後端工程師

    一個實用組合示例:

    • 模型:Qwen 2.5 7B / 14B(透過 llama.cppOllama 跑)
    • Runtime:Forge 當 guardrails
    • 工具層:一組 MCP server(例如 PostgreSQL、HTTP、Filesystem)

    你可以先做一個「自動搭建 CRUD 服務」的迷你 Antigravity:

    1. 使用者輸入需求(自然語言)
    2. architect-agent 產出設計 + 任務拆解
    3. backend-agent + frontend-agent 寫程式碼
    4. tester-agent 自動開發 & 執行測試
    5. integrator-agentbuild 並回報狀態

    適合誰用:三種典型場景

    1. 後端 / 全端工程師:自動化 CRUD 小專案

    你可以把「打造新微服務」變成一個表單:

    • 輸入資料模型 + 幾個業務規則
    • 多 Agent 流程負責 scaffold、API、測試、docker-compose

    行動:從一個只需要 3–5 小時就能手刻完的小服務開始,先讓多 Agent 幫你做到 70–80%,你只負責 code review。


    2. 資料團隊:資料管線與 ETL 任務

    • planner-agent:解析需求、拆成抽取/轉換/載入步驟
    • sql-agent:產生查詢與 view
    • check-agent:比對 row count、品質指標

    行動:挑一個每天都在重複手動跑的 ETL 任務,做成標準流程,讓 Agent 幫你自動生成 SQL + 驗證報表。


    3. 產品 / PM:快速驗證 Side Project

    • 搭配 Gemini 3.5(雲端)或本地 LLM
    • 定義一個「最小可行功能」(例如 landing page + 簡單 API)
    • 用多 Agent 完成第一版,再丟給工程師接手

    行動:每次新點子,給自己一個規則:「先讓多 Agent 寫一版 Demo,我只在最後 2 小時調整。」


    怎麼開始:一個最小可行範例

    這裡給一條「3–5 小時內可完成」的路線,你可以直接照做:

    步驟 1:選模型 + Agent 框架

    • 模型:
    • 想省錢/本地:Qwen 2.5 7B(透過 llama.cppOllama
    • 想雲端無痛:Gemini 3.5 Flash(透過 Google AI Studio
    • Runtime / 框架:
    • 想要 guardrails:裝 Forge
    • 想用現成 MCP:選一個支援 MCP 的 Agent 框架(如 OpenAI 官方 Agent SDK)

    步驟 2:挑一個小系統

    條件:

    • 單服務、沒有第三方整合
    • 你自己寫大約 3–5 小時能完成

    例:任務管理 CRUD API + 簡單 React 前端

    步驟 3:設計任務拆分與 Agent 角色

    1. 任務描述寫成一個 markdown 檔(會給 architect-agent 看)
    2. 在 Runtime 中註冊 4 個 Agent:
    3. architect
    4. backend
    5. frontend
    6. tester/integrator
    7. 為每個 Agent 明確:
    8. 可用工具(Git、Filesystem、HTTP…)
    9. 輸入(上一個 Agent 的輸出 / 檔案)
    10. 必須產出什麼檔案

    步驟 4:加上監控 Dashboard

    • 如果用 Forge:直接啟用它的 Dashboard,看每次工作流的步驟成功率
    • 若自己實作:
    • 為每個步驟記錄:開始時間、結束時間、是否重試
    • 每次失敗時存 log + 輸入輸出到一個資料夾

    步驟 5:只做一件事的迭代

    • 第一版只要求「能跑起來」,不追求漂亮結構
    • 每次失敗,你只調整:
    • 任務拆分是否太粗/太細
    • Agent 提示是否太模糊
    • 重試與 checkpoint 是否設太少

    等到這個小系統穩定後,你才讓 Runtime 去碰更大的專案。


    小結:Runtime 是你的「AI 開發主管」

    Antigravity 2.0 用 96 個 Gemini Agent 寫出一套能跑《Doom》 的 OS,看起來很遠,但背後用到的概念其實都可落在你今天的 side project 上:

    • 把任務拆成 Agent 可接手的小單位
    • 用 Runtime 管控流程,而不是寄望模型每次都猜對
    • 利用開源工具(Forge、llama.cpp、MCP)做出自己的「迷你 Antigravity」

    💡 關鍵: 關鍵不是再換一個更大的模型,而是把現有模型放進可靠的 Runtime,讓它真的「交付」可用產物。

    關鍵不是再換一個更大的模型,而是先把你手上的模型,放進一個可靠的 Runtime 裡,讓它真的幫你「交付」東西。

    🚀 你現在可以做的事

    • 在 GitHub 上看看 Forge 專案,了解多步代理的 guardrails 怎麼設計
    • 挑一個 3–5 小時能手刻完的 CRUD 小服務,照文中的 4 個 Agent 角色拆任務實作一次
    • 把既有的單 Agent 自動化腳本,加上 max_retries 和簡單 checkpoint 機制,量化成功率變化
  • 12-Factor Agents 實戰:讓 Agent 真正上得了線

    12-Factor Agents 實戰:讓 Agent 真正上得了線

    📌 本文重點

    • LLM/Agent 要先抽象成可替換依賴
    • Prompt/Tool/Memory 行為必須版本化與可回滾
    • 觀測性與成本控管是上線前必備基礎
    • 單體腳本可漸進重構為 12-Factor Agents

    多數 Agent demo 都卡在「好酷,但不敢上線」。12-Factor Agents 的目的,就是把 LLM/Agent 拉回正常軟體工程軌道:
    – 不被單一模型綁死,支援熱切換與灰度升級
    – prompt / tool / memory 都能 versioning + 測試 + rollback
    – 有 token-level log、decision trace,出問題找得到責任點

    下面用 12-Factor 觀念,拆成對工程實作有幫助的 4 個面向,最後用一個簡單 multi-agent pipeline 示範如何重構。


    重點說明

    1. 把 LLM/Agent 抽象成可替換的依賴

    核心做法:不要在業務程式碼裡直接綁某個模型 API,而是統一經過一層 LLMClient / AgentRuntime

    關鍵能力:
    – 用 model alias(如 report-writer@v2)取代具體 gpt-4.1-mini / claude-3.7
    – 支援 routing 策略:A/B test、流量分配、fallback
    – 對外只暴露 統一介面complete() / chat() / stream()

    // llm-registry.ts
    export type ModelAlias = 'planner@v1' | 'crawler@v1' | 'analyst@v2';
    
    interface LLMConfig {
      provider: 'openai' | 'anthropic' | 'local';
      model: string;
      maxTokens: number;
      temperature: number;
    }
    
    const REGISTRY: Record<ModelAlias, LLMConfig> = {
      'planner@v1': { provider: 'openai', model: 'gpt-4.1-mini', maxTokens: 1024, temperature: 0.2 },
      'analyst@v2': { provider: 'anthropic', model: 'claude-3.7', maxTokens: 2048, temperature: 0.1 },
      'crawler@v1': { provider: 'local', model: 'llama-3-8b', maxTokens: 512, temperature: 0.3 },
    };
    
    export function getLLMConfig(alias: ModelAlias): LLMConfig {
      return REGISTRY[alias];
    }
    

    業務端只拿 alias:

    // llm-client.ts
    export async function complete(alias: ModelAlias, messages: ChatMessage[]): Promise<string> {
      const cfg = getLLMConfig(alias);
      const client = getProviderClient(cfg.provider); // 封裝 OpenAI / Anthropic SDK
    
      const res = await client.chat({
        model: cfg.model,
        messages,
        max_tokens: cfg.maxTokens,
        temperature: cfg.temperature,
      });
    
      return res.output;
    }
    

    好處
    – 模型升級只改 registry config,不用全 repo 改 model: 'xxx'
    – 可以針對某 alias 做 灰度發布:10% 流量走新模型

    💡 關鍵: 透過 model alias 把模型細節藏在 registry,可以在不動業務程式碼的前提下做灰度升級與快速回滾。

    2. Prompt / Tool / Memory:行為配置要能 versioning + rollout

    對 Agent 而言,行為大多來自「配置」,而不是 code:
    – system prompt
    – tool schema / API 介面
    – memory 策略(context window、摘要邏輯)

    建議把這些都變成 宣告式 config,並且:
    – 每個 Agent 一個 behavior versionplanner@v1.3
    – 行為改動先跑 離線回放測試 + 小流量試 run

    # configs/agents/planner.v1.3.yaml
    name: planner
    version: v1.3
    model_alias: planner@v1
    system_prompt: |
      你是一個專門規劃網站資料收集與分析的技術 PM。
      - 只產出結構化 JSON
      - 不要寫多餘文字
    
    output_schema:
      type: object
      properties:
        crawl_targets:
          type: array
          items:
            type: object
            properties:
              url: { type: string }
              depth: { type: integer, maximum: 2 }
              notes: { type: string }
    
    memory:
      type: redis
      ttl_seconds: 3600
      key_prefix: planner_session_
    

    載入時明確綁定行為版本:

    // agent-loader.ts
    interface AgentSpec {
      name: string;
      version: string;      // e.g. v1.3
      modelAlias: ModelAlias;
      systemPrompt: string;
      outputSchema: JSONSchema;
    }
    
    export function loadAgentSpec(name: string, version: string): AgentSpec {
      const path = `configs/agents/${name}.${version}.yaml`;
      const raw = fs.readFileSync(path, 'utf8');
      const cfg = yaml.parse(raw);
      return {
        name: cfg.name,
        version: cfg.version,
        modelAlias: cfg.model_alias,
        systemPrompt: cfg.system_prompt,
        outputSchema: cfg.output_schema,
      };
    }
    

    好處
    – prompt 調整可以 像發版一樣受控,支援 rollback
    – tool schema 變更(新增欄位、型別改動)有明確 diff,避免隱性 breaking change

    💡 關鍵: 把 prompt、tool、memory 行為寫進版本化 config,可以像管理程式碼一樣管控變更與回滾。

    3. Observability:token-level log + decision trace + retry 策略

    傳統 APM 看不到「LLM 想了什麼」。受《The Rise of Cognitive Observability》啟發,建議:

    1. token-level log / cost log:每次 call 記錄 prompt_tokenscompletion_tokenscost_usd
    2. decision trace:multi-agent 流程中,記下每一步的:
    3. input
    4. output
    5. 使用的 model / behavior version
    6. tool 呼叫與對應結果
    7. 分類錯誤
    8. infra error(timeout、rate limit)→ 可以 retry
    9. cognitive error(推理錯誤、亂寫 schema)→ 需要 prompt/tool 設計調整
    // observability.ts
    export async function tracedLLMCall(params: {
      agent: string;
      behaviorVersion: string;
      modelAlias: ModelAlias;
      messages: ChatMessage[];
      spanId: string;
    }) {
      const start = Date.now();
      try {
        const res = await rawProviderCall(params.modelAlias, params.messages);
    
        logToWarehouse({
          span_id: params.spanId,
          agent: params.agent,
          behavior_version: params.behaviorVersion,
          model_alias: params.modelAlias,
          latency_ms: Date.now() - start,
          prompt_tokens: res.usage.prompt_tokens,
          completion_tokens: res.usage.completion_tokens,
          cost_usd: estimateCost(res.usage, params.modelAlias),
          raw_output: res.output,
        });
    
        return res.output;
      } catch (e) {
        logError({ span_id: params.spanId, agent: params.agent, error: e });
        throw e;
      }
    }
    

    重試策略

    export async function withRetry<T>(fn: () => Promise<T>, opts = { maxAttempts: 3, backoffMs: 500 }) {
      let lastErr;
      for (let i = 0; i < opts.maxAttempts; i++) {
        try { return await fn(); } catch (e: any) {
          lastErr = e;
          if (!isInfraError(e)) break; // 認知錯誤不要盲目重試
          await sleep(opts.backoffMs * (i + 1));
        }
      }
      throw lastErr;
    }
    

    4. Multi-Agent 任務重構:規劃 → 爬蟲 → 分析 → 報告

    目標:把一個看似「單體腳本」的 agent 流程,拆成可觀察、可恢復的 pipeline。

    服務切分
    planner-service:輸入題目 → 輸出 crawl plan
    crawler-service:依照 plan 用傳統爬蟲抓 HTML / 文本
    analyst-service:對資料做分析與結構化結論
    reporter-service:產出自然語言報告

    狀態管理
    – 任務狀態存在 PostgreSQLMongoDBtasksartifacts
    – 中間資料(暫存內容、短期記憶)放 Redis(key = task:{id}:stage

    隊列與超時
    – 使用 Redis Stream / Kafka / RabbitMQ 做 stage 間消息隊列
    – 每個 stage worker 有自己的 timeout + retry + DLQ(死信隊列)

    // pseudo: task Orchestrator
    async function runTask(taskId: string) {
      const spanId = newSpan();
    
      // 1) 規劃
      const plan = await withRetry(() => plannerAgent.run({ taskId, spanId }), { maxAttempts: 2 });
      await saveArtifact(taskId, 'plan', plan);
    
      // 2) 爬蟲(可能 fan-out 多個 URL)
      await enqueueCrawlJobs(taskId, plan.crawl_targets); // 放到 queue
    
      // 3) 等 crawler 全數完成,再觸發 analyst
      await waitForAllCrawls(taskId, { timeoutMs: 300_000 });
      const pages = await loadArtifacts(taskId, 'crawl_result');
    
      const analysis = await withRetry(() => analystAgent.run({ taskId, spanId, pages }), { maxAttempts: 2 });
      await saveArtifact(taskId, 'analysis', analysis);
    
      // 4) 報告
      const report = await reporterAgent.run({ taskId, spanId, analysis });
      await saveArtifact(taskId, 'report', report);
    
      await markTaskDone(taskId);
    }
    

    回退策略
    – 某 stage 連續失敗 → 使用 上一個穩定 behavior version 重跑
    – 報告無法產出 → 回傳「部分完成」狀態 + 中間分析結果給前端呈現


    實作範例

    以下示範如何把「planner」 agent 做到可替換模型、可版本管理、可觀察的最小實作。

    1. Planner Agent 行為定義

    # configs/agents/planner.v1.0.yaml
    name: planner
    version: v1.0
    model_alias: planner@v1
    system_prompt: |
      你負責規劃完成使用者任務所需的爬蟲與分析步驟。
      僅輸出 JSON,符合 output_schema 定義。
    output_schema:
      type: object
      required: [crawl_targets]
      properties:
        crawl_targets:
          type: array
          items:
            type: object
            required: [url]
            properties:
              url: { type: string }
              depth: { type: integer, default: 1 }
              notes: { type: string }
    

    2. 執行 Planner Agent

    // planner-agent.ts
    import { loadAgentSpec } from './agent-loader';
    import { tracedLLMCall } from './observability';
    import Ajv from 'ajv';
    
    const ajv = new Ajv();
    
    export async function runPlanner(taskId: string, goal: string, spanId: string) {
      const spec = loadAgentSpec('planner', 'v1.0');
      const validate = ajv.compile(spec.outputSchema);
    
      const messages = [
        { role: 'system', content: spec.systemPrompt },
        { role: 'user', content: `任務說明:${goal}` },
      ];
    
      const raw = await tracedLLMCall({
        agent: spec.name,
        behaviorVersion: spec.version,
        modelAlias: spec.modelAlias,
        messages,
        spanId,
      });
    
      let json;
      try { json = JSON.parse(raw); } catch {
        throw new Error('planner_output_not_json');
      }
    
      if (!validate(json)) {
        throw new Error('planner_output_schema_mismatch');
      }
    
      await saveArtifact(taskId, 'plan', json); // 存 DB
      return json;
    }
    

    好處
    – output 一旦 JSON 格式錯誤或 schema 不符合,會被明確標記為 cognitive error,方便後續調 prompt / schema
    – 透過 behaviorVersion 追蹤哪一版規劃器造成問題

    3. 成本暴衝防護

    // cost-guard.ts
    const MAX_COST_PER_TASK_USD = 0.5;
    
    export async function guardCost<T>(taskId: string, fn: () => Promise<T>): Promise<T> {
      const costSoFar = await getTaskCostUsd(taskId);
      if (costSoFar > MAX_COST_PER_TASK_USD) {
        throw new Error('task_cost_limit_exceeded');
      }
      const before = costSoFar;
      const res = await fn();
      const after = await getTaskCostUsd(taskId);
    
      if (after - before > 0.2) { // 單次呼叫超過 0.2 USD
        // 觸發告警
        emitAlert({ taskId, deltaCost: after - before });
      }
    
      return res;
    }
    

    tracedLLMCall 包在 guardCost 裡,就能防止 prompt 異常導致 token 疯狂膨脹。

    💡 關鍵: 設定 MAX_COST_PER_TASK_USD 與單次呼叫成本門檻,可以在成本暴衝前主動阻斷與告警。


    建議與注意事項

    1. 模型抽象層一定要一開始就設計好
    2. provider SDK 完全封裝起來(OpenAI、Anthropic、local),對業務端只暴露 統一型別
    3. 不要在 service 裡直接用 openai.chat.completions.create 這種具體 API。

    4. Prompt / Tool 變更要像 schema migration 一樣看待

    5. 每次變更必須 版本號 + changelog,否則 debug 會非常痛苦。
    6. tool 的欄位移除或語意改變,要視為 breaking change,需要同步更新所有使用該 tool 的 Agent。

    7. Observability 優先級要比「多搞幾個 Agent」高

    8. 沒 trace,multi-agent 只會變成 多倍混亂
    9. 最低限度:每一步的輸入、輸出、模型 alias、behavior version、token 用量都要記。

    10. 模型升級前先做 replay test

    11. 從線上 log 抽一批真實任務,對舊模型與新模型跑一遍,對比:

      • 通過率(JSON parse、schema validate)
      • 任務完成率(可部分人工標註)
      • 成本差異
    12. 不要迷信 retry,可以只是讓錯誤變貴

    13. infra error(timeout、429)才值得 retry
    14. cognitive error(結果不符合 schema / business rule)應該記錄下來,調整 prompt 或 tool,而不是盲目重試

    15. 從單體腳本往 12-Factor Agents 過渡的實務建議

    16. 先做 3 件事:
      • 抽出 LLMClient 抽象層
      • 把 prompt / schema 拉到 config + Git 管理
      • 導入最小版 token cost log + decision trace
    17. 等這三件穩定後,再考慮拆成獨立 microservices 或 multi-agent pipeline。

    照著這套把 demo 重構一次,你會發現:
    – 模型換得比較放心
    – 成本能被預期
    – 最重要的是:Agent 行為變得「可觀察、可控」,才有資格進入生產環境。

    🚀 你現在可以做的事

    • 把現有專案中的 openai / anthropic 呼叫封裝成統一的 LLMClient,並導入 model alias registry
    • 將目前的主要 Agent prompt、tool schema 抽出成獨立 config 檔,放進 Git 做版本管理
    • 為一個關鍵任務流程加入 token 用量與 cost_usd 的記錄,並開始對新模型做 replay test
  • A2A 多代理協議實戰與踩坑筆記

    A2A 多代理協議實戰與踩坑筆記

    📌 本文重點

    • A2A 讓 agents 變成可重用服務,而非每案重寫
    • 協議核心是註冊發現、任務路由與狀態冪等設計
    • 穩定的 A2A 契約可讓框架與部署自由演進

    一旦你有第二個客戶、第二條業務線,原本那套「單體 agent + 一大坨編排器」就會開始失控:每個客戶複製一份 agent 系統、工具無法共享、編排器越寫越巨大。A2A(Agent to Agent)協議的目標就是:用一個標準化通訊協議,把 agent 變成可重用服務,而不是每個專案重造一輪輪子。


    重點說明:A2A 的核心設計

    1. 代理註冊與發現:從「硬編碼 URL」到「可發現的服務」

    單體時代常見寫法:

    // 單體編排器內部硬呼叫
    const result = await routingAgent.handle(request);
    

    一旦你要把同一個 routingAgent 給 N 個客戶用,就需要:

    1. 註冊機制:每個 agent 在啟動時向一個 Registry / Discovery Service 報到:
    2. idshipment-validator
    3. capabilities:支援的任務類型(schema / tags)
    4. endpoint:如 https://agents.mycorp.com/shipment-validator
    5. 發現機制:編排器不再硬編 URL,而是呼叫 Registry API
    GET /agents?task=shipment.validate
    

    得到 agent 清單後再去調用具體 endpoint

    好處:同一組 agent 服務可以給多個客戶編排器共用;換掉實作(LangChain ➝ 自研框架)也只要更新註冊資料。

    💡 關鍵: 透過註冊 / 發現機制,同一個 agent 可被多客戶共用,大幅減少重複實作與維護成本。


    2. 任務路由:編排器既是 server 也是 client

    在多代理場景中,編排器不只是 HTTP server,也必須是 HTTP client

    • 收到來自外部系統、前端的請求:server 身份
    • 需要委派子任務給其他 agents / 其他編排器:client 身份

    一個最小 A2A 任務請求格式可以長這樣(HTTP + JSON):

    POST /invoke HTTP/1.1
    Content-Type: application/json
    X-Trace-Id: 9f2e0a1c-...
    
    {
      "task": "shipment.validate",
      "input": { "shipmentId": "S123" },
      "context": {
        "tenantId": "customer-a",
        "locale": "zh-TW"
      },
      "caller": {
        "agentId": "orchestrator-logistics",
        "replyUrl": "https://orch-a.mycorp.com/a2a/callback"
      }
    }
    

    返回結果:

    {
      "task": "shipment.validate",
      "status": "success",
      "output": {
        "isValid": true,
        "warnings": []
      },
      "error": null,
      "meta": {
        "traceId": "9f2e0a1c-...",
        "agentId": "shipment-validator",
        "durationMs": 324
      }
    }
    

    關鍵點

    • task:描述抽象任務,而不是具體路由 URL,方便 routing / 升級
    • caller.replyUrl:允許非同步回調(長耗時任務、跨 VPC 任務)
    • X-Trace-Id + meta.traceId:貫穿多跳 agent 的追蹤

    3. 狀態、錯誤、冪等:分散式 agent 的生存三寶

    多 agent 跨服務邊界後,你必須清楚回答三件事:

    1. 狀態放哪裡?

    2. 不要把 workflow state 塞在 LLM context 裡。

    3. 建議:

      • 長期業務狀態:外部 DB / 狀態機服務(如 Statewright 類型)
      • 短期呼叫狀態:每個 A2A 請求帶 taskRunId,在 DB 以 event-sourcing 或簡單 JSON blob 存歷程。
    4. 錯誤怎麼傳遞?

    {
      "status": "error",
      "error": {
        "type": "VALIDATION_ERROR",
        "message": "Unknown shipmentId S123",
        "retryable": false,
        "details": { "field": "shipmentId" }
      }
    }
    
    • retryable 很重要:編排器根據這個決定是否自動重試或改走 fallback。

    • 冪等怎麼做?

    • 每個任務呼叫帶 requestId

    {
      "task": "shipment.create",
      "requestId": "create-S123-20240501T100000Z",
      ...
    }
    
    • agent 收到相同 requestId 時,重複回傳同一結果而不是再次寫 DB
    • 真實踩坑:物流「建立訂單 + 發通知」若沒冪等,在重試時會重複發貨或發兩封簡訊。

    💡 關鍵: 為每個任務設計 requestId + retryable,是避免重複扣款、重複發貨等災難級錯誤的關鍵保險絲。


    實作範例:從單體 Agent app 演進到 A2A 系統

    下面是一個極簡版 A2A 實作,基於 Node.js + Express + HTTP + JSON,示範:

    • agent 如何註冊
    • orchestrator 如何發現 + 呼叫
    • 如何保留 traceId、處理重試

    1. Agent 啟動與註冊

    // agent/shipment-validator.ts
    import express from 'express';
    import fetch from 'node-fetch';
    
    const app = express();
    app.use(express.json());
    
    const AGENT_ID = 'shipment-validator';
    const REGISTRY_URL = process.env.REGISTRY_URL!;
    
    async function register() {
      await fetch(`${REGISTRY_URL}/agents/register`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          id: AGENT_ID,
          endpoint: process.env.PUBLIC_URL,
          capabilities: ['shipment.validate'],
          version: '1.0.0'
        })
      });
    }
    
    app.post('/invoke', async (req, res) => {
      const traceId = req.header('X-Trace-Id') || crypto.randomUUID();
      const { task, input, requestId } = req.body;
    
      if (task !== 'shipment.validate') {
        return res.status(400).json({ status: 'error', error: { type: 'UNKNOWN_TASK' }});
      }
    
      // TODO: 查 DB 或外部 API
      const exists = input.shipmentId?.startsWith('S');
    
      res.json({
        task,
        status: 'success',
        output: { isValid: !!exists },
        meta: { traceId, agentId: AGENT_ID }
      });
    });
    
    app.listen(3001, async () => {
      await register();
      console.log('shipment-validator listening on 3001');
    });
    

    2. Registry:最小可用版本

    // registry/index.ts
    import express from 'express';
    const app = express();
    app.use(express.json());
    
    const agents = new Map<string, any>();
    
    app.post('/agents/register', (req, res) => {
      const { id, endpoint, capabilities, version } = req.body;
      agents.set(id, { id, endpoint, capabilities, version });
      res.json({ ok: true });
    });
    
    app.get('/agents', (req, res) => {
      const task = req.query.task as string;
      const matches = [...agents.values()].filter(a =>
        a.capabilities.includes(task)
      );
      res.json(matches);
    });
    
    app.listen(3000, () => console.log('registry on 3000'));
    

    3. Orchestrator:既當 server 又當 client

    // orchestrator/logistics.ts
    import express from 'express';
    import fetch from 'node-fetch';
    
    const app = express();
    app.use(express.json());
    
    const REGISTRY_URL = process.env.REGISTRY_URL!;
    
    async function findAgentForTask(task: string) {
      const res = await fetch(`${REGISTRY_URL}/agents?task=${encodeURIComponent(task)}`);
      const list = await res.json();
      if (!list.length) throw new Error(`No agent for task ${task}`);
      return list[0]; // naive: take first
    }
    
    app.post('/shipment/check', async (req, res) => {
      const traceId = req.header('X-Trace-Id') || crypto.randomUUID();
      const { shipmentId } = req.body;
    
      const agent = await findAgentForTask('shipment.validate');
    
      const requestBody = {
        task: 'shipment.validate',
        requestId: `validate-${shipmentId}`,
        input: { shipmentId },
        context: { tenantId: 'customer-a' },
        caller: {
          agentId: 'orchestrator-logistics',
          replyUrl: null
        }
      };
    
      const resp = await fetch(`${agent.endpoint}/invoke`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Trace-Id': traceId
        },
        body: JSON.stringify(requestBody)
      });
    
      const data = await resp.json();
    
      // 簡化處理,實際上應依 data.status 分支
      res.setHeader('X-Trace-Id', data.meta?.traceId || traceId);
      res.json(data);
    });
    
    app.listen(4000, () => console.log('orchestrator on 4000'));
    

    這樣,你就從原本的「單體 app 內部函式呼叫」,演進到:

    • 多個客戶可以共用 shipment-validator agent
    • 想新增 pricing-agent,只要註冊到 Registry,不改 orchestrator 主程式

    進一步要上 gRPC、使用隊列系統(Kafka / SQS)時,只是把 /invoke 的 transport 換掉,協議 payload 大致可以不變。

    💡 關鍵: 先穩定 JSON 協議,再替換 HTTP、gRPC、Queue 等傳輸層,可以減少大規模重構帶來的風險。


    建議與注意事項:真實踩坑整理

    1. 編排器雙角色帶來的競態條件

    當 orchestrator 既是 server 又是 client 時,常見問題:

    • 同步與非同步混用:一部分任務是同步 HTTP 呼叫,一部分透過 queue 非同步回調,結果狀態管理爆炸。

    建議:

    • 明確區分 請求-回應 vs fire-and-forget 任務 的 API。
    • 在邏輯架構層(可參考 AI Agent Logical Architecture 那篇思路)先畫出 state machine,再實作;工具如 Statewright 類型可以讓流程更可視化。

    2. 訊息格式與 schema 演進

    多客戶、多 agent 之後,改一個欄位就是全網恐慌

    • 務必使用明確的 version 欄位:
    {
      "protocolVersion": "a2a-1.1",
      "task": "shipment.validate",
      ...
    }
    
    • 新增欄位 ➝ 預設 optional,舊 agent 收到可忽略。
    • 刪除 / 改名欄位 ➝ 用 Deprecation window(先標註 deprecated: true 一段時間)。

    3. 重試與冪等:不要指望下游「應該沒事」

    在多代理系統裡,任何一跳都可能:

    • timeout
    • 500
    • 只執行了一半邏輯

    建議:

    • 所有會造成 side effect 的任務必須有 requestId
    • 在 DB 以 (requestId, task) 做唯一索引
    • 重試時以 requestId 查找舊結果,若存在則直接回傳

    4. 日誌與追蹤:traceId 一定要往外帶

    常見錯誤是只在 API gateway 或第一個 service 打 log。多 agent 下:

    • 每個 A2A 呼叫都要帶 X-Trace-Id header。
    • 每個 agent 回傳結果時,把自己的 agentIdtaskdurationMs 打到 log。
    • 方便之後在 log system(如 ELK / OpenTelemetry)中串連整條 workflow。

    5. 和 MCP、serverless 編排器整合時的性能與隔離

    • MCP / LangChain / LlamaIndex 等框架
    • 不要把所有工具都塞進同一個 process;可以把重型工具封裝為獨立 agent,透過 A2A 呼叫,避免單一框架 process 變成巨石。
    • Serverless 編排器(如 Step FunctionsTemporal
    • 用 A2A 把「呼叫 agent」當成一個 task type。
    • 注意冷啟動 + LLM 啟動成本:盡量把 agent 部署為長跑服務,serverless 只負責 orchestration。
    • 隊列系統整合(Kafka / SQS / RabbitMQ
    • A2A 協議層仍用同一份 JSON schema,只是 transport 從 HTTP 換成 message。
    • 確保 message 中也有 traceIdrequestIdtaskprotocolVersion,否則 debug 會極其痛苦。

    總結

    • A2A 的本質不是某個框架,而是一套清楚的多代理通訊契約
    • 一旦協議穩定,你可以自由更換 LLM、agent framework、部署方式,但還能:
    • 在多客戶間重用同一組 agents
    • 控制編排器複雜度
    • 在真實生產環境中可觀測、可回溯、可演進。

    如果你已經有一個「會動但很醜」的單體 agent app,建議先抽出最常用的 1–2 個子任務,照上面的 minimal A2A 協議拆出去,從那裡開始演進,而不是一次重寫全系統。

    🚀 你現在可以做的事

    • 把現有單體 agent app 中 1–2 個常用任務,先按文中 JSON 協議拆成獨立 /invoke 服務
    • 為這些任務統一增加 requestIdX-Trace-Id,並在日誌中打出 agentIdtaskdurationMs
    • 實作一個最小版 Registry(照文中 registry/index.ts),讓 orchestrator 透過發現機制而不是硬編 URL 呼叫 agents
  • Symphony 與自管 Agent 的技術拆解

    Symphony 與自管 Agent 的技術拆解

    📌 本文重點

    • 讓 Agent 主動拉工單並自排程,減少工程師 babysit
    • 採用混合 Multi-Agent 模式與明確權限邊界
    • 透過 Task Queue + Worker + 審批閘門串起從工單到 PR 的全流程

    人類注意力已經成為工程團隊採用 AI 助手的主要瓶頸:Agent 能寫 code,但你要一直盯著它。Symphony 類的自管 Agent 系統,直接改變的是這件事:

    從「工程師 babysit 多個 Agent」→「Agent 自己從 Linear / Jira 拉工單、自排程、跑完整個 CI/CD pipeline,只在關鍵節點請你按一次 Approve」。

    下面從實作角度拆解:如何設計任務拉取、Multi-Agent workflow、與 CI/CD 權限邊界;最後給一個「自動修 bug → 開 PR → 回寫 Linear 狀態」樣板。


    重點說明

    1. 工單拉取與任務自排程

    核心是讓 Agent 變成一個長壽命 worker,定期從任務池拉工單,而不是被動等待 API 呼叫。

    工單來源

    • Linear: /issues, /webhooks, /comments
    • Jira: /rest/api/3/search, /rest/api/3/webhook

    Polling vs Webhook

    • Polling(簡單好 Debug)
    • 優點:
      • 實作簡單,只要定時 cron + API token
      • 不怕 webhook misconfig / 防火牆問題
    • 缺點:

      • 有延遲(30s–5min)
      • 需要自己做去重 / 任務狀態同步
    • Webhook(推薦長期方案)

    • 優點:
      • 事件即時觸發,適合高優先 bug / incident
      • 可根據事件類型直接分路由(bug vs feature)
    • 缺點:
      • 需要公開 endpoint + 驗簽
      • 部署與權限設定更複雜

    實務上常用 混合策略

    • Webhook 處理新建 / 更新事件
    • Polling 每隔 5–10 分鐘做 reconcile,修正漏觸發 / 失敗同步

    💡 關鍵: 用「Webhook 即時 + 每 5–10 分鐘 Polling 校正」的混合策略,可以在保持即時性的同時降低漏事件風險。

    任務分派與併發控制

    • 任務表核心欄位建議:
    • id, source(issue_id), priority, status(queued/running/failed/done), agent_type, lock_owner, lock_expires_at
    • 分派策略可以簡化成:
    • 優先級隊列:依 Linear priority / label 映射成數值
    • 技能匹配:根據 label → agent_type(例如 frontend, backend, infra

    併發與重試控制的關鍵:樂觀鎖 + visibility timeout

    -- 簡化的任務鎖定 SQL
    UPDATE tasks
    SET status = 'running', lock_owner = :agent_id, lock_expires_at = NOW() + interval '15 minutes'
    WHERE id = (
      SELECT id FROM tasks
      WHERE status IN ('queued', 'failed')
        AND (lock_expires_at IS NULL OR lock_expires_at < NOW())
      ORDER BY priority DESC, created_at ASC
      LIMIT 1
      FOR UPDATE SKIP LOCKED
    )
    RETURNING *;
    

    好處

    • 避免多個 Agent 搶同一張工單
    • Agent 崩潰 / timeout 時,lock 過期後可被其他 Agent 接手(類似 SQS visibility timeout)

    2. Multi-Agent:中心協調 vs 任務接力

    現代多 Agent 系統基本都落在兩種模式上(參考 Agents as Tools vs Handoffs)。

    模式 A:中心協調(Agents as Tools)

    • 一個「指揮官」Agent + 多個「工具」Agent
    • 主 Agent 保留全局 context 與決策權,子 Agent 像 function call

    • 示意(虛擬 code):

    const orchestrator = new OrchestratorAgent({
      tools: {
        codeAgent: callCodeAgent,
        testAgent: callTestAgent,
        infraAgent: callInfraAgent,
      }
    });
    
    await orchestrator.run({
      goal: "Fix bug #123 in service A and deploy to staging",
      constraints: { require_approval_for_deploy: true }
    });
    

    適合

    • 需求不明確,需要動態拆解子任務
    • 需要統一治理(quota、安全策略、審計)

    模式 B:任務接力(Handoffs)

    • 任務隨流程在 Agent 之間流動
    • 每個 Agent 處理完就寫結果 + 下一步指派
    // task.payload 示例(存在 DB / Task Queue)
    {
      "status": "code_fixed",
      "next_agent": "test_agent",
      "artifacts": {
        "branch": "fix/BUG-123-null-pointer",
        "diff_summary": "..."
      }
    }
    

    適合

    • Pipeline 已穩定(bugfix → test → PR → notify)
    • 易於水平擴展,每個 Agent 是一組 worker

    實務建議:多數專案採用 混合

    • 一個 中心協調 Agent,但遇到標準化步驟(跑測試、開 PR、通知 Slack)時,交給 固定 handoff stage 的 worker;類似「主流程由 LLM 控制,heavy lifting 由 deterministic step 執行」。

    💡 關鍵: 把「決策」交給中心協調 Agent,把「重複且標準化的步驟」交給固定 worker,可以在保持靈活度的同時確保穩定性與成本可控。


    3. 與 CI/CD、code review、事故流程整合

    自管 Agent 的威力,取決於你如何設計 權限邊界 + 審批閘門

    權限邊界設計

    • Repo 層級:
    • 建立專用 GitHub App / GitLab Token,只開放:
      • repo:contents:write(但限制特定 org / repo)
      • pull_request:write
    • 禁止直接 push main / production branch
    • 環境層級:
    • Agent 只允許:
      • Deploy 到 staging / preview env
      • 觸發 read-only incident tooling(查 log、查 metrics),不要一開始就給 rollback / scale 權限

    審批閘門(approval gate)

    • 在 CI pipeline 加一個手動 stage,例如 GitHub Actions:
    jobs:
      tests:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - run: npm test
    
      deploy_staging:
        needs: tests
        if: github.actor == 'agent-bot'
        environment:
          name: staging
          # GitHub Environments 的 Reviewers 即是 approval gate
        steps:
          - run: ./deploy-staging.sh
    

    審計 log

    • 每個關鍵行為都應落地:
    • 取得工單(issue_id, agent_id, reason, time
    • 對 repo 的修改(branch, commit_sha, diff_summary, tests_run
    • 任何 CI/CD trigger(workflow_id, inputs, result

    • 建議統一經過一個 AuditService.log(event)

    await AuditService.log({
      actor: "agent-bot",
      action: "CREATE_PR",
      metadata: {
        issue_id: "ENG-1234",
        repo: "org/service-a",
        branch: "fix/ENG-1234-null-pointer",
        pr_url: "https://github.com/..."
      }
    });
    

    💡 關鍵: 把權限鎖在「staging + PR 層級」並配合審批閘門與審計 log,可以在不影響生產安全的前提下,讓 Agent 最大化自動化範圍。


    實作範例:從 Linear 抓 bug → 開分支 → 修 code → 開 PR → 回寫狀態

    以下是一個縮小版 blueprint,你可以直接改成自家 stack。

    1. 任務入口:Linear Webhook + 任務表

    Linear Webhook 指向你的 /linear/webhook

    // Express 風格
    app.post('/linear/webhook', async (req, res) => {
      const event = req.body;
    
      if (event.type === 'IssueCreated' || event.type === 'IssueUpdated') {
        const issue = event.data;
    
        // 僅處理 bug + 特定 team
        if (issue.team.key === 'ENG' && issue.labelNames.includes('bug')) {
          await TaskRepo.enqueue({
            source: 'linear',
            source_issue_id: issue.id,
            priority: mapLinearPriority(issue.priority),
            agent_type: 'bugfix',
            status: 'queued'
          });
        }
      }
    
      res.sendStatus(200);
    });
    

    2. Bugfix Agent Worker(核心 loop)

    async function bugfixWorkerLoop() {
      while (true) {
        const task = await TaskRepo.acquireNext('bugfix', process.env.AGENT_ID);
        if (!task) {
          await sleep(5000);
          continue;
        }
    
        try {
          const issue = await LinearApi.getIssue(task.source_issue_id);
          const repo = mapIssueToRepo(issue);
          const branch = `fix/${issue.identifier}-${slug(issue.title)}`;
    
          await GitService.createBranch({ repo, from: 'main', branch });
    
          const diff = await CodeAgent.fixBug({
            repo,
            branch,
            issue_description: issue.title + '\n\n' + issue.description,
            files_hint: inferRelatedFiles(issue)
          });
    
          await GitService.commitAndPush({ repo, branch, message: `fix: ${issue.identifier}` });
    
          const pr = await GitService.createPR({
            repo,
            branch,
            base: 'main',
            title: `[Agent] Fix ${issue.identifier}: ${issue.title}`,
            body: renderPRBody(issue, diff)
          });
    
          await LinearApi.updateIssue(task.source_issue_id, {
            state: 'In Review',
            descriptionAppend: `\n\nLinked PR: ${pr.url}`
          });
    
          await TaskRepo.markDone(task.id);
        } catch (err) {
          await TaskRepo.markFailed(task.id, { error: String(err) });
        }
      }
    }
    

    關鍵點

    • CodeAgent.fixBug 本身可以是一個 Symphony / Claude Managed Agent:
    • 有自己的工具:get_file, apply_diff, run_tests
    • 有自己的「Outcomes」條件(例如:測試必須綠燈、diff 不能超過 500 行)
    • Worker loop 要能容錯:task failure 不要直接 crash process

    3. 錯誤恢復與常見坑

    (1) stale context / 版本衝突

    • 現象:Agent 基於舊 commit 生成 patch,push 時發現 remote 已有新 commit
    • 對策:
    • createBranch 前先 git fetch + 檢查 main 是否有新 commit
    • 若有衝突,改用 rebase + 再跑一次 CodeAgent,或直接加標籤請人工處理

    (2) 任務飢餓(某些工單一直排不到)

    • 常見原因:
    • 單純用 FIFO,長工時任務卡住隊列
    • 高 priority 任務一直插隊
    • 對策:
    • 採用 優先級 + aging:等待時間越久,自動提高 effective priority
    • 給長任務單獨的 queue 或 agent_type

    (3) 被動等待人工決策,Agent 資源被佔住

    • 例如:Agent 開 PR 後要等 Reviewer,期間 worker 就 idle with lock
    • 對策:
    • 把「等待人工」拆出成另一個狀態:
      • 任務設為 status = waiting_human
      • PR merge / Linear 狀態變更時再由 webhook 建下一個 task(例如 deploy)

    (4) AI 決策不穩(修了錯問題)

    • 這是現在 Agent 最大痛點之一(參考「AI is getting better at doing things, but still bad at deciding what to do」)。
    • 對策:
    • CodeAgent 設定明確 Outcome 定義
      • 測試要準備好一組 reproduction test
      • 用獨立 Evaluator Agent 根據 log / diff 給出 pass / needs-clarification
    • 讓 Agent 更常問問題:若重現步驟不完整,直接在 Linear 開 comment 要求補充,而不是盲修。

    建議與注意事項

    1. 從「觀察型 Agent」開始,不要一開始就給寫入權限

    2. 先只允許:讀工單 → 產生修復方案 / diff 草稿 → 貼回 Linear。穩定後再打開 PR 寫入、最後才接 CI/CD。

    3. 集中化審計與開關

    4. 所有 Agent 行為走一個 Agent Gateway / Orchestrator,集中:

      • 配額控制
      • 風險開關(feature flag 一鍵關掉所有 auto-deploy)
      • log / metrics / alert
    5. 明確定義「哪一段流程可以 0 人工」

    6. 常見安全配置:

      • bugfix PR 可以由 Agent 全自動產生,但 merge 必須人工
      • staging deploy 可自動,production deploy 必須經 Slack / PagerDuty approve
    7. 將 Agent 視為「非穩定服務」而非傳統微服務

    8. 接受它偶爾會做奇怪決策,因此整個系統必須:

      • 有清楚的 rollback 路徑
      • 任務永遠由 queue 控制,不綁死在單一 process
      • 重要資源(code、infra)永遠有 versioning + 審批

    如果你已經有 Linear / Jira + GitHub + CI/CD 的基本骨架,其實不用重建世界:

    只要加上一個 Task Queue + Agent Worker + 守門的 Orchestrator/Approval Gate,你就能讓 Symphony 類的自管 Agent 為團隊接手一條完整的「從工單到 PR」流水線,真正從盯著 Agent 寫 code,變成只盯少數關鍵決策點。

    🚀 你現在可以做的事

    • 在現有 Linear / Jira 加一個 Webhook,寫入自建的 tasks 資料表作為任務池
    • 實作一個最小版 bugfixWorkerLoop,先只產生修復方案與 diff 草稿貼回工單
    • 在 CI/CD 中加入只對 agent-bot 生效的 staging deploy job,並配置 GitHub Environments 審批閘門
  • Claude Code:把你的一人開發組變成小團隊

    Claude Code:把你的一人開發組變成小團隊

    📌 本文重點

    • Claude Code 扛「從 issue 到 PR」整條開發流程
    • 百萬 token 上下文,能做跨檔案大規模重構
    • 與 issue 管理工具整合,連動任務與代碼
    • 把它當工作流 Agent,而不是單純寫程式助手

    Claude Code 要解決的問題很單純:不要只幫你「寫幾行程式」,而是幫你「從 issue 到 PR 到 release note」整條開發流程一起扛掉。

    Claude Code 官方頁面|參考閱讀:Claude Code Isn’t a Coding Tool. It’s Your Team’s New Workflow Engine.


    核心功能:不只是會寫程式的 Chatbot

    1. 百萬上下文 + 跨檔案重構

    Claude Code 的關鍵不是「會寫程式」,而是一次看得懂整個專案:

    💡 關鍵: 百萬 token 上下文讓 Claude Code 能一次理解整個大型 repo,支援跨模組重構與設計級別調整。

    • 支援百萬 token 上下文,實務上可以:
    • 一次讀完整個 monorepo 的關鍵目錄
    • 同時理解前後端、infra、文件
    • 實際能做的事:
    • 統一命名規則、API 介面:
      • 指令範例:

        「請在整個 apps/webpackages/api 裡,把 user profile 統一改成 UserProfile 類型,並更新相關型別定義與呼叫點。」

    • 大規模重構:改 routing、auth、logging 邏輯,而不是只改單一檔案

    行動建議:
    – 第一次用時,直接把「專案關鍵資料夾」拖進 Claude Code,請它輸出:
    – 架構圖
    – 主要模組關聯
    – 技術債/風險清單

    2. 代碼審查 + 任務追蹤

    Claude Code 把「code reviewer + 小 PM」包在一起用:

    • 代碼審查:
    • 貼 PR diff 或讓它自己產生 patch,請它從幾個角度審查:
      • 可讀性
      • 安全性
      • 可測試性
    • 指令範例:
      > 「這個 PR 幫我做 code review,重點看:1) SQL 注入風險 2) log 裡有沒有可能洩漏個資。」
    • 任務追蹤:
    • 你丟一串 TODO、散落在註解、issue 裡,它可以:
      • 幫你整理成任務列表
      • 按複雜度排序
      • 標註依賴關係

    行動建議:
    – 把你專案裡的 // TODO 集中給 Claude Code,看它幫你:
    – 分成「1 小時內可完成」「需要討論設計」兩類
    – 生成對應 Issue 描述(等下一小節接管理工具)

    3. 與 Linear / Jira 等管理工具整合

    重點不是「Claude Code 會寫 issue」,而是它能 自己對應任務 ↔ 代碼

    • 典型流程:
    • 從 Linear / Jira 拉某個 issue 描述
    • Claude Code:
      • 解析需求
      • 找出相關檔案
      • 建議實作方案
      • 產生 patch / commit 訊息
    • 回寫到對應 issue(附 PR link、測試說明)
    • 這讓你可以用一句話驅動整個流程:
    • 「幫我處理 Linear 上 FE-1234 這張 ticket,照 acceptance criteria 寫完測試再開 PR。」

    行動建議:
    – 把團隊目前的 issue 模板、PR 模板貼給 Claude Code,請它:
    – 照樣學習格式
    – 以後所有「產生 PR 描述 / 測試計畫」都統一風格


    適合誰用?三種典型場景

    1. 單人開發者:讓 Claude Code 當你的 PM + Reviewer

    你一個人接案或做 side project,沒人幫你看架構、沒人幫你 review。Claude Code 可以扮演:

    • 專案 PM:
    • 幫你把「腦中需求」變成 roadmap:
      • 「這個月要完成:會員系統 v1、簡單報表」
    • 轉成 task list:db schema、API、UI、測試
    • code reviewer:
    • 每次 commit 前,請它檢查:
      • 功能風險
      • 重複邏輯
      • 可抽共用函式的地方

    具體做法:
    – 建立一個持續使用的 Claude Code 專案,放:
    – README、需求文件、todo list
    – 一份「我寫程式的偏好」(語言、框架、lint 風格)
    – 每天開工前一句:

    「根據目前 repo 與 TODO,幫我排今天 3 個最值得做的 task,控制在 3 小時內。」

    2. 小團隊:讓它維護 issue、測試、技術文件

    對 3–10 人團隊,Claude Code 好用在「把大家都懶得做的事」接走:

    💡 關鍵: 對 3–10 人的小團隊,把 issue 清理、測試補齊與文件生成交給 Claude Code,可顯著減少非核心開發時間。

    • Issue 維護:
    • 每週讓 Claude Code:
      • 清理過期 / 重複 issue
      • 把描述不清的 issue 重新改寫
    • 測試補齊:
    • 對於已存在的功能程式碼:
      • 要求它列出「目前缺哪些層級的測試」
      • 自動產生 test skeleton(unit / integration)
    • 技術文件:
    • 從 commit / PR 摘要產出:
      • 變更日誌
      • ADR(Architecture Decision Record)草稿

    具體做法:
    – 選一個模組先試點,例如「會員系統」:
    1. 把現有 PR、issue 歷史餵給 Claude Code
    2. 要它輸出一份「會員系統說明文件 v0」
    3. 團隊一起 review,修改後當作標準模板

    3. 大批量重構 / 遷移專案:讓它拆成可執行任務

    當你在做:
    – 從 JS → TS
    – 從 REST → GraphQL / gRPC
    – 從單體 → 模組化

    這時 Claude Code 的長上下文 + 任務拆解很實用:

    • 一次吃下:
    • 主要模組目錄
    • 現有測試
    • 部署設定
    • 輸出:
    • 分階段遷移計畫
    • 每階段具體改哪些檔、會壞掉什麼

    具體做法:
    – 問 Claude Code:

    「假設我要在 4 週內把 services/auth 從 JS 遷移到 TS,請在不影響現在線上環境的前提下,拆成 4 週計畫,每週列出可以單獨合併的 PR 列表。」


    怎麼開始:從註冊到跑完一條完整 workflow

    步驟 1:註冊與開啟 Claude Code

    1. claude.ai 註冊帳號(可用 Google / Email)。
    2. 登入後,點右上角 Code 進入 Claude Code 介面。
    3. 建議準備:
    4. GitHub repo 連結
    5. 專案 README、需求文件

    步驟 2:連接 GitHub / 專案庫

    目前常見兩種用法:

    • 直接拖拉檔案夾:
    • 小專案、side project 最快
    • 接 GitHub:
    • 依照介面授權,把指定 repo 掛上去
    • 在對話裡直接叫它打開某個檔案路徑,再請它操作

    行動建議:
    – 先選一個風險較低的 repo(side project 或工具庫)當實驗場,不要一開始就丟公司核心系統。

    步驟 3:示範一條具體 workflow

    以「從 TODO issue → 產生 PR → 自動寫 release note」為例:

    1. 整理 TODO
      在 Claude Code 裡貼上:
    2. 一個 Linear / Jira issue 內容,或
    3. 散落在程式裡的 TODO 註解

    請它:

    「幫我把這些 TODO 整理成一個明確的 issue 描述,列出 acceptance criteria。」

    1. 讓它實作並產生 PR
      接著說:

      「根據這個 issue,在目前 repo 裡完成實作,請:1)列出要改的檔案 2)給我完整 patch 3)附上測試建議。」

    你可以:
    – 先人工 review patch
    – 把 patch 套進本地分支
    – 提交 GitHub PR

    1. 自動寫 release note
      PR 開好後,把:
    2. PR diff / 連結
    3. 關聯 issue 連結

    貼給 Claude Code,指令:

    「幫我寫一段 release note,給非工程同事看的,限制 150 字內,列出 2-3 個 bullet point。」

    若你有一份既有 release note 模板,也一起貼上,請它照模板格式輸出。

    做完一次,你就有一條可重複的最小 workflow,之後只要換 issue 就能重跑。


    進階玩法:把 Claude Code 變成「小開發團隊」的一員

    1. 和輕量模型分工,省錢跑批量任務

    很多工作不需要 Claude 這種大模型,例如:
    – 大量 JSON 重新排版
    – 批次分類檔案
    – 從文字裡抽欄位

    參考這篇 Reddit 實作:Most of my Claude usage was on work that didn’t need Claude

    做法:
    – 另外架一個便宜的小模型 API(例如 DeepSeek V4 Flash
    – 在 Claude Code 這邊只放一個規則:
    – 「遇到格式轉換、摘要這種機械工作,一律呼叫那個外部工具,不要自己算」

    💡 關鍵: 把機械式任務交給便宜模型,可將大量批次任務成本壓到原本的約 1/10。

    效果:
    – 大量批次任務成本可壓到原本的 1/10 甚至更低

    2. 搭配 Relay 這類插件,讓多個 Claude Code 會話互通

    如果你常同時開:
    – 一個 session 管 backend
    – 一個 session 管 frontend
    – 另一個管 infra / CI

    可以照這篇的做法:built a plugin so my parallel Claude Code sessions can message each other

    概念是:
    – 用像 Relay 這種小工具,讓不同 Claude Code 視窗可以互相發訊息
    – 例如:
    – 前端 session 問:「User object 現在長怎樣?」
    – 後端 session 直接回,結果推回前端視窗顯示

    實際好處:
    – 你不用在多個對話間複製貼上
    – 等於有好幾個專職「子工程師」在各自 repo 幫你跑任務,互相同步狀態


    小結:把 Claude Code 視為「工作流 Agent」,不是「更聰明的 Copilot」

    使用 Claude Code 的關鍵心態是:
    – 不要只問「幫我寫這個 function」
    – 要改成「幫我把這個 issue 從需求 → 設計 → 實作 → 測試 → 文件,一次帶完」

    先從一條最小 workflow 開始做起(例如本文的 TODO → PR → release note),再逐步接上 issue 管理、測試、自動文件,Claude Code 才會真正變成你開發流程的一部分,而不是多一個可以聊天的 IDE 工具。

    🚀 你現在可以做的事

    • 選一個風險低的 repo,丟進 Claude Code,請它產出架構圖與技術債清單
    • 把現有的 issue / PR 模板貼給 Claude Code,讓它學會之後統一產生描述與測試計畫
    • 實做一次「TODO → issue → PR → release note」完整 workflow,確認能在團隊內重複使用