📌 本文重點
- 讓 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 要求補充,而不是盲修。
建議與注意事項
-
從「觀察型 Agent」開始,不要一開始就給寫入權限
-
先只允許:讀工單 → 產生修復方案 /
diff草稿 → 貼回 Linear。穩定後再打開 PR 寫入、最後才接 CI/CD。 -
集中化審計與開關
-
所有 Agent 行為走一個
Agent Gateway / Orchestrator,集中:- 配額控制
- 風險開關(feature flag 一鍵關掉所有 auto-deploy)
log/metrics/alert
-
明確定義「哪一段流程可以 0 人工」
-
常見安全配置:
- bugfix PR 可以由 Agent 全自動產生,但 merge 必須人工
- staging deploy 可自動,production deploy 必須經 Slack / PagerDuty approve
-
將 Agent 視為「非穩定服務」而非傳統微服務
-
接受它偶爾會做奇怪決策,因此整個系統必須:
- 有清楚的 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 審批閘門





