標籤: 多代理系統

  • 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,確認能在團隊內重複使用