《蜘蛛人》裡有句話:「 能力越大,責任越大(With great power comes great responsibility)。」
假設未來某天,一份基因檢測加上 AI 分析,就能提示你在某些疾病上可能面臨較高的風險。這樣的技術也許能幫助我們更早開始研究與預防;但如果報告被未經授權的人看見,成為保險或求職的差別待遇理由,科技的進步也可能帶來新的傷害。
這裡必須先說清楚:現有 AI 無法憑一次檢測就 100% 預知一個人未來 30 年會不會罹患某種疾病。 基因變異的分子效應、疾病風險與最終臨床診斷是不同層次的問題。以本專欄介紹的 AlphaGenome 為例,官方也明確指出模型尚未設計或驗證為直接臨床用途。
密碼外洩還能重設,基因資訊卻和一個人的身分、健康、親屬關係長期相連。今天是 30 天專欄的倒數第二天,我們要談的不是 AI 還能算出多少分數,而是:我們該如何讓人類在享受基因科學進步的同時,仍保有隱私、選擇與被公平對待的權利?
基因檢測可能揭露某些疾病的風險線索,但「帶有變異」不等於「一定會發病」,也不代表 AI 分數已經完成致病性判定。若雇主或保險業者忽略這個差別,便可能造成歧視。
美國的《基因資訊無歧視法》(GINA)提供部分健康保險及就業領域的保障,但並非涵蓋所有保險種類,例如壽險、長照險與失能保險就有不同法律界線。台灣的《個人資料保護法》也將基因、醫療、病歷等列為受到特別規範的個人資料;實際適用仍應依個案、資料使用目的和當時有效法規判斷。
DNA 資訊不只和本人有關,也可能透露血親之間的連結。研究已顯示,即使資料先移除了姓名等識別欄位,仍可能在特定情境下和其他資料交叉比對而重新識別個人或親屬。
所以 去掉姓名,不代表資料就完全匿名。尤其罕見變異、特殊疾病表型、年齡、地理資訊等組合,仍可能構成再識別線索。
| 防線 | 白話比喻 | 能做什麼 | 仍需注意 |
|---|---|---|---|
| 聯邦學習(Federated Learning) | 資料留在各醫院,模型更新參與合作 | 降低集中傳輸原始病人資料的需求 | 更新參數仍可能洩漏訊息,需要安全聚合、存取控制與治理;不能自稱「100% 符合 GDPR」 |
| 假名化、資料最小化與差分隱私 | 用代碼、減少不必要欄位、在統計上控制資訊洩漏 | 降低直接識別與部分統計查詢風險 | Hash 不是加密;假名化不等於真正匿名;差分隱私需有正式機制和隱私預算 |
| Human-in-the-Loop 與研究治理 | AI 提供線索,人類審查證據與用途 | 將模型結果放回醫學、倫理與法規脈絡 | 單一 consent=True 欄位無法證明 IRB、知情同意、跨境移轉或臨床適法性 |
這些防線不是三選一,而是相互補充的技術、組織與法律措施。
我們把原本設想的 privacy_preserving_gene_pipeline.py 改造成 可以實際執行、但預設拒絕真實病人資料與外部傳輸的教學範例。
今日練習有四個目標:
MANUAL_REVIEW_REQUIRED 與 external_transfer_allowed=False,不連接 AlphaGenome、Gemini 或其他雲端 API。請建立檔案 privacy_preserving_gene_pipeline.py,貼上以下完整範例。只使用 Python 3.12+ 標準函式庫。
"""Day 29: local-only SYNTHETIC genome-data review exercise.
No network access, no real-patient processing, no legal compliance claims.
This exercise does NOT anonymize genuine genomic data.
"""
from __future__ import annotations
import json
import re
import secrets
from collections.abc import Mapping
from typing import Any
# 驗證變異格式:
# chr1:100:A:G
# chrX:12345:C:T
#
# 結構:
# 染色體:座標:參考鹼基:替換鹼基
_VARIANT_PATTERN = re.compile(r"^chr(?:[1-9]|1[0-9]|2[0-2]|X|Y|M):[1-9][0-9]*:[ACGT]+:[ACGT]+$")
def prepare_synthetic_local_preview(record: Mapping[str, Any]) -> dict[str, Any]:
"""Prepare minimal *synthetic* teaching fields, with external transfer denied.
A string or flag in an input record cannot establish true consent, source
provenance, IRB approval, anonymisation, or legal compliance. This function
deliberately refuses non-synthetic inputs; it is not a production safeguard.
"""
# 檢查輸入是否為 dict-like 結構
if not isinstance(record, Mapping):
raise TypeError("Expected a mapping")
# 僅允許標記為 SYNTHETIC 的資料集
if record.get("dataset_kind") != "SYNTHETIC":
raise PermissionError("Only explicitly synthetic teaching records are supported")
# ------------------------------------------------------------------
# Demo Policy 檢查
# ------------------------------------------------------------------
policy = record.get("demo_policy")
if not isinstance(policy, Mapping):
raise PermissionError("Missing local education review")
# 僅允許本地教育用途
if policy.get("purpose") != "LOCAL_EDUCATION":
raise PermissionError("Purpose not allowed for this demonstration")
# 必須明確標註已完成本地審查
if policy.get("local_demo_reviewed") is not True:
raise PermissionError("Local demonstration has not been reviewed")
# 必須禁止外部傳輸
if policy.get("external_transfer_allowed") is not False:
raise PermissionError("External transfer must be explicitly prohibited")
# ------------------------------------------------------------------
# Variant 格式驗證
# ------------------------------------------------------------------
variant = record.get("variant_query")
# 確認符合標準 teaching 格式
if not isinstance(variant, str) or not _VARIANT_PATTERN.fullmatch(variant):
raise ValueError("Invalid teaching variant notation")
# ------------------------------------------------------------------
# Phenotype 驗證
# ------------------------------------------------------------------
phenotype_terms = record.get("phenotype_terms")
# 允許 1~10 個 phenotype
if not isinstance(phenotype_terms, list) or not (1 <= len(phenotype_terms) <= 10):
raise ValueError("Expected 1–10 synthetic phenotype terms")
# 每個 phenotype 必須: 為字串、 長度 1~80 字元
if any(not isinstance(p, str) or not (1 <= len(p) <= 80) for p in phenotype_terms):
raise ValueError("Invalid synthetic phenotype term")
# ------------------------------------------------------------------
# 建立 Preview
# ------------------------------------------------------------------
# Random token, not deterministic hashing of an identifiable name or ID.
# No persistent linkage table is created or published by this exercise.
#使用隨機 Token: 不來自病患姓名、不來自身分證號、不建立對照表,因此不具備重新識別能力
return {
"demo_token": "DEMO_" + secrets.token_hex(16),
"variant_query": variant,
"phenotype_terms": list(phenotype_terms),
"data_provenance": "SYNTHETIC_EXAMPLE_ONLY",
"intended_use": "LOCAL_EDUCATION",
"external_transfer_allowed": False,
"anonymization_claim": "NOT_ESTABLISHED",
"governance_review_status": "MANUAL_REVIEW_REQUIRED",
}
def demo() -> None:
# Completely fictional teaching record. No patient database is read.
#Demo 執行入口,使用完全虛構資料:不連接病患資料庫、不讀取真實電子病歷、不呼叫任何 API
simulated_record = {
# 指定為 Synthetic 資料
"dataset_kind": "SYNTHETIC",
# 以下皆為虛構內容
"patient_id": "FICTIONAL-001",
"full_name": "Fictional Example",
"age": 6,
# 範例 Variant,僅示意格式,不代表真實致病證據
"variant_query": "chr1:100:A:G",
# 範例 Phenotype
"phenotype_terms": ["SIMULATED_PHENOTYPE_A", "SIMULATED_PHENOTYPE_B"],
# 示範政策設定
"demo_policy": {
"purpose": "LOCAL_EDUCATION",
"local_demo_reviewed": True,
"external_transfer_allowed": False,
},
}
# 建立本地教學預覽
preview = prepare_synthetic_local_preview(simulated_record)
print("LOCAL_SYNTHETIC_PREVIEW_ONLY — NO API REQUEST")
# 美化輸出 JSON
print(json.dumps(preview, ensure_ascii=False, indent=2))
print("NOTICE: This is not anonymization certification or lawful-use approval.")
# 直接執行檔案時啟動 demo
if __name__ == "__main__":
demo()
python3 privacy_preserving_gene_pipeline.py
將會看到 LOCAL_SYNTHETIC_PREVIEW_ONLY — NO API REQUEST,以及像下面這樣的 JSON 欄位(每次隨機 Token 都不同):
{
"demo_token": "DEMO_<RANDOM_TOKEN>",
"variant_query": "chr1:100:A:G",
"phenotype_terms": ["SIMULATED_PHENOTYPE_A", "SIMULATED_PHENOTYPE_B"],
"data_provenance": "SYNTHETIC_EXAMPLE_ONLY",
"intended_use": "LOCAL_EDUCATION",
"external_transfer_allowed": false,
"anonymization_claim": "NOT_ESTABLISHED",
"governance_review_status": "MANUAL_REVIEW_REQUIRED"
}
請特別注意: dataset_kind="SYNTHETIC" 是示範程式用來阻擋其他標記的輸入,不足以證明一份資料在現實中真的沒有病人資訊。demo_policy 也只是教學規則,不能取代正式同意書核實、IRB/研究倫理審查、資安評估或法遵作業。當 variant_query 與 phenotype_terms 換成真實資料時,仍有敏感資料或再識別風險;這支程式 禁止拿去處理真實病人資料,也不允許資料上雲。
patient_id、full_name、age。external_transfer_allowed: false 與 MANUAL_REVIEW_REQUIRED。以下是一個 研究發展願景,而不是已經實現的功能或精準預測:
第一步|模型先學會誠實說不知道。 從「只給一個高低分」進步到「附上組織情境、資料來源、模型版本、缺值與不確定性」。讀者在 Day 28 所看到的 Limitations & Evidence Reporter,正是朝這個方向設計的獨立離線 MVP。
第二步|跨院研究先做好信任與治理。 在適用法規、倫理審查與資料共享政策下,探索安全運算、聯邦學習與差分隱私,讓研究合作不必以無限制集中病人資料為代價。
第三步|從分子假說走向可驗證的照護。 真正負責任的精準醫療需要生物實驗、族群驗證、臨床研究、專業審查與病人參與;AI 可以提出值得驗證的假說,但不能跳過這些環節。
這 29 天,我們從 DNA、非編碼調控、模型架構、AVI 與變異效應,一路走到資料管線、分子機制、離線 CLI、證據限制與基因隱私。
明天 Day 30,我想帶大家做最後一件真正重要的事:把每天學到的觀念,和實際可以執行的程式清楚連起來。 我會整理 30 天知識地圖、文章與 GitHub 參考實作對照表,清楚註明哪些已完成離線驗證、哪些仍是教學代理、哪些還需要研究驗證。
因為好的 AI for Science,不是每一題都回答「正確」或「成功」,而是讓別人看得懂 證據從哪裡來、程式做了什麼、還有哪些問題沒有解答。
聲明:本文程式為合成資料的本機教育示範,非臨床、資安或法遵認證系統,也未連接真實 AlphaGenome API。