autoswarm 自我優化本地 Agent 實戰

autoswarm 自我優化本地 Agent 實戰

📌 本文重點

  • 本地 Agent 痛點在於行為難以持續優化與自動化
  • autoswarm 透過 reflect → rewrite → evaluate → write-back 形成閉環
  • skills.yaml + 驗證集讓 Agent 行為像「可訓練參數」持續調整
  • 先從可量化任務(coding/CLI/FAQ)導入 autoswarm 成效最佳

本地 Agent 最大的痛點不是「模型不夠強」,而是行為難以持續調整:你改了一堆 prompt、skills,效果好壞全憑體感,難以複製、更難自動化。autoswarm 類的自我優化流程,把這件事工程化:讓 Agent 自己從對話紀錄學習、反思、改寫技能檔,並用驗證集嚴格篩選只留下「真有幫助」的改動。

💡 關鍵: autoswarm 把「調 prompt 靠手感」變成「技能檔可度量、可回滾的工程流程」。

換句話說,你不再手動調 prompt,而是給 Agent 一套 reflect → rewrite → evaluate → write-back 的閉環,讓本地 coding 助手、CLI 助手、企業 FAQ agent 在你睡覺時自己變強。


重點說明

1. autoswarm 關鍵架構:從對話到技能檔

典型 autoswarm 流程可以拆成四個模組,每個都可以獨立嵌進現有系統:

  1. 對話記錄收集(logs)
  2. 來源:真實使用對話、benchmark(如 TerminalBench)、內部工單。
  3. 形式:(task, context, agent_action, outcome),最好能標註 success/failscore

  4. 反思(reflect)

  5. 用一個「較強或同級」的 LLM 對失敗例子做事後檢討。
  6. 產出:錯誤原因改進方向需要修改的 skill 名稱/段落

  7. 技能候選改寫(rewrite)

  8. skills.yaml 內容為條件,請 LLM 產生有界改動:新增/刪除/替換特定節點,而不是整檔轟掉重寫。
  9. 借鏡 SkillOpt:每個改動要有 diff 形式rationale,方便審核與回滾。

  10. 驗證集評估 + 寫回(evaluate & write-back)

  11. 對每個候選 skills 版本,跑一輪驗證集,計算 明確的 success metric(accuracy、任務完成率、延遲等)。
  12. 只有 嚴格提升 才寫回主線 skills.yaml,其餘丟棄;可選擇保留失敗改動作為「負樣本」提示未來避免。

💡 關鍵: 整體流程等同「技能檔梯度下降」,用驗證集決定每次改寫是否保留。

整體就是一個離線/準線上的 技能檔梯度下降:技能檔被當成可訓練參數,用反覆試錯 + 驗證集擇優更新。


2. skills.yaml schema 與 success metric 設計

要讓 autoswarm 好養,技能檔要易於定位、易於局部修改。一個實用的 YAML schema 可以長這樣:

version: 3
meta:
  agent_name: local_cli_helper
  description: "CLI + coding local agent"

skills:
  - id: shell_exec
    type: tool
    trigger: ["terminal", "bash", "cli"]
    prompt: |
      你是一個嚴謹的 CLI 助手。只執行使用者要求的指令:
      - 先用自然語言解釋你要做什麼
      - 再給出具體指令
      - 不要執行具有破壞性的指令(rm -rf 等)
    guardrails:
      forbidden_patterns:
        - "rm -rf /"
        - ":(){ :|:& };:"

  - id: code_edit
    type: coding
    languages: ["python", "bash"]
    prompt: |
      你是一個本地 code 編輯助手:
      - 優先最小改動
      - 保留原有註解
      - 回傳可直接貼上的 patch

  - id: faq_lookup
    type: retrieval
    index: "internal_faq.jsonl"
    prompt: |
      你是企業 FAQ 助理,回答時:
      - 引用文件來源 id
      - 若找不到答案,要明確說明而不是亂猜

幾個關鍵點:

  • id 必須穩定:autoswarm 透過 id 來定位要改哪個 skill。
  • 把行為拆成多個 skill,而不是一個 mega prompt,讓 autoswarm 有「局部調參」的空間。
  • 為每個 skill 準備可計算的 success metric,例如:
  • coding:測試通過數 / 單元測試覆蓋率提升。
  • CLI:命令 exit code == 0 且輸出包含 expected pattern。
  • FAQ:答案包含 ground truth 片段、或人工標註 score

💡 關鍵: 每個 skill 綁一個可量化 metric,才能自動決定「這次改寫有沒有真的變好」。


3. 驗證集與回放:怎麼自動化

關鍵是把「我覺得好」變成可計算的 pass/fail

  • 來源
  • 基準測試(TerminalBench、內部腳本集)。
  • 真的使用者對話 + 事後標註(成功:1、失敗:0)。
  • 半自動生成:用模型自己產 task,再請另一模型打分。

  • 回放機制

  • 對每個驗證樣本 (input, expected),在新 skills.yaml 下跑一次 Agent,產生 output
  • 用簡單的 scorer 函數 計算分數,例如:
    • coding:跑 pytest,看全部通過比例。
    • CLI:比對 stdout 是否包含關鍵字,exit code 是否為 0
    • FAQ:用一個 judge LLM(或傳統 NLP 指標)評估是否回答到點。

這層其實就是一個小型 harness:把「模型+skills」包成可測試的函式,對照 Deepseek 提出的觀點,就是那層讓 LLM 變成 Agent 的 runtime code。


4. 如何嵌進現有本地 Agent(MCP/子代理/skills-based)

不需要重寫整個 Agent,只要插入兩個 hook:

  1. log hook:在 MCP server、子代理 router 或 skills selector 前後,記錄輸入、選到的 skill、輸出、評分。
  2. offline autoswarm worker:定期(例如每天)跑反思-重寫-評估 loop,更新一個新的 skills_version,下次重啟 agent 或熱更新時載入。

常見集成方式:

  • MCP:把 skills.yaml 當作 MCP tool 的配置,autoswarm 只負責改 YAML,MCP server 本身不改。
  • 多代理框架(如 revfactory/harness):autoswarm 對每個 agent 的 skill 檔做優化,讓「meta-agent」負責決定何時切版本。
  • 傳統 skills-based 系統:把原本寫死在程式碼裡的 prompt 抽到 YAML,才能用 autoswarm 自動調參。

實作範例:最小可行 autoswarm(Python + YAML + Ollama)

下面是一個極簡版的 autoswarm:針對單一 skill(faq_lookup),用對話紀錄做反思、改寫 YAML,然後用驗證集評估是否接受改動。

1. 專案結構

project/
  skills.yaml
  logs.jsonl         # 真實對話紀錄
  val_set.jsonl      # 驗證集
  autoswarm.py

skills.yaml 示意(只保留 FAQ skill):

skills:
  - id: faq_lookup
    type: retrieval
    prompt: |
      你是 FAQ 助理,只能根據提供的文件回答。
      若找不到答案,就回答「找不到」。

2. Python:反思 → 重寫 → 評估 loop

# autoswarm.py
import json, copy, subprocess, textwrap
from pathlib import Path
import yaml

SKILLS_PATH = Path("skills.yaml")
VAL_PATH = Path("val_set.jsonl")
LOGS_PATH = Path("logs.jsonl")

# --- 基礎調用 Ollama ---

def call_ollama(prompt: str, model="llama3.1") -> str:
    res = subprocess.run(
        ["ollama", "run", model],
        input=prompt.encode("utf-8"),
        stdout=subprocess.PIPE,
        check=True,
    )
    return res.stdout.decode("utf-8").strip()

# --- Step 1: 從失敗 log 產生改進建議 ---

def load_failed_examples(limit=5):
    examples = []
    with LOGS_PATH.open() as f:
        for line in f:
            obj = json.loads(line)
            if obj.get("success") is False:
                examples.append(obj)
            if len(examples) >= limit:
                break
    return examples


def reflect_on_failures(examples):
    prompt = """你是資深 prompt engineer。以下是 FAQ agent 的失敗案例:

{cases}

目前 FAQ skill 的行為描述較弱,請提出如何修改 skill prompt 才能避免這些錯誤。

輸出格式:
- mistakes: 一段文字說明主要錯誤
- patch: 改寫後的完整 prompt 內容(繁體中文)
"""
    cases_txt = "\n\n".join(
        [
            f"[CASE]\nquestion: {c['input']}\nwrong_answer: {c['output']}\nexpected: {c['expected']}"
            for c in examples
        ]
    )
    resp = call_ollama(prompt.format(cases=cases_txt))
    return resp

# --- Step 2: 產生候選 skills 版本 ---

def generate_candidate_skills():
    skills = yaml.safe_load(SKILLS_PATH.read_text())
    base_skills = copy.deepcopy(skills)

    failed = load_failed_examples()
    if not failed:
        print("no failed examples; skip")
        return None

    reflection = reflect_on_failures(failed)

    # 簡化處理:從 LLM 回應中用標記擷取 patch 區塊
    if "patch:" in reflection:
        patch = reflection.split("patch:", 1)[1].strip()
    else:
        patch = reflection

    # 套用到 faq_lookup
    for s in base_skills["skills"]:
        if s["id"] == "faq_lookup":
            s["prompt"] = patch

    return base_skills

# --- Step 3: 評估一個 skills 版本 ---

def run_agent(question: str, skills_obj) -> str:
    faq_skill = next(s for s in skills_obj["skills"] if s["id"] == "faq_lookup")
    sys_prompt = faq_skill["prompt"]
    full_prompt = textwrap.dedent(f"""
    系統指令:
    {sys_prompt}

    使用者問題:{question}
    請直接回答。
    """)
    return call_ollama(full_prompt)


def score_skills(skills_obj) -> float:
    total, ok = 0, 0
    with VAL_PATH.open() as f:
        for line in f:
            obj = json.loads(line)
            question = obj["input"]
            expected = obj["expected"]
            out = run_agent(question, skills_obj)
            total += 1
            if expected.strip() in out:
                ok += 1
    return ok / total if total else 0.0

# --- 主流程 ---

def main():
    current_skills = yaml.safe_load(SKILLS_PATH.read_text())
    base_score = score_skills(current_skills)
    print("base_score:", base_score)

    cand = generate_candidate_skills()
    if cand is None:
        return

    cand_score = score_skills(cand)
    print("candidate_score:", cand_score)

    if cand_score > base_score:
        backup = SKILLS_PATH.with_suffix(".bak.yaml")
        backup.write_text(SKILLS_PATH.read_text())
        SKILLS_PATH.write_text(yaml.dump(cand, allow_unicode=True))
        print("updated skills.yaml (backup saved)")
    else:
        print("candidate rejected; no improvement")


if __name__ == "__main__":
    main()

這個最小範例已經包含核心閉環:

  • 反思reflect_on_failures 用 LLM 分析失敗案例。
  • 重寫generate_candidate_skills 產出新的 FAQ skill prompt。
  • 評估score_skills 在驗證集上打分。
  • 寫回 + 回滾:只有 score 提升才覆蓋 skills.yaml,並保留 .bak 方便回滾。

你可以把 run_agent 換成實際的 MCP 調用、子代理 router,整套邏輯依然成立。


建議與注意事項

1. 避免過度擬合驗證集

問題:skills 慢慢只會在 val_set 上變強,實戰反而變差。

建議

  • train / val / live 三層:
  • train:用來產生候選改動。
  • val:只決定是否接受改動。
  • live:真實流量,週期性抽樣評估是否「線上變好」。
  • 定期替換驗證集樣本,避免被「背題」。

2. 技能檔膨脹與行為漂移

問題:LLM 每輪都喜歡加條款、加例外,skills.yaml 越寫越厚,最後誰也看不懂。

建議

  • 為 autoswarm 的 rewrite prompt 加上硬性約束:字數上限、禁止新增無根據規則
  • 定期跑「壓縮輪」:請模型把冗長 skill 壓縮成短版,再用同一驗證集確認不降分。
  • 每個 skill 保持一個簡短的 design doc(目的、scope、anti-goals),避免 autoswarm 把 skill「學壞」。

3. 無標準答案任務的侷限

在開放式對話、創作任務上,很難定義客觀 success metric。

可以考慮:

  • 使用一個獨立 judge 模型,給 1–5 分,才算作 metric。
  • 只對「明確可評」技能開 autoswarm(如 coding、CLI、FAQ),聊天維持手動設計。
  • 針對負面行為(安全、合規)單獨設計 守門驗證集,只要出現就直接拒絕 candidate。

4. 版本控制與回滾策略

  • 版本號:在 skills.yamlversion 欄位,每次 autoswarm 成功更新 +1
  • Git 管理:把 skills 連同 autoswarm logs 一起 commit,方便 bisect
  • 多版本 AB 測試:對企業內部 Agent,可同時跑兩個 skills 版本,對比使用者滿意度或工單解決率。

實際好處總結:

  • 對本地 coding 助手:用單元測試當驗證集,讓 Agent 自動學會你的專案風格與工具鏈。
  • 對 CLI 助手:從錯誤指令和 crash log 中反覆學習,逐步降低「爆炸指令」風險。
  • 對企業 FAQ/ops agent:用真實工單與 FAQ 命中率做閉環,減少大家輪流調 prompt 的人工成本。

核心心態是:skills.yaml 當成模型參數來訓練,而不是只在 README 裡手動修改的一段文案。有了 autoswarm loop,你的本地 Agent 就能在既有硬體上持續「自我優化」,而不是每天重訓一個新模型。

🚀 你現在可以做的事

  • 把現有 Agent 的系統 prompt 抽成 skills.yaml,為每個 skill 補上穩定 id 與對應 metric
  • 寫一個最小版 autoswarm.py,先針對單一 skill(例如 faq_lookup)跑 reflect → rewrite → evaluate loop
  • 準備一小批驗證集(10–20 筆即可起步),接上 CI 或排程,讓 skills 每天自動小幅優化

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *