分類: 🤖 AI 與自動化

  • Claude 分流實戰:訂閱 / API / Foundry / 本地怎麼選 + 省 Token

    重點摘要

    • 真正的重點不是「省幾個 token」,是哪種工作走哪個通道:公開/通用 → 訂閱、公司資料 → Azure Foundry(留 Azure 邊界)、機敏/不確定 → 本地 LLM。
    • 從零開發:原型用訂閱(便宜、快迭代),第一次「真公司資料 / schema / 憑證」要進 prompt 才切 Foundry——切換點是資料事件,不是階段名
    • 真機敏用「假資料 → 雲端產出 → 換回真值」混合法,真值永遠不出公司。
    • 公司的東西用「公司商用訂閱(Team/Enterprise)或 API/Foundry」,不是員工個人 Pro/Max——非機敏也不該走消費級條款。
    • 底層功夫:context 是每輪重算的乘數,長 context 又貴又笨(準確率掉 13.9–85%);同事續用 compact、換事用 clear、怕忘的寫進檔案。
    • 各模型快取門檻不按貴賤排:Opus 4.8 與 Haiku 4.5 都要 4,096 tokens,Sonnet 4.6 與 Fable 5 只要 2,048。

    很多人把「用 AI 怎麼划算」想成「省 token」,其實真正的重點在更上層:哪種工作該走哪個通道(訂閱 / API / Azure Foundry / 本地),以及怎麼分階段切換。把通道分對、把資料分流對,比你在單一通道裡省那幾個 token 重要太多。這篇先講分流與分階段(大局),再講進了通道之後怎麼省 token、保持聰明(底層功夫)。所有定價與快取數字都以官方資料核對過。

    Part 1|分流:哪種工作走哪個通道

    第一件要釐清的事:「訂閱 vs API」不是「機密與否」的軸。訂閱和 API 都是把資料送到 Anthropic 雲端,兩者差別是計費方式與資料條款,不是「資料會不會外洩」。真正的機密分流要靠第三、第四個選項:留在你既有雲邊界的 Azure Foundry,以及完全不出公司的本地 LLM。先把三條軸分開:

    • 機密軸:本地 ↔ 雲端。決定資料能不能離開公司。
    • 信任邊界軸:Anthropic 自己的雲 ↔ 你既有的雲(Azure/AWS/GCP)。Foundry 讓資料留在公司已核准的 Azure 邊界。
    • 計費 + 模式軸:訂閱(互動、固定費)↔ API(程式化、按量、商用條款)。

    哪些資料可以做哪些:三層分流

    資料類型 走哪 為什麼
    公開 / 不重要 訂閱 便宜;公開資料不怕被拿去訓練
    內部但機密(已在 Azure) Azure Foundry(或商用 API) 留 Azure 邊界、預設不訓練、可開 ZDR
    機敏 / 涉密 / 不確定 本地 / 地端 LLM 絕不上雲;default-deny,不確定就當機敏

    為什麼公司資料走 Foundry 是最佳解?因為信任邊界早就跨過了。如果你的 code 已經在 Azure DevOps、公司也接受 Azure Foundry,那走 Foundry 的 Claude 是留在同一個 Azure 邊界裡推論,不是再送到 Anthropic 自己的雲——邊際的資料暴露趨近於零。它複用你早就過關的 Azure 合約與資料條款,比直連 Anthropic API 更乾淨。(注意:Foundry 是功能子集,不支援 Anthropic 的 Managed Agents 與 server 端工具,純 code 生成 / 對話 / 一般 tool use 沒問題。)

    你的工作 → 用哪個

    工作 性質 用哪個
    ESG 討論 / 問問題 公開、通用 訂閱
    ESG 文案(通用骨架) 公開 訂閱
    ESG 文案(含公司真實數據) 內部 Foundry 或假資料混合
    專案討論(通用、不涉密) 一般 訂閱
    專案討論(涉公司設計 / 架構) 公司資產 Foundry
    開發 / BUG(公司 code) 公司資產 Foundry

    切換規則:只要問 2 個問題

    ① 碰到「公司機密 / 內部資料 / code」嗎?
    否(公開 / 通用) → 訂閱
    是 → ② 真機敏 or 不確定?
    不(內部但可上 Azure) → Foundry
    是 → 假資料混合 / 本地

    預設是訂閱(互動 + 公開),只有「踩到公司資料」或「要自動化」才翻到 Foundry / API。重點:這是按任務類型路由,不是每句話狂切——你開一個工作時就決定走哪條,不會中途換。兩個帳戶(訂閱 + Foundry/API)各管各的場景,既省又乾淨:訂閱吃高頻互動 + 公開的大量量(已預付、邊際成本趨近 0),Foundry/API 只碰公司資料 + 自動化(貴通道只餵小東西)。

    公司用的「訂閱」是商用方案,不是員工個人帳號

    上面講「公司資料用訂閱也行」時,有個關鍵前提要釘清楚:處理公司的東西,要用「公司開的商用訂閱」(Team / Enterprise),不是員工個人的消費級 Pro / Max。這跟資料機不機密是兩道分開的閘——就算沒有機敏問題,帳戶條款與治理仍是另一關。

    帳戶 處理公司(非機敏)事 為什麼
    員工個人 Pro / Max(消費級) ⚠️ 不建議 消費級條款,資料預設可能被拿去訓練(除非手動關);無 DPA;公司無管控/稽核;工作綁個人帳號,人離職就失去
    公司開的 Team / Enterprise ✅ 可以 商用條款、不訓練、有 DPA、admin 管控、帳號歸公司
    公司 API / Azure Foundry ✅ 可以 商用條款、可自動化;Foundry 還能留 Azure 邊界

    一句話:非機敏不代表可以走消費級條款。公司的東西用公司商用帳戶,別躺在某個員工的個人訂閱裡,否則訓練、稽核、離職交接、IP 歸屬全是漏洞。(消費級的確切訓練/保留條款 Anthropic 改過幾次,對外講死前建議查當下版本;但商用 vs 消費級的分野是穩的。)

    從零開發:原型用訂閱,串真資料才切 Foundry

    把上面的原理套到「從零開發一個東西」的生命週期,就是這篇最實用的一招。原型階段沒有任何公司資料,用訂閱快速迭代;等要串接真實公司資料,才切到 Foundry。但切換點不是「原型做完了」這種階段標籤,而是一個具體的資料事件:

    第一次「真公司資料 / 真 schema / 真憑證 / 真專有邏輯」要進 prompt 的那一刻——在這之前,全部留訂閱。

    換句話說,只要你餵進去的還是假資料 / mock / 通用結構,就算你在寫「串接用」的 code,也還能留在訂閱:

    階段 餵進去的是什麼 用哪個
    原型 / scaffolding 通用架構、mock 資料、假 schema 訂閱(快、便宜、高頻迭代)
    串接(打 fake schema / mock) 仍是假的,只是形狀對 還是訂閱
    串接(碰真 schema / 真資料) 真公司東西 Foundry(留 Azure 邊界)

    有一個判斷會決定你「切多早」:機密的是「值」還是「結構」?

    • 只有資料值機密、schema 是通用的 → 用假資料混合法,幾乎全程留訂閱,真值在自己這端換回去,Foundry 幾乎用不到。
    • schema / 業務邏輯本身就機密(欄位名洩漏商業設計)→ 一碰真結構就切 Foundry,切得比較早。

    三個實務提醒:(1) 原型從第一天就用合成 / mock 資料,別圖方便把真實樣本烤進原型——一旦烤進去,訂閱階段就不乾淨了。(2) 切換是一個真步驟:換後端 / 換 key / 換設定,切完跑個 smoke test 確認行為一致(不同後端 model 版本可能微差)。(3) 快取不跨帳戶,切過去第一次是冷的,正常。

    假資料混合法:真機敏值永遠不出公司

    當產出真的要碰機敏值,用「假資料 → 產出 → 換回真資料」三步,讓你既能用最強的雲端模型產出,真機敏值又完全不離開公司:

    1. 在自己這端,把機敏欄位換成假資料 / 佔位符(masked)。
    2. 把「假資料版」丟給雲端 LLM,產出結構、內容、排版、分析框架。
    3. 在自己這端把真資料 find-replace 換回佔位符。

    讓這招順的關鍵是佔位符要一致、可一鍵全域取代——用穩定命名如 [公司名]{{2025_範疇一排放量}},不要散落同義變體;需要假數字時標明是佔位值,別混入像真的數字。程式碼也適用:含活憑證(API key、DB 密碼、內部 endpoint)的檔案一律先抽掉再送,那是另一種洩漏面,跟在不在 Azure 無關。

    Part 1 一句話:資料先過機密分類,再決定通道;原型用訂閱、串真資料才切 Foundry、機敏走假資料混合或本地。把通道分對,比省 token 重要得多。

    Part 2|底層功夫:進了通道之後怎麼省 token、保持聰明

    通道分對之後,才輪到「在通道裡怎麼用得省又聰明」。這部分是底層功夫——對訂閱省的是「使用額度」,對 API/Foundry 省的是「真金白銀」,而且省 token 不只省錢,還能讓模型保持在最聰明的狀態。

    Context 是乘數:為什麼長對話又貴又笨

    Context(對話視窗)不是只算一次,而是每一輪都重算一次。我讀進一個 2000 行的檔,那 2000 行接下來每一輪對話都重新帶著計費。所以「在對話早期讀一個大檔」會污染後面整段對話的成本。

    更關鍵的是:長 context 不只貴,還會讓模型變笨。Chroma 對 18 個前沿模型(含 Claude Opus 4、GPT-4.1、Gemini 2.5)的實測顯示,每一個都隨輸入變長而退化——即使「需要的資訊 100% 在 context 裡」,準確率仍隨長度掉 13.9% 到 85%。這叫 context rot。所以省 token 同時是讓模型保持聰明。另外兩個失效模式:Lost in the middle(關鍵埋中段準確率掉 30%+,重要指令放開頭、當前問題放最後)、context poisoning(混進一個幻覺會被當前提複製,該截斷到污染點之前重啟)。

    三個動作:繼續、compact、clear 怎麼選

    動作 對之前對話做了什麼 能否接著聊同一件事
    繼續聊 全部逐字帶著 能,但越疊越大、越慢、越貴、越笨
    /compact 壓縮 換成一份摘要(有損,細節掉、重點留) 能,thread 不斷
    /clear 清除 全部丟掉(只剩 CLAUDE.md、auto memory 重載) 不能,這次記憶歸零

    原則:同一件事還要繼續且馬上繼續,用 compact;要停一陣、換事、或 context 已經很肥,先寫筆記再 clear。

    5 層記憶模型:Note 與 Brain 是兩條垂直的軸

    存什麼 活多久 / 何時載入
    Context 對話視窗 這次對話的一切 clear 就沒;每輪都在、每輪算錢
    Note 接手筆記 做到哪、下一步 任務做完即丟;叫它讀才讀
    MEMORY.md 你是誰、偏好、專案狀態 跨所有對話;每次開對話自動載
    Brain 踩過的坑 + 領域知識 永久跨專案;宣告 Domain Brain 才載
    Skill 正確做法的模板 永久;用到才呼叫

    最容易混淆的是 Note 跟 Brain,它們是兩條互相垂直的軸:Note 答「這次做到哪」(短期、綁任務、會過期);Brain 答「這類事怎麼做才不踩坑」(永久、跨專案)。clear 時 Note 把工作進度帶過去、Brain 把教訓帶過去——不是二選一,兩個都寫但寫不同東西,一個搬狀態、一個搬智慧。

    Context × Loop:乘數效應在迴圈裡會放大

    /loop 或排程反覆跑時,單輪成本是「context 大小 × 1」,帶著肥大 context 的迴圈是「context 大小 × 迭代次數」。所以每一輪開始前把 context 收乾淨,比一路累積更省也更準:每次迭代讀回精簡狀態檔(Note)→ 做這一輪 → 寫回狀態檔 → 收掉工作 context。狀態活在檔案裡,活躍 context 保持小而新鮮,這就是 long-running agent 能跑幾十輪不退化的關鍵。

    ccbot 是 UI 工具,不是 context 容器

    ccbot 這種「review → triage → 逐條修」一次幾十條 finding 的流程,最容易把上面所有原理一次踩雷。它應該被當成一個「UI 工具」——讓你逐條決策的介面——而不是用來長壓 context 的容器。心法:一個 finding(或一個 cycle)就是一個任務邊界,分批做、批次之間 clear,絕不一個對話硬幹幾十條。到約 100K token 時 context rot 發作,後面越判越糊;分批 clear 反而讓每條都用最乾淨的腦判,還更省 token。每條判完把「決定→存檔、教訓→Brain、進度→Note」三件事歸位,再開乾淨 context 做下一條。

    API / Foundry 端怎麼算成本(含程式範例)

    走 API / Foundry 時 token 直接是帳單,值得認真算。先講怎麼量——不要用 tiktoken(那是 OpenAI 的 tokenizer,對 Claude 會低估 15–20%)。用官方 count_tokens:

    from anthropic import Anthropic
    
    client = Anthropic()
    resp = client.messages.count_tokens(
        model="claude-opus-4-8",
        messages=[{"role": "user", "content": open("CLAUDE.md").read()}],
    )
    print(resp.input_tokens)

    成本公式:(input ÷ 1,000,000 × input 單價) + (output ÷ 1,000,000 × output 單價)。以 Opus 4.8($5 / $25)、50,000 input + 2,000 output 為例:input $0.25 + output $0.05 ≈ $0.30/次。加上 prompt caching(同一大前綴重複用):讀取只要基礎 input 價約 0.1 倍,寫入 1.25 倍(5 分鐘)或 2 倍(1 小時)。同樣 50K 前綴重複 10 次:不快取 $2.50,有快取 ≈ $0.54,省約 78%

    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=4096,
        system=[{
            "type": "text",
            "text": LARGE_STABLE_CONTEXT,        # 穩定的大前綴
            "cache_control": {"type": "ephemeral"},
        }],
        messages=[{"role": "user", "content": user_question}],  # 變動內容放後面
    )
    print(response.usage.cache_read_input_tokens)   # 驗證命中;一直是 0 = 前綴被污染

    快取是前綴完全比對,差一個字元就全 miss——常見元兇:datetime.now()、UUID、沒排序的 json.dumps()、或工具清單變動(工具一改整個快取全滅)。非即時的批量工作可走 Batches API,直接半價

    各模型定價與快取門檻(官方數字)

    模型 Input $/1M Output $/1M Context 適合的活
    Fable 5 $10 $50 1M 最難的長程推理 / agentic
    Opus 4.8 $5 $25 1M 架構決策、複雜推理、跨檔案邏輯
    Sonnet 4.6 $3 $15 1M CRUD、API 對接、測試、文件
    Haiku 4.5 $1 $5 200K 檔案掃描、目錄盤點、簡單搜尋

    「最低可快取前綴」門檻各模型不同,而且不按貴賤排——這點最反直覺:

    模型 最低可快取前綴
    Opus 4.8 / Haiku 4.5 4,096 tokens
    Sonnet 4.6 / Fable 5 2,048 tokens

    具體後果——同樣一段 3,000 token 的前綴,在 Sonnet 4.6 與 Fable 5(門檻 2,048)快取得起來,在 Opus 4.8 與 Haiku 4.5(門檻 4,096)卻會靜默不快取,你不會收到錯誤,只會發現帳單沒省到。所以用 Haiku 做大量小請求時,若前綴不到 4,096,拿不到任何 cache 折扣。門檻不按貴賤排,別憑感覺假設;不同模型 tokenizer 也不同,跨模型估成本一定要用該模型自己的 count_tokens 重算。

    省過頭反而害事:三個要避免的過度優化

    1. 壓縮砍太狠:摘要寧可先求高 recall(多留)再慢慢收。一開始壓很乾,會砍掉日後才變關鍵的細節,逼出更多來回反而更貴。
    2. 為省而硬拆多輪:研究顯示同一 prompt 拆成多輪累積,品質掉 39%(context clash)。該一次講清的別硬切。
    3. 濫用子代理:多代理約用 15 倍 token。廣度研究、檔案掃描很划算;緊耦合、要共享上下文的事用子代理反而又貴又糊。判準:任務價值 > token 成本才划算。

    一句話心法

    先分流,再省 token。哪種工作走哪個通道才是大局:公開/通用走訂閱、公司資料走 Foundry(留 Azure 邊界)、機敏走假資料混合或本地;從零開發時原型用訂閱、第一次碰真公司資料才切 Foundry——切換點是資料事件,不是階段名。通道分對之後,底層才講省 token:context 是每輪重算的乘數、長 context 又貴又笨,同事續用 compact、換事用 clear、怕忘的寫進檔案,API 端認真做快取並按模型選對 tier。把通道分對的價值,遠大於在單一通道裡省那幾個 token。
  • 把 HR 表單系統接上 A2A:讓 AI 幫新人填表與上傳證件

    重點摘要

    • 把一個 Flask 做的 HR 新人入職表單系統,加一層 A2A(Agent2Agent),讓外部 AI agent 能查狀態、填表、上傳證件。
    • 接得起來的關鍵不是協定本身,而是資料驅動的 form_schema:同一份 schema 同時驅動表單、驗證、PDF、指標,也直接當成 A2A 的機器契約吐給對方 agent。
    • 把關留給人:身分證重複「偵測不擋」、上傳檔只檢 magic bytes 不判真偽——系統只負責收得到、開得了,真偽由 HR 人工核對。
    • 一個血淋淋的工程坑:回歸測試在同一個 live 資料庫上 reseed,把使用者正在填的資料反覆洗掉。測試一定要隔離。

    前一篇〈A2A 是什麼:用一個 Python 把資料庫變成 AI 外掛技能〉講的是概念。這篇是實戰續篇:我把一個真的在跑的 HR 新人入職表單系統接上 A2A,讓外部 AI agent 可以幫新人「查件、填表、上傳證件」,而且全程把關都還在。過程中最有價值的領悟,跟最痛的坑,都寫在這裡。

    背景:一個全假資料的 HR 入職 demo

    這個系統是給 HR 看的過渡期工具:新人報到前在線上把入職資料填好(基本資料、聯絡、銀行、學歷、委任函簽回、證件上傳…),取代「郵寄紙本表單、報到日逐張人工核對」。技術上是 Flask + SQLite + vanilla JS,全假資料、不接任何正式系統,但架構為「日後接真」預留。

    核心是一份 form_schema.py:16 個欄位群組、34 個必填欄位、4 個 repeater、條件顯示(男性才有兵役欄)。整個系統是資料驅動的——加一個欄位群組,前端表單、即時驗證、預填 PDF、HR 指標統計全部自動跟著生。這個設計後來成了接 A2A 時最大的本錢。

    為什麼這個系統「天生」適合 A2A?

    A2A 的三個核心原語,剛好對上這個系統本來就有的三個特性:

    A2A 原語 系統本來就有的東西
    機器可讀的能力契約 資料驅動的 form_schema——直接就是「要填什麼、什麼格式、什麼規則」的契約
    input-required 任務狀態 流程本來就 human-in-the-loop:委任函要人簽、HR 要審、重複證號要人工核對
    非同步、長命任務 入職流程本來就跨天(委任函三個工作天內簽回)

    換句話說,A2A 不是要硬塞進來的東西;它只是在同一套核心邏輯上,再加一個「給 agent 用」的介面。原本給人用的 Web UI 一行都不用動。

    四個 skill:查、填、傳檔

    實作上就是兩個端點:GET /.well-known/agent.json(Agent Card,宣告能力)和 POST /a2a(JSON-RPC 2.0,method 一律 message/send)。對方 agent 要呼叫哪個 skill,就把 skill 名放進訊息裡。四個 skill:

    • get_requirements(唯讀、公開)→ 把 form_schema 當機器契約吐出
    • get_status(唯讀、帶 token)→ 回案件狀態與完成度,不含任何個資
    • submit_data(寫入)→ 填/更新欄位,可半填累積,回逐欄錯誤;final=true 才正式送出
    • upload_document(寫入)→ 上傳證件/照片(PNG/JPEG/PDF,≤5MB)

    填表的呼叫長這樣——agent 先半填,系統回逐欄錯誤,agent 照著補,直到 ok:true 再帶 final=true 送出:

    POST /a2a
    {"jsonrpc":"2.0","id":1,"method":"message/send",
     "params":{"message":{"parts":[
       {"kind":"data","data":{"skill":"submit_data","token":"<TOKEN>",
         "data":{"name":"王小美","mobile":"0912000333"},"final":false}}
     ]}}}
    
    // 回傳: {"ok":false, "errors":[{"field":"birthday","label":"出生年月日","message":"此欄為必填"}, ...],
    //        "progress":{"pct":15,"done":5,"total":34}}

    關鍵資產:把 schema 當契約吐出去

    外部 agent 要幫人填表,最痛的是「不知道要填哪些欄、什麼格式、什麼規則」。一般系統得另外寫一份文件或 OpenAPI;而這個系統因為是資料驅動的,get_requirements 直接把 form_schema 轉成乾淨的 JSON 契約丟過去——欄位 key、型別、是否必填、選項、條件顯示、repeater 子欄位,全都在。

    這就是「資料驅動設計」在接 A2A 時直接變現的地方:本來要額外做的「能力描述」,變成免費的副產品。同一份 schema,人看到的是表單,agent 看到的是契約。

    把關留給人:偵測不擋、不判真偽

    開放給 AI 寫入,最該想清楚的是「哪些要擋、哪些只標記」。兩個實際決定,都選擇偵測但不阻擋,把判斷交給人:

    • 身分證重複:直覺上身分證唯一,該擋重複。但台灣確實有不同人合法持相同身分證字號的歷史案例(戶政歷史錯誤)。硬擋會把真人擋在門外。所以改成偵測到就在 HR 送件頁標記「請人工核對」,仍允許送出。
    • 上傳檔的真偽:系統只檢 magic bytes(檔頭簽名)——把 virus.txt 改名 id.png 騙不了,因為內容開頭騙不了。但 magic bytes 只能證明「這是一張合法的 PNG」,不能證明「這是真的身分證」。一張 1×1 的空白 PNG 也過。所以系統明確不宣稱判真偽,那是 HR 的事。

    這條原則救了一次:demo 時對方 agent 把照片用 submit_data 塞成 base64 字串,系統「來者不拒」收進了資料欄,但 HR 頁面讀的是上傳表,顯示「未上傳」。看起來像 bug,其實是「值照存、把關在顯示/驗證層」。修法不是讓它更寬鬆,而是讓 submit_data 遇到檔案欄就回 error、明確指引去用 upload_document——把錯誤導向正確的通道,而不是默默吞下

    最痛的坑:測試別在 live 環境上 reseed

    這是整個過程最值得記的教訓。我有個習慣:每改一次 code,就自動跑全套回歸測試,而每個測試前都會 seed.py 把資料庫砍掉重建,確保乾淨狀態。問題是——那個資料庫,就是對外 demo 正在用的同一個

    於是使用者在做 live A2A demo、外部 agent 正在填表的同時,我在旁邊「自己驗證自己的 code」,每跑一輪就把對方填的資料洗掉一次。使用者連問三次「為什麼資料一直不見」我才意識到:我把「我的開發測試」當成看不見的背景工作,但它跟使用者的正式環境是同一台 server、同一個 DB

    正解是測試隔離:資料庫路徑、埠號、debug 模式全部吃環境變數,測試跑在獨立的 data/test/ + 另一個埠,跑前後驗證 live 資料庫的修改時間沒變,來證明真的沒碰到。一個小插曲:第一次選的測試埠被機器上別的服務佔了,回的是英文 HTML,害測試的 .json() 解析爆掉——所以測試埠要挑冷門的、並先確認是空的。

    更廣的一條:不要在使用者正在用的共用 live 系統上,未經告知就跑會破壞狀態的操作。而且使用者說「我的資料怎麼不見」時,要用證據查清楚再回答——我一開始斷定「是我的 reseed」,查 server log 才發現那個時間點其實是 agent 自己的寫入(檔案修改時間任何寫入都會更新,分不出來源)。先看 log,承認不確定,別急著講一個乾淨的故事。

    結語:協定是介面,schema 是資產

    把一個系統接上 A2A,真正的工作量不在協定信封(那很薄),而在你有沒有一份機器讀得懂的能力描述、以及想清楚哪些把關不能交給機器。資料驅動的 schema 讓前者幾乎免費;human-in-the-loop 的紀律讓後者不出事。協定只是讓 agent 進得來的那扇門,門後該有的東西,還是得自己先蓋好。

  • A2A 是什麼:用一個 Python 把資料庫變成 AI 外掛技能

    重點摘要

    • A2A 是什麼:把服務包成「一張 AI 看得懂的名片(Agent Card)+ 一個任務入口(/tasks)」,別的 AI 給它一個網址就能自己使用你。
    • 跟 MCP 的差別:MCP 是把「死工具」掛給一個 AI(像 JDBC 驅動);A2A 是讓兩個「會思考的服務」互相喊話(像微服務互呼)。
    • 怎麼被呼叫:分兩層——LLM 讀名片自己挑 skill 是「自然語言層」;身分憑證走 HTTP header 是「水管層」,兩層不混。
    • 只有一個 DB:本質就是「一個 Flask + 一張名片」,本文附可跑程式碼。
    • 權限怎麼帶:token 不放 skill 參數、放 header;「能看什麼」由 server 從 token 推導,不讓呼叫方自報。認證掛在 Nginx 也能發名片——把發現路徑設成白名單即可。

    這篇從「A2A 是什麼」一路講到「放上 production、要管權限時怎麼設計」。對象是上一個世代的後端 RD——你熟悉 REST、微服務、JDBC、Nginx、服務發現,所以全程用你已經會的概念來對照。最後的程式碼我自己在跑,而且真的被另一台機器的 agent 呼叫成功過。

    一、A2A 是什麼?

    A2A(Agent2Agent)是一個讓「AI agent 之間互相呼叫」的開放協議。它由 Google 提出,現已捐給 Linux Foundation,版本到 v1.0。核心只有兩個東西:

    1. Agent Card(名片):一份放在固定網址的 JSON,描述「我是誰、我會哪些技能(skills)、任務要打哪個網址、要怎麼認證」。別的 agent 靠它「發現」你。
    2. Task 入口:一個收任務的端點(例如 POST /tasks),別人帶著「我要用哪個 skill」打進來,你執行、回 JSON。

    就這樣。一個 A2A agent,對別的 AI 來說,就像一個「外掛技能」:本來不會查你系統的 LLM,你給它一個網址,它讀了名片就「學會」用你了——不需要工程師事先把兩邊接線。

    用生活化比喻:名片 + 通訊錄

    想像你是一間公司的窗口。你印了一張名片,上面寫「我負責:查包裹、開通知單、查住戶數」。任何人拿到這張名片,看一眼就知道能找你做什麼、該打哪支電話。A2A 的 Agent Card 就是這張名片;/tasks 就是那支電話。差別只在於:讀名片、打電話的不是人,是另一個 AI。

    二、上世代 RD 怎麼理解 A2A 與 MCP 的差別?

    這是最多人卡住的地方。用你熟悉的後端概念對照,一秒就懂:

    你熟悉的概念 MCP A2A
    JDBC / ODBC 驅動程式 ✓ 標準介面,把工具(DB/檔案/API)接給「一個」AI 用
    微服務互相呼叫(REST) ✓ 一個服務呼叫「另一個會思考的服務」
    服務發現(Eureka / Consul) ✓ 靠 Agent Card 自我描述被發現
    對方是「活的」還是「死的」 死的:工具被動被呼叫,不會自己判斷 活的:對方是個會用 LLM 自己判斷的 agent

    一句話收斂:MCP 是「AI ↔ 工具」,A2A 是「AI ↔ AI」。MCP 把一隻手伸向工具箱;A2A 是兩個有腦袋的人互相打電話。兩者不衝突,常常一起用——你的 agent 用 MCP 拿工具,同時用 A2A 去問別的 agent。

    三、A2A 怎麼跟 AI Agent 一起運用?(MCP 與 Skill 的分工)

    • MCP:當你的 AI 需要用「工具」——查 DB、讀檔案、呼叫某個 API——就掛一個 MCP server。工具不會思考。
    • A2A:當你的 AI 需要請「另一個 agent」幫忙——對方有自己的 domain 知識、會自己判斷——就用 A2A 呼叫它。
    • Skill:在 A2A 名片裡,一個 agent 把自己會的事拆成一個個「技能(skill)」宣告出來。呼叫方的 LLM 讀這些技能描述,自己挑要用哪一個。

    所以 Skill 是 A2A 名片裡的最小單位。一張名片可以宣告多個 skill,每個 skill 背後接不同的後端——有的查即時 DB、有的走知識圖譜、有的呼叫生成式模型。呼叫方不需要知道背後怎麼接,它只看得到「技能清單」。

    四、怎麼用自然語言「呼叫」一個 A2A agent?

    關鍵觀念:呼叫方不寫死「呼叫 skill X」。它把「名片上的技能清單」加上「使用者講的自然語言」一起交給 LLM,讓 LLM 自己挑出最適合的 skill,再去打 /tasks。流程三步:發現 → 判斷 → 呼叫。這是「判斷」那一步的真實程式碼:

    def llm_pick(user_says, skills):
        menu = "\n".join(f"- {s['id']}: {s['name']} — {s['description']}" for s in skills)
        prompt = (f"使用者說:「{user_says}」\n"
                  f"下面是某個 agent 提供的 skill,挑最適合處理這句話的一個,"
                  f"只回那個 skill 的 id、不要任何解釋:\n{menu}")
        # ...把 prompt 丟給 LLM,回應裡比對出 skill id

    先記住這個分層:自然語言層 vs 水管層(後面講權限會用到)

    一次 A2A 呼叫其實有兩層,先分清楚,等一下講權限才不會打結:

    誰在做 放什麼
    自然語言層 LLM 讀名片、挑 skill 業務參數(query、id)
    水管層(HTTP) client 程式發請求 身分憑證(Authorization header)

    所以「用自然語言達到 A2A」,是把對方的名片餵給你的 LLM、讓它把人話翻成「該呼叫哪個 skill」;而身分憑證從頭到尾不經過 LLM,是底層水管自動帶的。名片寫得好,LLM 就挑得準。

    五、只有一個 DB,怎麼做出一個 A2A agent?

    直接回答最多人的疑問:對,本質就是「一個 Python 寫的 API 口」——只是比普通 REST API 多兩樣:一張名片、用 skill 分路。下面是能跑的最小骨架(Flask),背後接一個資料庫:

    from flask import Flask, request, jsonify
    app = Flask(__name__)
    
    # ① 名片:宣告我會哪些 skill、task 打哪
    CARD = {
      "name": "社區管理大腦",
      "url": "http://localhost:9999",
      "skills": [
        {"id": "parcel_status", "name": "包裹卡單查詢",
         "description": "查 outbound 各狀態的真實件數,即時查 DB"},
      ],
    }
    
    @app.get("/.well-known/agent-card.json")   # 別人靠這個網址發現我
    def card(): return jsonify(CARD)
    
    @app.post("/tasks")                          # 別人帶 skill 打進來
    def tasks():
        skill = request.get_json().get("skill")
        if skill == "parcel_status":
            rows = db_query("SELECT status, COUNT(*) FROM parcels "
                            "WHERE direction='outbound' GROUP BY status")
            return jsonify({"facts": rows})
        return jsonify({"error": "unknown skill"}), 400

    名片 endpoint + task endpoint + 一句 SQL,你的資料庫就成了一個 A2A agent。要加技能,就在 CARD["skills"] 多宣告一筆、在 /tasks 多一條分支。

    把名片從「自我介紹」升級成「可被機器編排的技能契約」

    上面那張名片只夠「人」看懂。要讓另一個 AI 自動挑對 skill、帶對參數,再補三個欄位:parameters(要帶什麼)、returns(會拿到什麼)、whenToUse(什麼情境該挑我)。這等於「透過 API 發布一份技能契約」:

    {
      "name": "Tom 的部落格 Agent",
      "usageHint": "每個 skill 附 parameters/returns/whenToUse,呼叫方 LLM 讀完即可自行編排,無需接線。",
      "skills": [
        {
          "id": "search_posts",
          "name": "用關鍵字搜尋文章",
          "description": "全文搜尋,回最相關的前 5 篇(標題/摘要/連結/id)",
          "parameters": { "query": {"type": "string", "required": true, "desc": "搜尋關鍵字"} },
          "returns":    "hits[]{id,title,link,date,excerpt} + total",
          "whenToUse":  "使用者問題能抽出明確關鍵字、要定位文章時"
        }
      ]
    }

    有了 whenToUse + parameters,呼叫方的 LLM 就能自己編排多步。這就是「用 Data + API 把你的資料融入 AI」的具體長相:資料是真實內容,API 是入口,而這張契約是讓 AI 自己會用的關鍵。

    它真的被呼叫成功了——一段真實的 server log

    把這個 agent 跑起來後,區網另一台機器(192.168.0.51)的一個 agent 來呼叫,log 完整記錄了它「猜協議 → 發現名片 → 從錯誤學會 → 成功」的過程:

    # 它先亂猜各種常見慣例(全 404):
    GET /health ... /v1/chat/completions ... /mcp ... /openapi.json   → 404
    
    # 命中標準路徑:
    GET  /.well-known/agent-card.json   → 200   ← 讀到名片!
    POST /tasks                         → 400   ← 沒給對 skill,被回 available 清單
    POST /tasks                         → 200   ← 從錯誤學到 skill 名,改對了,成功

    注意那個 400 → 200:呼叫方第一次打錯,server 回了「可用技能清單」,它自己讀懂、改對、成功。這就是 A2A 的精神——服務自我描述,呼叫方自己學會用,中間沒有工程師接線。

    六、同一個 /tasks 入口,不同 skill 走不同後端

    對外永遠是同一個 /tasks 入口,進來後依 skill 分流。下面四個 handler 各代表一種典型後端——呼叫生成式 Agentic SDK、走快取、查 DB、純快速計算——呼叫方完全不需要知道背後差異。

    import anyio
    from claude_agent_sdk import query, AssistantMessage, TextBlock
    
    # ① Agentic SDK 後端:呼叫會思考的 agent 生成文字(慢、秒級)
    def route_draft_notice(body):
        prompt = f"用繁體中文寫一段 50 字內催領通知,目前有 {body.get('stuck', 0)} 件待領包裹。"
        async def _ask():
            out = []
            async for msg in query(prompt=prompt):          # Claude Agent SDK 一次性查詢
                if isinstance(msg, AssistantMessage):
                    out += [b.text for b in msg.content if isinstance(b, TextBlock)]
            return "".join(out)
        return {"route": "agentic_sdk", "generated": anyio.run(_ask)}
    
    # ② 快取後端:第一次 miss 才查 DB,之後走記憶體(毫秒)
    def route_community_stats(body):
        hit = cache_get("community_stats")
        if hit is not None:
            return {"route": "cache_hit", "data": hit}
        data = {"households": db_query("SELECT COUNT(*) FROM households")[0][0]}
        cache_set("community_stats", data)
        return {"route": "cache_miss_then_db", "data": data}
    
    # ③ DB 後端:即時查真實事實,完全不靠模型
    def route_parcel_status(body):
        rows = db_query("SELECT status, COUNT(*) FROM parcels "
                        "WHERE direction='outbound' GROUP BY status")
        return {"route": "db_realtime",
                "facts": [{"status": s, "count": c} for s, c in rows]}
    
    # ④ 快速計算後端:純算、無 IO(最快)
    def route_late_fee(body):
        days = int(body.get("overdue_days", 0))
        return {"route": "compute", "overdue_days": days, "late_fee": min(days, 30) * 5}

    /tasks 本身只是一張「skill → handler」對照表,進來分流出去就好。名片對外宣告技能,但背後是 DB、快取、純算還是會思考的 agent,全藏在門面後;加後端只要多一個 handler + 對照表一行。

    七、權限:誰能看什麼資料?(認證 vs 授權)

    真實系統的 DB 一定有「誰能看哪些 row」。新手最常問:這種權限要不要做成 skill 參數、讓使用者連的時候把帳密帶進去?都不要。先把兩件事拆開:

    • 認證(Authentication)= 你是誰 → 驗 token 簽章
    • 授權(Authorization)= 你能看哪些 row → server 從已驗證的身分推導範圍

    核心原則一句話:token 不放 skill 參數、放 HTTP header;「能看什麼」由 server 從 token 推導,不讓呼叫方自報。還記得第四段的兩層嗎——身分屬於「水管層」,不屬於「自然語言層」。A2A 名片用 securitySchemes 宣告認證方式(Bearer JWT / API Key / OpenID Connect),呼叫方把憑證放 Authorization header,而不是塞進 skill 的 parameters

    # 名片宣告認證方式(A2A securitySchemes)
    CARD["securitySchemes"] = {"bearer": {"type": "http", "scheme": "Bearer", "bearerFormat": "JWT"}}
    CARD["security"] = [{"bearer": []}]
    
    @app.post("/tasks")
    def tasks():
        # ① 認證:token 從 HEADER 取(不是 body 參數!),驗簽
        token = request.headers.get("Authorization", "").removeprefix("Bearer ").strip()
        claims = verify_jwt(token)
        if not claims:
            return jsonify({"error": "unauthorized"}), 401
        ctx = {"user_id": claims["sub"], "community_id": claims["community_id"], "role": claims["role"]}
    
        body = request.get_json()
        handler = SKILL_MAP.get(body.get("skill"))
        return jsonify(handler(body, ctx))         # ② 把已驗證身分傳給 handler
    
    # ③ 授權:範圍來自 ctx(token),不是 body —— caller 改不了別人的 community_id
    def route_parcel_status(body, ctx):
        rows = db_query("SELECT status, COUNT(*) FROM parcels "
                        "WHERE community_id = %s GROUP BY status", ctx["community_id"])
        return {"facts": rows}

    更保險的做法是把範圍下推到 DB 層的 RLS(Row-Level Security):handler 只從 ctx 設一次,之後資料庫自己擋,handler 想繞都繞不過。為什麼一定要這樣?因為 caller 帶進來的 body 一律不可信——它可以亂填 community_id=別人的。讓 caller 自己指定範圍,等於誰來問都能撈全部,這就是經典的 confused deputy(被搞混的代理人) 漏洞。

    那個 token 哪來?放哪?(你不用把帳密唸給 AI 聽)

    token 不走自然語言。使用者對登入端登入一次、換到一個短期 JWT,之後由 client 程式自動帶,LLM 碰都碰不到。token 放在一個秘密檔(像 .env,chmod 600),呼叫時讀出來貼 header——不貼進對話、也不做成 skill:

    # token 放秘密檔,呼叫時才讀出來貼 header(整個過程沒人看到 token 的值)
    curl -H "Authorization: Bearer $(cat ~/.config/a2a/token)" \
         -d '{"skill":"parcel_status"}' https://your-agent/tasks
    
    # 帳密要定期刷 token 的話:先拿憑證換動態 token,再打 A2A
    TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" https://idp/oauth/token | jq -r .access_token)
    curl -H "Authorization: Bearer $TOKEN" -d '{"skill":"parcel_status"}' https://your-agent/tasks

    定期刷的場景就是 OAuth2 的 client-credentials / refresh 流程:你準備好「帳密 + 一個換 token 的小程式」,呼叫方先拿帳密換動態 token,再打 A2A,過期就再換一次。注意:發 token 的(登入端 / IdP)要跟驗 token 的(A2A server)分開,別把登入服務塞進 A2A 本身。

    八、發現 vs 認證:服務全鎖時,名片還怎麼發?

    這裡有個雞生蛋問題:如果服務要認證,那「還沒有帳密的人」怎麼讀得到名片、知道怎麼用?更現實的是——大多數系統的 auth 掛在最前面的 Nginx 層、ingress annotation 或 WAF,請求根本到不了你的 router 就被踢掉,那名片不也一起被擋了?

    解法一:名片分兩層,公開的那層本來就免認證

    名片 路徑 要認證? 內容
    公開名片 /.well-known/agent-card.json ❌ 免 基本技能 + 「我怎麼認證」(securitySchemes)
    進階名片 /extendedAgentCard ✅ 要 驗證後才看得到的完整 / 隱藏技能

    「怎麼用我」這件事本身是公開的:公開名片不需要帳密就讀得到,而且它自己會告訴你「要進來請走這個認證方式」。發現永遠在認證之前。至於最初那組帳密哪來?A2A 協議不發帳密——它是透過 out-of-band(協議之外)拿到的,也就是一個人的決定:管理員幫你開帳號、給你 client_id/secret。協議不會從零變出信任。

    解法二:把發現路徑設成 Nginx 白名單(跟 /login 同一招)

    你早就有一批「必須公開的 bootstrap 路徑」:/healthz(LB 探活)、/.well-known/acme-challenge/*(Let’s Encrypt 續憑證)、/oauth/token(認證端自己不能要認證)。公開 Agent Card 就是再加一條進這個白名單而已:

    # 其他全鎖,只開這一個發現路徑
    location = /.well-known/agent-card.json {
        auth_request off;          # 不套那道 auth
        proxy_pass http://a2a_backend;
    }
    location / {
        auth_request /_auth;       # /tasks、/extendedAgentCard 照常鎖
        proxy_pass http://a2a_backend;
    }

    安全上不虧:A2A spec 明講公開名片不可放機密,它只放「名稱 + 怎麼認證 + 非敏感技能」,敏感技能放進階名片。所以開白名單不洩漏東西,只是貼一張「敲門方式」在門口。

    解法三:全內網死鎖時,名片根本不從這台機器送

    如果你連白名單都不想開(整個服務鎖在防火牆後),那就不要用公開發現,改用 A2A 另外兩種發現方式。關鍵觀念:名片只是一份可攜的 JSON,不一定要從「被保護的那台機器」送出去——發現 ≠ 執行,名片可以跟服務不同台。

    • Direct Configuration:你直接把名片 JSON(或內部 URL)手動給授權的呼叫方。
    • 內部 Registry:名片發布到一個內部 agent 目錄,授權 client 去那查。

    呼叫方本來就得在你的網路邊界內(VPN / 內網)才打得到 /tasks,那它也能從同一個內網管道拿到名片——你不用為了發名片在防火牆上戳洞

    九、實戰會踩的坑

    • a2a-sdk 版本坑:網路範例多半用 A2AStarletteApplication(0.x,pydantic + Starlette);但現在 pip install a2a-sdk 裝到的 1.1.0 是 protobuf / gRPC 生成,API 完全不同,照舊範例會整段跑不起來。協議穩定,SDK 的 API 會變——手刻一個極簡 HTTP server 反而最穩。
    • 把認證塞進 skill 參數:最常見的設計錯。憑證走 header、走 securitySchemes,絕不放進 skill 的 parameters;範圍永遠由 server 從 token 推導。
    • Cloudflare / WAF 擋 UA:agent 去抓套了 Cloudflare 的服務,Python urllib 不帶 User-Agent 會被回 403;帶一個瀏覽器 UA 就 200。

    結論:A2A = API 口 + 一張名片 + 一道標準的認證

    把 A2A 想成「微服務互呼,但對方是會思考的 agent,用一張名片自我介紹、讓呼叫方的 LLM 自己學會用」,核心就抓到了。技術上它可以小到一個 Flask 檔 + 一句 SQL;放上 production 時,認證走標準 header、授權由 server 從身分推導、發現用公開名片或內部 registry——每一塊都對得上你已經會的後端慣例,沒有新魔法。難的從來不是協議,而是:你那張名片上,值得被別的 AI 呼叫的技能,到底是什麼?

    延伸閱讀(實戰續篇):把 HR 表單系統接上 A2A:讓 AI 幫新人填表與上傳證件——把這篇的概念套到一個真的在跑的 HR 入職系統,含四個 skill、偵測不擋的把關哲學,與測試別碰 live 的踩坑。

  • 一張圖看懂 AI Agent 系統:Loop、Harness、MCP、A2A 差在哪

    每次跟同事解釋 AI Agent 系統,最常見的反應,是看著 Loop、Harness、MCP、A2A、Dataset 一堆名詞發呆。會迷茫,是因為這些詞常被當成「平行並列」硬背。其實它們分屬三層、各司其職,而且有先後順序。這篇用一張全景圖,加上「員工在公司做事」的比喻,讓完全不懂技術的人也能 30 秒看懂彼此的關係,以及最容易混淆的 MCP 與 A2A 到底差在哪——最後再談一個實際問題:怎麼讓整個團隊在一個平台上共用 agent。

    重點摘要

    • Loop / Harness / Agent / Skill / MCP / API / Dataset / A2A 不是平行概念,是三層:HARNESS(手腳)→ KNOWLEDGE(規矩與記憶)→ LOOP(節奏與目標)。
    • MCP 讓 agent 接「工具與資料」(把對方當死的工具);A2A 讓 agent 接「其他 agent」(把對方當活的同事)。兩者互補,不打架。
    • 要讓整個團隊共用 agent,關鍵不是「又一個聊天框」,而是一個共享的知識中樞,讓全團隊的 agent 站在同一份事實上工作。

    先看這張圖:30 秒看完全部關係

    如果下面的文字看不完,只要記住這張圖就夠了。外層的 LOOP 包著 KNOWLEDGE 和 HARNESS,Agent 用 MCP 接工具、用 A2A 接其他 agent。

    🗺️ 30 秒全景圖(外框就是 LOOP)
    🟢 KNOWLEDGE 規矩 + 記憶(Agent 做事時隨時回來查)
    📋 Skill 正確做法 🩹 Brain 踩過的坑 📒 KM 接真實資料庫的事實
    🔵 HARNESS 環境 + 對外插座
    🧑‍💼 Agent ──MCP──▶ 工具 / API / 資料庫(死的工具) ──A2A──▶ 其他 Agent(活的同事)
    📚 Dataset = 造出模型的底層料(已煮進模型、會記錯,所以才需要上面的 KM 當場查真相)
    一句話:HARNESS 給手腳 → KNOWLEDGE 給規矩記憶 → LOOP 給節奏目標。

    三層,不是一排:正確理解的關鍵

    這些名詞會讓人頭痛,是因為大家把它們當成同一層的東西在背。把「AI 幫你做一件事」拆開,其實由下往上是三層:下層給能力,中層給規矩與記憶,上層給節奏與目標。而且有一條鐵律:一定是 HARNESS → KNOWLEDGE → LOOP。工具沒備好、規則沒寫好,就先讓 agent 自己跑,它會被冒出來的錯誤推著改個沒完,沒有終點。

    用「員工在公司上班」秒懂每個名詞

    把整套 AI 系統想成一位員工在公司做事,每個名詞都對得上一個你熟悉的東西:

    名詞 一句話 員工比喻 屬哪層
    Agent會自己判斷、動手做事的 AI 本體員工本人工具層
    Harness承載 agent 的環境、工具與權限辦公室與設備工具層
    MCP接「工具/資料」的標準插座萬用識別證工具層
    API外部系統對外的窗口部門窗口工具層
    A2A接「另一個 agent」的協定同事間協作工具層
    Dataset造出模型的原始料(會煮進模型、會記錯)讀過的書工具層
    Skill某類任務的正確做法作業 SOP規則層
    Brain 防錯腦踩過的坑(事實,不背叛)血淚筆記規則層
    KM 正道腦接真實資料庫的事實 + 可糾正的判斷公司帳本 + 老師傅規則層
    Loop做到可驗證目標達成才停工作節奏 / KPI流程層

    最容易搞混的:MCP 與 A2A 差在哪?

    一句話分清楚:看你把對方當「死的工具」還是「活的同事」。MCP 是 agent 跟工具、資料的對話;A2A 是 agent 跟另一個 agent 的對話。

      MCP A2A(Agent-to-Agent)
    對象工具 / 資料(死的,聽話)另一個 agent(活的,會自己判斷)
    做什麼幫我查、幫我寫進去交辦多步驟任務、追蹤進度、他做完回報
    員工比喻員工 ↔ 部門窗口員工 ↔ 別的員工

    兩者不打架,是互補的:一個團隊用 A2A 在 agent 之間分工協作,而每一個 agent 內部都用 MCP 去接自己要用的工具。A2A 管「同事之間的對話」,MCP 管「每個人跟工具的對話」。

    A2A 實際怎麼運作:靠一張「名片」

    A2A 的核心是 Agent Card(代理名片)。每個 agent 在一個固定網址掛一張公開的名片,上面寫清楚:我會做什麼、我的服務入口在哪、怎麼跟我認證。別的 agent 不需要知道你內部怎麼運作,只要讀這張名片,就能發現你、把任務交給你、等你做完回報。就像兩家公司合作,看的是對方門口「服務項目 + 聯絡窗口」的牌子,不需要走進對方辦公室看他們怎麼做事。

    這在 2026 已經是業界標準:A2A 由 Google 發起、現在交給 Linux Foundation 治理,有 Python、JavaScript、Java、Go、.NET 五種語言的開發套件,並已內建進 Microsoft Copilot Studio、Azure AI Foundry、Amazon Bedrock 等平台。意思是,不同廠商、不同框架做出來的 agent,現在能用同一套規矩互相對話——這正是「讓大家的 agent 互通」的基礎。

    關鍵:知識層為什麼要接「真實資料」,而不是寫死答案

    AI 會幻覺、會忘記。所以把知識接給 agent 時,真正可靠的不是「標準答案」——答案是判斷,會隨著架構改變而過期。可靠的是兩種事實:一是「過去踩過的坑」(真的發生過,不會變),二是「資料庫此刻的真實數字」(當場查得到)。讓事實去約束 AI 的嘴,而不是讓 AI 的判斷當真理。這就是為什麼進階的知識系統(KM)會直接接上正式資料庫,而不是把答案寫死在文件裡——真相在帳本裡,不在 AI 的記憶裡。

    進階:怎麼讓整個團隊在一個平台上共用 agent?

    現在多數人是「一個人對一個 AI 工具」,各做各的——知識不共享、agent 不互通、同樣的事每個人重做一次。如果要讓整個團隊(包含不會寫程式的同事)在一個平台上共用 agent,要補三個能力,由淺到深:

    1. 共享的知識/工具中樞(最該先做):用一個團隊共用的 MCP 中樞,讓每個人的 agent 都連到同一套知識庫和工具。這樣大家查到的是同一份事實、同一套規矩,不再各憑記憶。這就是平台的心臟。
    2. agent 之間能協作:同一個系統內,可以一個「主管 agent」把任務拆給幾個「工人 agent」;跨不同系統、不同廠商,就用前面講的 A2A,讓各自的 agent 互掛名片、互相委派。
    3. 讓非技術同事也能用:大部分 agent 工具是給工程師的指令列介面,一般同事用不了。要在前面包一層簡單的網頁入口,同事用下拉選單選角色、打字提問就好。

    落地有兩條路。買現成平台(例如 monday.com、Microsoft Copilot Studio)走免寫程式、上手快,適合通用流程;但它通用、不認識你的產業,也接不上你公司的真實資料庫。自己搭(用 agent 開發框架 + 自建的共享 MCP 中樞 + 網頁入口)工要多一些,但能接上你自己的領域知識和真實營運資料——而這正是現成平台給不了的差異。

    一個關鍵判斷:平台的價值不在「又一個聊天框」,而在那個共享的知識中樞——它讓全團隊的 agent 站在同一份事實上工作。先把這個中樞建起來,agent 協作和網頁入口都是接上去的事。

    一句話收尾

    下次再看到這一串名詞,不用硬背。記住三層就好:HARNESS 給手腳、KNOWLEDGE 給規矩與記憶、LOOP 給節奏與目標;而 MCP 接工具、A2A 接同事。要把團隊一起拉上來,先建一個大家共用的知識中樞,剩下的細節,都掛在這個骨架上。

  • 拔掉 RLS 的兩天:AI 時代規模化 Day One 為何從奢侈變預設

    重點摘要

    • 540 萬包裹壓測,警衛的社區包裹列表要 7330 毫秒。病根是 RLS 兩條 PERMISSIVE policy 用 OR 合併,讓查詢規劃器用不到 community_id 索引。
    • 全面拔除 173 條 policy、85 張表的 RLS,租戶隔離 100% 改由應用層帶 community_id。同一條查詢從 7330ms 降到 1.34ms,約 5500 倍。
    • 但拔掉 RLS 不是終點——第二波跨社區洩漏被「單租戶壓測」蓋住了:對照社區在多數表是 0 筆,洩漏判準(本社區數=全平台數)自動成立。要每張表都灌 ≥2 個社區才測得出;而且漏帶 community_id 不只洩漏,更是少了索引,同一個病根換地方又長。
    • AI 把規模準備的「建造成本」打掉了,但有兩個成本它打不掉:分區帶來的「複雜度稅」(維護照繳),與「取決於規模實測才知道對錯」的經驗決策(RLS 自己就是反例)。
    • 結論:AI 時代「規模化 Day One」從奢侈變預設,但「準備什麼」的判斷力更值錢——有把握的提前上,取決於壓測的,老實留給壓測。

    一個 V2 產品、兩天、一個 AI 協作者,把一套多租戶系統從「靠資料庫兜底」推進到「應用層自己負責」。這篇記錄的不是 commit log,是技術選型的隱性成本,怎麼在特定規模與特定哲學下才現形——以及 AI 怎麼悄悄改寫了「該不該提前準備規模化」這道老題目。

    先講結論:MVP 智慧是成本算出來的啟發法,不是定律

    傳統智慧說:MVP 先做,別過度工程,規模化以後再說。這句話我一直信,直到這兩天我意識到——它是一條成本驅動的啟發法,不是定律

    它成立的前提是「規模準備很貴」。以前要做分區、多租戶隔離、idempotency、離線佇列這整套規模機械,往往要多三到四倍的人力、好幾個月。那個成本,才讓「先別做、等需要再說」變成理性選擇。但兩件事同時改變了這個算式:

    1. AI 把建造成本打掉了。那套規模機械,AI 輔助下生成 + 維護的人力崩塌。
    2. 這是 V2,不是 try。前一版已經證明了領域——住戶、警衛、包裹是真需求,而且會有很多社區。規模不是猜測,是 near-certainty。「You Ain’t Gonna Need It」的前提「你可能不需要」,直接是假的。

    所以對一個 AI 輔助、領域已驗證的 V2,Day One 就準備規模化,比經典 MVP 智慧主張的更該做。但這篇真正有料的地方,是兩個 AI 也打不掉的成本。後面講。

    當初為什麼這樣選技術?

    這套系統的技術選型,是三股力量的合力:領域驅動 + 規模前瞻 + 不重蹈前版覆轍

    • Flutter 單一 codebase:住戶用手機、警衛用平板,功能大半重疊靠角色 gate。兩份原生 = 兩倍維護;一份 + responsive 是省力的對。加上離線優先是硬需求(警衛平板斷網也要能收件、拍照、印通知條)。代價老實說:CanvasKit 的 web 端很痛,e2e 自動化一路在跟它的無障礙語意樹搏鬥。
    • Go + GraphQL(型別契約):Go 單一 binary 好部署、並發強,對著「1000+ RPM / 1000 社區」的目標。GraphQL 用型別嚴謹的契約——這是對前版的反動:舊版用 category/method 字串路由 + PHP 的型別強制轉換怪招,踩過坑。型別世界 = runtime 少驚喜。
    • PostgreSQL + RLS(Row-Level Security):這個最值得講,因為我們親手拆了它

    RLS 的故事:為安全而選,為清亮而拆

    RLS 當初為什麼選?防禦縱深。理由聽起來無懈可擊:「把租戶隔離放在資料庫層,app 出 bug 也繞不過。」每個社區的資料用 policy 鎖死,誰都別想跨社區看到別人的包裹。

    然後規模化壓測來了。我們灌了 540 萬包裹、5.4 萬戶、202 個社區,模擬一個 V2 跑兩三年後的樣子。一量——警衛的社區包裹列表,7330 毫秒。七秒。

    病根不是索引沒建,是 RLS 的兩條 PERMISSIVE policy 用 OR 合併(是系統管理員) OR (社區=X)。community_id 只出現在 OR 的一邊,查詢規劃器就用不到 community_id 索引,只能 Seq Scan 掃完整張表的所有分區。這個病,設計時看不出來,要到 5.4M 才現形

    業主的反應很關鍵。他不要「在 DB 加更多限制」來繞,他要的是更乾淨:「我不要我的資料庫跟我的 AP 有這樣的依賴。本來就該做到零洩漏,怎麼會依賴 RLS?」

    於是我們全面拔除 RLS——173 條 policy、85 張表,全部 DROP。租戶隔離 100% 改由應用層:每一條碰租戶資料的查詢,自己帶上 community_id = current_setting('app.community_id')

    拆的過程,反過來證明「本來就該零洩漏」當時是假的

    審計時我抓到,授權中介層對「同社區範圍」的操作寫死了一行註解:「RLS 負責租戶隔離,這裡不另外檢查。」也就是說,有好幾個改別人資料的後端進入點(停用警衛、在別社區建戶、復活別社區的軟刪戶),它們的隔離正確性,本來就完全押在 RLS 上。RLS 一拔,這些就是跨社區提權漏洞。

    派去掃的 AI 子代理一開始判了 23 個缺口;我逐條人工驗證,收斂到 3 個真缺口——其餘有的早被別的守衛擋著、有的是子代理幻覺出根本不存在的函式。這也是個教訓:AI 的清單要逐條驗,不能盲信。

    拆完,效能呢?同一條查詢,帶上 community_id:

    查詢 RLS 開(OR 合併擋索引) RLS 拔除 + 應用層 community_id
    警衛社區包裹列表(5.4M 列) 7330 ms(Seq Scan 全分區) 1.34 ms(Index Scan)
    包裹改動歷程鑽取 0.2 ms

    從 7330ms 到 1.34ms,約 5500 倍。反諷的地方:當初選 RLS 是「為了安全」。它不但變成效能地雷,還讓 app 層偷懶——「反正 DB 會兜底」,於是 app 層的隔離就不嚴謹了。兜底機制養出了被兜底者的鬆懈。

    拔完 RLS 之後:洩漏沒結束,是換了個地方躲

    拔掉那天修了 3 個提權,我以為收工了。錯。RLS 一拔,等於把「DB 兜底」這層拿掉,所有原本偷懶的查詢全部裸奔——真正的第二波,要再跑一輪壓測才現形。

    一個包裹計數查詢,給某社區警衛回了 280 萬——那是整個平台的數字,不是他那個社區的。病根:這個 count 自己手寫 WHERE,繞過了會自動補 community_id 的中央 helper。同一類的還有一票:社區統計(*Stats)、各種計數(*Count)、住戶/包裹 picker、以及「先 load-by-id 再改」的 mutation——全是各自為政手寫查詢、漏帶租戶欄位的高風險地帶。

    但這篇最該記住的,是為什麼第一次壓測沒抓到。答案很反直覺:單租戶結構上測不出跨租戶洩漏。

    我第一次灌的 540 萬,只灌在 parcelshouseholds 兩張表,其他維度(使用者、訪客、公告、picklist)對照社區根本 0 筆。而洩漏的判準是「本社區查到的數字 == 全平台的數字」——當對照組是 0,這條恆等式自動成立,洩漏被 0 資料蓋得死死的。修法不只是補 WHERE,是補資料形狀:每一張要驗的表,都灌進 ≥2 個社區的資料,動態探針才有對照組去抓「你回給我的,有沒有混進別人的」。

    還有一層,業主一句話點破:漏帶 community_id 不只是洩漏,是效能。「為什麼還有功能沒戴上 ID,這不只會洩漏,重點是效能會變差,沒用到 index。」少了那個欄位,查詢就跟當初 RLS 的 OR 一樣用不到索引、掃全表。防洩漏和上索引,是同一個動作——community_id 既是隔離邊界,也是索引前綴。當初那個「OR 擋索引」的病根,拔了 RLS 之後,在每一條手寫查詢裡換個地方又長了出來。

    規模下另外兩個 Day One 就得拍的板

    同一輪還拍了兩個一旦上線就很難回頭的板,都是「規模 + 時間」逼出來的。

    • 快照 vs 正規化:歷史標籤不准 join。包裹上的物流公司、儲位、包裹類型、收件人姓名,全部存成當下的文字快照,不是外鍵。為什麼不正規化?因為這些是歷史事實。若做成外鍵去 join 現行字典,哪天某家物流公司改名或下架,過去的包裹紀錄會被回頭改寫——未來的公司出現在過去的資料上。原則一句話:身分用外鍵,歷史標籤用快照。這跟「證據鏈不可竄改」是同一個底層要求。
    • 控制面狀態用單例快取,不是每頁查 DB。社區可被系統管理員停用,每個請求都得確認「這社區還活著嗎」。最笨的做法是每頁打一次 DB——那又是另一種 RLS 式的過度防禦。做法是一個程序級單例快取(map + 鎖),10 分鐘 TTL,miss 才查 DB,停用/復活時主動逐出;隔離檢查收斂在一個 chokepoint(進交易時查一次),不撒在每條查詢。順手修了個誠實問題:社區停用後登入原本回「帳密錯誤」會誤導用戶,改成帳密對的人才告知「社區暫停服務中」——既不誤導本人,也不洩漏社區存在給攻擊者。

    兩個 AI 也打不掉的成本

    回到開頭的 thesis。AI 讓規模準備「便宜到值得 Day One 就做」——但有兩個成本它打不掉。

    成本 AI 打掉了什麼 AI 打不掉什麼
    複雜度稅 建造成本(生成分區/隔離/佇列) 維護稅:每次改動/debug 都要付。例:pg_total_relation_size 對分區母表回 0,最大的表都報 0,要展開分區層才量得到
    經驗決策 實作速度 壓測經驗:RLS 的「OR 擋索引」要 5.4M 才看得見,連 AI 都沒辦法 Day One 告訴你對的選擇

    成本一:AI 打掉「建造成本」,沒打掉「複雜度稅」。月分區讓程式更難推理。這兩天我們親自繳了這個稅:監測資料量時,pg_total_relation_size 對分區母表只算母表本身(回 0);還有 FK 要複合鍵、分區不繼承 RLS、清測試資料時被自己剛上的 append-only trigger 擋住……這個複雜度,是每一次未來改動、每一次 debug 都要付的稅,連 AI 也付。「AI 讓規模準備好建」是真的,「規模準備免費」是假的——稅照繳,只是從建造繳給了維護。

    成本二:有些規模決策是「經驗的」,Day One 就是準備不了——RLS 自己就是鐵證。RLS 本來就是 Day One 的規模準備(多租戶隔離),結果它是錯的 Day One 選擇。為什麼當初設計看不出來?因為「OR 擋索引」這個病要 5.4M 壓測才看得見。有些決策,正確答案取決於規模行為,而那行為你預測不了——那是壓出來的,不是設計出來的。而且如前面那一節的教訓:光有規模還不夠,要對的「資料形狀」——對照社區是 0 筆的那次壓測,把第二波洩漏整個蓋住了。經驗決策不只需要壓力,需要對的壓力

    AI 時代,「規模化 Day One」從奢侈變預設。但「準備什麼」的判斷力反而更值錢:有把握的結構提前上(便宜了);取決於規模實測的決策,老實留給壓測。

    有把握的(會有很多社區 → 按社區/時間分區;離線不可妥協 → 佇列),提前做。沒把握的(隔離機制、索引策略),別假裝設計階段就能拍板。這跟我之前寫過的 企業 AI 落地為什麼失敗 是同一個底層觀念:方法論不能照抄,要看你的前提條件還成不成立。

    方法:規格化、決策留證、以及「我自己打臉自己」的報告

    這兩天還做了第二件大事——把包裹做成可被法庭級檢驗的證據鏈。改動寫進不可竄改的 log(鑽一顆包裹的歷程,5.4M 下 0.2 毫秒)、簽名與照片在儲存層鎖死不可刪、系統管理員調查要「破窗」且每次都留審計。但比功能更值得分享的是方法

    • 規格先行。每個設計決定都先寫進規格、辯論清楚、鎖進文件,才動手。對話會被壓縮遺忘,規格不會。
    • 決策留證,不靠主觀評分。業主不信任 AI 加工過的「成本/風險」評分,他要看真實檔案、真實行數、schema 影響。所以需要他拍板的時刻,我生的是事實卡片,不是紅黃綠燈。
    • 三份報告的誠實檢驗。最後他要一份評分報告。但他要的不是一個數字——他要三份做比較:原始版、我「現在的預估」(鎖時間戳,不准事後改)、和「全部做完 + 全面測試後的真實量測」。核心是拿我的主觀預估去對真實量到的,差多少 = 我的評估可信度。

    結果:我預估綜合 7.5,真實約 7.8,誤差約 0.3 分;方向性預測(「dev 環境的測試污染會讓部分整合測試紅、但那不是回歸」「forensic 能力做完會升」「效能會守住」)全中。唯一校準:我對「系統穩定度」過度保守——實際零回歸。這種「逼 AI 先承諾預測、再用真實數據打臉」的設計,把「AI 的話可不可信」變成一個可量測的問題。

    人機協作:最好的部分不是分工,是辯論

    這兩天的分工大概是:業主出領域知識與方向決策,AI 出執行、驗證與反思。但最好的部分不是分工,是辯論。RLS 該不該拆、拆了 sysadmin 怎麼查日誌、照片資料夾要不要鏡射分區、孤兒清理會不會變成刪證據的後門——這些不是「下指令、執行」,是來回推。

    業主用領域常識把我拉回現實(「哪有警衛不分社區的,警衛 A 在四個社區工作就是四個警衛」),我用壓測數據和審計把假設證偽(「你說本來就零洩漏,但我們現有 code 就漏了 3 個」)。AI 不會累、能掃完每個呼叫點、能把 23 個候選逐條驗到剩 3 個真的;但判斷「準備什麼」「什麼時候該停下來問人」,還是要人。

    結語

    如果只能留一句:老的 RD 有老的包袱,所以才有「MVP、先別管規模」的智慧。但那個智慧是成本算出來的。當 AI 把建造成本打掉、當你做的是領域已驗證的 V2——規模化就是 Day One 的事。只是別忘了,AI 打不掉複雜度稅,也替不了你壓測;有把握的提前上,沒把握的,老實壓出來——而且要用對的資料形狀去壓,單租戶測不出跨租戶的洩漏。

    RLS 是我們「Day One 準備了錯的東西、規模化才發現」的活標本。它沒有讓這個決定變壞——它讓這個決定有了教材

    技術細節:Flutter + Go(gqlgen) + PostgreSQL 16;月分區、River 佇列、MinIO。壓測 540 萬包裹 / 202 社區 / RLS-off:熱查詢 1.34ms、改動 log 鑽歷程 0.2ms。

  • 讓 Claude Code 走企業自管:從直連 Azure Foundry 到 API Gateway

    重點摘要

    • Claude Code 官方原生支援把後端從 Anthropic 訂閱換成雲端供應商,本文走 Azure / Microsoft Foundry 這條,目標是把資料與計費留在公司合規邊界內。
    • 第一階段:用 CLAUDE_CODE_USE_FOUNDRY=1 直連 Foundry 部署的 Claude,含 settings.json、Entra ID 認證、原始 curl。
    • 第二階段:在前面架一個自家 DNS 的 API Gateway,Claude Code 改用 ANTHROPIC_BASE_URL 只打一個入口,Gateway 依 model 欄位路由到後端——這才是企業統一控管的正解。
    • 關鍵觀念:不是每個模型一個網址,而是一個入口、用 body 的 model 名分流。

    為什麼要弄:當 AI 訂閱開始「換軌」

    2026 年起,前沿模型供應商的計費邏輯正在改變:訂閱方案把「互動使用」和「自動化 / Agent 使用」拆成不同的計量池,企業帳號甚至無法直接購買訂閱、只能走 API。對個人開發者這是成本問題;但對企業,真正的痛點是另外兩個字:控管

    企業導入 AI 編碼工具時,資安與法遵部門會問的第一個問題永遠是:「我們的程式碼與機密,送去哪裡?誰能存取?怎麼稽核?成本怎麼歸戶?」 把 Claude Code 直接接公開 API,這些問題全部無解。解法是讓推論跑在公司自己的雲端租戶裡,資料留在合規邊界內,並在前面架一道統一閘道。本文就是這條路的逐步實戰,從最簡單的直連,進化到可上線的企業架構。延伸閱讀可參考我先前寫的 用 Claude Code Hooks 打造大腦反饋迴路

    全局:兩個階段

    整條路分兩階段。先讓 Claude Code 直連雲端供應商上的 Claude(證明機制),再把它收斂到自家閘道後面(正式控管)。

    階段一(直連):
      Claude Code  --->  https://<resource>.services.ai.azure.com/anthropic/v1/messages
    
    階段二(閘道):
      Claude Code  --->  https://ai-gw.yourcompany.com/v1/messages  --->  雲端供應商後端
                         (自家 DNS、統一入口、依 model 路由、注入真憑證)

    第一階段:Claude Code 直連雲端 Foundry

    1. 在 Foundry 部署 Claude 模型

    在 Foundry 入口建立資源並部署 base model。三個實務重點,踩過才知道:

    • 地區限定:Claude 模型目前只開放在特定區域(本文撰寫時為 East US 2 與 Sweden Central),選錯區一定部署失敗。
    • 務必接受服務條款:第一次在資源上部署 Claude,後台要建立一個對應的供應商組織(Anthropic Organization)。部署時跳出的 Terms of Service 一定要在「正確登入帳號」狀態下按接受,否則握手失敗。
    • bad-state 陷阱:一旦某次部署握手失敗進入 bad state,該資源就修不好、重部任何模型都會死。正解是建立全新資源,別在壞掉的資源上重試。

    2. 設定 Claude Code(settings.json)

    最乾淨的做法是把環境變數寫進 Claude Code 的 settings.jsonenv 區塊(跨平台、持久,Windows 與 Linux 通用)。檔案位置:Linux 是 ~/.claude/settings.json,Windows 是 %USERPROFILE%\.claude\settings.json

    {
      "language": "繁體中文",
      "theme": "dark",
      "env": {
        "CLAUDE_CODE_USE_FOUNDRY": "1",
        "ANTHROPIC_FOUNDRY_RESOURCE": "<your-resource-name>",
        "ANTHROPIC_FOUNDRY_API_KEY": "<your-foundry-key-or-omit-for-entra-id>",
        "ANTHROPIC_DEFAULT_SONNET_MODEL": "<your-sonnet-deployment-name>",
        "ANTHROPIC_DEFAULT_OPUS_MODEL":   "<your-opus-deployment-name>",
        "ANTHROPIC_DEFAULT_HAIKU_MODEL":  "<your-haiku-deployment-name>"
      }
    }

    各變數的意義:

    變數 作用
    CLAUDE_CODE_USE_FOUNDRY設為 1 啟用 Foundry 整合。沒設的話 Claude Code 會走預設的公開 Anthropic API。
    ANTHROPIC_FOUNDRY_RESOURCE你的資源名稱;Claude Code 會自動組成端點 https://<resource>.services.ai.azure.com/anthropic
    ANTHROPIC_DEFAULT_*_MODEL三個層級(Sonnet/Opus/Haiku)各自的「部署名稱」,不是 model id。注意部署名可能跟 model 名不同(例如同名重建時會自動加序號)。

    重要:ANTHROPIC_DEFAULT_*_MODEL 一定要填「實際部署名」。Claude Code 內部會依當下任務挑層級(主要寫 code 用 Sonnet/Opus,讀檔、摘要等雜活用 Haiku),把對應的部署名塞進請求送出。

    3. 認證:Entra ID(建議)或 API 金鑰

    兩種選擇。企業環境建議 Entra ID:不把金鑰寫進檔案,改用 Azure CLI 的身分,集中式身分管理、適合團隊與 CI/CD。只要在啟動 Claude Code 前登入即可:

    # 方案 A:Entra ID(不放金鑰進檔案,建議)
    az login
    az account show        # 確認登入到正確訂閱
    # 然後在 settings.json 拿掉 ANTHROPIC_FOUNDRY_API_KEY 那行即可
    
    # 方案 B:API 金鑰(快速測試用)
    # 直接把金鑰填進 settings.json 的 ANTHROPIC_FOUNDRY_API_KEY

    4. 驗證設定

    啟動 claude,在裡面打 /status,確認 API provider 顯示 Microsoft Foundry、resource 與 model 都正確。啟動橫幅若顯示類似 Sonnet 4.5 · API Usage Billing,代表它走的是 API 計量(雲端供應商),不是訂閱。最後送一句測試訊息,有正常回應就代表端到端打通。

    5. 直接打 Messages API:預設協議就能用

    很多人會問:不能直接用「預設的 Messages API」嗎?能,而且它就是。 Foundry 的端點本來就是標準的 Anthropic Messages API,只是換了網址與認證。跟原生 Anthropic API 只有三點差別:網址不同、model 欄位填「部署名」、認證用 Azure 的方式。以下是兩種認證的原始 curl:

    # 用 API 金鑰(Header 是 x-api-key)
    curl -X POST https://<resource>.services.ai.azure.com/anthropic/v1/messages \
      -H "Content-Type: application/json" \
      -H "x-api-key: $AZURE_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -d '{
        "model": "<your-deployment-name>",
        "max_tokens": 256,
        "messages": [{"role":"user","content":"Hello, which model are you?"}]
      }'
    
    # 用 Entra ID(Header 是 Authorization: Bearer,scope https://ai.azure.com/.default)
    curl -X POST https://<resource>.services.ai.azure.com/anthropic/v1/messages \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $AZURE_AUTH_TOKEN" \
      -H "anthropic-version: 2023-06-01" \
      -d '{
        "model": "<your-deployment-name>",
        "max_tokens": 256,
        "messages": [{"role":"user","content":"Hello, which model are you?"}]
      }'
    

    6. 一個必知限制:訂閱資格與配額

    有個坑要先知道:Foundry 上的 Claude 通常限定企業等級訂閱(Enterprise / MCA-E),而且非企業訂閱的預設配額可能是 0 RPM / 0 TPM,免費 / 試用 / 純 credit 帳號不支援。意思是——你用個人帳號可以「部署成功」,但真正送推論時可能撞到 0 配額或資格錯誤。這正是企業要在正式的公司訂閱下跑、而不是個人帳號的硬理由。

    第二階段:進化成 API Gateway

    為什麼要 Gateway

    直連能動,但每台機器各自拿著後端憑證、各自直接打雲端——這在企業是不可維護也不安全的。把一道閘道架在中間,你得到一個單一控制點:

    • 統一認證與 RBAC:誰能用、能用哪些模型,集中管理;client 只拿你發的 token,永遠看不到後端真憑證。
    • 稽核與成本歸戶:每一筆請求記 log,依使用者 / 專案歸戶成本。
    • 限流與配額:在閘道做,而不是寄望每個 client 自律。
    • 供應商解耦:哪天要把某個模型從 A 雲換成 B 雲,改閘道就好,幾百台 client 一行都不用動。

    關鍵架構原則:一個入口,依 model 路由

    最容易設計錯的地方:不要做成「Sonnet 一個網址、Opus 另一個網址」。 Claude Code 整個 session 只認一個 base URL,它靠請求 body 裡的 model 欄位區分模型,所有請求都送到同一個入口。所以正確設計是:閘道對外只露一個 DNS 入口,內部再依 model 名稱路由到對應的後端部署。你想像中的「API1 / API2 分流」應該活在閘道後面,對 client 只露一扇門。

    Claude Code 改成 Gateway 模式

    不再用 Foundry 那組變數,改用通用閘道模式。注意 model 這裡填「乾淨的標準名」,讓部署名的映射藏在閘道裡:

    {
      "env": {
        "ANTHROPIC_BASE_URL": "https://ai-gw.yourcompany.com",
        "ANTHROPIC_AUTH_TOKEN": "<gateway-issued-token>",
        "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-5",
        "ANTHROPIC_DEFAULT_OPUS_MODEL":   "claude-opus-4-1",
        "ANTHROPIC_DEFAULT_HAIKU_MODEL":  "claude-haiku-4-5",
        "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY": "1"
      }
    }
    • ANTHROPIC_BASE_URL(通用)取代 CLAUDE_CODE_USE_FOUNDRY;Claude Code 會打 {BASE_URL}/v1/messages
    • ANTHROPIC_AUTH_TOKEN 會以 Authorization: Bearer 送出(若閘道收 x-api-key,改用 ANTHROPIC_API_KEY)。
    • model 填標準名,閘道內部再對應到實際部署名——client 從此不必知道後端命名怪癖。

    閘道必須遵守的契約

    你的閘道本質是一個 Anthropic Messages API 相容的透傳反向代理。違反任一條,Claude Code 與所有官方 SDK 就打不進去:

    要求 說明
    對外端點 POST /v1/messages選配 /v1/messages/count_tokens/v1/models(供模型發現)。
    body 原樣透傳收到什麼 Anthropic Messages JSON,就照樣轉發,絕不改 schema
    支援 SSE streamingstream:true 必須逐塊串回,這是最常翻車的點。
    依 model 欄位路由把標準名映射成對應後端部署名並轉發。
    後端注入真憑證閘道持有後端金鑰 / service principal,client 永遠看不到。
    錯誤碼原樣回429 / 401 / 400 照轉,client 才能正確重試。

    一條封包的端到端追蹤

    把上面串起來,一通 Sonnet 請求與一通 Haiku 請求,打的是同一個網址,只有 body 的 model 不同:

    # Claude Code 做主要工作(Sonnet 層)
    POST https://ai-gw.yourcompany.com/v1/messages
    Authorization: Bearer <gateway-token>
    anthropic-version: 2023-06-01
    {"model":"claude-sonnet-4-5","messages":[...],"stream":true}
    
    # Claude Code 做雜活(Haiku 層)-- 網址與 token 一模一樣,只有 model 變
    POST https://ai-gw.yourcompany.com/v1/messages
    Authorization: Bearer <gateway-token>
    {"model":"claude-haiku-4-5","messages":[...]}
    
    # 你的 Gateway 收到後:
    #   1) 驗 token + RBAC(這個人 / 這隊能用哪些 model)
    #   2) 讀 model 欄位,查路由表:
    #        claude-sonnet-4-5 -> 後端部署 "claude-sonnet-4-5-xx"
    #        claude-haiku-4-5  -> 後端部署 "claude-haiku-4-5"
    #   3) 改寫 model 成真部署名、換上後端真憑證、轉發到雲端
    #   4) 後端回標準 Anthropic 回應 -> Gateway 原樣串回 -> Claude Code 收到

    用現成的,別手刻 schema

    別自己發明一套 JSON 格式包起來——那會讓 Claude Code 和所有官方 SDK 全部失效,很多公司「封裝 API」就死在這。直接用支援 Anthropic 相容 + model-based routing 的成熟方案:雲端原生的 API 管理服務(如 Azure API Management)、或開源的 LLM 閘道(如 LiteLLM proxy、Portkey)。它們原生就能做認證、限流、路由與 log。

    常見錯誤與排查

    症狀 原因 / 解法
    Claude Code 一直要你登入 Anthropic沒設 CLAUDE_CODE_USE_FOUNDRY=1,它走了預設公開 API。
    model is not availableANTHROPIC_DEFAULT_*_MODEL 沒對到實際部署名(注意同名重建的序號後綴)。
    401 / 403金鑰錯,或 Entra scope 不是 https://ai.azure.com/.default,或缺 RBAC 角色。
    429 / 0 配額非企業訂閱預設配額為 0;改用企業訂閱或申請配額。
    部署一直 Failed 又刪不掉資源進入 bad state;建新資源,別在壞掉的上面重試。
    經閘道後 streaming 不會動閘道沒正確透傳 SSE;確認 stream:true 的逐塊轉發。

    結語

    這條路的核心其實只有一句話:Foundry 的端點就是標準 Messages API,所以閘道只要當一個透傳代理。 先用直連證明機制能通,再用閘道把它收斂成「單一入口、依 model 路由、注入真憑證」的企業架構——資料留在合規邊界、計費可歸戶、供應商可替換。當前沿模型的使用門檻越來越高,能把它穩穩接進公司治理框架的能力,本身就是一種競爭力。

  • 當 AI 夠重要,價值與風險就是一體兩面:談 AI 治理與 ROI

    重點摘要

    • AI 的 ROI「難算又好算」:別只看表面省工,要看頻率質變——一個分析從「一年做一次」變成「一月一次」,價值是跳級的。
    • ROI 要對到競爭本質與戰略目標,不是中階的過程 KPI。
    • 當 AI 夠重要,它的價值與風險就是一體兩面,這不是缺陷,是事實。
    • 治理心法:讓法遵、風險、業務所有人在同一個平台看同樣的問題與機會,達成共識才放行。
    • 底線是主權 AI:公司的資料不能丟到公開 AI 去訓練。

    這是 SAP NOW AI Tour 系列的最後一篇。前面談了方法論、技術、案例,這篇談一個比技術更難、卻真正決定成敗的東西——AI 治理與 ROI。這天聽下來,最深刻的幾段都不是在講模型多強,而是在講「怎麼算它的價值」和「怎麼管它的風險」。

    一、ROI 難算又好算:關鍵在「頻率質變」

    一位銀行高管分享的 ROI 觀點,我覺得每個要替 AI 專案爭預算的人都該聽。他說 AI 的 ROI「難算,但也好算」。

    難算,是因為一個企業要用 AI 做什麼,沒辦法被量化反推;好算,是因為當 AI 對到「三到五年後的巨大競爭優勢」時,那些成本相對就不是重點。他舉了一個企業信用分析的例子,非常經典:

    一開始算 ROI,是「原本一個人要做 36 小時,AI 降到 3 小時」。聽起來省了工,但因為做的人不多,效益看起來普通。後來他們發現算錯了重點——因為過去要花 36 小時,這個分析一年只能做一次;但 AI 只要 3 小時,就能改成一季一次、甚至一個月一次。頻率一變,質就變了:能提早發現客戶信用變好(多給額度)、或提早發現問題(不用等到明年,中間就預警)。他說:「這對銀行是很大的突破,效益沒辦法估量,因為太大了。」

    這就是頻率質變:真正大的效益,往往不在「同一件事做得更快」,而在「快到可以改變做這件事的頻率」。表面的工時 ROI,會嚴重低估它。

    二、ROI 要對到戰略本質,不是中階 KPI

    承上,他的結論是:AI 專案的 ROI,應該對到「你原本要創造的競爭優勢是什麼」,而不是中階的過程指標。製造業的講者也呼應這點——挑 AI 專案的優先順序,是「越能直接反映客戶需求的越優先」(良率、產出、交期),而不是從內部好做的地方開始。

    另一個容易被低估的效益是潛在損失的避免。一家電子大廠提到,AI 最大的價值往往不是看得到的降本,而是「在第一關就攔截一個品質議題,避免整批損失」——這種效益很難寫進試算表,卻可能是最大的。還有橫向複製:一個廠導入成功,就能複製到二十個廠,效益會放大到難以估算。

    三、價值與風險,是一體兩面

    講到治理,那位銀行高管用了兩個會場引用的軍事 AI 案例,把問題講得很透。同一套 AI 影像辨識系統:

    • 故事一:在任務中辨識出前方的威脅,救了一條人命。
    • 故事二:把一個人手上拿的東西誤判成危險物,造成了無法挽回的誤傷。

    同一個系統,兩個極端。只看故事二,你會想「隔天就把系統關掉」;只看故事一,你會繼續用。他的洞察是:當你的 AI 夠重要,它一定同時帶著高價值與高風險——這是一體兩面,不是哪邊做得不夠好。

    四、治理心法:所有人在同一個平台達共識

    既然價值與風險綁在一起,怎麼管?他的答案很簡單,也很難:讓所有人在同一個平台上。

    以他們銀行為例,法遵、風險、業務人員,都在同樣的平台、看同樣的 AI、同樣的問題與機會。沒有共識,就沒辦法離開那個辦公室——因為一定有人覺得「該關掉」,有人覺得「不能關(關掉會出事)」,必須當場喬到共識。這比任何一份治理文件都實在:把對的人放在同一個畫面前,逼出共識。這也呼應全場另一個反覆出現的觀點——AI 治理的重點,是讓 AI「行為有序」地在企業內運行,而不是放任它亂竄。

    五、底線:主權 AI

    如果說全場有一條最強的暗線,那就是主權 AI(Sovereign AI)——這個詞在不同講者口中至少出現了三次。顧問業引用的調查顯示,超過七成的企業領導者認為「AI 在哪裡開發/運算」是選技術的關鍵考量;製造業強調總部集中算力、守住數位主權;而傳產的設備主管講得最白:

    每個公司都有自己的機密,你不會希望把自己的資料丟到公開的 AI 上去訓練。所以你需要的是主權 AI。

    對製造業、金融業這種高度重視資料的產業,這會是董事會問的第一個問題。所以在選型時,「資料留在哪、誰能存取、會不會被拿去訓練」往往比「模型多聰明」更早被決定。

    結語:難的不是技術,是人與治理

    四篇寫到這裡,剛好繞回系列第一篇的結論:數位轉型 80% 卡在組織與人,不是技術。AI 治理也是同一回事——真正難的,不是把模型接起來,而是怎麼算清楚它的價值、管得住它的風險、讓所有人對它有共識。

    把整個系列濃縮成一句話:AI 降低了工具的門檻,卻抬高了「懂業務、會判斷、守得住治理」的人的價值。工具會越來越好用,但會用工具的人和組織,才是差距所在。

    常見問題 FAQ

    怎麼評估 AI 專案的 ROI 才不會低估?

    別只看「同一件事做得更快」省了多少工時,要看「頻率質變」——當一個分析從一年一次變成一月一次,能提早發現機會與風險,價值是跳級的。ROI 應對到競爭本質,而非中階過程 KPI。

    AI 的價值和風險可以分開管嗎?

    很難。當 AI 夠重要,價值與風險是一體兩面。務實的治理是讓法遵、風險、業務在同一個平台看同樣的問題與機會,達成共識才放行。

    什麼是主權 AI(Sovereign AI)?

    指企業掌握「AI 在哪裡開發、運算,資料由誰存取、會不會被拿去訓練」的主導權。對重視資料的產業,公司機密不丟公開 AI 訓練是底線。

    導入企業 AI,最該先想清楚什麼?

    不是先選模型,而是先想清楚資料主權與治理(資料留在哪、誰能存取),以及這個 AI 要對到的競爭本質。技術反而是相對後面的問題。

    📚 本系列:SAP NOW AI Tour 的 4 堂課

  • 傳產與金融怎麼把 AI 落地?三個真實場景

    重點摘要

    • 鋼鐵廠:讓機器狗進約 1,200°C 的高爐巡檢,並用「設備健康指標像人的健康指標」的概念,做動態預知維護。
    • 銀行:把客戶經理變成 AI Agent,靠「下游的下游有訂單」的線索,搶在同業之前打那通電話。
    • 電子代工:信奉「工廠不是實驗場」,所有試錯與優化先在數位孿生裡跑完,再上實體。
    • 三個產業差很遠,但共通點一致:AI 不是取代人,而是把人從危險、重複、來不及反應的地方解放出來。

    這是 SAP NOW AI Tour 系列的第三篇。前兩篇談方法論與技術骨架,這篇講最好看的部分——真實案例。我挑了三個差異很大的產業(鋼鐵、銀行、電子代工),看他們各自怎麼把 AI 落到地上。為尊重分享者,以下用產業代稱、只引用公開分享的內容。

    一、鋼鐵廠:讓機器狗進 1,200 度的高爐

    鋼鐵是典型的「3K 場域」——危險、骯髒、辛苦,再加上傳產普遍的缺工壓力。這家鋼鐵龍頭的設備部門,把 AI 用在兩個地方,我覺得都很有啟發。

    無人化:機器狗、無人機、無人天車

    高爐的高點,溫度約 1,200°C,爐板一旦出問題可能導致熱點甚至爆炸——這種地方不適合人進去。他們的解法是把巡檢路徑寫成程式,讓機器狗去走、去看,背後的資料庫做預知分析。有人問「機器狗為什麼要練爬樓梯?」講者的回答很妙:人也不是天生會走路,是學會之後才會;機器人往前走要耗大量運算在做平衡,如果目的是去收集數據,那就讓它走遍各種路去練。同樣的思路也用在無人天車上——AI 控制吊掛鋼捲時,左右自動防擺,比人操作還穩。

    設備健康指標,就像人的健康指標

    這是我整天聽到最好的一個比喻。買設備時,廠商會告訴你「多久保養一次」,那是固定規範。但設備用久了會慢慢變化,固定規範不一定適用。講者拿人來類比:

    小孩子量身高、體重、頭圍最重要;到了中老年,身高體重沒太大意義,要量三高。設備也一樣——剛買的設備和用了十年的設備,同一個指標代表的意義完全不同,不能用同一套標準看。

    所以他們用 AI(深度學習模型 + 領域專家的特徵工程)把老師傅的經驗變成「智慧健康指標」,在設備出問題前就抓到初期徵兆。核心一句話:用「數據驅動」取代「直覺或規範」。

    二、銀行:把客戶經理變成 AI Agent

    一家大型銀行的企業金融部門問了自己一個尖銳的問題:我們的服務方式會不會被取代?他們的答案是「會」,所以乾脆自己先動手。

    最精彩的是一個「搶先機」的案例。某個企業客戶可能接到一筆訂單——這種公開資訊大家都看得到。但這家銀行的客戶經理,會在早上收到系統提示:「你可能要去拜訪某客戶。」怎麼知道的?因為系統掌握到這個客戶「下游的下游」可能有訂單,照這個模式推斷它有機會接單,再比對它最近的新聞表現。因為它會接單,就可能有備料與資金需求——於是客戶經理提前打了那通電話。結果是:客戶的財務長第一個接到的,是這家銀行打來的。

    更進一步,他們的想像是把客戶經理本身變成一個常駐客戶端的 AI Agent。一個真人沒辦法一天到晚守在客戶那裡待命,但 AI 可以。背後的技術,就是用前一篇談過的協定,把銀行服務嵌進客戶的 ERP 流程裡。這呼應了一個全場反覆出現的觀點:AI 不是要取代你,而是讓你把「人做不到的覆蓋率」補起來。

    三、電子代工:工廠不是實驗場

    一家全球佈廠的電子代工大廠,分享了他們十多年的 AI 進化。最打動我的,是一句很樸素的話:「工廠是每天在生產運行的地方,並不是給你做實驗的地方。」

    所以他們的核心策略是數位孿生:所有的生產設計、AI Agent 的驗證、流程的優化,都先在虛擬世界裡跑完,再上實體。一個模擬若用實體去做實驗可能要兩個月,在數位孿生裡快很多;而且實體還沒蓋,就能先把問題找出來、把良率拉上去。他們也坦白分享了 Agent 的導入節奏:今年初做了第一個 Agent,到年中大概第八個——剛開始導入比較辛苦,但越往後越快,因為 know-how 會累積。這跟前面銀行、鋼鐵的經驗一致:先做最關鍵的那一個,驗證了再放心擴展。

    結語:三個產業,同一個底層邏輯

    把這三個案例疊在一起,會發現它們其實在講同一件事:

    • 方向一致:都是把人從危險(高爐)、重複(守客戶)、來不及反應(品質與訂單)的地方解放出來。
    • 節奏一致:都先做一個最關鍵的 MVP,驗證了再擴展,沒有人一次性全導入。
    • 對人的定位一致:AI 接手「人做不到或不該做」的部分,人回到判斷與經驗的價值上。

    下一篇是系列最後一篇,談一個比技術更難、卻決定成敗的東西——AI 治理與 ROI:當 AI 夠重要,它的價值與風險就是一體兩面,你該怎麼算、怎麼管?

    常見問題 FAQ

    AI 怎麼用在設備維護上?

    用深度學習模型加上領域專家的特徵工程,把老師傅的經驗變成「智慧健康指標」,在設備出問題前抓到初期徵兆,做動態的預知維護,而不是照固定的保養規範。

    為什麼說「工廠不是實驗場」?

    因為工廠每天都在生產,不能拿來反覆試錯。改用數位孿生,把生產設計、AI 驗證、流程優化先在虛擬世界跑完再上實體,可大幅降低風險與時間。

    AI 會取代客戶經理或第一線人員嗎?

    案例顯示的方向是「補覆蓋率」而非取代:AI Agent 常駐客戶端、處理人力做不到的即時與規模,人則回到判斷、經驗與關係經營的價值上。

    導入 AI Agent 一開始就會很有效率嗎?

    不會。實務經驗是「先苦後快」——第一個最辛苦,隨著 know-how 累積,後面越做越快、效益越來越可觀。建議先做一個最關鍵的 MVP。

    📚 本系列:SAP NOW AI Tour 的 4 堂課

  • AI Agent 怎麼接進企業系統?看懂 MCP 與 A2A 兩個關鍵協定

    重點摘要

    • AI 應用正從「單一模型/聊天機器人」走向 Agentic AI(自主規劃、推理、跨系統行動)
    • Agentic AI 有兩個關鍵挑戰:Agent 怎麼連接工具?怎麼跟其他 Agent 合作?由此誕生兩個開放協定。
    • MCP(Model Context Protocol)= 垂直整合:讓單一 Agent 往下接工具與資料源。
    • A2A(Agent-to-Agent)= 水平協作:讓多個 Agent 之間互相委派任務。
    • 資料層上,趨勢是「串接而非搬遷」——地端資料可以留在原地,用連接器接上雲端分析。

    這是 SAP NOW AI Tour 系列的第二篇。第一篇談方法論(為什麼轉型會失敗),這篇換上工程師的眼睛,談技術骨架:當大家都在喊 Agentic AI,到底 AI Agent 是怎麼接進一家企業既有的系統?這一整天聽下來,金融、製造、雲端三方不約而同指向同兩個字母組合——MCP 與 A2A

    一、先看演進:從 Traditional AI 到 Agentic AI

    AI 在企業裡的應用方式,大致經過三個階段:

    1. Traditional AI:單一模型、單一任務(聊天機器人、文件摘要)。
    2. AI chatBot:AI 嵌入應用,輔助人員完成工作。
    3. Agentic AI:AI 自主規劃、推理、行動,並跨系統協作

    到了第三階段,問題就來了:一個 Agent 要做事,得能呼叫工具、讀寫資料;而真實的企業流程往往要好幾個 Agent 接力。於是兩個關鍵挑戰浮現——Agent 如何連接工具?如何與其他 Agent 合作?

    二、兩個開放協定:MCP 與 A2A

    這兩個挑戰,分別由兩個開放協定來解。它們不是競爭關係,而是互補——一個管「垂直」,一個管「水平」。

    維度 MCP(Model Context Protocol) A2A(Agent-to-Agent)
    連接對象 Agent ↔ 工具/資料源 Agent ↔ Agent(雙向協作)
    整合方向 垂直整合(取用工具) 水平協作(分工委派)
    典型用法 Agent 透過 MCP 存取 ERP 資料庫 / API 一個 Agent 透過 A2A 把任務委派給另一個 Agent

    一句話記憶:MCP 讓 Agent 往下接系統,A2A 讓 Agent 之間互相傳接棒。

    三、實際跨系統流程長怎樣

    會場舉了一個很好懂的端到端流程,看完就知道兩個協定是交替使用的:

    • 採購 AgentMCP 查庫存
    • 物流 AgentA2A 被委派去安排出貨
    • 財務 AgentMCP 更新帳務
    • → 完成一條自動化流程

    每個 Agent 用 MCP 往下接自己負責的系統,再用 A2A 把棒子交給下一個 Agent。這就是 Agentic AI「跨系統協作」的具體長相。

    四、資料層:串接,而不是搬遷

    講到 Agent 接資料,現場有個觀眾問了一個很實際的問題:「用 AI 是不是一定要把所有資料都搬上雲?」畢竟資安、上雲成本、地端的第三方系統,都是真實顧慮。

    答案是「不用」。現在的資料雲走的是「串接」而不是「搬遷」——透過連接器(Data Provisioning Agent 這類機制)直接接上地端資料,資料可以留在原地,上層再用 AI 做分析與呈現。對於有資安顧慮、又想用 AI 的企業,這條路很關鍵。一個實際的搭法是:既有系統(ERP/設備系統)→ 連接器 → 雲端的資料模型層(如 Datasphere)+ 報表層(如 SAP Analytics Cloud),最前面再接一層自然語言(Joule),就能「用一句話問、自動跑出分析圖表」。

    五、官方參考架構:把內外 Agent 安全地串起來

    最後一張技術總圖,把上面這些拼成了一個完整的互通架構(這是雲端與 ERP 兩大廠的聯合參考架構):

    • 企業內部的 Agent(Orchestrator + 各種 Custom/Low-Code/Pro-Code Agent)透過 A2A 跟外部雲端的 Agent 協作;
    • 透過 MCP 接到 ERP、資料雲等既有系統;
    • 身份與信任由統一的 Identity Service 治理(authenticate / trust)。

    值得一提的是,雲端廠在大會上一口氣發布了多項與 ERP 深化整合的東西,包括官方的 MCP Server(讓 AI Agent 透過整合套件安全存取 ERP 商業數據)、支援 ABAP 開發者的 AI IDE,以及基於雲端模型平台的 Agentic AI 方案。換句話說,MCP 已經不是概念,而是有官方實作可以開始試的東西。

    結語:協定先行,骨架才穩

    如果你也在規劃企業內的 AI Agent,這篇的重點只有一個:先把「Agent 怎麼接系統、怎麼互相協作」這層協定想清楚,再談上面要跑什麼應用。MCP 負責垂直、A2A 負責水平,資料層走串接不搬遷,身份治理統一——這就是下一代企業 AI 自動化的骨架。下一篇換個角度,看真實的傳產與金融公司,是怎麼把這套東西落到地上的。

    常見問題 FAQ

    MCP 和 A2A 有什麼差別?

    MCP 是讓單一 Agent 垂直連接工具與資料源(例如存取 ERP 資料庫);A2A 是讓多個 Agent 之間水平協作、互相委派任務。實際流程裡兩者交替使用。

    用 AI Agent 一定要把資料搬上雲嗎?

    不一定。可以用連接器「串接」地端資料,讓資料留在原地,再由雲端的分析層處理,兼顧資安與成本。

    什麼是 Agentic AI?

    相對於單一任務的傳統 AI 與輔助型的 chatBot,Agentic AI 能自主規劃、推理、行動,並跨多個系統協作完成任務。

    MCP 現在可以實際使用了嗎?

    可以。雲端與 ERP 大廠已推出官方的 MCP Server,讓 AI Agent 透過整合套件安全存取 ERP 商業數據,並有支援開發者的相關工具。

    📚 本系列:SAP NOW AI Tour 的 4 堂課

  • 數位轉型不是換系統:企業 AI 落地為什麼失敗,又該怎麼做對

    重點摘要

    • 麥肯錫研究指出:數位轉型失敗的主因 80% 在「組織與人」,而不是技術
    • AI 世代的轉型有四大關鍵核心:人員、流程、應用、數據,四者要同步處理,不能只做一個。
    • 轉型有不能跳過的順序:合理化 → 標準化 → 自動化。跳過前段直接自動化,等於把錯的流程加速。
    • 很多企業的「戰情室/儀表板」做完沒人用,是因為它只看落後指標;當員工覺得「自己下載資料用 Excel 更快」,系統就開始死亡。
    • 一句話:數位轉型只是手段,真正的目的是創造價值。

    我參加了一整天的企業 AI 大會,聽了金融、半導體、電子製造、鋼鐵、顧問與雲端平台共六、七家公司分享他們怎麼把 AI 落地。把這些不同產業的經驗放在一起聽,最有趣的發現是:他們講的「成功關鍵」高度一致,而且那個關鍵幾乎都不是技術。這篇是系列第一篇,先談方法論——企業 AI 為什麼會失敗,又該怎麼做對。

    一、先承認:80% 的轉型卡在「人與流程」,不是技術

    會場引用了一份麥肯錫研究:數位轉型失敗的主因在於「組織與人」,而非技術本身。成敗大約 80% 取決於「組織與人」的改變與「方法」的正確性,而「資料」與「內容」是實現價值的核心基石。

    把它拆開來看,組織面的挑戰是:缺乏清晰的轉型願景、組織結構僵化、跨部門協作困難、決策流程緩慢、資源分散。人員面的挑戰是:員工抗拒改變、數位技能不足、人才流失、缺乏主人翁意識、溝通不足導致信任缺失。這些沒有一條是「買哪個 AI 工具」能解的。

    現場有位經營者講得更直接:很多人怕因為跟不上而被淘汰,所以拒絕改變;而真正成功的企業,是想辦法讓「最懂業務的資深人員」被 AI 賦能,而不是被取代。AI 降低了工具門檻,卻抬高了「懂業務、會問對問題」的價值。

    二、四大關鍵核心:人員、流程、應用、數據

    在 AI 世代,數位轉型規劃有四個關鍵核心,每一個都帶著自己的痛點。整理成一張表最清楚:

    核心 三大痛點
    人員 技能隔閡、變革阻力、組織知識流失
    流程 過時流程、跨系統依賴、合規問題
    應用 過度客製、技術債、整合挑戰
    數據 數據孤島、數據品質問題、數據安全與合規

    關鍵在於這四個要同步處理。只把「數據」清乾淨、卻不動「流程」和「人員」,AI 一樣跑不起來;反過來也一樣。多家公司不約而同提到的共通痛點——數據孤島、技術債、缺乏單一真實來源——其實都落在這四個象限裡。

    三、不能跳步:合理化 → 標準化 → 自動化

    一位資深製造業高管分享了一個很樸素但很重要的原則:轉型沒有捷徑,過程必須照順序走——

    1. 先把做事情的順序合理化
    2. 再想辦法標準化
    3. 標準化之後,才能自動化(接著才是 AI)

    為什麼順序這麼重要?因為如果你跳過合理化與標準化、直接自動化,你的標準很可能是錯的——這等於把一個錯的流程加速,是一場無效的轉型。這也呼應了現場另一個觀察:很多人誤以為「拿一個工具來、不需要前面那些步驟,就能把事情做好」,但這從來不會成立。

    對應到角色,轉型會依序需要三種人:BA(業務分析)把現況忠實記錄成流程、SA(系統分析)定義這些需求該用什麼系統滿足、SD(系統設計/開發)實作。順序顛倒,後面全部白做。

    四、為什麼「戰情室」做了沒人用

    一家深耕 SAP 二十多年的整合商,分享了一個我覺得每個做過 BI 專案的人都會心一笑的觀察:傳統的策略支援系統(戰情室、儀表板)會沿著一條曲線慢慢失效。

    階段 作用強度 狀態
    過去 100% 決策利器,報表即時、深受信任
    幾年前 75% 仍具價值,但開始延遲、需人解讀
    現在 40% 內容固定、無法靈活、使用率下降
    不久後 15% 「自己做更快」,轉向替代方案
    未來 5% 報表停更、系統荒廢

    真正的死亡轉折點,發生在「現在 → 不久後」之間:當員工覺得「我自己下載資料、用 Excel 加工更快」,這個系統就開始死亡。幾年後公司又起一個新專案、重做一個新的戰情室,如此不斷循環。

    根因是什麼?傳統戰情室只給你落後指標——告訴你「過去發生了什麼」。但經營者真正面對的世界,不是內部報表,而是外部的快速變化。一句話點破:現在企業經營,最大的風險不在「做錯決策」,而是「太晚知道這世界變了」。所以下一代的決策平台,要從「內部、落後、檢討過去」轉向「外部、領先、預判未來」。

    五、把方法論變成步驟:從經營分析到決策機制

    那實際要怎麼建?現場分享的一套五步驟方法論,把上面這些抽象原則落成了可執行的流程:

    1. 經營分析:先對準企業目標——「企業到底需要什麼」,盤點現有流程與痛點。
    2. 資訊探索:從資料裡看清楚「現在發生了什麼問題、哪些資料必須收集進來」。
    3. 要因分析:用模型與統計方法,找出最重要的影響因子,把它變成你的領先指標
    4. 建立決策引擎:做出預測模型與預警儀表板。
    5. 形成決策機制:導入流程、教育訓練、持續優化,確保它真的被用起來。

    注意第三步「要因分析」才是重點——找出領先指標,而不是把舊的三十幾個 KPI 再畫一次。如果你做數位轉型時,還是只盯著以前那幾張報表看,那不會從根本改變公司的體質。

    結語:轉型是手段,創造價值才是目的

    麥肯錫、BCG、Gartner 對「數位轉型」的定義各不相同,但他們都強調同一件事:要創造價值。多數公司過於聚焦在前半段的「數位化」(導入工具、優化局部流程、提升效率),結果改善了效率、價值卻有限,難以帶動企業成長。真正的數位轉型,是重新設計商業模式與價值交付。

    所以如果只能記一句話,我會記這句:數位轉型只是手段,真正的目的在於創造價值。工具會越來越好用,但真正的差距,落在你有沒有把流程、資料與人,重新組織成一個 AI 跑得動的樣子。

    這是 SAP NOW AI Tour 系列的第一篇(方法論)。接下來幾篇會談技術骨架(MCP 與 A2A 怎麼讓 AI 接進企業系統)、真實落地案例(傳產與金融怎麼做),以及 AI 治理與 ROI。

    常見問題 FAQ

    數位轉型失敗的最主要原因是什麼?

    根據麥肯錫研究,主因是「組織與人」而非技術,成敗約 80% 取決於組織與人的改變、以及方法的正確性,資料與內容則是實現價值的基石。

    為什麼不能直接導入自動化或 AI?

    因為順序是「合理化 → 標準化 → 自動化」。跳過前面直接自動化,等於把一個還沒理順的錯誤流程加速,是無效的轉型。

    為什麼很多 BI 戰情室做完就沒人用?

    因為它只提供「落後指標」、內容固定難以靈活。當員工覺得自己下載資料用 Excel 更快,使用率就會一路下滑到系統荒廢。解法是轉向外部感知與領先指標。

    數位化和數位轉型有什麼不同?

    數位化偏向導入工具、優化局部流程、提升效率;數位轉型則是重新設計商業模式與價值交付。前者改善效率但價值有限,後者才能驅動企業持續成長。

    📚 本系列:SAP NOW AI Tour 的 4 堂課