顯示具有 韌體 標籤的文章。 顯示所有文章
顯示具有 韌體 標籤的文章。 顯示所有文章

兩電極 ECG 為什麼總是雜訊滿天飛?MAX30001 三電極與 RLD 實戰筆記

ECG 工程師桌面

第一次拿 MAX30001 EV kit 接到自己身上量 ECG,我以為會看到漂亮的 QRS 複合波。結果示波器上是一條粗到不行的弦波,60 Hz 整整齊齊塞滿整個畫面。

那個瞬間我才真的懂為什麼所有教科書都在講「共模拒斥比」(CMRR)。datasheet 給你一條很漂亮的「CMRR vs 頻率」曲線、低頻段輕鬆破百 dB,但這個數字跟你把兩根電極貼上肉之後實際量到的東西,根本是兩個世界。

這篇是我把 MAX30001 從 EV kit 改成自己 layout 的 ECG patch 一路撞到牆的整理。重點放在 三電極 + RLD(Right-Leg Drive) 這個 datasheet 寫得很簡短、但決定產品能不能用的關鍵環節。

為什麼兩電極不夠用?

ECG 訊號量級大概 0.5–4 mV,而你身上隨便揹著的 60 Hz 共模電壓動輒幾百 mV 到幾伏特。差距是 1000 倍以上。

差動放大器確實會抑制共模——但前提是兩個輸入端「看到的共模電壓真的一樣」。實際上電極與皮膚的接觸阻抗不對稱,就會把一部分共模轉成差模混進訊號裡。

這是 TI 那篇經典 app note SBAA188 Improving Common-Mode Rejection Using the Right-Leg Drive Amplifier 講得很清楚的事(雖然是寫給自家 ADS1298,但原理對 MAX30001 完全通用):整個系統的 CMRR 不是 AFE 的 CMRR,而是 AFE × 電極匹配度的乘積。AFE 給你 100 dB,電極不平衡只有 40 dB,整體就只有 40 dB。

於是兩電極設計的 ECG,最常見的結果就是底下這張圖:

60Hz 干擾淹沒 ECG

QRS 波被 60 Hz(在台灣也常常是 50 Hz 加諧波)整個吃掉。你可以靠 notch filter 把它砍掉,但代價是 R 波會變形、HRV 計算的準度直接報廢。

第三電極的三種接法(從廢到神)

當你被 60 Hz 蹂躪到第三次,自然會想到「再多接一根線到身體上」。第三電極有三種主流接法,效果差很多。

做法 1:第三電極直接接 GND(最直覺、也最廢)

把第三電極(通常接右腿,所以叫 right leg)直接拉到電路 ground。聽起來很簡單,但有兩個大問題:

  1. 安全:如果系統沒有 isolated,萬一漏電直接從這條線灌進病人身體。醫療裝置不能這樣搞。
  2. 沒效:電極與皮膚的接觸阻抗可能高達 100 kΩ,這條「ground 線」其實是一條 100 kΩ 的阻抗,根本拉不住人體電位。

Electrical Engineering Stack Exchange 上有人問過同樣的問題 ,下面的回答直接引用了 Winter & Webster 1983 年那篇被引爆的經典 IEEE TBME 論文:用一個 op-amp 主動 feedback,就能把這個 100 kΩ 的等效阻抗砍掉好幾個數量級。

做法 2:MAX30001 內建 VCM 拉電極(datasheet 官方做法)

這是 MAX30001 datasheet 裡其實寫得清清楚楚、但很多人沒注意到的招式。

晶片內部有一顆 common-mode buffer,產出 650 mV 的 VCM 電壓,原本是給內部電路用的。datasheet 的 General Description 段有一句很關鍵的話:

The common-mode voltage, VCM, can optionally be used as a body bias to drive the body to the common-mode voltage by connecting VCM to a separate electrode on the body through a 200kΩ or higher resistor to limit current into the body according to IEC 60601-1:2005, 8.7.3.

翻成人話:把 VCM 經過一顆 ≥200 kΩ 電阻接到第三電極,貼到病人身上。這顆 200 kΩ 不是隨便寫的,是 IEC 60601-1 第 8.7.3 條對「病人輔助電流」的安全限制——任何單一故障都不能讓流進病人身體的電流超過規定值。

接法大概長這樣(mermaid 流程):

graph LR
  subgraph MAX30001
    VCM[VCM pin, 650 mV]
    ECGP[ECGP]
    ECGN[ECGN]
  end
  VCM -->|R = 200kΩ| BIAS[第三電極]
  ECGP --> ELP[ECG+ 電極]
  ECGN --> ELN[ECG- 電極]
  BIAS -.-> BODY((人體))
  ELP -.-> BODY
  ELN -.-> BODY

EV kit 上有一個叫 BB_SEL 的 jumper(Body Bias Select):

  • BB_SEL 1-2:直接用 VCM 當 body bias(datasheet 預設做法)
  • BB_SEL 2-3:用一個可調電壓(R7 trimpot 0–OVDD),方便你實驗其他偏壓

我量過:光是把第三電極從「不接」改成「VCM via 200kΩ」,60 Hz 干擾大概砍掉 30–40 dB,原本被淹沒的 QRS 直接清楚跳出來。這就是為什麼 MAX30001 大多數量產設計都是這個三電極配置。

注意:如果啟用了 VCM body bias,datasheet 建議可以把內部 lead bias resistor(CNFG_GEN 0x10 暫存器裡的 50/100/200 MΩ)關掉,避免兩種 biasing 機制打架。

做法 3:外掛 op-amp 做主動 RLD(最強,但要多一顆 IC)

VCM 的缺點是它是被動的——只是把人體拉到 650 mV 附近,不會主動抵銷共模雜訊。要真的把 CMRR 推到極限,就要加一顆外部 op-amp 做主動 feedback,這就是經典的 Driven Right Leg(DRL) 或 Right-Leg Drive(RLD) 電路。

ADI 官方有一篇 app note 直接給你抄:How to Add Wilson's Central Terminal/Right Leg Drive Functions to the MAX30001/MAX30003 ECG AFEs in a Medical Wearable (若官網連結時好時壞,也可以查同名 Maxim Integrated 鏡像 )。建議的 op-amp 是 MAX44260 (低功耗、低 offset、SC70 包裝),跟 MAX30001 是天作之合。

RLD 的核心原理用一句話講:把 ECGP、ECGN 兩端的共模電壓抓出來、反相放大、回打到第三電極。這個 feedback loop 會主動把人體共模電位「壓回 reference」。

graph LR
  ECGP[ECGP] --> R1[R = 1MΩ]
  ECGN[ECGN] --> R2[R = 1MΩ]
  R1 --> SUM((+))
  R2 --> SUM
  SUM --> OPAMP([Op-Amp / MAX44260])
  VREF[VCM / Vref] --> OPAMP
  OPAMP --> RF[R = 350kΩ, safety limit]
  RF --> RL[Right Leg, 第三電極]

加了 RLD 之後,等效共模阻抗可以從 100 kΩ 級掉到幾百 Ω 級,整體 CMRR 直接加 20–40 dB。代價就是多一顆 op-amp 與三四顆電阻,以及一個你必須認真設計的 stability margin(loop gain 太高會自激)。

三種做法的選擇表

做法額外元件CMRR 改善安全性適用場景
直接接 GND0≈ 0 dB差不建議
VCM body bias(datasheet 官方)1 顆 200 kΩ+30~40 dBIEC 60601-1 合規多數消費級 / 中階醫療
外掛 RLD op-amp1 顆 op-amp + 4 顆 R+50~70 dB需 safety resistor高階醫療、IEC 60601-2-47 認證

我自己的選法:原型先 VCM bias 跑出可看的 ECG,產品送認證前再決定要不要升級到 RLD。多數 wearable patch(不是診斷級 12-lead)VCM bias 就夠了。

MAX30001 EV kit 上手實戰

三電極概念圖

下面是我從拿到 EV kit 到能穩定看到 ECG 的流程,這部分 Mbed MAX30001-FeatherWing 文件 寫的不完整,這裡補一些細節。

前置條件

  • 硬體:MAX30001EVSYS#(含 MAX30001 EV board + MAX32630FTHR + 三條 ECG cable)
  • 電源:USB micro 直接餵(或外接 5V 經 LDO)
  • GUI:Maxim 官方 Windows GUI(Win7/8/10 OK,Win11 我實測也能跑)
  • 電極:3M Red Dot 或 Ambu BlueSensor,丟掉那種沒牌子的便宜貨

Jumper 設定(三電極模式)

J_DRVP   open   ← BioZ 用,三電極 ECG 時不接
J_DRVN   open
DP_BP    open
DN_BN    open
BP_BN    open
BB_SEL   1-2    ← 用 VCM 作 body bias(三電極關鍵!)
J_RBIAS  1-2    ← 接 324kΩ 外部偏壓電阻

預設 jumper 其實已經是「兩電極 + BB_SEL=VCM」,但你必須真的把第三電極(黑色那條 RL/RA cable)接在身上才有效果。我看過太多人 jumper 沒動但 cable 只接兩條,然後抱怨「跟兩電極差不多啊」。

暫存器初始化

關鍵幾個暫存器(這是我做 PCB 之後韌體用的,EV kit GUI 會幫你設):

// 1. 軟體 reset
spi_write(0x08, 0x000000);

// 2. CNFG_GEN (0x10) — 啟用 ECG 通道 + 設定 lead bias
//   EN_ECG=1, EN_DCLOFF=1, EN_RBIAS=01 (ECG channel)
//   IPOL=0 (sourcing), IMAG=000 (5nA), VTH=00 (300mV)
//   EN_BLOFF=00 (BioZ lead off disabled, 因為沒用 BioZ)
//   RBIASN=1, RBIASP=1 — 啟用 100MΩ lead bias 到 VMID
//   注意:如果你採用 VCM body bias(三電極接法),
//         建議改為 RBIASN=0, RBIASP=0 避免兩種 biasing 打架。
//         以下這組值是「先單獨驗證 ECG 通道、暫未啟用 VCM bias」的設定。
spi_write(0x10, 0x081007);

// 3. CNFG_CAL (0x12) — 內建校正源(debug 用,量產關掉)
spi_write(0x12, 0x720000);

// 4. CNFG_ECG (0x15) — ECG 通道參數
//   RATE=00 (512 SPS), GAIN=11 (160 V/V)
//   DHPF=1 (0.5Hz HPF), DLPF=01 (40Hz LPF)
spi_write(0x15, 0x005000);

// 5. 啟動同步
spi_write(0x09, 0x000000);  // SYNCH

如果你要進一步加 R-to-R 偵測或 pace detection,再去設 CNFG_RTOR1 (0x1D) 與 CNFG_PACE (0x1A)。

第一次量測的儀式感

電極貼好(RA = 右胸鎖骨下、LA = 左胸鎖骨下、RL = 右下腹),GUI 按下 Start,看到 P-QRS-T 一波一波跑出來的瞬間真的會起雞皮疙瘩。

但你也會發現:當你深呼吸的時候,baseline 會跟著漂;當你動手臂的時候,整個畫面會出現大尖峰(motion artifact)。這些是 ECG patch 接下來要面對的第二輪戰爭,已經超出 RLD 能解決的範圍,要靠數位濾波 + IMU 融合。

從 EV kit 到量產 PCB

ECG patch 量產示意

EV kit 跑通之後,自己畫板的時候會撞到的問題比想像中多很多。整理我自己跟同事的踩坑紀錄:

踩坑 1:類比電源沒有單獨 LDO

我第一版偷懶把 VAVDD 跟 VDVDD 都從同一顆 1.8V switching regulator 拉。結果 ECG 波形上躺著一隻 SMPS 開關頻率的小尾巴。

解法:類比電源一定要用 ultra-low-noise LDO,例如 MAX8512、TPS7A47 那種 PSRR 高的;EV kit 上用的就是 MAX8512EXK。1.8V 不貴,多放一顆。

踩坑 2:input series resistor 太小,IEC 60601-2-47 測試掛點

EV kit BOM 裡 R26, R27, R29, R30 預設是 0 Ω jumper,但 datasheet Note 3 明確說:

One electrode drive with <10Ω source impedance, the other driven with 51kΩ in parallel with a 47nF per IEC 60601-2-47.

意思是認證測試時,會強制給你一邊接 51 kΩ ‖ 47 nF 的不平衡網路打進來,要看你能不能撐住。量產板務必把這四顆電阻換成 10–51 kΩ + 47 nF 形成 EMI / 共模 LPF,這也是 ECG patch 過 IEC 60601-1-2 EMC 測試的關鍵。

踩坑 3:lead-off 一脫落,RLD loop 自激

這是 TI 那篇 RLD app note SBAA188 特別警告的場景:當其中一個 ECG 電極脫落,feedback loop 會失去輸入訊號,op-amp 直接被 lead-off bias current 推到 rail,整個系統當機。

解法:

  1. 韌體要連續監測 lead-off 狀態(MAX30001 的 STATUS (0x01) 暫存器有 LDOFF_NL/NH/PL/PH 四個 bit)
  2. 偵測到 lead-off 立刻把 RLD loop 用 analog switch(TS5A3157 那類)打開,避免 op-amp 鎖死
  3. 重新接觸後再閉合 loop,並做一次 ECG Fast Recovery(MNGR_DYN 0x05 設定)

如果你用 VCM body bias 沒外加 op-amp,這個問題不存在——VCM 是被動 driver,脫落了頂多沒效,不會反鎖。這也是我建議「沒必要就別跳 RLD」的另一個理由。

踩坑 4:BioZ 電流耦合進 ECG

這是同時啟用 ECG 與 BioZ 通道時很常遇到的問題:BioZ 注入的 kHz 級 AC 電流會耦合到 ECG 通道。一些社群實作經驗(例如 TU Wien 一份 bio-signal 整合論文 在類似 wearable 平台上)也回報過必須採用時分量測。

解法:

  • 時分(pseudo-simultaneous):交替啟用 ECG 跟 BioZ,犧牲時間解析度換乾淨度
  • 或者把 BioZ 電流壓到最小(datasheet 給 8 µA 起跳),並把 ECG LPF 設在 40 Hz 把 BioZ 的 80 kHz 載波濾掉

踩坑 5:電極 cable 太長,遮蔽沒做好

EV kit 給的 cable 是 touchproof 的醫療規格,但我第一版 patch 自己接 1.5m FFC,結果 60 Hz 又回來了。ECG cable 一定要用 shielded twisted pair,shield 接 VCM(不是接 GND)。Patch 設計則應該讓電極離 IC 越近越好(< 5 cm),這也是 chest patch 的優勢。

什麼時候要升級到主動 RLD?

我整理的決策樹:

graph TD
    A[ECG 設計需求] --> B{要送 FDA / CE Class IIa+?}
    B -->|是| C{要求 12-lead 級 CMRR?}
    B -->|否| D[VCM body bias 即可]
    C -->|是| E[外掛 RLD op-amp]
    C -->|否| F{臨床環境多干擾?}
    F -->|手術房, ICU| E
    F -->|門診, 居家| D
    D --> G[2-3 顆元件就搞定]
    E --> H[MAX44260 + 4 顆 R + lead-off switch]

簡單講:消費級 wearable、運動手錶、家用 patch → VCM bias 夠了;醫院監護儀、Holter、過 IEC 60601-2-47 認證 → RLD。

結語

MAX30001 的 datasheet 把三電極設計藏在「Common-Mode Buffer」那一節短短兩句話裡,但這兩句話幾乎決定了你的產品能不能用。VCM body bias 是 80% 場景的最佳解,外掛 RLD 是 20% 高階場景的必須品。

如果你還沒拿到 EV kit,但已經在規劃 ECG 產品,建議直接從 Digi-Key / Mouser 訂一塊 MAX30001EVSYS#(價格自己查當前報價,預算抓百元美金等級),自己貼上身體量一次,比看 100 篇 app note 都有感。等你親眼看過第一次 QRS 從雜訊裡浮出來,所有 RLD、CMRR、IEC 60601 的英文縮寫才會真的進到你的腦袋裡。

下一篇我打算寫「MAX30001 BioZ 量呼吸實戰」——把第四電極加進來、跑 tetrapolar 模式、把胸阻抗信號從 motion artifact 裡撈出來的細節。有興趣的話留言告訴我,我會調整 priority。

延伸閱讀

從養蝦到蓋 Agent OS:拆解 Anthropic Managed Agents 的腦手解耦架構與本地復刻實踐

managed-agents-cover

我同時開著5個 Claude Code 視窗。一個跑編碼、一個專責 Code Review、一個寫測試、一個守著 lint、最後一個是我自己用來貼錯誤訊息的「人肉訊息佇列」。一旦哪個窗口的上下文被壓縮,記憶就掉了一截;一旦某個容器跑歪,我得手動把整個目錄掃過去重來。

直到 2026 年 4 月 8 日,Anthropic 在 engineering 部落格悄悄丟出一篇文章 ,標題叫做 Scaling Managed Agents: Decoupling the brain from the hands。我讀完那個下午就明白:所謂的「蜂群 Agent」不是要靠工程師硬刻 harness 把模型框起來,而是要把腦、手、記憶徹底拆開,再讓編排者像 RTOS 一樣調度。這篇文章接下來會帶你一路走過:那篇部落格到底在說什麼、Managed Agents 的四個齒輪怎麼咬合、Memory Store 為什麼是真正的「腦」、我怎麼用一週復刻這套架構在本地跑、以及為什麼騰訊在 4 月底開源的 Cube Sandbox 會把 Docker 比下去。

環境與前置知識:本文涉及的版本是 Claude Managed Agents Beta(API header managed-agents-2026-04-01)、Claude Agent SDK 對應的 Python/TypeScript 套件、以及 Cube Sandbox 開源版本。讀者最好對 Docker、訊息佇列、有限狀態機任一個有基本概念,後面會用到嵌入式韌體類比,但不需要硬體背景。

那篇被低估的部落格,到底在恐嚇什麼

Anthropic 那篇文章 開場就放了一個工程師血淚史:團隊曾經為了 Claude Sonnet 4.5 的「context anxiety」(模型過早壓縮上下文造成的焦慮行為)寫了一整套 harness 補丁,邏輯精妙、考慮周全。結果 Claude Opus 4.5 一發布,這些補丁不只變廢碼,還會干擾新模型的判斷。整篇文章最狠的一句是:

「Harnesses encode assumptions that go stale as models improve.」 (Harness 把假設寫死,但模型一進化,這些假設就餿掉了。)

這句話我反覆讀了三次。對硬體工程師來說,這跟我們做晶片 workaround 是同一個感覺——某顆 MCU 有個 erratum,你寫一段神奇的延遲循環去繞過它;下一個 silicon revision 把 bug 修了,你那段 workaround 變成莫名其妙拖慢系統的死肉。模型也是矽晶片,只是改版週期更快、更殘酷。

Anthropic 的回應是把整個 agent 拆成三個獨立元件:

  1. Brain(Harness):Claude 本體 + control loop,無狀態、可隨時替換。
  2. Hands(Sandbox):執行容器與工具,跟 brain 互不認識。
  3. Session:append-only 的事件日誌,存在 harness 與 container 之外。

關鍵的一句翻譯成 API 語意:「harness 不再住在容器裡,它呼叫容器的方式跟呼叫任何工具一樣,就是 execute(name, input) → string。」這跟硬體界的 HAL(硬體抽象層)是一模一樣的思維——驅動程式不該假設它跑在哪個 SoC 上,只要透過固定 API 跟硬體說話就好。

而這個解耦的收益,Anthropic 自己給了硬數字:p50 TTFT(time-to-first-token)下降約 60%,p95 TTFT 下降超過 90% 。要注意這是他們重構自家基礎設施前後的對比——本質是「砍掉容器冷啟動 + 建立預先暖好的 brain pool」帶來的收益,不是外部 benchmark 可以直接複現的數字。但 p95 砍掉九成這種改進,已經不是優化,是換引擎。

寵物與牛馬:為什麼你的本地 Agent 注定會死

managed-agents-pets-vs-cattle

伺服器運維圈有個老梗叫 pets vs cattle:寵物你會給牠取名、生病了帶去看醫生、死了會難過;牛馬你只看編號,倒了就補一隻新的。十幾年前的虛擬機時代我們把伺服器當寵物養,後來容器化、Kubernetes、不可變基礎設施(immutable infrastructure),整個產業慢慢被「牛馬化」拯救。

把 Anthropic 那段話翻成大白話就是:「以前 Agent 是寵物,現在 Agent 要當牛馬。」 部落格原文有一句更狠:

「The container became cattle. If the container died, the harness caught the failure as a tool-call error.」 (容器變成牛馬。容器死了,harness 只是把它當成一次工具呼叫失敗去處理。)

對應到我自己之前養龍蝦的失敗經驗,根本原因就是當時把 brain、hands、context 全綁在同一個 Docker 容器:模型呼叫工具會修改容器的檔案、conda 環境、<sub>/.cache 被各種 LLM SDK 灌滿、又或者某個 MCP server 半夜默默死掉。一旦這個容器壞了,整個 Agent 的「人格」也跟著毀了。修不修得回來,全看那一刻運氣。

從韌體工程師的角度,這個錯誤幾乎是必然——狀態跟硬體(執行環境)綁在一起的設計,永遠擴展不出去。RTOS 的訊息佇列、雙緩衝、watchdog 自動重啟,本質上都是把「狀態」跟「處理單元」解耦。AI Agent 工程比硬體晚了二十年才學到這個教訓,這篇 Anthropic 部落格其實就是 AI 圈遲到的工業革命宣言。

拆解 Managed Agents 的四個齒輪

managed-agents-four-gears

光看「解耦」這兩個字還不夠,我得拆開 官方 docs 才能看清楚整個齒輪箱怎麼咬合。Anthropic 把整個系統建立在四個核心概念上:

齒輪 角色 類比(嵌入式視角)
Agent 靜態身份模板:模型、system prompt、工具、MCP servers、skills RTOS 任務的 task descriptor
Environment 容器模板:預裝套件、網路規則、掛載檔案 編譯時決定的 board support package
Session 動態實例:跑著 agent + environment 的一次任務,含 append-only event log RTOS 啟動後的具體 task instance
Events App 與 agent 之間的訊息:使用者輸入、工具結果、狀態 訊息佇列裡的 message
[mermaid 圖表 — 原始 HackMD 版本可正常渲染]

flowchart TB subgraph Static[靜態定義 / Bake Time] A[Agent
model + prompt + tools + skills] E[Environment
container template] end subgraph Runtime[執行時 / Runtime] S[Session
append-only event log] T1[Thread #1
coordinator] T2[Thread #2
reviewer] T3[Thread #3
test-writer] end subgraph Persistence[跨會話持久層] M[(Memory Store
/mnt/memory)] V[(Vault
credentials)] end A -.referenced by.-> S E -.referenced by.-> S S --> T1 --> T2 T1 --> T3 M -.mounted into.-> S V -.attached at.-> S

對影片裡提到的「coordinator」,我特地翻了 multiagent 文件 確認所有數字。實際的限制是:

  • Coordinator 的 roster 最多 20 個 unique agents,但每個 agent 可以被開出多份 copy。
  • 單一 session 最多 25 個並發 thread。
  • Delegation 只能往下一層,depth > 1 會被直接忽略,避免無限遞迴的呼叫塔。
  • 加入 {"type": "self"} 可以讓 coordinator 派同種類的自己出去處理子任務。

實際的 Python 程式碼長這樣(直接照 官方範例 改寫):

from anthropic import Anthropic

client = Anthropic()

# 先建兩個 worker agent
reviewer = client.beta.agents.create(
    name="Reviewer",
    model="claude-opus-4-7",
    system="You are a strict code reviewer. Reply with concise findings.",
    tools=[{"type": "agent_toolset_20260401"}],
)

test_writer = client.beta.agents.create(
    name="TestWriter",
    # 寫測試這種模式化工作配 Sonnet 4.6(比 Opus 便宜很多)就夠用,
    # 重要的 reviewer 與 coordinator 才需要 Opus 4.7。
    model="claude-sonnet-4-6",
    system="Write pytest-style tests for the provided code.",
    tools=[{"type": "agent_toolset_20260401"}],
)

# coordinator 拿到的是 reviewer 和 test_writer 的 ID
coordinator = client.beta.agents.create(
    name="Engineering Lead",
    model="claude-opus-4-7",
    system=(
        "Delegate code review to the reviewer agent "
        "and test writing to the test agent."
    ),
    tools=[{"type": "agent_toolset_20260401"}],
    multiagent={
        "type": "coordinator",
        "agents": [
            {"type": "agent", "id": reviewer.id},
            {"type": "agent", "id": test_writer.id},
        ],
    },
)

這段程式有幾個值得停下來看的細節。第一,coordinator 跟 worker 都是 agents.create() 出來的同一種東西,差別只在前者多了 multiagent 配置;換言之,「coordinator」不是一個特殊角色,只是一個被授予 roster 的普通 agent。第二,每個 agent 可以指定不同的模型——影片裡提到「coordinator 用大模型、worker 用小模型」最佳化 token efficiency,這是真實可行的設計,因為這四個齒輪的解耦讓「模型選擇」變成 per-agent decision,而不是 per-system decision。

常見陷阱:開頭那支介紹 managed agents 的影片把 SDK beta 講成有「6 個模組」(agents/environments/sessions/skills/memory stores/vaults),但對照 官方 overview 文件 ,核心概念其實是 agent/environment/session/events 這四個;memory stores、skills、vaults 是延伸的資源型 API。影片的「6 個模組」是把資源型 API 一起算進來——理解上沒錯,但講課時要分清楚層次,免得被讀者抓出來鞭。

Memory Store 才是真正的「腦」

managed-agents-memory-store

整套架構裡最讓我「後背發涼」的設計,是 Memory Store 。它表面上只是個雲端儲存,但放在四齒輪架構裡看就完全不一樣:Anthropic 把長期記憶從 agent 身上拔走,掛到 session 上。

[mermaid 圖表 — 原始 HackMD 版本可正常渲染]

flowchart LR A[Agent
「我是誰」] --> S[Session
「我現在在幹什麼」] S --> MS[Memory Store
「我以前學過什麼」] MS -.mounted at.-> FS[/mnt/memory/] FS --> Tool[Claude 用普通 file IO 讀寫]

關鍵的設計哲學是**「不發明新 API,就用檔案系統」**。memory store 掛載到容器內的 /mnt/memory/ 目錄,模型用它寫程式碼時用的同一套 file tool 讀寫。Anthropic 在文件裡明說:「a note describing each mount is automatically added to the system prompt so the agent knows where to look.」對應到嵌入式工程,這完全就是「把 EEPROM 區段 mmap 到位址空間」的概念。

實際的限制可以記住三組數字:

維度 上限 為什麼這樣設計
單一 session 可掛載 store 8 個 對應不同 owner / access rule:例如 user 偏好、團隊規範、專案 context 分開放
單一 memory 檔案大小 100 KB(約 25k tokens) 強迫你切細,避免被一個爛掉的大檔毀掉 context 預算
Memory version 保留 30 天(不過 head version 永久保留) 給審計與點對點還原用

最被低估的細節是 content_sha256 樂觀並發控制——更新時可以傳一個 precondition,如果儲存端的 hash 不再吻合,更新會被拒絕。這是 etcd / DynamoDB 級別的 concurrency 設計被搬進 agent 記憶層:

client.beta.memory_stores.memories.update(
    memory_id=mem.id,
    memory_store_id=store.id,
    content="CORRECTED: Always use 2-space indentation.",
    precondition={
        "type": "content_sha256",
        "content_sha256": mem.content_sha256,
    },
)

當你有多個 agent 同時修改同一份規範時,這條 precondition 就是你的最後一道防線。

安全踩雷區:memory store 預設是 read_write。Anthropic 文件給了一段明確警告——如果 agent 處理不可信輸入(使用者 prompt、抓回來的網頁內容、第三方 tool output),一次成功的 prompt injection 就能把惡意內容寫進 store,後續 session 把它當成可信記憶讀回來。實務上,所有共用的參考資料一律掛 read_only,只有專屬於該使用者、會話、專案的 store 才開 read_write。 這條規矩跟硬體裡「程式碼區絕對不能可寫」的紀律是同一個血統。

我的本地復刻:把蜂群塞進 Docker

managed-agents-local-replica

讀完所有 docs 後我花了一週把這套架構復刻在本地。我沒辦法完全做到 Anthropic 的雲端等級解耦——我的 worker 是 Docker 容器,每個容器裡塞著一個 Claude Code / Codex / 自製 harness(Pi),所以 brain 跟 hands 還是耦合在 worker 行程裡。但我至少做到了三件事:

  1. 無狀態 worker:每個 Docker 啟動時注入 model / harness / skill / 從哪個 session 哪個位置恢復 / SSH key / 工作目錄,跑完就銷毀。
  2. 集中編排:一個主控伺服器拿著任務圖(task graph),fan-out 給 worker,再 fan-in 收結果。
  3. 異質模型組合:不同節點用不同模型——例如初步搜尋用 Haiku、整合寫作用 Opus、最終驗證再回到 Opus,整體 token efficiency 比單一 Opus 跑全程便宜得多。

對應 RTOS 的視角,這就是一個典型的 master/worker + 訊息佇列 結構:

[mermaid 圖表 — 原始 HackMD 版本可正常渲染]

sequenceDiagram participant U as User participant M as Master (Orchestrator) participant Q as Task Queue participant W1 as Worker #1
(Opus, coder) participant W2 as Worker #2
(Sonnet, reviewer) participant W3 as Worker #3
(Haiku, test-runner) participant Mem as Memory Store U->>M: 「幫我加一個 OAuth 登入」 M->>Q: enqueue(code_task) Q->>W1: dispatch code_task W1->>Mem: read coding conventions W1->>Q: enqueue(review_task, patch) Q->>W2: dispatch review_task W2->>W1: 「這裡有 race condition」 W1->>Q: enqueue(test_task, fixed_patch) Q->>W3: dispatch test_task W3->>M: 結果 M->>U: 「OAuth 已完成、測試通過」

唯一痛點:Docker 啟動慢。本機跑一個帶 Python + Node + 必要工具的容器,冷啟動大概 1.53 秒。對單個任務沒感覺,但當 master 同時要 fan-out 12 個 worker 時,那 3 秒乘以 12 變成感官上的「卡了一下」,這在互動式 agent 對話裡是會被使用者投訴的延遲。

Docker 不夠快,Cube Sandbox 接棒

managed-agents-cube-sandbox

正好在我為 Docker 延遲頭痛的時候,2026 年 4 月 21 日 騰訊雲把 Cube Sandbox 全量開源了 ,Apache 2.0,整套 production stack 包含 SDK、控制平面、runtime。它的 GitHub repo 給了一組讓人坐直的 benchmark:

指標 Cube Sandbox 一般 Docker
冷啟動(單併發) 約 60 ms 1–3 秒
50 併發冷啟動 P95 約 90 ms 數秒到十幾秒
50 併發冷啟動 P99 約 137 ms —
單實例記憶體額外開銷 < 5 MB 數十 MB
隔離等級 硬體級(RustVMM + KVM) namespace(共享 kernel)

技術上它是基於 RustVMM 與 KVM 重寫的輕量級 microVM,搭配 CoW(copy-on-write)記憶體共用、Rust 重寫過的 runtime,把每個 sandbox 砍到 5 MB 以下。對單機跑「數千個 agent」這個野心目標來說,這幾乎是必備硬體基礎——Docker namespace 那種共享 kernel 的方案,光是 memory overhead 就會在 1000 instance 處撞牆。

更貼心的是它 相容 E2B SDK 與 OpenAI Python SDK:你不需要重寫 agent code,把 endpoint 從 E2B 換成 Cube 就能跑。這對 agent infra 工程師來說等於白送一個遷移路徑,已經把產品決策難度從「要不要換」降到「什麼時候換」。

我目前的做法是 保留 Docker 作為長期 reside 的 worker pool(例如 master 伺服器本身、log aggregator),把 Cube Sandbox 用在 ephemeral 任務(fan-out 子任務、deep research 搜尋節點、單純跑一段 sandbox 化的 Python)。兩個層級的容器各司其職,跟 Linux 裡 systemd unit 和 transient scope 的關係很像。

戰場不只是 SDK:企業基礎設施的大遷徙

如果你以為只有 Anthropic 在玩這套,那就低估了這波的規模。攤開時間軸看一下 2026 年前半年:

時間 廠商 動作 早期客戶
2026-02-05 OpenAI Frontier 平台發布 ,跨本地、企業雲、OpenAI runtime 的 agent 平台 Uber、Intuit、State Farm、HP、Oracle
2026-04-08 Anthropic Managed Agents 公開 beta Notion、Rakuten、Sentry、Asana
2026-04-21 騰訊雲 Cube Sandbox 全量開源(Apache 2.0) 自家 CodeBuddy 即用
持續中 Palantir AI FDE ,AIP 之上的對話式 Foundry 操作員 政府、金融、製造業

連帶推升的一個新興職位是 FDE(Forward Deployed Engineer)。最早是 Palantir 的特色工種,The Pragmatic Engineer 把它定義成 「介於 customer success、solution engineer 與 product engineer 之間的混合體」。換句話說,agent 不再只是程式設計師的玩具,而是一種新的企業基礎設施——你得有人帶著它走進客戶現場、跟既有系統融合、處理權限與資料治理。

把這個格局拉回華語圈來看,當很多人還在比 Openclaw 跟 Hermes 哪個 wrapper 比較好用、誰跑分高的時候,海外四大廠已經把戰場搬到 agent OS:誰能定義「agent 的容器、會話、記憶、編排」的標準,誰就拿到下一個十年的 infra 入場券。這不是 token 多少錢的競爭,是作業系統等級的競爭。

從韌體視角,這套架構為什麼讓我冷汗直流

我自己是硬體 / 韌體工程師背景,看完整套 Managed Agents 設計最強烈的感受是——這幾乎就是一個跑在雲端的 RTOS。 把對應關係攤開:

Managed Agents 概念 嵌入式 / RTOS 對應 共通的設計教訓
Agent(靜態模板) task descriptor / TCB 描述「我是誰」與「我能做什麼」要分離
Environment(容器模板) Board Support Package 環境依賴必須 declarative,不能塞進 task 邏輯裡
Session(執行實例) task instance 同一個 task 可以被 spawn 多份,狀態要本地化
Event stream(append-only log) 訊息佇列 + RTC trace 所有狀態變遷必須可追溯、可重放
Memory Store(持久記憶) 外部 EEPROM / FRAM 跨 power cycle 的狀態必須跟易失狀態解耦
Coordinator + Threads dispatcher + worker tasks 編排者不該幹活,只能調度
容器壞掉直接重建 watchdog reset 失敗的修復策略:reset,而不是 patch

換句話說,AI 圈花了五年才意識到「狀態跟硬體要解耦、編排者不能幹活、失敗了不修只重啟」這幾條教訓——而這些是嵌入式工程師在 2000 年代就已經被市場毒打到肌肉記憶的紀律。當你看 Anthropic 的部落格說「the container became cattle」時,韌體圈會心一笑:我們十五年前就在說「watchdog reset 不丟臉,丟臉的是不會 reset」。

可立即動手的三個改動:

  1. 如果你還在維護 harness 補丁:對照官方 docs 確認哪些功能 Anthropic 已經內建,把你的補丁砍掉。模型版本一進化,這些補丁就是技術債。
  2. 如果你在跑本地多 agent:先做的不是換框架,而是把「狀態」(記憶 / 對話 / 中間檔)從 worker 容器拆出來。容器要可以隨時殺。
  3. 如果你在評估 sandbox 方案:把 Docker 跟 Cube Sandbox 並存——常駐服務用 Docker,ephemeral 任務換 Cube。冷啟動延遲從秒級降到 100 ms 內,使用者體感差異是肉眼可見的。

參考資料


本文最初發布於 HackMD @BASHCAT。

8GB 的 RK3588 能跑多聰明的 LLM?ROCK 5C 用 NPU 實測 5 個模型

先講結論,省得你滑到最後: 在一片 8GB 的 RK3588 板子上,用 NPU 跑得最聰明的是 Qwen3-4B-Instruct-2507,我出的 7 題全對,但每秒只吐 3.7 個 token。 想要順一點的對話體驗,Qwen3.5-2B 的 8.4 tok/s 是比...