文章目錄
本文架構的靈感來自 Anthropic 於 2025 年 10 月發布的 Skills 機制,並延伸至醫療場景。文中提到的「Progressive Disclosure(漸進式揭露)」是 Anthropic 官方使用的原始術語,本文沿用以便讀者順藤摸瓜研究原始文件。
Key Takeaways
- 為什麼醫療場景需要 Progressive Disclosure? 不只是為了省 Token,而是讓病歷模板的維護與 AI Agent 系統的部署完全解耦:模板改了,系統不用重跑。
- Token 節省邏輯: 傳統方式把所有模板一次塞進 Prompt(約 3,000–5,000 tokens),分層載入後初始化只需約 300–500 tokens,執行時才動態補進所需模板,單次呼叫平均節省 70%。
- 急診醫師問「幫我寫 ER record」,系統在第二次 LLM 推理才載入急診模板——第一次推理只是在判斷「需要哪份模板」。
- 新增科別為何從 2 天縮短到 30 分鐘? 傳統方式需要修改 Prompt 程式碼並重新部署;現在只需新增一個
references/er-note.md檔案,系統自動識別。- 先備知識:本文用到 Tool Calling 概念,建議先讀 Anthropic Tool Use 官方文件。
醫療場景為什麼特別需要 Progressive Disclosure?
LLM 不擅長同時處理多套格式規則。你把十種病歷模板同時放進 Prompt,模型確實都能看到,但「看到」與「正確執行」之間有明顯落差——特別是當模板之間格式相近(例如 SOAP 與 Nursing Note 都有主訴區)時,模型容易混用。
但 Token 成本只是表面問題。醫療系統面對的更深層挑戰是維護週期:
- 牙科診所每季可能更新一次 Dental SOAP 格式
- 精神科引入新的 DSM-5-TR 診斷標準後,Mental Status Exam 的欄位需要調整
- 長照機構在通過評鑑後,Follow-up Report 增加了新的 ADL 評估項目
傳統的做法是把模板直接寫進 System Prompt。只要有任何一個模板改動,就必須:
- 修改 Prompt 字串(觸及程式碼)
- 重新部署服務
- 測試所有其他科別是否受影響
這個週期,光是內部審查與重新部署,通常就需要 1–2 天。
Progressive Disclosure 的設計把模板檔案與Agent 邏輯徹底分開。模板是獨立的 Markdown 檔案,由各科室自行維護;Agent 邏輯只知道「有哪些模板存在」,不把模板內容硬編進去。模板改了,Agent 下次執行時自動讀到新版本。不需要碰程式碼,不需要重新部署,不需要全科別回歸測試。
Token 成本的具體計算
假設一個醫療 AI Agent 支援以下 5 種病歷類型:
| 模板 | 估計 Token 數 |
|---|---|
| SOAP Note | 350 tokens |
| Follow-up Report | 280 tokens |
| Discharge Summary | 450 tokens |
| Nursing Note | 320 tokens |
| ER Record | 400 tokens |
傳統方式: 每次呼叫都把所有模板放進 System Prompt,加上 Skill Instructions(約 200 tokens)與 Tool Definitions,總計約 2,200 tokens 的固定開銷,無論使用者只是要寫一份 SOAP Note。
Progressive Disclosure 方式:
- 初始化:Skill Instructions(200 tokens)+ Reference 清單(僅檔名,約 50 tokens)+ Tool Definitions(約 150 tokens)= 400 tokens
- 執行時才載入單一模板,例如 SOAP Note:+350 tokens
- 單次呼叫總計:約 750 tokens
從 2,200 tokens 降到 750 tokens,節省幅度約 66%。如果模板數量增加到 8–10 種,節省比例還會更高。實務上計入 System Prompt 其他部分之後,業界常見的測量結果落在 70% 左右。
急診醫師問「幫我寫 ER record」——系統怎麼運作?
這是 Progressive Disclosure 最直觀的示範場景。
第一層:初始化(Agent 啟動時,只做一次)
Agent 啟動時,完成以下四件事:
- 讀取
skill.md:取得 Agent 的角色定義、輸出規則、語言要求。 - 掃描
references/目錄:取得可用模板的檔名清單(僅檔名,不讀內容):soap-note.md follow-up.md discharge-summary.md nursing-note.md er-note.md dental-soap.md mental-status.md - 建立 Tool:定義
read_reference工具,讓模型可以在需要時主動呼叫。 - 建立初始 Context:此時 Context Window 只佔用約 400 tokens。急診模板的內容完全沒有被讀取。
System Prompt + Skill Instructions + Reference 檔名清單 + Tool Definitions
第二層:第一次 LLM 推理(判斷意圖)
急診醫師輸入:
幫我寫 ER record,病患 38 歲男性,主訴胸悶 3 小時,BP 145/90,心電圖 ST 段無明顯變化,安排 Troponin,觀察 6 小時後出院。
模型收到的 Context 是:
[Skill Instructions]
[可用模板清單:soap-note.md / follow-up.md / discharge-summary.md / nursing-note.md / er-note.md / ...]
[Tool: read_reference]
[使用者輸入]
模型在這一次推理中,不生成病歷。它只做一件事:判斷需要哪份模板,並輸出 Tool Call:
{
"tool": "read_reference",
"arguments": { "name": "er-note.md" }
}
此時急診模板仍未進入 Context。這一步只是決定「下一步要讀什麼」。
第三層:工具執行 → 第二次 LLM 推理(生成病歷)
Agent 執行 Tool Call,從磁碟讀取 er-note.md 的完整內容,注入 Context:
[Skill Instructions]
[er-note.md 完整內容] ← 急診模板在這裡才正式進入
[使用者輸入]
模型進行第二次推理,生成結構化的 ER Record:
# Emergency Record
## Chief Complaint
38 歲男性,主訴胸悶 3 小時。
## Vital Signs
BP 145/90 mmHg,其他生命徵象穩定。
## Assessment
12-lead ECG:ST 段無明顯偏移。
初步排除 STEMI,安排 Troponin 系列檢測。
## Plan
- 觀察 6 小時
- 若 Troponin 陰性且症狀緩解,可安排出院
- 出院前進行 ACS 衛教
急診模板從進入 Context 到生成病歷,只在第三層發生。SOAP、Follow-up 等其他模板全程未被載入。
新增科別:從 2 天縮短到 30 分鐘
傳統方式需要哪些步驟?
假設牙科診所要新增 Dental SOAP 模板:
- 撰寫模板內容(30 分鐘)
- 找到 System Prompt 的字串,插入新模板(15 分鐘,但容易破壞格式)
- 修改程式碼,確保模型知道有這個新格式(30 分鐘)
- 提交 Pull Request,等待 Code Review(數小時至隔天)
- 重新部署服務(15–30 分鐘)
- 回歸測試:確認其他 5 個科別的輸出沒有被新模板干擾(數小時)
最樂觀的情況:1 個工作天。有任何問題要修正,就變成 2 天。
Progressive Disclosure 的方式
- 撰寫
references/dental-soap.md(30 分鐘) - 把檔案放進
references/目錄(1 分鐘)
完成。
Agent 下一次啟動時,掃描 references/ 目錄會自動發現 dental-soap.md,並將其加入可用模板清單。模型在下次收到牙科相關請求時,會主動呼叫這份模板。整個過程不碰程式碼,不重新部署,不需要回歸測試其他科別。
Skill 目錄設計
一個完整的 Skill 結構如下:
skills/
├── medical-writing-assistant/
│ ├── skill.md
│ └── references/
│ ├── soap-note.md
│ ├── follow-up.md
│ ├── discharge-summary.md
│ ├── nursing-note.md
│ ├── er-note.md
│ ├── dental-soap.md
│ └── mental-status.md
├── appointment-scheduler/
├── drug-interaction/
└── insurance-checker/
skill.md 定義 Agent 的角色與共通規則,不存放任何模板內容:
---
name: medical-writing-assistant
description: Generate structured medical documentation.
version: 1.0
---
# Instructions
You are an experienced medical documentation assistant.
## General Rules
- Never fabricate symptoms or diagnoses.
- Preserve all medical terminology.
- Use objective and professional language.
- Do not infer information that is not provided.
- Follow the referenced template whenever one is available.
- Output in Markdown format.
## Output Requirements
- Maintain section hierarchy.
- Keep terminology consistent.
- Avoid unnecessary explanations.
- Return only the requested documentation.
真正的 SOAP 格式、ER 格式、Mental Status 格式,全部拆開存放在 references/。這是 Progressive Disclosure 的核心:Skill 定義能力,Reference 定義格式,兩者完全分離。
程式碼實作
以下是完整的 Python 實作,可直接複製到專案中修改:
import os
from pathlib import Path
from anthropic import Anthropic
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
SKILL_ROOT = Path("./skills/medical-writing-assistant")
def load_skill_metadata():
"""讀取 skill.md 的 instructions 部分。"""
return (SKILL_ROOT / "skill.md").read_text(encoding="utf-8")
def list_references():
"""列出可用的 reference 檔名(不讀取內容)。"""
return [p.name for p in (SKILL_ROOT / "references").glob("*.md")]
def read_reference(name: str) -> str:
"""真正讀取指定 reference 的內容。"""
return (SKILL_ROOT / "references" / name).read_text(encoding="utf-8")
# Tool Schema:讓模型可以主動呼叫
tools = [{
"name": "read_reference",
"description": "讀取指定的醫療紀錄模板內容。",
"input_schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "reference 檔名,例如 er-note.md"
}
},
"required": ["name"]
}
}]
# 初始化 Context:只有 Skill Instructions + Reference 清單 + Tool Definitions
system_prompt = f"""{load_skill_metadata()}
## Available References
{chr(10).join(f'- {r}' for r in list_references())}
當需要生成醫療文件時,請先透過 read_reference 工具載入對應的模板。
"""
# 急診醫師的輸入
user_input = """幫我寫 ER record,病患 38 歲男性,主訴胸悶 3 小時,
BP 145/90,心電圖 ST 段無明顯變化,安排 Troponin,觀察 6 小時後出院。"""
# 第一次推理:模型判斷需要哪個模板,輸出 Tool Call
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=2048,
system=system_prompt,
tools=tools,
messages=[{"role": "user", "content": user_input}],
)
# 處理 Tool Call
messages = [{"role": "user", "content": user_input}]
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
ref_content = read_reference(block.input["name"])
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": ref_content,
})
messages.append({"role": "user", "content": tool_results})
# 第二次推理:模型現在有了模板,生成正式病歷
final_response = client.messages.create(
model="claude-sonnet-5",
max_tokens=2048,
system=system_prompt,
tools=tools,
messages=messages,
)
print(final_response.content[0].text)
這段程式碼的結構與「急診醫師場景」完全對應。第一次 create 呼叫是意圖判斷層,第二次 create 呼叫才是真正的病歷生成層。
各科別 Reference 模板範例
references/soap-note.md
# SOAP Note
## Subjective
主訴症狀摘要。
## Objective
客觀臨床發現:生命徵象、體格檢查、檢驗結果。
## Assessment
臨床評估與診斷印象。
## Plan
治療計劃:藥物、檢查、轉介、回診安排。
references/er-note.md
# Emergency Record
## Chief Complaint
主訴與到院時間。
## Vital Signs
BP / HR / RR / SpO2 / Temp
## History of Present Illness
現病史,含症狀起始、變化與相關病史。
## Physical Examination
系統性體格檢查。
## Assessment & Plan
急診評估、處置計劃、後續安排(住院 / 觀察 / 出院)。
references/mental-status.md
# Mental Status Examination
## Appearance & Behavior
外觀、合作度、眼神接觸。
## Speech
語速、語量、語調。
## Mood & Affect
情緒陳述(主觀)與情感表達(客觀)。
## Thought Process & Content
思維流程、強迫意念、自傷他傷風險評估。
## Cognition
定向感、注意力、記憶力。
## Insight & Judgment
病識感與判斷力。
完整工作流程
使用者輸入
│
▼
Medical Agent 初始化
├── 讀取 skill.md(角色定義)
└── 掃描 references/(只取檔名)
│
▼
第一次 LLM 推理
└── 判斷意圖 → 輸出 Tool Call(read_reference)
│
▼
Tool Execution
└── 從磁碟讀取指定模板(此時才讀內容)
│
▼
第二次 LLM 推理
└── 模板 + 使用者輸入 → 生成結構化病歷
│
▼
輸出 Markdown 格式病歷文件
重點整理
- Skill 負責定義 Agent 的角色、能力與共通規則;
skill.md裡不存放任何模板。 - Reference 將 SOAP、護理紀錄、ER Record 等模板獨立管理,每個科別一個檔案。
- Tool Calling 讓 Agent 僅在第一次推理判斷意圖後,才在第二次推理時載入對應模板。
- Progressive Disclosure 把初始化(掃描清單)與執行(讀取內容)分成兩層,有效控制每次 LLM 呼叫的 Token 用量。
- 新增科別 只需要新增一個 Markdown 檔案,不碰程式碼、不重新部署、不影響其他科別。
- 維護週期 從 1–2 天縮短到 30 分鐘以內,差距來自「是否需要觸及程式碼與部署流程」。
相關文章:FHIR R4 與台灣醫療數據整合




討論區 (0 則留言)