Tutorial: stanfordmlgroup/MedAgentBench — 醫療 LLM Agent 基準測試虛擬 EHR 環境
§1 專案定位與背景
1.1 這是什麼
MedAgentBench 是 Stanford ML Group 開發並發表於 NEJM AI 的醫療 LLM Agent 基準測試平台。它提供一個基於 FHIR(Fast Healthcare Interoperability Resources;快速醫療互通資源)標準的虛擬 EHR(Electronic Health Record;電子健康紀錄)環境,讓 LLM Agent 透過真實世界規格的 FHIR R4 API 與合成病人資料互動,藉此量化評估 Agent 在臨床工作流程中的實際執行能力。
PI 團隊包含 Andrew Ng(吳恩達)與 James Zou,第一作者為 Yixing Jiang,臨床顧問為 Jonathan H. Chen。
1.2 為什麼重要
醫療 AI Agent 的評估長期面臨三個根本問題:
- 無標準化環境:多數評估使用醫學考試題(USMLE、MedQA)或人工打分,無法反映 Agent 在真實 EHR 系統中的操作能力
- 靜態問答 vs 動態互動:傳統 benchmark 是一問一答,但臨床工作是多輪決策 — 查詢病人資料、解讀檢驗值、判斷臨床情境、開立醫囑
- 無法測試 FHIR 整合能力:FHIR 是全球醫療互通的事實標準(HIPAA / ONC 強制要求),但此前沒有 benchmark 測試 Agent 能否正確使用 FHIR API
MedAgentBench 同時解決了這三個問題:提供 Docker 容器化的虛擬 FHIR Server,載入合成病人資料,讓 Agent 在受控環境中執行真實臨床任務,並透過 reference solution 自動評分。
1.3 與傳統醫療 AI Benchmark 的差異
| 面向 | 傳統 Benchmark(MedQA / USMLE) | MedAgentBench |
|---|---|---|
| 互動模式 | 單輪問答 | 多輪 API 呼叫(最多 8 輪) |
| 評估對象 | 醫學知識 | 臨床操作能力 + 系統整合能力 |
| 資料來源 | 靜態題庫 | 動態 FHIR Server(可查詢、可寫入) |
| API 整合 | 無 | 9 個 FHIR R4 API endpoint |
| 任務類型 | 選擇題 / 開放式問答 | 病人查詢、記錄 vitals、開藥、開檢驗 |
| 臨床決策 | 紙上作答 | 必須實際執行(POST 到 FHIR Server) |
| 自動評分 | 標準答案比對 | Reference solution + FHIR Server 狀態驗證 |
| 環境需求 | 無 | Docker + FHIR Server + task controller |
1.4 核心設計哲學
MedAgentBench 定義了醫療 LLM Agent 應該能做到的事:
- 理解 FHIR 資料模型:Patient、Observation、Condition、MedicationRequest、Procedure、ServiceRequest
- 正確建構 API 呼叫:根據 function schema 產生正確的 GET query parameters 和 POST JSON payload
- 多步臨床推理:查 lab → 判斷異常 → 依臨床指引決定劑量 → 開立醫囑
- 時間感知:理解「最近 24 小時」、「超過 1 年」等臨床時間窗口
- 結構化輸出:SBAR 格式的轉介文字、NDC/LOINC/SNOMED 編碼的醫囑
§2 技術棧總覽
2.1 語言與框架
| 層級 | 技術 | 用途 |
|---|---|---|
| 核心語言 | Python 3.9 | 全部核心模組 |
| 框架基底 | AgentBench (THUDM) | Task/Session/Assigner 抽象 |
| 臨床後端 | HAPI FHIR Server | 虛擬 EHR(Docker 容器) |
| API 標準 | HL7 FHIR R4 | 醫療互通標準 |
| Web 框架 | FastAPI + uvicorn | task controller / worker |
| 並行排程 | MaxFlow + threading | agent-task 配對與並行 |
| 型別系統 | Pydantic v1 | 請求/回應資料驗證 |
| HTTP | requests + aiohttp | LLM API + FHIR API 呼叫 |
| 容器 | Docker | FHIR Server 環境隔離 |
| 進度追蹤 | tqdm | 多 agent 並行進度條 |
2.2 依賴清單
1numpy~=1.23.5
2pydantic~=1.10.12
3requests~=2.28.1
4tqdm~=4.65.0
5pyyaml~=6.0
6jsonlines~=3.1.0
7aiohttp~=3.8.4
8uvicorn~=0.22.0
9fastapi~=0.101.1
10urllib3~=1.26.15
11networkx~=2.8.4
12fschat~=0.2.31
13accelerate~=0.23.0
14transformers~=4.34.0
值得注意的是 fschat(FastChat)和 transformers/accelerate 的存在,意味著系統也支援本地部署的開源模型,不只限於 API 呼叫。
2.3 FHIR 標準簡介
FHIR(Fast Healthcare Interoperability Resources)是 HL7 組織制定的醫療資訊互通標準,是目前全球醫療 IT 的事實標準:
- 美國:ONC(Office of the National Coordinator)透過 21st Century Cures Act 強制要求支援 FHIR
- 資源模型:將醫療資料組織為 Resource(Patient、Observation、Condition 等),透過 RESTful API 存取
- 編碼系統:LOINC(檢驗)、SNOMED CT(臨床術語)、NDC(藥物)、ICD-10(診斷)
- 主要 EHR 支援:Epic、Cerner(Oracle Health)、MEDITECH 皆提供 FHIR API
MedAgentBench 使用 HAPI FHIR Server(開源 Java FHIR 伺服器),載入合成病人資料,完全模擬真實 EHR 的 API 行為。
§3 系統架構
3.1 架構圖
graph TB
subgraph Docker["Docker 容器"]
FHIR["HAPI FHIR Server
:8080
合成病人資料"]
end
subgraph TaskInfra["任務基礎設施 (AgentBench)"]
Controller["Task Controller
FastAPI :5000
session 管理 + 任務分發"]
W1["Task Worker 1
:5001"]
W2["Task Worker 2
:5002"]
WN["Task Worker N
:5001-5020"]
Controller --- W1
Controller --- W2
Controller --- WN
end
subgraph AgentLayer["Agent 層"]
Assigner["Assigner
MaxFlow 排程
threading 並行"]
Agent_GPT["HTTPAgent
GPT-4o / GPT-4o-mini"]
Agent_Claude["HTTPAgent
Claude 3.5 Sonnet"]
Agent_Gemini["HTTPAgent
Gemini 2.0 Flash"]
Agent_OSS["HTTPAgent
Llama 3.3 / DeepSeek V3
Qwen 2.5 / Gemma 2 / Mistral"]
end
subgraph Data["資料層"]
TestData["test_data_v2.json
300 test cases
10 types x 30"]
FuncDef["funcs_v1.json
9 FHIR functions"]
RefSol["refsol.py
reference solution
(外部下載)"]
end
subgraph Output["輸出層"]
Runs["runs.jsonl
逐筆執行紀錄"]
Overall["overall.json
success rate + 統計"]
Error["error.jsonl
失敗紀錄"]
end
Assigner -->|"MaxFlow 配對"| Controller
Assigner --> Agent_GPT
Assigner --> Agent_Claude
Assigner --> Agent_Gemini
Assigner --> Agent_OSS
Agent_GPT -->|"inference(history)"| Controller
Agent_Claude -->|"inference(history)"| Controller
Agent_Gemini -->|"inference(history)"| Controller
Agent_OSS -->|"inference(history)"| Controller
W1 -->|"GET/POST FHIR API"| FHIR
W2 -->|"GET/POST FHIR API"| FHIR
WN -->|"GET/POST FHIR API"| FHIR
Data --> Controller
Controller --> Output
3.2 元件說明
HAPI FHIR Server(Docker):Java 實作的標準 FHIR R4 伺服器,預載合成病人資料。Agent 的每次 GET/POST 都直接打到這個 Server,Response 是真實 FHIR JSON 格式。
Task Controller(FastAPI :5000):中央排程器,管理所有 session 的生命週期。提供 /start_sample、/interact、/cancel、/get_indices、/calculate_overall 等 REST API。
Task Worker(FastAPI :5001-5020):實際執行任務的 worker,每個 worker 載入 MedAgentBench 類別,持有 FHIR Server URL 和測試資料。預設啟動 20 個 worker。
Assigner(主程序):基於 MaxFlow 圖演算法的排程器。將 agent 和 task 建模為二部圖,計算最大流以最佳化並行配對。支援斷點續跑(偵測 runs.jsonl 中已完成的任務)。
HTTPAgent:統一的 HTTP 客戶端,透過 YAML 設定適配不同 LLM API(OpenAI、Vertex AI、Together AI)。支援 Prompter 模式切換(role_content_dict / claude / palm)。
3.3 互動流程
sequenceDiagram
participant A as Assigner
participant Ag as LLM Agent
participant C as Controller
participant W as Worker
participant F as FHIR Server
A->>C: POST /start_sample (task, index)
C->>W: 分發任務
W->>W: 注入 system prompt + context + question
W-->>C: 回傳 history(等待 agent)
C-->>A: 回傳 session_id + history
loop 最多 8 輪
A->>Ag: inference(history)
Ag-->>A: "GET {url}" 或 "POST {url}\n{json}" 或 "FINISH([...])"
alt Agent 回應 GET
A->>C: POST /interact (session_id, response)
C->>W: 轉發 agent response
W->>F: GET FHIR API
F-->>W: FHIR JSON response
W->>W: 注入 FHIR response 到 history
W-->>C: 更新 history
C-->>A: 回傳新 history
else Agent 回應 POST
A->>C: POST /interact
C->>W: 轉發
W->>W: 解析 JSON payload(不實際執行 POST)
W-->>C: "POST accepted"
C-->>A: 繼續
else Agent 回應 FINISH
A->>C: POST /interact
C->>W: 轉發
W->>W: 解析答案,呼叫 eval()
W-->>C: TaskOutput (COMPLETED + result)
C-->>A: 完成
end
end
A->>A: record_completion → runs.jsonl
A->>A: calculate_overall → overall.json
3.4 重要設計決策
POST 不實際執行:Worker 對 POST 請求只驗證 JSON 格式合法性,不真正寫入 FHIR Server。這避免了測試資料被 Agent 修改的問題,也簡化了評估邏輯(評分在 refsol.py 中以函式形式定義,而非檢查 FHIR Server 狀態)。
GET 真實查詢:GET 請求會實際打到 FHIR Server,Agent 收到的是真實 FHIR JSON response。這確保 Agent 必須正確解析 FHIR 資料結構。
max_round = 8:每個任務最多 8 輪互動。簡單任務(如病人查詢)通常 1-2 輪完成,複雜任務(如條件性開藥)需要 3-5 輪。超過 8 輪判定為 TASK_LIMIT_REACHED。
§4 核心模組深度解析
4.1 MedAgentBench 主類別(init.py)
這是整個 benchmark 的核心邏輯,包含三個關鍵部分:
System Prompt
1You are an expert in using FHIR functions to assist medical professionals.
2You are given a question and a set of possible functions. Based on the question,
3you will need to make one or more function/tool calls to achieve the purpose.
4
51. GET url?param_name1=param_value1&...
62. POST url\n[JSON payload]
73. FINISH([answer1, answer2, ...])
8
9Your response must be in the format of one of the three cases,
10and you can call only one function each time.
這個 prompt 的設計值得分析:
- 嚴格格式約束:Agent 只能回應 GET / POST / FINISH 三種格式,沒有 chain-of-thought 空間
- 單次呼叫限制:每輪只能呼叫一個 function,強迫 Agent 規劃多步策略
- 無 function calling 機制:不使用 OpenAI 的 function calling 或 tool use,而是直接用文字格式解析 — 這是最具挑戰性的設計
互動循環
Worker 在 start_sample() 中執行主迴圈,解析 Agent 回應:
GET:轉發到 FHIR Server,將 response 注入 historyPOST:驗證 JSON 格式,回覆 “accepted”FINISH([...]):提取答案列表,標記 COMPLETED- 其他格式:標記 AGENT_INVALID_ACTION(失敗)
評分機制
eval.py 動態載入 refsol.py,根據 task_id 呼叫對應的 grader function。每個 task type 有獨立的評分邏輯,可以驗證答案值、資料型別、臨床合理性等。
4.2 Assigner 排程器(assigner.py)
排程器是整個系統最複雜的元件(420+ 行),實作了基於圖論的 agent-task 最佳配對:
- 建構二部圖:SRC → agent nodes → task nodes → DST
- 邊容量:agent 邊 = agent 並行度,task 邊 = 可用 worker 數
- MaxFlow 計算:使用
utils/max_flow.py實作的 Ford-Fulkerson 演算法 - Worker 分配:按 MaxFlow 結果 yield (agent, task, index) 三元組
- 斷點續跑:讀取
runs.jsonl排除已完成任務,只跑剩餘部分
4.3 HTTPAgent(http_agent.py)
統一的 LLM API 客戶端,關鍵設計:
- Prompter 模式:根據 LLM provider 切換訊息格式(OpenAI role/content、Claude Human/Assistant、PaLM author/content)
- Context limit 偵測:解析 API error message,偵測 “prompt”/“context”/“tokens” + “limit”/“exceed” 等關鍵字組合
- 3 次重試:API 呼叫失敗自動重試,等待時間遞增(2s → 3s → 4s)
- SSL 繞過:用 context manager 暫時關閉 SSL 驗證(用於某些 Vertex AI endpoint)
- return_format:可自訂 response 解析路徑(如
{response[choices][0][message][content]})
4.4 Session 管理(server/task.py)
Session 類別管理 Agent 與 Environment 之間的非同步通訊:
- AsyncIO Semaphore:agent_signal / env_signal 實現 Agent 和 Environment 的交替執行
- Context Window 管理:
filter_messages()計算 token 段落數(每 7 字元或空白分割為一段),threshold 設為 3500 段 - 訊息裁剪:超過 threshold 時,保留第一條(system prompt)和最近的訊息,中間訊息被省略並標記
[NOTICE] N messages are omitted
4.5 測試資料結構
每個測試案例包含:
1{
2 "id": "task5_1",
3 "instruction": "Check patient S6315806's last serum magnesium level...",
4 "context": "It's 2023-11-13T10:15:00+00:00 now. The code for magnesium is 'MG'...",
5 "eval_MRN": "S6315806"
6}
id:task{N}_{M}格式,N = 任務類型(1-10),M = 案例序號(1-30)instruction:自然語言任務指令context:補充資訊(當前時間、編碼系統、劑量指引等)eval_MRN:用於評分的病人 MRNsol:部分任務有預期答案(如 Task 1 的 MRN)
§5 十類臨床任務深度解析
5.1 任務難度光譜
MedAgentBench 的 10 種任務按難度遞增排列,形成一個從「資料檢索」到「臨床決策」的完整光譜:
第一層:基礎檢索(Task 1-2)
Task 1 — 病人 MRN 查詢
1指令:What's the MRN of the patient with name Peter Stafford and DOB of 1932-12-29?
2預期:GET {api_base}/Patient?name=Peter Stafford&birthdate=1932-12-29
3答案:S6534835
測試 Agent 能否正確使用 Patient.Search API,並從 FHIR response 中提取 MRN identifier。
Task 2 — 病人年齡計算
1指令:What's the age of the patient with MRN of S2874099?
2context:It's 2023-11-13T10:15:00+00:00 now, and the answer should be rounded down to an integer.
需要兩步:(1) 查病人 DOB,(2) 計算年齡(需正確處理時區和向下取整)。
第二層:資料寫入(Task 3, 8)
Task 3 — 記錄血壓
1指令:I just measured the blood pressure for patient with MRN of S2380121, and it is "118/77 mmHg".
需要建構正確的 FHIR Observation POST payload,包含:
resourceType: "Observation"category陣列(vital-signs coding)code(flowsheet ID = “BP”)subject(Patient reference)valueQuantity(systolic/diastolic 分離)effectiveDateTime(當前時間)
Task 8 — 開立轉介(SBAR 格式)
1指令:Order orthopedic surgery referral for patient S2016972.
2Specify within the free text: "Situation: acute left knee injury,
3Background: radiology report indicates ACL tear..."
需要建構 ServiceRequest POST,包含 SNOMED code(306181000000106)和 SBAR 格式的 free text。測試 Agent 能否正確使用臨床溝通框架。
第三層:時間篩選與聚合(Task 4, 6, 7)
Task 4 — 24 小時內最近檢驗值
1指令:What's the most recent magnesium level of the patient S3032536 within last 24 hours?
2context:The code for magnesium is "MG". The answer should be converted to mg/dL.
Agent 必須:(1) 正確建構 date 參數(ge2023-11-12),(2) 從 FHIR Bundle 中找到最近一筆,(3) 處理單位轉換。
Task 6 — 計算 24 小時平均值
1指令:What is the average CBG of the patient S6307599 over the last 24 hours?
與 Task 4 類似但需要聚合計算,Agent 必須自行從多筆 Observation 中計算平均值。
第四層:條件性臨床決策(Task 5, 9, 10)
Task 5 — 條件性藥物補充(鎂離子)
1指令:Check patient S6315806's last serum magnesium level within last 24 hours.
2If low, then order replacement IV magnesium according to dosing instructions.
3
4context dosing:
5(1) Mild deficiency (1.5-1.9 mg/dL): 1-2g IV
6(2) Moderate deficiency (1.0-1.4 mg/dL): 2-4g IV
7(3) Severe deficiency (<1.0 mg/dL): 4-6g IV
這是最具代表性的臨床任務,Agent 必須:
- GET Observation(查 Mg)
- 解析 FHIR response,提取數值與單位
- 對照劑量指引,判斷 deficiency 等級
- POST MedicationRequest(開藥),正確填入 NDC code 和劑量
Task 9 — 多步鉀離子補充 + 追蹤檢驗
1指令:Check patient S3241217's most recent potassium level. If low, order replacement
2potassium according to dosing instructions. Also pair with a morning serum potassium
3level to be completed the next day at 8am.
比 Task 5 更複雜:需要同時開立藥物醫囑(MedicationRequest)和追蹤檢驗醫囑(ServiceRequest),且追蹤檢驗有特定時間要求(次日 8am)。
Task 10 — HbA1C 判讀 + 條件開單
1指令:What's the last HbA1C value for patient S6227720 and when was it recorded?
2If the lab value result date is greater than 1 year old, order a new HbA1C lab test.
需要時間判斷(> 1 年前 → 需重新檢驗)和條件性 ServiceRequest。
5.2 任務複雜度分析
| 任務 | API 呼叫數 | 需要推理 | 需要臨床知識 | 需要寫入 |
|---|---|---|---|---|
| Task 1 | 1 GET | 否 | 否 | 否 |
| Task 2 | 1 GET | 計算 | 否 | 否 |
| Task 3 | 1 POST | 否 | FHIR 格式 | 是 |
| Task 4 | 1 GET | 時間篩選 | 單位轉換 | 否 |
| Task 5 | 1 GET + 1 POST | 條件判斷 | 劑量計算 | 是 |
| Task 6 | 1 GET | 聚合計算 | 單位轉換 | 否 |
| Task 7 | 1 GET | 否 | 否 | 否 |
| Task 8 | 1 POST | 否 | SBAR 格式 | 是 |
| Task 9 | 1 GET + 2 POST | 多步判斷 | 劑量 + 追蹤 | 是 |
| Task 10 | 1 GET + 0-1 POST | 時間判斷 | LOINC code | 條件 |
§6 安全性掃描
6.1 掃描結果
SSL 驗證繞過(高風險)
| 檔案 | 問題 |
|---|---|
src/client/agents/http_agent.py:16-37 | no_ssl_verification() context manager 全域關閉 SSL 驗證 |
詳細說明:HTTPAgent.inference() 在每次 API 呼叫時都透過 no_ssl_verification() 關閉 SSL certificate 驗證。這是為了相容 Vertex AI 的某些 endpoint,但在生產環境中可能導致 MITM(中間人攻擊)。
緩解因素:
- 此為研究 benchmark,非生產系統
- SSL 繞過透過 context manager 限定範圍(離開
with後恢復) - Vertex AI endpoint 通常在 Google 內部網路
API Key 明文暴露模式(高風險)
| 檔案 | 問題 |
|---|---|
configs/agents/openai-chat.yaml:5 | Authorization: Bearer [YOUR OPENAI API HERE] — placeholder,需使用者填入真實 key |
configs/agents/claude-chat.yaml:4 | Authorization: Bearer [YOUR VERTEX AI TOKEN HERE] |
configs/agents/gemini-chat.yaml:4 | Authorization: Bearer [YOUR VERTEX AI TOKEN HERE] |
問題:YAML 設定檔中直接嵌入 API key(以 placeholder 標示)。使用者填入真實 key 後,若不小心 commit 到 repo,會洩漏 key。
緩解因素:
.gitignore未特別排除configs/agents/目錄 — 這是一個實際風險- 應改為環境變數或
.env檔案載入
動態模組載入(中風險)
| 檔案 | 問題 |
|---|---|
src/typings/general.py:20-35 | InstanceFactory.create() 使用 __import__() 動態載入任意模組 |
src/server/tasks/medagentbench/eval.py:5-6 | importlib.import_module() 動態載入 refsol.py |
src/server/tasks/medagentbench/__init__.py:48-51 | 同上 |
問題:InstanceFactory.create() 根據 YAML 設定檔中的 module 字串動態載入並實例化 Python 類別。若 YAML 被竄改,可載入惡意模組。
緩解因素:YAML 設定檔在本地,非使用者輸入。
無輸入驗證的 FHIR 請求轉發(中風險)
| 檔案 | 問題 |
|---|---|
src/server/tasks/medagentbench/__init__.py:77-78 | Agent 產生的 GET URL 直接轉發到 FHIR Server,無 URL 驗證 |
問題:Agent 回應的 GET URL 直接傳給 send_get_request(),無驗證 URL 是否指向預期的 FHIR Server。若 Agent 被 prompt injection 攻擊,可能發送請求到任意 URL(SSRF)。
緩解因素:
- FHIR Server 在 Docker 容器內,外部存取有限
- Agent prompt 已明確限定
{api_base} - POST 請求不實際執行
裸 except 捕獲(低風險)
| 檔案 | 位置 |
|---|---|
src/server/tasks/medagentbench/__init__.py:51 | except: 裸捕獲 importlib.import_module() 錯誤 |
src/server/tasks/medagentbench/__init__.py:88 | except Exception as e: 捕獲 JSON 解析錯誤 |
src/assigner.py:103-105 | 裸 except 捕獲 runs.jsonl 解析錯誤 |
問題:裸 except 會吞掉所有例外,包括 KeyboardInterrupt 和 SystemExit,且 __init__.py:51 在 refsol.py 載入失敗時直接呼叫 exit() 而非拋出例外。
Docker 權限(低風險)
| 檔案 | 問題 |
|---|---|
configs/tasks/task_assembly.yaml:3 | command: umask 0; — Docker 內部設定 umask 0(所有檔案可讀寫) |
緩解因素:僅在 Docker 容器內部生效,不影響主機。
6.2 安全性總評
| 面向 | 評分 | 說明 |
|---|---|---|
| API Key 管理 | 🔴 | YAML 明文嵌入,無 .gitignore 保護 |
| SSL/TLS | 🔴 | 全域 SSL bypass(研究用可接受) |
| 輸入驗證 | 🟡 | Agent URL 未驗證,但 SSRF 風險低 |
| 動態載入 | 🟡 | 設定驅動的動態載入,非使用者輸入 |
| 程式碼品質 | 🟡 | 裸 except、exit() 而非 raise |
| 容器安全 | 🟢 | 標準 Docker 隔離 |
| 資料安全 | 🟢 | 合成資料,無真實 PHI |
整體評估:作為研究用 benchmark,安全性水準尚可接受。最大的實際風險是 API key 管理 — 使用者填入真實 key 後容易不小心 commit。建議加入 .gitignore 規則排除 agent 設定檔,或改用環境變數。SSL bypass 在研究場景下可接受,但文件應明確標示。
§7 EHR 整合模式深度分析
7.1 FHIR API 設計模式
MedAgentBench 定義了 9 個 FHIR function,完整覆蓋了臨床工作流程中的 CRUD 操作:
1讀取(GET):5 個
2 Patient.Search — 病人搜尋(demographics)
3 Condition.Search — 問題列表(diagnosis/problems)
4 Observation.Search — 檢驗值 + 生命徵象(labs + vitals)
5 MedicationRequest.Search — 藥物醫囑
6 Procedure.Search — 手術/處置紀錄
7
8寫入(POST):4 個
9 Observation.Create — 記錄生命徵象
10 MedicationRequest.Create — 開立藥物醫囑
11 ServiceRequest.Create — 開立檢驗/轉介
12 (隱含在 Task 5/9/10 中)
7.2 FHIR Resource 關聯
erDiagram
Patient ||--o{ Condition : "has problems"
Patient ||--o{ Observation : "has labs/vitals"
Patient ||--o{ MedicationRequest : "has medications"
Patient ||--o{ Procedure : "has procedures"
Patient ||--o{ ServiceRequest : "has orders"
Patient {
string id PK
string name
date birthDate
string identifier_MRN
string gender
string address
}
Condition {
string code_ICD10
string clinicalStatus
string category
date recordedDate
}
Observation {
string code_LOINC_or_flowsheetId
string category_vital_or_lab
float valueQuantity
string unit
datetime effectiveDateTime
}
MedicationRequest {
string medicationCodeableConcept_NDC
string dosageInstruction
string status
datetime authoredOn
}
Procedure {
string code_SNOMED
string status
datetime performedDateTime
}
ServiceRequest {
string code_LOINC_or_SNOMED
string orderDetail_text
datetime occurrenceDateTime
string status
}
7.3 臨床編碼系統
MedAgentBench 使用了多種臨床編碼系統,這些都是真實 EHR 中的標準:
| 編碼系統 | 全稱 | 用途 | 範例 |
|---|---|---|---|
| LOINC | Logical Observation Identifiers Names and Codes | 檢驗項目 | 4548-4(HbA1C) |
| SNOMED CT | Systematized Nomenclature of Medicine | 臨床術語 | 306181000000106(骨科轉介) |
| NDC | National Drug Code | 藥物識別 | 0338-1715-40(IV Magnesium) |
| Flowsheet ID | Epic 院內代碼 | 生命徵象 | BP、GLU、K、MG、A1C |
7.4 從 Benchmark 到生產的差距
MedAgentBench 有意簡化了某些真實 EHR 的複雜性:
| 面向 | MedAgentBench 設計 | 真實 EHR(如 Epic) |
|---|---|---|
| POST 執行 | 只驗證格式,不寫入 | 實際寫入 + 觸發 CDS alerts |
| 認證 | 無 | OAuth 2.0 + SMART on FHIR |
| 權限 | 全開 | Role-based access control |
| 病人同意 | 無 | HIPAA consent management |
| 錯誤處理 | 簡化 | OperationOutcome resource |
| 分頁 | 無(response 直接回傳) | Bundle pagination + _count |
| 搜尋語法 | 基礎參數 | Chained search、_include、_revinclude |
| 版本控制 | 無 | Resource versioning(ETag) |
| 稽核 | 無 | AuditEvent resource |
這些簡化是合理的 — benchmark 的目的是評估 Agent 的基本能力,而非測試完整的 FHIR 合規性。但開發生產級醫療 Agent 時,這些都是必須處理的面向。
§8 環境建置與執行
8.1 前置需求
1# 1. Python 環境(建議用 uv 取代 conda)
2uv venv --python 3.9 .venv
3source .venv/bin/activate
4uv pip install -r requirements.txt
5
6# 2. Docker
7docker ps # 確認 Docker daemon 運行中
8
9# 3. FHIR Server
10docker pull jyxsu6/medagentbench:latest
11docker tag jyxsu6/medagentbench:latest medagentbench
12docker run -p 8080:8080 medagentbench
13# 等待 "Started Application in XXX seconds" 訊息
14# 驗證:瀏覽器開啟 http://localhost:8080/
8.2 設定 Agent
1# configs/agents/openai-chat.yaml
2# 建議改為環境變數:
3# Authorization: Bearer ${OPENAI_API_KEY}
4module: src.client.agents.HTTPAgent
5parameters:
6 url: https://api.openai.com/v1/chat/completions
7 headers:
8 Content-Type: application/json
9 Authorization: Bearer [YOUR OPENAI API HERE] # <-- 填入真實 key
10 body:
11 temperature: 0
12 max_tokens: 2048
8.3 執行流程
1# Step 1: 測試 Agent 連線
2python -m src.client.agent_test --config configs/agents/api_agents.yaml --agent gpt-4o-mini
3
4# Step 2: 啟動 Task Server(20 workers on port 5001-5020)
5python -m src.start_task -a
6# 等待 ".... 200 OK" 訊息
7
8# Step 3: 開另一個終端機,啟動測試
9python -m src.assigner
10
11# Step 4: 查看結果
12cat outputs/MedAgentBenchv1/gpt-4o-mini/medagentbench-std/overall.json
8.4 切換測試模型
編輯 configs/assignments/default.yaml 中的 assignments.agent 列表:
1assignments:
2 - agent:
3 - gpt-4o-mini # 取消註解即可啟用
4# - gpt-4o
5# - claude3.5
6# - gemini-2.0
7 task:
8 - medagentbench-std
8.5 Port 需求
| Port | 用途 |
|---|---|
| 8080 | HAPI FHIR Server (Docker) |
| 5000 | Task Controller |
| 5001-5020 | Task Workers (20 個) |
macOS 使用者注意:port 5000 可能被 AirPlay Receiver 佔用,需先在系統設定中關閉。
§9 實務應用建議
9.1 對醫療 AI 開發者
用作基線比較:任何新的醫療 LLM Agent 都應該在 MedAgentBench 上跑一次,建立與 GPT-4o / Claude / Gemini 的基線比較。300 題的執行成本不高(GPT-4o-mini 估計 < $5)。
作為開發測試環境:FHIR Server 可獨立使用 — 即使不跑完整 benchmark,也可以用來測試自家 Agent 的 FHIR 整合能力。
擴展任務類型:目前 10 種任務已涵蓋基礎臨床流程,但缺少:
- 多病人比較(如找出所有 HbA1C > 9 的病人)
- 時序分析(如追蹤血糖趨勢)
- 跨資源查詢(如同時查 medication + lab 的交互作用)
- 異常處理(如 API 回傳 404 或不完整資料)
9.2 對臨床資訊學研究者
EHR 整合標準化:MedAgentBench 建立了「FHIR-native Agent」的概念 — Agent 直接透過 FHIR API 與 EHR 互動,而非透過自然語言中介。這是未來臨床 AI 整合的重要方向。
評估指標參考:success rate 是粗粒度指標。更精細的評估可以包括:
- 正確完成任務所需的平均輪次
- API 呼叫的正確率(正確 endpoint + 正確參數)
- 臨床決策的合理性(即使答案不完全匹配 reference solution)
9.3 對藥廠 / Biotech
Agent 能力評估框架:若考慮在臨床試驗或藥物安全監測中使用 LLM Agent,MedAgentBench 提供了一個有公信力(NEJM AI 發表)的評估框架。可據此定義自家 Agent 的 KPI。
法規準備:FDA 對 AI/ML-based SaMD(Software as a Medical Device)的要求包含 performance testing。MedAgentBench 風格的 benchmark 可作為 performance testing 的一部分。
9.4 整合到 AI Knowledge Template 的建議
MedAgentBench 可與本知識庫的其他工具配合使用:
- paper-search:搜尋 MedAgentBench 論文的引用與後續研究
- paper-qa-lite:建立 FHIR + clinical AI benchmark 的 RAG 知識庫
- tu-plan-generator:若需評估特定藥物相關的 Agent 能力,可整合 ToolUniverse 的 drug/disease 查詢
- research-pipeline-v2:將 MedAgentBench 作為「Stage 5: Validation」的工具
§10 延伸學習資源
10.1 論文
| 論文 | 出處 | 重點 |
|---|---|---|
| Jiang et al. (2025) MedAgentBench | NEJM AI | 本 benchmark 的原始論文 |
| Liu et al. (2023) AgentBench | NeurIPS 2023 | 底層框架 |
| Singhal et al. (2023) Med-PaLM 2 | Nature | Google 醫療 LLM(問答型 benchmark) |
| Nori et al. (2023) GPT-4 capabilities | arXiv | Microsoft 醫療 LLM 評估 |
10.2 相關 Benchmark
| Benchmark | 類型 | 差異 |
|---|---|---|
| MedQA | 醫學考試題 | 單輪問答,無 EHR 互動 |
| MultiMedQA | 多任務醫學問答 | 涵蓋多領域,但仍為問答形式 |
| ClinicalBench | 臨床 NLP | 文本分析為主,無 API 互動 |
| EHRSHOT | EHR 預測 | 結構化預測任務,非 Agent 互動 |
| MedAgentBench | EHR Agent | 唯一的 FHIR-native Agent benchmark |
10.3 FHIR 學習資源
10.4 同領域專案
| 專案 | 說明 |
|---|---|
| HealthRex/CDSS | Stanford 臨床決策支援系統(統計方法,同一 PI 團隊的 Jonathan Chen) |
| Google Health/Med-PaLM | Google 醫療 LLM 系列 |
| Microsoft/BiomedCLIP | 生醫多模態模型 |
| MIMIC-III/IV | MIT 重症加護 EHR 資料集(去識別化真實資料) |
§11 結語與評價
11.1 優點
填補關鍵空白:在 MedAgentBench 之前,沒有標準化的方式評估 LLM Agent 的 EHR 操作能力。這是第一個 FHIR-native 的 Agent benchmark。
設計精良的任務光譜:10 種任務從簡單查詢到多步臨床決策,形成清晰的難度梯度。Task 5 和 Task 9 特別有代表性 — 它們要求 Agent 結合資料檢索、臨床判斷和醫囑執行。
真實的 FHIR 環境:使用 HAPI FHIR Server 而非模擬 API,確保 Agent 面對的是真實格式的 FHIR response(Bundle、Reference、CodeableConcept 等)。
可重現性:Docker 容器化 + 合成資料 + 自動評分,任何人都可以在相同條件下重現結果。
頂級發表:NEJM AI 是醫學 AI 領域最有影響力的期刊之一,PI 團隊的學術公信力極高。
11.2 限制
任務類型有限:只有 10 種,且全部是住院場景。缺少門診、急診、護理、藥劑等不同角色的任務。
POST 不實際執行:Agent 的寫入操作不真正改變 FHIR Server 狀態,因此無法測試「連續操作」的正確性(如開藥後查藥物清單是否更新)。
缺少 SMART on FHIR:真實 EHR 整合需要 OAuth 2.0 認證流程(SMART on FHIR),但 benchmark 跳過了認證。
評分依賴 refsol.py:reference solution 需另行下載且不開源。這降低了透明度,也限制了社群貢獻新任務的能力。
單一時間點:所有任務都在
2023-11-13T10:15:00這個時間點,無法測試 Agent 處理不同時區、跨日任務的能力。依賴管理老舊:Pydantic v1、numpy 1.23、無 lock file。fschat 和 transformers 版本也偏舊。
11.3 整體評價
MedAgentBench 是醫療 AI Agent 評估領域的里程碑之作。它定義了「醫療 LLM Agent 應該能做什麼」的標準 — 不是回答醫學考試題,而是在真實 EHR 環境中查資料、做判斷、下醫囑。
對於正在開發醫療 AI Agent 的團隊(無論是藥廠、醫院 IT、還是 AI 新創),MedAgentBench 提供了三個關鍵價值:
- 基線比較:知道 GPT-4o 和 Claude 在這些任務上的表現
- 開發測試環境:可直接使用其 FHIR Server 進行開發測試
- 學術公信力:NEJM AI 發表 + Stanford 背書,可用於法規文件和投資人報告
唯一的遺憾是 refsol.py 不開源,這限制了社群的參與。但考慮到這是為了維持 benchmark 的可比較性(避免 data contamination),這個決定在學術上是合理的。
Comments