triAIge 技術導讀:架構、取捨與評審問答

模型為什麼不決定檢傷級數?現場擷取為什麼不讓模型推理,醫師端的鑑別診斷卻要?Guardrails 為什麼關著?F1 0.95 用的是什麼資料?評審追問的多半是這類設計取捨。這份導讀用白話說明現在的系統怎麼組成、每個設計決定的理由與我們放棄的做法,也逐一講解三個畫面與每一項 AI 功能,最後整理關鍵數字、評審可能問的問題,以及代替產品負責人示範時的備援腳本。

內容以 2026-10-22 的 main 為準:階段 2 與 UAT 修正已經合併並部署(be3614d2)。每個數字都附上 repository 裡的出處。繁體中文口述稿由模型寫成,還沒有臨床人員審閱,所以這份文件不說「已通過臨床驗證」(eval/README.md〈誠實規則〉)。程式結構的細節在〈架構說明〉,給評審的正式說明在〈評審報告〉。三份報告同一天依同一版程式更新;若彼此對不上,以程式碼為準。

1. 整個系統怎麼運作?

救護員在平板的救護端網頁送出一句話,這句話送到醫院端一台 DGX Spark 上的 FastAPI 服務。服務先存下這句話、立刻回應,再在背景透過 NeMo Agent Toolkit 呼叫 vLLM 上的 Nemotron 3 Super,把這句話擷取成救護紀錄表的欄位。模型的回覆先通過一組確定性檢查,再依「人填的值優先」的規則寫進紀錄表,經 SSE 推回畫面,標成「待複查」。救護員送出紀錄後,急診檢傷護理師看到預先填好的檢傷表與規則算出的 TTAS 建議級數,由護理師決定級數;護理師送出檢傷後,醫師看到規則組出的摘要、模型改寫的「AI 整理」,以及一個會搜尋醫學知識庫的智慧體(agent)整理的鑑別診斷:常見 Top 5 與最致命 Top 5。

回答時,有四件事要先講清楚:

  1. 模型整理資料、提供參考,臨床決定由規則與人負責。 TTAS 建議由規則計算,級數由護理師送出;鑑別診斷只是供醫師參考的選項,不含機率,每一項附上依據的病人資料與知識庫出處。
  2. AI 填的值都要經過複查,人填的值不會被覆蓋。 AI 的建議直接顯示在欄位上,不用對話框打斷現場人員。
  3. 現場擷取求快,醫師端的鑑別診斷求深。 擷取每句一次呼叫、關閉推理,延遲以秒計;鑑別診斷是會呼叫工具的智慧體,開啟推理,背景執行,約需 1 到 3 分鐘。兩者的取捨在 §4.2。
  4. 系統全部跑在一台 DGX Spark 上,模型可以替換,各層的邊界由測試強制。 推論不使用雲端模型;與模型有關的設定集中在一個 ModelProfile 物件裡。

1.1 三個畫面各做什麼?

正式介面在根目錄 /,首頁選角色。每個畫面頂列都有「重置 demo 資料」,會清空所有案件,示範前後要留意。

救護員(E0 案件清單、E1 對話、E2 紀錄表)。 新增案件後,用文字(語音輸入還沒做)一句一句送出對話,每句標說話者:救護員、病人或旁人。AI 即時把內容填進 E2 紀錄表,欄位旁標「待複查」;救護員可以在欄位上確認、修改或刪除。右側欄常駐三樣東西:TTAS 參考級數、完成度與缺漏欄位、建議詢問與危險訊號。選送往的醫院時,選單上會多一行「AI 建議需要重度/中度/一般急救責任醫院」。必填欄位補齊後「送出至急診」。送出必填共六項:性別、年齡、創傷或非創傷、主訴、至少一組含意識與脈搏的生命徵象、藥物過敏史(寫「不清楚」也算),另外還要選送往醫院(engine/completeness.py)。送出後播「救護車」轉場,落在急診檢傷台。

檢傷護理師(N1 待接收清單、N2 檢傷台)。 N1 依預估到院時間列出院前預通知,即時收到新案件,可預覽交接包,並用「讀取健保卡(模擬)」確認身分(20 張虛構的卡)。N2 的左側有檢傷評估、院前紀錄與時間軸三個分頁,右側是 AI 助理。檢傷表由救護紀錄預填,沒有救護員確認過的欄位標「未複查」。TTAS 列顯示規則算出的建議級數與每一條依據;護理師接受或調整,與建議不同時必須寫理由。護理師也可以在 AI 助理裡打一段話,AI 擷取成欄位提案,勾選「套用」後才寫入。若救護端在檢傷中又送出新版本,會出現「救護端有更新」橫幅,只提示、不自動套用。送出檢傷後播「移到看診區」轉場,落在醫師摘要。

急診醫師(D1 病人清單、D2 摘要)。 D1 只列已完成檢傷的病人,依最終級別排序,1 級在前。D2 由上而下是:交接摘要(含「AI 整理」)、待追蹤事項、鑑別診斷與建議檢查、主訴、檢傷、病史、生命徵象、時間軸與稽核紀錄。每一句摘要、每一項診斷都附來源標籤,點了回到原始欄位。

三個角色在 demo 環境各自用固定的虛構使用者登入,不需要輸入帳號;護理師與醫師可以處理三家示範醫院(重度、中度、一般急救責任醫院)的案件(migrations/004_user_hospitals.sql)。

1.2 AI 在哪裡出手?

功能誰看到觸發優先級開關詳細
欄位擷取救護員每一句對話P0一直開§3.1
主訴翻譯救護員、急診擷取完成後P2 背景開§3.1
建議詢問救護員、護理師對話停 8 秒;護理師端送出P2 背景開§3.2
護理師輸入擷取護理師護理師送出一段話P1開§3.2
急救責任醫院建議救護員紀錄表欄位變動P2 背景開§3.2
醫師「AI 整理」醫師救護端送出、檢傷送出P2 背景開§3.2
鑑別診斷與建議檢查醫師救護端送出、檢傷送出閒置(IDLE)開§3.3
路由分類器、案件備忘整理、Guardrails 自我檢查———關§4.9

開關的正式環境值在 infra/inventory/group_vars/servers.yml。

2. 系統由哪些部分組成?

flowchart LR
  subgraph Front["前端(Vercel)"]
    LIVE["/ 正式介面<br/>救護端、急診檢傷、醫師"]
    MOCK["/internal 模擬版<br/>瀏覽器內的模擬後端"]
  end
  TUNNEL["Cloudflare Tunnel"]
  subgraph Spark["醫院端 DGX Spark"]
    API["FastAPI 服務<br/>api、ai、engine、task_rules、llm"]
    NAT["NeMo Agent Toolkit<br/>(同一個行程)"]
    VLLM[("vLLM<br/>Nemotron 3 Super NVFP4")]
    PG[("PostgreSQL<br/>案件 JSONB+知識庫 kb_passages")]
  end
  LIVE --> TUNNEL --> API
  API --> NAT --> VLLM
  NAT -- "搜尋知識庫" --> PG
  API --> PG
  API -- "SSE 推播" --> LIVE
圖表載入中…

3. AI 工作怎麼跑?

3.1 一句話從送出到畫面更新,經過哪些步驟?

sequenceDiagram
  participant W as 救護端網頁
  participant A as FastAPI
  participant D as PostgreSQL
  participant S as 排程與依序
  participant M as Nemotron 3 Super
  W->>A: 打開案件頁:連上 SSE(GET /cases/{id}/events)
  A-->>W: SSE:心跳(每 15 秒,帶 aiAvailable)
  W->>A: 送出一句話(POST,帶 clientMessageId)
  A->>D: 交易:存下這句話+空的 AI 回覆(pending)
  A-->>W: 提交後 SSE:message.created
  A->>S: 排進 AI 工作(不等它執行)
  A-->>W: 201,先回應
  Note over S: 等排程名額(正式環境同時 3 個)
  S-->>W: SSE:assistant.started
  Note over S: 救護員的話:等同一案件前面的句子寫完
  S->>M: 一次呼叫:這句話+前三句+紀錄表現況
  M-->>S: 一行 JSON(附 token 機率)
  S->>D: 交易:取出 JSON、確定性檢查、依來源規則寫入
  S-->>W: 提交後 SSE:record.updated、message.updated、assistant.completed
  S->>M: 背景(P2):主訴翻成繁中
  S-->>W: 翻好、通過檢查後 SSE:record.updated
圖表載入中…
  1. 前端依序送出。 送出的句子進入先進先出的佇列,一次送一則;前一則還沒送達,後面的就不會先送,所以 AI 讀到的對話順序不會顛倒。每則訊息帶 clientMessageId,重送時伺服器會排除重複。斷線時句子留在畫面上,恢復連線後自動送出(web/src/hooks/outbox-store.ts)。
  2. 伺服器先存檔再回應。 POST /cases/{id}/messages 存下訊息就回 201,AI 在背景執行,所以畫面不必等模型(server/src/triaige_server/ai/service.py)。
  3. 確定性分流,不呼叫模型。 空白或只有標點的句子直接略過。說話者決定用哪一組提示詞、值上要標記誰說的,但不決定寫不寫:救護員的話用 R1(含生命徵象),病人與旁人的話用 R2。不論誰說的,擷取到的值都可以填進空欄位、標「待複查」,並記下說話者(救護員、病人、旁人,或辨識信心低於 0.6 的救護員),畫面上會標出「家屬說的」這類來源(engine/routes.py、engine/record.py、docs/api/data-model.md §7)。
  4. 排程。 送給模型的請求有固定名額,正式環境同時 3 個。工作分四個優先級:P0 是即時的句子,P1 是說話者修正後的重跑與護理師提案,P2 是主訴翻譯、摘要、追問、醫院分級建議這類背景工作(同時最多占 1 個名額),閒置(IDLE)只有在沒有任何工作執行或等待時才啟動。即時的句子等不到名額時,執行中的 P2 會被取消,之後重新排隊;任何其他工作一到,閒置的工作也會被取消、從頭重跑(ai/scheduler.py)。
  5. 同一個案件依序處理。 R1 的提示詞要帶上前三句與它們在紀錄表上的內容,模型才知道「不對,是一百三」要更正哪一個值,所以同一個案件的 R1 句子要等前一句寫完才呼叫模型。不同案件之間、病人與旁人的話,可以同時處理(ai/sequencer.py)。
  6. 呼叫模型一次。 現場擷取每句話只呼叫一次模型,不經過智慧體的多輪迴圈:溫度設 0、關閉推理、最多輸出 300 個 token,並回傳每個 token 前五名候選的機率。輸出是一行精簡的 JSON,涵蓋年齡、性別、主訴、生命徵象、疼痛、病史、用藥與過敏等 12 個欄位(llm/profiles/nemotron_3_super/)。
  7. 整理回覆,再嚴格檢查。 模型層先把回覆整理成一個 JSON 物件,任務層再嚴格檢查:未知的欄位、超出合理範圍的生命徵象、沒有原文依據的「無過敏」,都會被丟掉。選項欄位(性別、過敏狀態、病史)另外用 token 機率計算信心分數,分數會存下來,但目前不顯示(見 §4.9)。
  8. 依來源規則寫入。 空欄位直接寫入並標「待複查」,附上來源句與說話者。還沒有人複查的 AI 值,可以被看過相關句子的新判斷取代;人填的或已確認的值不會被覆蓋,AI 給的不同值以替代選項列在旁邊。人刪掉的 AI 值會被記住,AI 不會再寫回去(engine/record.py、engine/retroactive.py)。
  9. 推播。 寫入的交易提交之後,才依序推播 record.updated、assistant.completed 等事件,前端據此更新快取(server/src/triaige_server/bus.py、web/src/api/live.ts)。
  10. 背景翻譯。 英文主訴由背景工作翻成繁體中文,譯文並列顯示、標「AI 翻譯」,紀錄表本身一律存英文。譯文能不能顯示,由一組確定性檢查決定;主訴含數字或明確次數時不翻譯(engine/complaint_translation.py、task_rules/complaint_guard.py)。

模型呼叫失敗時怎麼辦? 每次呼叫的逾時是 15 秒,失敗就推播 assistant.failed,不重試:所有 LLM 角色的 num_retries 都設為 1,也就是只嘗試一次(llm/nat_config.py)。連續失敗 3 次,心跳訊息會帶出 aiAvailable=false,畫面顯示「AI 暫停」;之後只要成功一次就恢復。手動填表任何時候都能用。

3.2 送出前後的其他 AI 功能

下面五項都用同一個 Super、關閉推理、不重試。失敗時都不會擋住任何操作,也不會算進「AI 暫停」。

功能觸發與排程模型輸出確定性檢查失敗時使用者看到什麼
建議詢問(ai/followups.py)救護端對話停 8 秒且擷取都完成;護理師端送出。P2,最多 3 題同時開著一行 JSON,最多 3 題,每題 40 字以內必須是繁中問句,不能是治療、劑量、診斷;欄位已有值、與開著或忽略過的相同的題不開(task_rules/followup_checks.py)只寫稽核,不重試;同一份證據不會再自動重跑救護端右側「建議詢問」、護理師端 AI 助理;可標「已問」或「忽略」,忽略過的不會回來。護理師端第一題會優先提醒尚未做的 TOCC
護理師輸入擷取(ai/nurse_notes.py)護理師在檢傷畫面送出一段話。P1檢傷欄位提案,最多 12 項只能落在白名單欄位,值要合法;數值必須是護理師原文裡寫出的數字(task_rules/nurse_note_checks.py)占位回覆換成失敗訊息,寫稽核AI 助理的回覆下掛提案清單,護理師勾選後「套用」才寫入,已有人填的值不會被蓋掉
急救責任醫院建議(engine/hospital_level.py)紀錄表欄位變動後等 2 秒。P2。只給救護端{level, reason, fields},約 160 token理由 80 字內,引用的欄位必須是送給模型的已填欄位(task_rules/hospital_level_checks.py)沒有建議,欄位維持空白送往醫院選單上一行「AI 建議需要重度/中度/一般」附理由,標待複查;救護員確認或改選,改了之後 AI 不再動它
醫師「AI 整理」(engine/ai_summary.py)救護端送出、檢傷送出。P2;依據沒變就不再呼叫3 到 5 句,每句附事實代號,約 300 token,實測 9 到 12 秒,逾時 60 秒最多 6 句、每句 160 字;來源必須是有內容的事實;句中數字要出現在引用的欄位;不能出現診斷、建議、劑量等用語(task_rules/summary_checks.py)顯示簡短原因,下面的規則版摘要照常;不重試D2 摘要最上方「AI 整理」,每句可點開來源;救護端或檢傷有新資料時標「更新中」

急救責任醫院建議還有一道臨床下限:到院前檢傷 1 到 2 級、危急個案、心電圖疑似 STEMI 三者任一成立時,模型建議的「一般」一律改成「中度」,稽核記下調整。這個欄位與理由是救護端的參考,不進送出快照,急診看不到。

3.3 鑑別診斷:會搜尋知識庫的智慧體

這是整個系統裡唯一的智慧體,只給醫師。

  1. 觸發。 救護端送出(院前預通知)與檢傷送出時,後端先在同一個交易裡把狀態寫成「整理中」,醫師畫面馬上看得到新的一輪,再排進背景工作。案件事實(最新送出的紀錄、檢傷評估、確認的身分與院內既往資料)算出指紋,指紋沒變就不重做;整理中又有要求,整理完再看一次(engine/differential_facts.py、ai/service.py)。
  2. 排程。 優先級是閒置:沒有任何其他 AI 工作在跑也沒有在等時才開始,任何其他工作一到就被取消(vLLM 會中止請求)、從頭重跑。等了 60 秒,或被取消 3 次,就升為 P2。這樣做是因為一次要花好幾分鐘,不能擋住現場的擷取。
  3. 智慧體迴圈。 NAT 函式 triaige_differential 讓模型看到編了號的案件事實(f1、f2…),並提供一個搜尋工具 search_knowledge(query, sources, k)。模型最多搜尋 4 次,每次可以指定來源(Tintinalli、臨床指引、臺北市手冊)與回傳段落數(1 到 8,預設 3);次數用完就收回工具,要求直接作答。每次呼叫最多輸出 8192 個 token,開啟推理(並設 low_effort,單次呼叫的輸出從 4,133 降到 1,843 個 token,見模型設定檔註解),整次逾時 600 秒(ai/nat_differential.py、llm/profiles/nemotron_3_super/__init__.py)。
  4. 輸出。 一個 JSON 物件,常見與最致命各 5 項。每項有診斷名稱、支持的發現、不符合或尚缺的資料、2 到 4 項建議檢查、依據的案件事實編號,以及引用的知識庫段落 id。
  5. 確定性檢查(task_rules/differential_checks.py):依據必須指向案件裡存在且有值的欄位,不認得的編號拿掉,一個都不剩的項目整個丟掉;引用的段落只留這次執行裡搜尋工具真的回傳過的 id,並換成「來源、章節、頁碼」的出處字串,書中原文不會進輸出;每組最多 5 項、同組診斷不重複;診斷名稱含百分比、其他文字含「機率 30%」這類說法的項目丟掉;兩組有一組完全沒有項目,整次失敗,不輸出缺一半的卡片。
  6. 失敗。 逾時、模型錯誤、檢查沒過都明確標成失敗並寫稽核,沒有重試、沒有備援模型;畫面說明原因,並標明下面若還顯示舊結果,不是最新的。伺服器重啟時,上一個行程留下的「整理中」會結算成失敗。
  7. 使用者看到什麼。 每搜尋一次,後端推播一次 differentials.updated(只推給醫師),D2 的「AI 整理過程」逐步顯示:搜尋了什麼、讀取了哪些出處。完成後呈現兩欄清單,附「不含機率或信心分數,需醫師判斷」。「移到看診區」轉場在這段時間等它:顯示讀取紀錄、查詢知識庫、閱讀段落、推理、整理五個階段與進度條,最多等 150 秒,任何時候都能按「略過」(web/src/guide/transition-wait.ts)。
  8. 多久。 開發時實測約 70 到 110 秒,正式環境一次現場驗證約 2.5 分鐘;設計上限是 600 秒。時間主要花在推理與 3 到 4 次搜尋後再推理。

3.4 送出之後的規則流程

檢傷與看診的決定仍由規則與人負責,不呼叫模型。急診看到預先填好的檢傷表,救護端沒人確認過的欄位標成「未複查」並附上來源。TTAS 引擎依規則算出建議級數,每一項理由都附上觸發的規則;需要人判斷的條件(例如「收縮壓低於 90 是否伴隨休克?」)會列出來交給護理師,引擎不替人決定。護理師送出的級數和建議不同時,必須填寫理由。醫師只看得到已完成檢傷的案件,規則版摘要與危險訊號由規則從紀錄組出;危險訊號就是最新一組救護量測裡,所有落在危急範圍的生命徵象(engine/ttas.py、engine/views.py、engine/vital_tint.py)。

4. 為什麼這樣設計?

4.1 為什麼模型不做臨床決定?

產品的定位是:凡是有公開規則可循的臨床決定,都交給確定性規則,最後由人決定(docs/product/triaige.md §3.3)。TTAS 有公開的判定標準,生命徵象的異常界線也有 TTAS、NEWS2、PALS 等公開來源,所以這些都用規則計算,結果可以逐條查到依據,也不會因為模型換版而改變。

模型擅長兩件事:把口語整理成結構化資料,這是現場最花時間的工作;以及讀大量文字後列出選項。所以模型負責欄位擷取、翻譯、把已有資料改寫成幾句摘要、建議還該問什麼,以及醫師端的鑑別診斷。這些輸出都不是決定:擷取的值待複查,摘要不能出現診斷與建議,鑑別診斷是附出處的選項、不含機率。這樣分工,模型出錯時最壞的結果是一個待複查的欄位填錯,或醫師多看到一個不合適的選項;檢傷級數不會因此算錯。

4.2 為什麼現場擷取一句只呼叫一次、不推理,鑑別診斷卻是開推理的智慧體?

兩件事的時間預算差了兩個數量級,所以做法不同。

現場擷取:求快。 救護員一句話說完,欄位要在幾秒內出現。我們比較過推理強度:關閉推理時,擷取延遲中位數 4.2 秒、F1 0.956;完整推理時 24.9 秒、F1 0.954。在這個任務上,推理沒有提高準確度(eval/README.md〈推理強度〉,舊設定的數字)。智慧體迴圈也一樣,每多一輪,就多一次要花好幾秒的呼叫。所以擷取每句只呼叫一次,系統層的智慧體行為交給模型外的確定性程式負責:追蹤案件狀態與缺漏欄位;依說話者選擇提示詞,並標記每個值的來源;AI 的新值和人填的值不同時,列成替代值而不覆蓋;出現更正時,判斷要不要回頭重評舊值(必要時送第二次呼叫);依優先級排程。

鑑別診斷:求完整。 這項工作在檢傷之後、醫師看診之前背景執行,結果是給醫師的參考,不在現場的關鍵路徑上,可以花一到三分鐘。它需要的又正好是智慧體的能力:先讀病人資料,決定要查什麼,查完讀段落,發現還有不確定的危險診斷時再查一次,最後才寫出兩份清單。一次搜尋結果無法預先決定,下一步查什麼取決於上一步讀到的內容,所以是迴圈而不是固定流程。推理則用在把病人資料與查到的段落逐項比對,這是擷取不需要的工作。

要注意的是兩者的證據不對稱:擷取有 133 筆案例的評測與保留集數字;鑑別診斷還沒有準確度數字。評分流程已經備好,但標準答案要由醫師提供,目前沒有。我們能說的是它的檢查(出處必須真實、依據必須存在、不含機率)都由程式強制,不能說它診斷得準。

4.3 為什麼 AI 的值直接寫進欄位,而不跳出確認卡?

救護員一邊處置病人一邊用平板,任何彈出視窗都會打斷工作。所以 AI 的值直接顯示在要填的欄位上,標「待複查」;救護員要做的是複查,不必在卡片彈出的當下決定接受與否。缺漏的必填欄位與 TTAS 參考級數固定顯示在畫面上的一個區域,送出時還沒複查的欄位,也只在送出列上常駐提示,不用對話框擋住。醫院分級建議、建議詢問與護理師的欄位提案也遵守同一個原則:提示放在原地,由人決定接受、修改或忽略。

為了讓這樣做是安全的,寫入規則很保守:人填的值不會被 AI 覆蓋;AI 的值一律待複查,並標出是誰說的(病人、旁人說的也一樣);刪掉的 AI 值不會再被寫回去;每個欄位都保留來源句、說話者與變更歷程。

4.4 為什麼失敗不重試,也沒有備援模型?

我們認為默默降級比明確失敗更危險。如果 JSON 壞了就重試,或改用比較弱的備援模型,畫面上的值看起來一樣,品質卻可能不同,使用者也無從得知。所以每個 LLM 角色的 num_retries 都設為 1,也就是只嘗試一次(NAT 的 LLM client 預設會對 429、5xx 自動重試共 5 次,我們特地降掉;llm/nat_config.py):失敗就推播 assistant.failed,連續失敗就顯示「AI 暫停」,手動填表照常可用。背景功能失敗時,也明確顯示失敗或空白,不補一段看起來像成功的內容。啟動時也採同樣的原則:設定了不認得的模型設定檔,或要求不能回傳 token 機率的模型計算信心,伺服器在啟動時就會停止。

4.5 為什麼安全規則寫成程式,而不寫進提示詞?

我們試過只靠提示詞擋下錯誤的「無過敏」:3 次整段口述中有 2 次,模型對一個從沒提到過敏的案例寫了「無」(eval/README.md〈R1 採用標準與重新判定〉)。錯誤的「無過敏」會關掉缺漏過敏的提醒,後果嚴重,所以這條檢查改用程式執行:來源句裡沒有提到過敏的字眼時,「無」與「未知」都會被丟掉。階段 2 的功能沿用同一個做法:摘要的數字必須出現在引用的欄位裡,鑑別診斷的依據必須是案件裡真的有值的欄位,醫院分級的理由只能引用送給模型的欄位。

一條檢查該放在哪一層?我們問的是:如果模型完美無缺,這條檢查還需要嗎?仍然需要的檢查(生命徵象範圍、過敏要有依據、翻譯檢查)放在任務層 task_rules/,只用標準函式庫,換模型也不必改;只是為了修補這個模型輸出習慣的檢查,才放在模型層 llm/(docs/architecture/README.md §7)。

4.6 為什麼要有模型適配層?

模型更新得很快,為某一個模型做的調整,不該分散在整個程式裡。現行模型的所有設定,包括提示詞、取樣參數、怎麼關閉推理、怎麼把回覆整理成 JSON、怎麼讀取 token 機率、工具呼叫的定義、逾時與同時請求數,都集中在 server/src/triaige_server/llm/ 的 ModelProfile 物件裡。server/tests/unit/test_architecture.py 強制這條邊界:llm/ 以外不能出現模型名稱、取樣參數與端點字串,下層也不能 import 上層,沒有例外清單。

Nemotron 3.5 Super VL 推出後,我們實際換過一次:只新增一個設定檔、改一個部署變數,就把它換上正式環境評估,再用同一份部署腳本(playbook)換回來,前後約 57 分鐘。評估結果比 3 Super 差,所以正式環境維持 3 Super(eval/results/nemotron-3-5-super-vl-2026-10-18/README.md)。

4.7 為什麼一個案件存成一列 JSONB,而且只有一個行程?

一個案件本身就是一份文件:紀錄表、對話、建議、稽核與檢傷都屬於同一個案件,幾乎每次讀寫都以案件為單位,拆成多張正規化的表,只會讓交易更複雜。每次寫入時,在交易內用 SELECT … FOR UPDATE 鎖住那一列,套用規則後寫回,提交之後才推播。資料庫的鎖在提交時就釋放了,為了讓推播順序與寫入順序一致,同一個案件的寫入另外在行程內排隊,所以後端只有一個行程(server/src/triaige_server/store.py)。

這是依一台 Spark、一家醫院的規模做的選擇。事件不保存、不補送;前端連上 SSE 之後再讀一次快照,所以連線建立後的事件不會遺漏。

4.8 為什麼前端要有兩套後端?

真後端要有 Spark 才能執行,但展示、設計審查與醫師評述不該依賴它。/internal 在瀏覽器內用 TypeScript 實作同一套案件規則,資料存在 IndexedDB。兩邊的規則必須一致,所以有一份共用的測試案例(server/tests/fixtures/mock_parity.json),逐筆比對後端與模擬後端的結果;生命徵象色塊、備忘、回溯更正、急救責任醫院建議等規則都包含在內。模擬後端裡的 AI 回覆是預先寫好的,不是即時模型輸出。

4.9 為什麼有些功能做好了卻沒有開啟?

每一項 AI 功能上線前,我們先寫下採用標準與保留集,保留集只跑一次,沒通過就不開啟。下面幾項是沒通過或還沒準備好的,評審問到臨床風險時可以用來說明。階段 2 新增的功能(鑑別診斷、AI 整理、建議詢問、護理師輸入擷取、醫院分級建議)在正式環境都已開啟,但它們沒有保留集數字,原因在 §4.2 與 §8。

功能狀態原因
Guardrails 自我檢查護欄已接上,關閉每次擷取要多一次模型呼叫,設計估計多 1–3 秒;安全檢查改由確定性程式負責
路由分類器(判斷一句話是不是病歷內容)關閉召回率 0.981,沒達到 0.99 的目標,而且要多一次呼叫(eval/routing/README.md)
選項欄位的信心等級分數已計算並儲存,等級不顯示校準後發現,模型幾乎對每個值都給很高的機率,包括少數錯誤的值,門檻分不出對錯(eval/results/choice-confidence-2026-10-18/summary.md)
AI 寫案件備忘人可以寫備忘,AI 寫備忘的功能關閉兩個版本都沒通過保留集:一版降低了擷取 F1 並增加延遲,另一版寫出太多不需要的備忘(eval/README.md〈M5 的結果〉、〈案件備忘 第 3 版〉)

4.10 為什麼知識庫只顯示出處,不顯示書中原文?

三類來源的授權不同,我們依各自的條件使用(詳細清單在 §10):Tintinalli 有版權,版權頁禁止未經同意重製或存入檢索系統,所以書的內容不進 repository、只放在不進版控的 private/,介面只顯示來源、章節與頁碼;開放指南只收 Creative Commons 授權的全文,同樣只在介面顯示出處;臺北市手冊的版權屬臺北市政府消防局,引用需事先書面申請,沒有公開授權,介面也只顯示章節與頁碼。

檢索層只依賴一個介面:查詢進去,回傳段落 id、出處與文字。未來醫院換成自己購買授權的知識庫,或把全文檢索換成向量檢索,只要換一個實作,智慧體、提示詞與檢查都不用動(server/src/triaige_server/kb.py、ai/kb_binding.py)。

5. 用了哪些 <帳號> 技術,用到什麼程度?

元件用途狀態
DGX Spark(GB10,128 GB 統一記憶體)醫院端唯一的主機,模型、後端與資料庫都在上面執行中
Nemotron 3 Super 120B-A12B NVFP4流程中唯一的模型:欄位擷取、主訴翻譯、追問、護理師輸入、醫院分級、AI 整理(關閉推理),以及鑑別診斷智慧體(開啟推理、工具呼叫)執行中
vLLM v0.31.0提供 OpenAI 相容 API;多 token 預測(MTP)的推測解碼一次 3 個 token、前綴快取、fp8 KV cache;開啟自動工具選擇與工具呼叫解析、推理解析,支援智慧體的 function calling執行中
NeMo Agent Toolkit 1.9.0每一次模型呼叫都是一個 NAT 函式,在 FastAPI 行程內由 WorkflowBuilder 載入;鑑別診斷是一個 NAT 串流函式,內含工具呼叫的智慧體迴圈,搜尋工具接 PostgreSQL 知識庫;最多九個 LLM 角色(含鑑別診斷)由模型設定檔組成執行中
NeMo Guardrails(透過 NAT 的 guardrails 中介層)中介層包在每個函式外面;自我檢查護欄已經寫好已接上,護欄關閉
Nemotron 3.5 Super VL換上正式環境評估比 3 Super 差,沒有採用
Nemotron 3.5 Lightning 30B-A3B評估能否當作較快的擷取模型準確度較低,也不能和 Super 放在同一台機器上,沒有採用
pgvector資料庫映像已含,kb_passages 預留向量欄位已安裝,未使用:檢索目前是全文檢索,向量檢索要先用一批案例比對再決定
NeMo Evaluator、Nemotron embedding、OpenShell評測框架、向量檢索、智慧體沙箱規劃中
NemoClaw調查後發現還在 alpha 階段,也沒有說明如何接上自行開發的智慧體沒有整合

為什麼鑑別診斷用 NAT?NAT 讓函式、LLM 設定、中介層與串流事件接在同一個框架裡:擷取、翻譯、追問用同一套載入與設定方式,鑑別診斷只是多一個會呼叫工具的函式,搜尋工具與知識庫的接法透過 kb_binding 登記,不必另外寫一套服務。

為什麼用 NVFP4?BF16 的 Super 約 240 GB,一台 Spark 放不下;NVFP4 的權重是 74.8 GiB,載入並配置 KV cache 後約佔 95 GiB,留給主機、後端與資料庫約 16 GiB(docs/product/slides-outline.md 第 10 頁、eval/README.md〈輸出格式與 vLLM 版本〉)。

單一請求的解碼速度約 31 tok/s,已經接近這台機器的上限:Spark 的記憶體頻寬約 273 GB/s,Super 每產生一個 token 要讀約 6 到 7 GB 權重,單一請求的上限約 40 tok/s。所以降低延遲的主要做法是讓模型少寫字:改成精簡的 JSON 輸出後,輸出 token 少約 40%、延遲少約 31%,F1 不變(eval/README.md〈服務參數實測〉)。鑑別診斷的推理無法用這個辦法縮短,所以改成背景執行,並在畫面上逐步顯示搜尋與閱讀的過程。

6. 前端怎麼組成?

項目選擇
框架Next.js 16(App Router)、React 19
樣式與元件Tailwind CSS 4、Base UI
資料存取TanStack Query 5;SSE 事件直接更新查詢快取
API 型別由 docs/api/openapi.yaml 產生,前後端共用同一份介面規格(42 個操作);推播事件定義在 asyncapi.yaml
模擬後端瀏覽器內的 TypeScript 規則引擎,資料存在 IndexedDB
醫師評述引導流程裡的評述存在 Neon(PostgreSQL),由 Drizzle 管理
部署GitHub Actions 跑完 bun run check 後部署到 Vercel

現場畫面有兩條規則。首先,任何操作都不阻塞畫面,AI 的結果經推播逐步出現。其次,救護與急診的現場畫面不用浮動通知,提示放在畫面中固定佔位的提示列,不會蓋住任何按鈕。

階段之間的銜接是兩個轉場。救護端送出後播「救護車」轉場,最多等 6 秒,讓急診端的交接包與檢傷評估讀回來;檢傷送出後播「移到看診區」轉場,等鑑別診斷整理,最多等 150 秒。兩個轉場都有一顆隨時可按的「略過」。轉場只是等待的畫面,不影響後端是否完成(web/src/components/flow/stage-advance.tsx、web/src/guide/transition-wait.ts)。

7. 關鍵數字速查

數字意思出處
F1 0.954/0.957整段口述擷取 12 個欄位的宏平均 F1(種子 1 的 132 段/種子 2 的 133 段)eval/README.md〈輸出格式與 vLLM 版本〉
幻覺欄位 4/1127、4/1147同上兩個種子中,模型填了口述沒說的欄位數同上
2.89 秒整段口述擷取的延遲中位數,平均輸出 71 個 token同上
F1 1.000、幻覺 0/401透過真後端逐句處理 47 段保留集口述(163 句):F1 是 11 個結構化欄位的結果,幻覺以全部預測欄位計算eval/results/r1-context-fix-2026-10-14/
1.42 秒/2.08 秒同上,每句延遲的中位數/p95同上
3.89 秒同時 3 個請求、壓力測試 30 分鐘的擷取 p95;CUDA 錯誤、重啟、逾時都是 0docs/specs/2026-10-13-ai-routing/soak-results.md
3正式環境同時送給模型的請求數(設定檔預設 2)infra/inventory/group_vars/servers.yml
4.2 秒對 24.9 秒關閉推理與完整推理的擷取延遲,F1 0.956 對 0.954(舊的完整輸出格式;現行約 2.9 秒)eval/README.md〈推理強度〉
−31% 延遲、−40% token精簡 JSON 輸出與完整格式相比,F1 不變eval/README.md〈輸出格式與 vLLM 版本〉
0.909 → 1.000帶上前文後,回溯更正的召回率(保留集 34 句中的 11 句回溯更正);沒有指名欄位的更正 3/9 → 8/9eval/results/r1-context-fix-2026-10-14/
6/15 → 0/15救護員不是病歷內容的話(問病人、問 AI、閒聊)被寫成欄位的句數(保留集);其中問句 4/5 → 0/5eval/README.md〈後續:問句不是陳述〉
2/3只靠提示詞時,對沒提到過敏的案例寫出「無過敏」的次數eval/README.md〈R1 採用標準與重新判定〉
×1.007要求回傳 token 機率的延遲成本;同樣設定重跑的對照組是 ×1.004eval/results/choice-confidence-latency-2026-10-14/README.md
17/163溫度 0 時重跑同一批句子,輸出文字不同的句數同上
31 tok/s單一請求的解碼速度;依頻寬推算的上限約 40 tok/seval/README.md〈服務參數實測〉
74.8 GiB/約 95 GiBNVFP4 權重大小/載入並配置 KV cache 後的佔用docs/product/slides-outline.md、eval/README.md
4.3 倍、F1 0.938Lightning 比 Super 快的倍數,以及它的 F1(Super 0.955)eval/README.md〈服務參數實測〉
8.7% 對 1.6%3.5 Super VL 與 3 Super 的重複填入率eval/results/nemotron-3-5-super-vl-2026-10-18/README.md
133 張評測案例卡,來自 MIMIC-IV-ED demo 中 47 位病人的救護車到院紀錄eval/README.md〈目前產出〉
3,714 段知識庫總段數:Tintinalli 1,745、開放指南 1,688(31 份)、臺北市手冊 281server/scripts/export_kb.py 的輸出
0.978/0.924臺北市手冊檢索,45 題自擬查詢的章節層級 recall@5/MRR;金標有 8 題是看過結果後依內文校正的,不是未調整的成績eval/ems_protocol/README.md
4 次、8192 token、600 秒鑑別診斷智慧體的搜尋次數上限、每次呼叫的輸出上限、整次逾時llm/prompt_sets/ems_compact/differential.py、llm/profiles/nemotron_3_super/__init__.py
70–110 秒;約 2.5 分鐘鑑別診斷開發時實測的時間;正式環境一次現場驗證的時間(單一案例,不是統計)模型設定檔與轉場常數的註解;現場驗證為團隊回報,repository 沒有紀錄檔
9–12 秒醫師「AI 整理」一次呼叫的實測延遲(逾時 60 秒)llm/profiles/nemotron_3_super/__init__.py 註解
150 秒、6 秒「移到看診區」與「救護車」轉場最多等多久web/src/guide/transition-wait.ts
42API 操作數docs/api/openapi.yaml
約 1,530/2,020/440後端、網頁、評測的測試數(以 def test_、it(、test( 計算定義數,2026-10-22 計算)server/tests/、web/src/、eval/

8. 評審問答

回答時注意三件事:不說「臨床驗證過」,只說「在模型寫的繁中口述上量過」;不把規劃中的功能說成已經完成(OpenShell、NeMo Evaluator、向量檢索、語音輸入都還沒做);只引用 repository 裡有出處的數字。鑑別診斷、AI 整理、建議詢問這幾項階段 2 的功能沒有準確度數字,被問到時直接說沒有,並說明我們用程式強制了哪些檢查。

場景與產品

問:這跟「語音轉文字之後交給 ChatGPT 填表」有什麼不同?

差別在模型外的規則。每個 AI 值都標成待複查,附上來源句與說話者(病人、旁人說的會特別標出);人填的值不會被覆蓋;沒有依據的「無過敏」會被丟掉;檢傷級數由規則建議、由護理師決定。另外,整套系統跑在醫院端的一台 DGX Spark 上,推論不使用雲端模型。

依據:§3、§4.3、docs/api/data-model.md §2。

問:AI 填錯了,誰負責?

AI 的值是草稿,標成「待複查」,救護員確認後才算數;送到急診時,沒人確認過的欄位會標成「未複查」。檢傷級數只能由護理師送出,改動建議級數時要附上理由,每一次寫入、複查與送出都有稽核紀錄。責任仍然在人身上,和現在一樣;系統讓人看得到哪些值是 AI 填的、依據的是哪一句話。

依據:docs/api/data-model.md §2、§10。

問:救護員在現場真的有空複查嗎?

我們刻意不要求救護員當下就決定。AI 的值直接出現在欄位上,不跳出視窗;救護員可以在運送途中有空時一次複查,送出列上也會常駐顯示還有哪些欄位沒複查。現場畫面不打斷使用者,是我們定下的介面原則。

依據:§4.3。

問:為什麼不直接串接醫院的 HIS/EMR?

黑客松期間沒有真實的醫院系統可以串接,健保卡查詢與院內既往資料都用虛構病人代替。API 裡已經有查詢與確認身分的操作,導入時再換成院方的介面。

依據:docs/api/README.md §1.3。

問:整個流程裡,AI 到底做了哪幾件事?

七件事,都在背景或畫面上有明確的位置:欄位擷取、主訴翻譯(救護端);追問建議(救護端與護理師);護理師打的一段話擷取成欄位提案;醫院分級建議(救護端選醫院時);醫師的「AI 整理」摘要;鑑別診斷。每一項的觸發、優先級、檢查與失敗時的畫面見 §1.2 與 §3.2、§3.3。

依據:§1.2。

智慧體

問:這算智慧體嗎?看起來只是一個擷取 API。

有兩層。現場擷取刻意做成單次呼叫,因為延遲預算以秒計,而推理並沒有提高準確度;系統層的智慧體行為包括持續追蹤案件狀態與缺漏欄位、依說話者選擇提示詞並標記來源、AI 值與人填的值不同時列成替代值、遇到更正時判斷要不要回頭重評舊值、依優先級排程即時與背景工作。

醫師端的鑑別診斷則是完整的工具呼叫智慧體:模型讀病人資料,自己決定搜尋什麼、查哪個來源,讀回傳的段落,必要時再搜尋(最多 4 次),最後輸出兩份清單。搜尋次數用完就收回工具,要求直接作答。

依據:§3.3、§4.2、ai/nat_differential.py、engine/retroactive.py、ai/scheduler.py。

問:為什麼不讓模型多推理一點?

現場擷取我們量過:完整推理時,擷取延遲中位數 24.9 秒;關閉推理時 4.2 秒,F1 是 0.954 對 0.956(舊的完整輸出格式;現行設定約 2.9 秒)。在這個任務上,開啟推理慢了約六倍,準確度沒有提高。鑑別診斷則開啟推理,因為它在背景執行、結果是給醫師的參考,花一到三分鐘可以接受,而且需要把病人資料與查到的段落逐項比對。

依據:eval/README.md〈推理強度〉、§4.2。

問:鑑別診斷準不準?

我們沒有準確度數字。評分流程(常見 Top 5 是否含最終診斷、最致命 Top 5 是否列出不可漏診斷)已經備好,但標準答案要由醫師提供,目前沒有。能說的是它受到哪些檢查:每一項的依據必須是案件裡真的有值的欄位;引用的出處必須是這次搜尋真的回傳過的段落;不含機率或信心分數;兩組清單缺一組就整次失敗,不輸出半張卡片。輸出是給醫師考慮的選項,不是診斷或醫囑。

依據:eval/README.md〈鑑別診斷評測〉、task_rules/differential_checks.py。

問:鑑別診斷會不會誤導醫師?

會有風險,所以設計上有幾道限制。清單不含機率,避免給人過度的確定感;「最致命」那一組本來就要列出可能性不高但不能漏的診斷,所以名單出現罕見診斷是設計,不是錯誤;每一項都寫明「不符合的地方或尚缺的資料」與建議檢查,並附上依據的病人資料與知識庫出處,醫師可以點回原始欄位核對;失敗時明確顯示失敗,不顯示看起來像成功的內容。最終判斷仍然是醫師的。

依據:task_rules/differential_checks.py、web/src/screens/physician/DifferentialCard.tsx。

問:智慧體搜尋的知識庫是什麼?怎麼搜?

知識庫在同一個 PostgreSQL 的 kb_passages 表,共 3,714 段,來源是 Tintinalli 急診手冊第 7 版(1,745 段)、31 份開放授權的臨床指引(1,688 段)和臺北市到院前緊急救護作業程序手冊第六版(281 段)。英文用 PostgreSQL 的英文全文檢索,中文手冊用相鄰兩字切詞的全文檢索;沒有用向量。完整的來源、版本與授權在 §10。

依據:§10、server/src/triaige_server/kb.py。

問:為什麼不用向量檢索(embedding)?

目前的檢索是全文檢索加排序,足以讓智慧體用精確的臨床詞彙查到段落,也不需要再多部署一個 embedding 模型。已知的限制是同義詞:例如臺北市手冊的內文用「呼吸困難」與藥名,不出現「氣喘」,字面比對就找不到。向量檢索排在後續,要先用一批案例比較再決定;pgvector 已經裝在資料庫映像裡,但沒有使用。

依據:eval/ems_protocol/README.md。

問:知識庫的內容有版權,怎麼處理?

書與手冊的全文只放在不進版控的 private/ 和 Spark 的資料庫裡;repository 只有轉換與檢索程式,以及指引的來源清單。介面上只顯示來源、章節與頁碼,從不顯示書中原文,這也是為什麼畫面的出處格式是「Tintinalli 7e, Ch. 章號 章名, pp. 起–迄」。Tintinalli 的版權頁禁止未經同意重製與存入檢索系統,所以這本書只用於示範,正式產品的方向是改用醫院自行購買授權的知識庫(檢索層可以抽換)。開放指引只收 Creative Commons 授權的全文。臺北市手冊的版權屬臺北市政府消防局,引用需事先書面申請;repository 裡沒有取得書面同意的紀錄。

依據:§4.10、§10、eval/README.md〈Tintinalli 檢索〉、docs/team-discussion-todo.md A16。

問:鑑別診斷要等多久?現場等得起嗎?

一個案例約 70 到 110 秒,正式環境一次現場驗證約 2.5 分鐘,上限是 600 秒。它在背景執行,不在現場的關鍵路徑上:救護端送出時就開始整理,檢傷送出後再把檢傷資料算進去。醫師看到的是逐步出現的搜尋與閱讀過程,不是空白轉圈;「移到看診區」轉場最多等 150 秒,之後放行,結果出來時會在畫面上更新。

依據:§3.3、web/src/guide/transition-wait.ts。

邊緣運算與 <帳號>

問:為什麼一定要在邊緣執行?雲端模型不是更強?

病人的個資、病史與醫院的病歷都在院內,醫院購買的臨床資料庫也多半限院內使用。模型放在資料所在的地方,資料就不必離開醫院。我們也量過,一台 Spark 跑得動 120B 等級的模型:透過真後端,每句擷取的延遲中位數是 1.42 秒。展示用的前端放在 Vercel,後端經 Cloudflare Tunnel 對外,所以展示時請求會經過 Cloudflare 的網路;模型推論本身不離開那台 Spark,展示用的病人全是虛構的。

依據:docs/product/triaige.md §3.2、本文 §7。

問:一台 Spark 能支援幾台救護車?

我們量的是同時 3 個請求、連續 30 分鐘:沒有崩潰、沒有逾時,擷取 p95 是 3.89 秒;同時 4 個請求時,p95 升到 4.70 秒。這是只跑擷取的數字。階段 2 加入背景功能之後,鑑別診斷等所有其他工作都閒著才會開始,會讓出名額給即時的句子,但我們沒有重新量過包含鑑別診斷的混合負載。能支援幾台救護車,取決於每台車說話的頻率,我們沒有實測多台救護車同時口述的情境,所以不提供這個數字。

依據:docs/specs/2026-10-13-ai-routing/soak-results.md、ai/scheduler.py。

問:為什麼選 Super,不選更快的 Lightning?

Lightning 快約 4.3 倍,但 F1 是 0.938 對 0.955;口述只講舒張壓時,它有 9 筆把舒張壓留空。它也不能和 Super 同時放在一台 Spark 上,記憶體不夠。

依據:eval/README.md〈服務參數實測〉。

問:Nemotron 3.5 Super 推出了,為什麼不換?

我們換上正式環境評估過。它快約 23%,但用事先宣告的標準來看,整段口述的三項指標都沒有通過;重複填入率是 3 Super 的 5 倍(8.7% 對 1.6%),路由分類的召回率從 0.952 降到 0.857。依照我們的規則,在保留集上不比現行模型差才切換,所以維持 3 Super。

依據:eval/results/nemotron-3-5-super-vl-2026-10-18/README.md。

問:NeMo Agent Toolkit 在這裡做了什麼?只是多包一層嗎?

每一次模型呼叫都是一個 NAT 函式,由 NAT 的 WorkflowBuilder 在 FastAPI 行程內載入,LLM 的設定由模型設定檔組成。擷取、翻譯等函式是單次呼叫;鑑別診斷是一個串流函式,內含工具呼叫的智慧體迴圈,每次搜尋就送出一個事件,後端據此更新案件並推播給醫師。Guardrails 以 NAT 中介層的形式包在每個函式外面。好處是護欄、評測與檢索都接在同一個地方,不必各接一套。

依據:server/src/triaige_server/ai/workflow.yml、ai/extractor.py、ai/nat_differential.py。

問:Guardrails 為什麼沒有開?

自我檢查護欄已經寫好、接上中介層,但每次擷取要多一次模型呼叫,設計估計多 1 到 3 秒。一直開著的安全檢查是確定性的程式:格式、範圍、過敏要有依據、翻譯檢查、摘要與鑑別診斷的出處檢查,這些不花模型的時間,也不會因為模型換版而改變。

依據:§4.9、infra/inventory/group_vars/servers.yml(triaige_self_check_output: false)。

問:NemoClaw、OpenShell 呢?

我們調查過 NemoClaw,它還在 alpha 階段,也沒有說明如何接上我們自己的智慧體,所以沒有整合。OpenShell 排在後續試裝,構想是把智慧體放進沙箱,只允許連到資料庫與 vLLM;目前智慧體只有一個搜尋工具,而且工具只能讀 kb_passages。

依據:docs/specs/2026-10-13-backend/decision.md、research-<帳號>-stack.md。

模型與評測

問:F1 0.95 是怎麼量的?資料可信嗎?

案例卡來自公開的 MIMIC-IV-ED demo,是美國急診 47 位病人的 133 次救護車到院紀錄;繁中口述稿由模型依案例卡寫成,經過程式檢查,還沒有臨床人員審閱。所以這個數字說明的是這條流程從乾淨的繁中口述擷取欄位的能力,不代表臨床驗證,也不代表在吵雜語音或台灣案例上的表現。大多數結果只跑過一次,千分之幾的差異是雜訊。這個數字只涵蓋欄位擷取,不涵蓋鑑別診斷、摘要與追問。

依據:eval/README.md〈誠實規則〉、〈目前產出〉。

問:怎麼防止模型編造口述裡沒說的內容?

有三層。提示詞要求沒提到的欄位不寫;任務層丟掉未知欄位、超出範圍的值與沒有依據的「無過敏」;寫入規則讓每個 AI 值都標成待複查並附上來源句。整段口述的幻覺欄位是 1127 個中 4 個;透過真後端逐句處理的保留集,全部 401 個預測欄位中是 0 個。摘要與鑑別診斷用另一種做法:模型只能用編號引用事實,程式把編號換回欄位,編造的編號會被丟掉;摘要裡的數字還要出現在引用的欄位裡。

依據:§3、§7、task_rules/summary_checks.py。

問:病人說的話和救護員說的話怎麼區分?

每句話都帶說話者:救護員、病人或旁人。說話者決定用哪一組提示詞,也記在每個值上,畫面會標出「家屬說的」這類來源,救護員複查時就知道這個值是誰說的。不過,不論誰說的,值都一樣先填進空欄位、標成待複查,已複查或人填的值不會被覆蓋。目前文字輸入的說話者預設是救護員,可以在對話裡修改,改了之後那句話會依新的說話者重新處理;規劃中由語音端的說話者辨識帶入,信心低於 0.6 時標成「說話者不確定」。

依據:engine/routes.py、docs/api/README.md §6。

問:救護員說錯後更正,例如「不對,是一百三」,系統怎麼處理?

擷取時,提示詞會帶上前三句與它們在紀錄表上的內容,模型因此知道要更正哪一個值。保留集 34 句裡有 11 句回溯更正,召回率從 0.909 提高到 1.000;沒有指名欄位的更正,從 9 句對 3 句提高到 9 句對 8 句。如果舊值的依據不在這次看過的句子裡,系統會送第二次呼叫重評,不會直接覆蓋。

依據:eval/results/r1-context-fix-2026-10-14/、engine/retroactive.py。

問:「他有沒有藥物過敏?」這種問句會不會被寫成資料?

以前會,這是我們在後端測試中自己發現的問題。修改提示詞之後,保留集裡被抽出欄位的過敏問句,從 5 句中 4 句降到 0 句;範圍放寬到救護員所有不是病歷內容的話(問病人、問 AI、閒聊),被寫成欄位的從 15 句中 6 句降到 0 句,並用測試固定下來。

依據:eval/README.md〈後續:問句不是陳述〉。

問:為什麼不用 vLLM 的結構化輸出(structured output),以 JSON schema 強制格式?

我們試過,結果更差。不允許 null 時,模型只要寫出一個填不出值的欄位,就只能填數字,口述沒提到的生命徵象變成 0,F1 降到 0.884;允許 null 時 F1 是 0.912,體溫大量漏填。不加 schema 時解析失敗是 0 次,沒有非用不可的理由。

依據:eval/README.md〈輸出格式與 vLLM 版本〉。

問:信心分數呢?為什麼沒有顯示?

分數已經在計算,也存了下來:沿著模型實際寫出的 token,把每個決定點的機率相乘。要求回傳 token 機率幾乎沒有成本(×1.007,對照組 ×1.004)。但校準後發現,模型幾乎對每個值都給很高的機率,包括少數錯誤的值,門檻分不出對錯,所以「高/需留意」的等級不顯示;分不出對錯的信心等級,反而會誤導使用者。鑑別診斷同樣不顯示機率。

依據:eval/results/choice-confidence-2026-10-18/summary.md、docs/specs/2026-10-14-inline-review/plan.md §4。

問:溫度設 0,為什麼同一句話的結果還會不一樣?

GPU 上的貪婪解碼並不完全確定。同一批 163 句重跑,有 17 句的輸出文字不同;壓力測試時,同一批訊息在單一請求下重送,欄位一致率也只有 97.8%。所以我們以 3 次的平均與範圍當作基準,不根據單次的小差異下結論。

依據:eval/results/choice-confidence-latency-2026-10-14/README.md、docs/specs/2026-10-13-ai-routing/soak-results.md。

問:知識庫的檢索品質量過嗎?

只量過臺北市手冊:45 題自擬查詢(口吻是 EMT 或護理師會問的問題),章節層級 recall@5 是 0.978、MRR 是 0.924。要誠實說明:題目與標準答案由工程端依手冊內文自擬,沒有臨床人員審過,而且有 8 題的標準答案是看過結果後才依內文校正的,所以這不是未調整的成績。Tintinalli 與開放指引的檢索品質,repository 裡沒有量化的評測;只有一次單一案例的實跑,確認工具呼叫正常、查詢合理、沒有編造段落 id。

依據:eval/ems_protocol/README.md、eval/README.md〈Tintinalli 檢索〉。

問:醫師「AI 整理」的摘要,會不會下診斷或編造?

提示詞要求只改寫事實清單,不下診斷、不建議。程式再檢查:每一句都要附來源,來源必須是這次給模型看的、有內容的事實;句子裡的數字必須出現在引用的欄位裡;出現「建議」「疑似」「診斷」「劑量」這類用語,除非引用的欄位本身就有,否則整句丟掉;通不過就顯示失敗原因,下面的規則版摘要照常。這一項同樣沒有保留集數字。

依據:task_rules/summary_checks.py。

問:醫院分級建議安全嗎?

它只是救護員選醫院時的參考:標「待複查」,附一句理由與依據的欄位,救護員可以直接確認,也可以改成別的分級,改了之後 AI 不再動它。規則另設下限:到院前檢傷 1 到 2 級、危急個案、心電圖疑似 STEMI,三者任一成立時不會建議「一般」,會改成「中度」。這個欄位不進送出的快照,急診看不到。

依據:engine/hospital_level.py、task_rules/hospital_level_checks.py。

安全與可靠度

問:錯誤的「無過敏」怎麼擋?

只靠提示詞擋不住,3 次整段口述中有 2 次寫出錯誤的「無」。所以現在改用程式規則:來源句沒有提到過敏的字眼時,「無過敏」與「未知」都會被丟掉;只提到非藥物過敏的句子,不會勾選「無過敏」。另外,在 24 句的過敏保留集上(只看模型輸出),錯誤的「無」是 0,但這個集合太小,不能算是驗證。

依據:§4.5、task_rules/record_checks.py。

問:模型故障了怎麼辦?

現場擷取每次呼叫的逾時是 15 秒,失敗就明確告訴使用者,不重試,也不換備援模型(每個角色只嘗試一次)。連續失敗 3 次,畫面顯示「AI 暫停」,手動填表照常可用;之後只要成功一次就恢復。背景功能失敗各有自己的畫面:鑑別診斷顯示失敗原因,AI 整理顯示簡短原因並保留規則版摘要,追問與醫院分級建議則不出現,不擋任何操作。伺服器重啟時,被中斷的鑑別診斷會結算成失敗,不會永遠停在「整理中」。

依據:§3.1、§3.3、§4.4。

問:資料安全怎麼做?

後端只聽本機,對外只有 Cloudflare Tunnel 這一個入口;模型端點沒有 API 金鑰,所以只開放給本機與 tailnet 介面。登入後拿到有期限的簽章 token(預設 12 小時);請求大小上限 256 KiB;日誌不記錄 query string。API 只接收文字,展示用的病人都是虛構的。智慧體的搜尋工具只能讀知識庫,不能寫入,也沒有其他工具。維運儀表板的公開唯讀頁會顯示日誌與模型輸入輸出的摘錄,所以示範用的輸入不要放真實病患資料。

依據:docs/specs/2026-10-13-backend/design.md〈公開上線的加固〉、infra/README.md。

問:主訴翻譯會不會翻錯?

紀錄表一律存英文,譯文只是並列顯示,標成「AI 翻譯」。一組確定性檢查會比對左右側、身體部位、數字與簡體字,沒通過就只顯示英文;含數字或明確次數的主訴不翻譯。在 69 個當時沒用來調整的新主訴上,63 個通過,左右側 18 個全部正確;這是 2026-10-13 那一版檢查的結果,之後的檢查更嚴,擋下的譯文更多。這組檢查由工程師草擬,還在等臨床人員審閱。

依據:eval/complaint_zh/README.md。

工程與部署

問:換一個模型要多久、要改哪裡?

程式只需要在 llm/ 新增一個設定檔,再加上 infra/ 裡那個模型的部署腳本。花時間的是評測:先宣告標準,再跑完保留集,比現行模型差就不換。3.5 Super VL 從換上到換回約 57 分鐘,其中冷啟動 12 分鐘。

依據:docs/architecture/README.md §9、本文 §4.6。

問:怎麼確定展示版和真後端的行為一致?

兩邊共用一份測試案例檔,後端測試逐筆比對 Python 引擎與 TypeScript 模擬後端的結果,規則不一致時測試就會失敗。模擬後端的 AI 回覆是預先寫好的,所以它展示的是畫面與規則,不是模型的即時表現。

依據:server/tests/unit/test_engine_parity.py、test_drift.py。

問:救護車上斷網怎麼辦?

斷線時畫面會顯示提示,已輸入的句子與欄位修改都留在畫面上,恢復連線後依序自動送出,伺服器以 clientMessageId 排除重複。限制是:佇列存在網頁的記憶體裡,換頁還在,關掉分頁就沒了;斷線期間也沒有 AI,因為模型在醫院端。簡報提過「存在裝置上的離線佇列」,這部分還沒做。

依據:web/src/hooks/outbox-store.ts、web/src/screens/ems/CaseBanners.tsx。

問:語音辨識呢?

不在這個 repository 裡。API 已經接受語音訊息的欄位,規劃是在平板的瀏覽器內辨識,音訊不離開平板;展示版用文字操作,評測的也是文字路徑。示範時的台詞面板(§9)用來代替語音,一次送一句。救護端目前有的是反方向的功能:透過耳機用語音念出新的提醒。

依據:docs/api/README.md §6、web/src/screens/ems/announcer.ts。

問:TTAS 建議準不準?

我們沒有量。規則集是 TTAS-adult@105-draft,涵蓋第一層的生命徵象調節變數與疼痛;依主訴而定的判定標準還沒有資料來源。評測資料裡的檢傷標記是 AI 草擬、還沒審閱的,不能當作標準答案。級數最後由護理師決定。

依據:engine/ttas.py、eval/README.md。

問:怎麼確保程式品質?

後端約有 1,530 個測試、網頁約 2,020 個、評測約 440 個,bun run check 沒通過就不能部署。架構邊界、提示詞的內容、模型設定檔的值,都由測試固定下來;改動伺服器、介面規格或提示詞時要經過獨立審查,只有 P0 到 P2 的問題會阻擋部署。

依據:server/tests/、web/src/、.github/workflows/deploy-demo.yml。

問:部署長什麼樣子?

後端、資料庫與 vLLM 在同一台 DGX Spark 上用容器執行,用 Ansible 部署,不靠手動步驟;前端在 Vercel。後端只聽本機,經 Cloudflare Tunnel 對外;每一次模型呼叫寫一行紀錄,維運儀表板顯示主機負載、vLLM 流量與呼叫紀錄。知識庫另外在部署時用 -e triaige_kb_import=true 匯入,匯入可以重複執行。

依據:infra/README.md。

9. 示範備援:代替產品負責人帶一遍

這一節假設你要在評審面前把產品從頭到尾帶一遍,所有畫面和功能都已經在 §1 到 §3 說明過。示範用真後端的根目錄 /,不用 /internal。

9.1 開場前檢查

  1. 打開首頁 /,確認角色選單正常,點「系統狀態」連結看 vLLM 與後端是否正常(頁面會顯示輸入輸出摘錄,不要在螢幕上共享給評審看日誌)。
  2. 若上一場留下案件,按頂列的「重置 demo 資料」清空。重置會清掉所有案件,包括別人的。
  3. 開三個分頁:/ems、/ed、/physician。三個路徑各自用固定的虛構使用者登入,不需要輸入帳號。
  4. 示範期間不要同時讓別人在同一台後端打字或跑別的案件:鑑別診斷只在其他 AI 工作都閒著時才開始,有人送句子就會把它中斷、重跑,等待時間會變長(§3.3)。

9.2 示範腳本

用內建的劇本「胸痛:62 歲男性」,18 句台詞加一個收尾步驟。劇本面板在救護端案件畫面,平常收合,按畫面最上層的按鈕展開;每按一次「下一步」送一句,前一句的 AI 還沒處理完時按鈕暫停。

步驟操作可以怎麼說
1救護員 → 新增案件,進入對話;展開劇本面板,選「胸痛:62 歲男性」「語音輸入我們還沒做,劇本一句一句代替救護員、病人和家屬說話,每句都標說話者。」
2送「主訴」段(病人、家屬、救護員各幾句),看右邊紀錄表「AI 邊聽邊填,填進去的值都標『待複查』,家屬說的會標『家屬說的』。人填的值 AI 永遠不會覆蓋。」
3送「生命徵象」段,包括口誤那句「不對不對,剛剛血壓講錯了……是一百零五、七十」「救護員講錯後更正,系統帶著前三句判斷要改哪個值,血壓從 125 改成 105。這是回溯更正,保留集召回率 0.909 到 1.000。」
4送「病史用藥」段(有救護員的問句與家屬的回答)「救護員問的問句不會被寫成資料;家屬說的病史、用藥才會。」
5送「過敏與處置」段:家屬說「我真的不知道」「模型沒聽到過敏就不能寫『無過敏』,這條是程式強制的,不靠提示詞。下一步的收尾會把過敏標成『不清楚』。」
6按最後一步「補齊送出必填」「語音沒有,意識、GCS、創傷與否和送往醫院這幾項用一個按鈕補齊,和手動填寫走同樣的寫入。」(它填入非創傷、意識清醒、GCS E4V5M6、過敏不清楚、送往重度急救責任醫院)
7看右側欄與送往醫院選單「TTAS 參考級數由規則算,每一條理由可查;缺漏欄位和建議詢問常駐在這裡;醫院選單上這一行是 AI 建議的急救責任醫院分級,附理由,救護員可以改。」
8按「送出至急診」「送出後播救護車轉場,急診端同時收到預通知,鑑別診斷這時就已經在背景開始跑。」
9檢傷護理師 N1:預覽交接包、開啟檢傷;N2:看預填的檢傷表、TTAS 建議、建議詢問;在 AI 助理輸入一段含數值的話,勾選提案後「套用」;用「讀取健保卡(模擬)」選林國華(62 歲男性,與劇本一致)「檢傷表是預填的,沒有救護員確認過的欄位標『未複查』。護理師打的一段話,AI 只提案、不直接寫;數值必須是護理師寫過的數字。級數由護理師決定,與建議不同要寫理由。」
10接受或調整級別後送出檢傷「檢傷級別由人送出,沒有任何一步是模型決定的。」
11「移到看診區」轉場:看五個階段與搜尋步驟,可以等,也可以按「略過」「這時智慧體在搜尋知識庫、讀段落、推理。這是系統裡唯一的智慧體,只給醫師,大約一到三分鐘。」
12醫師 D2:看「AI 整理」、規則版摘要、鑑別診斷兩欄、「AI 整理過程」,點一個來源標籤回到原始欄位「摘要每一句都附來源。鑑別診斷分常見和最致命各五項,不含機率;每一項寫了支持與不符合的地方、建議檢查,並附病人資料與知識庫出處。畫面只顯示出處,不顯示書中原文。」

這個流程裡用到的是真模型:欄位擷取每句約 1.4 秒;AI 整理約 10 秒;鑑別診斷 1 到 3 分鐘。

9.3 示範時出狀況怎麼辦

狀況為什麼怎麼做、怎麼說
畫面頂端出現「AI 暫停」連續 3 次模型呼叫失敗;成功一次就恢復說明這是設計:失敗就明確失敗,不重試、不換備援模型,手動填表照常可用。可以直接手動填一個欄位示範人工值
某句話沒有填進預期的欄位,或填的值不同溫度 0 的輸出也不完全確定(17/163 句文字不同);檢查也可能丟掉不合格的值說明 AI 的值只是待複查的草稿,手動改就好,這正是「人填優先」要處理的情況;不要重送同一句
鑑別診斷等了很久,轉場放行時結果還沒出來轉場最多等 150 秒;背景工作被其他請求中斷會重跑說明結果出來會直接更新 D2,「AI 整理過程」可以看到目前搜尋到哪;先講 AI 整理和規則版摘要,再回頭看清單
鑑別診斷顯示「整理失敗」逾時、模型錯誤或檢查沒通過;設計上不重試唸出畫面上的失敗原因,說明這是刻意的:不補一份看起來成功的內容。AI 整理與規則版摘要不受影響。接著改用 /internal 的模擬案例(預先寫好的鑑別診斷)示範畫面,並說清楚那是模擬
「AI 整理」沒有出現還沒整理好(約 10 秒),或失敗失敗時畫面寫明原因,下面的規則版摘要照常;說明兩者的差別:規則版由程式組出,AI 整理只改寫已有資料
醫院分級建議沒有出現它只是參考,失敗時不顯示,也沒有重試直接略過,不影響送出
轉場卡在「救護車」急診端讀交接包與檢傷評估讀不到;最多 6 秒按「略過」,檢傷台會自己顯示錯誤與重試
整個後端連不上Spark、Tunnel 或網路中斷;畫面顯示連線中斷橫幅改用 /internal:同一組畫面連瀏覽器內的模擬後端,AI 回覆是預先寫好的,要明說這一點;已輸入的句子留在畫面上,恢復後自動送出
評審要看語音輸入語音辨識還沒做直說:API 有語音訊息的欄位,規劃在平板瀏覽器內辨識;今天的展示用文字劇本代替
評審問鑑別診斷的準確度沒有準確度數字直說沒有;評分流程備好、等醫師提供標準答案;說明我們強制的檢查(§8)
評審問資料、版權見 §4.10、§10畫面只顯示出處;Tintinalli 僅供示範;臺北市手冊的書面同意沒有紀錄

9.4 這個產品不做、也不要說成做了的事

10. 附錄:鑑別診斷用的知識庫來源

鑑別診斷的智慧體只搜尋 PostgreSQL 的 kb_passages 表,共 3,714 段,分三個來源(server/scripts/export_kb.py 的輸出):

來源代號完整名稱版本與出版者段數語言授權依據
tintinalliTintinalli's Emergency Medicine Manual(急診醫學手冊)第 7 版,McGraw-Hill,20121,745英文有版權,只供示範
guidelines31 份開放授權的臨床指引與共識(清單見 §10.2)2013 至 2026 年各期刊,取自 PubMed Central(PMC)1,688英文每份是 Creative Commons 授權
ems_protocol《臺北市政府緊急救護技術員到院前緊急救護作業程序手冊》第六版,115 年 4 月,臺北市政府消防局,140 頁281繁體中文版權屬臺北市政府消防局,引用需書面申請

三個來源共用的做法:全文只放在不進版控的 private/ 與 Spark 的資料庫,repository 只放轉換與檢索程式、指引的來源清單;智慧體讀到的是段落全文,醫師與評審在介面上只看到出處字串,從不顯示書中原文;模型被要求不得引用原文(llm/prompt_sets/ems_compact/differential.py),確定性檢查也只讓真的被搜尋工具回傳過的段落 id 進輸出,並換成出處。

10.1 Tintinalli 急診醫學手冊

10.2 開放授權臨床指引(31 份)

下表是 31 份文章的完整清單(資料來源:建置完成的索引,標題為期刊原題):

簡稱PMCID標題期刊(年)授權段數
ANMCO-SIMEU Chest Pain 2016PMC5520764ANMCO-SIMEU Consensus Document: in-hospital management of patients presenting with chest painEuropean Heart Journal Supplements(2017)CC BY-NC 4.043
Acute Vertigo ED Consensus 2024PMC11364714Consensus paper on the management of acute isolated vertigo in the emergency departmentInternal and Emergency Medicine(2024)CC BY 4.056
Asia-Pacific NVUGIB 2018PMC6145289Asia-Pacific working group consensus on non-variceal upper gastrointestinal bleeding: an update 2018Gut(2018)CC BY-NC 4.030
BSG Ascites 2021PMC7788190Guidelines on the management of ascites in cirrhosisGut(2021)CC BY-NC 4.070
BTS Outpatient PE 2018PMC6018844British Thoracic Society Guideline for the initial outpatient management of pulmonary embolismBMJ Open Respiratory Research(2018)CC BY-NC 4.040
BTS Oxygen 2017PMC5531304British Thoracic Society Guideline for oxygen use in adults in healthcare and emergency settingsBMJ Open Respiratory Research(2017)CC BY-NC 4.050
Brazilian Chest Pain ED 2025PMC12981354Diretriz Brasileira de Atendimento à Dor Torácica na Unidade de Emergência – 2025Arquivos Brasileiros de Cardiologia(2025)CC BY 4.0155
ED Delirium GRADE 2026PMC12875304GRADE‐Based Clinical Practice Guidelines for Emergency Department Delirium Risk Stratification, Screening, and Brain Imaging in Older Patients With Suspected DeliriumAcademic Emergency Medicine(2025)CC BY 4.045
ED Hyperkalemia Consensus 2021PMC8485984Hyperkalemia management in the emergency department: An expert panel consensusJournal of the American College of Emergency Physicians Open(2021)CC BY-NC-ND 4.022
ESE-ES Adrenal Insufficiency 2024PMC11180513European Society of Endocrinology and Endocrine Society Joint Clinical Guideline: Diagnosis and Therapy of Glucocorticoid-induced Adrenal InsufficiencyThe Journal of Clinical Endocrinology and Metabolism(2024)CC BY-NC 4.061
ESGE NVUGIH Cascade 2018PMC6175685Nonvariceal upper gastrointestinal hemorrhage: European Society of Gastrointestinal Endoscopy (ESGE) Cascade GuidelineEndoscopy International Open(2018)CC BY-NC-ND 4.016
ESGE Variceal Cascade 2020PMC7329372Endoscopic treatment of variceal upper gastrointestinal bleeding: European Society of Gastrointestinal Endoscopy (ESGE) Cascade GuidelineEndoscopy International Open(2020)CC BY-NC-ND 4.016
EUSEM Syncope 2024PMC11198953The syncope core management process in the emergency department: a consensus statement of the EUSEM syncope groupEuropean Journal of Emergency Medicine(2024)CC BY-NC-ND 4.018
European Trauma Bleeding Guideline 2023PMC9977110The European guideline on management of major bleeding and coagulopathy following trauma: sixth editionCritical Care(2023)CC BY 4.0111
GOLD 2023PMC10066569Global Initiative for Chronic Obstructive Lung Disease 2023 Report: GOLD Executive SummaryThe European Respiratory Journal(2023)CC BY-NC 4.068
Hyperglycaemic Crises Consensus 2024PMC11343900Hyperglycaemic crises in adults with diabetes: a consensus reportDiabetologia(2024)CC BY 4.044
J-SSCG 2020PMC8384927The Japanese Clinical Practice Guidelines for Management of Sepsis and Septic Shock 2020 (J-SSCG 2020)Journal of Intensive Care(2021)CC BY 4.0246
JBDS HHS 2023PMC10107355Management of Hyperosmolar Hyperglycaemic State (HHS) in Adults: An updated guideline from the Joint British Diabetes Societies (JBDS) for Inpatient Care GroupDiabetic Medicine(2022)CC BY-NC 4.032
KSHF Acute HF 2023PMC10406529Korean Society of Heart Failure Guidelines for the Management of Heart Failure: Advanced and Acute Heart FailureKorean Circulation Journal(2023)CC BY-NC 4.034
PERT Consortium PE 2019PMC6714903Diagnosis, Treatment and Follow Up of Acute Pulmonary Embolism: Consensus Practice from the PERT ConsortiumClinical and Applied Thrombosis/Hemostasis(2019)CC BY-NC 4.026
SEOM Febrile Neutropenia 2018PMC6339667SEOM clinical practice guideline: management and prevention of febrile neutropenia in adults with solid tumors (2018)Clinical & Translational Oncology(2018)CC BY 4.032
SIRM-SIC Acute Chest Pain 2025PMC12669346SIRM/SIC consensus document on the management of patients with acute chest painLa Radiologia Medica(2025)CC BY 4.022
Scandinavian Head Injury 2013PMC3621842Scandinavian guidelines for initial management of minimal, mild and moderate head injuries in adults: an evidence and consensus-based updateBMC Medicine(2013)CC BY 2.034
TSANZ Oxygen 2015PMC4654337Thoracic Society of Australia and New Zealand oxygen guidelines for acute oxygen use in adults: ‘Swimming between the flags’Respirology(2015)CC BY-NC 3.025
WSES AMI 2022PMC9580452Acute mesenteric ischemia: updated guidelines of the World Society of Emergency SurgeryWorld Journal of Emergency Surgery(2022)CC BY 4.030
WSES Cholecystitis 2016PMC49087022016 WSES guidelines on acute calculous cholecystitisWorld Journal of Emergency Surgery(2016)CC BY 4.053
WSES Elderly Trauma 2023PMC11140935The 2023 WSES guidelines on the management of trauma in elderly and frail patientsWorld Journal of Emergency Surgery(2024)CC BY 4.0111
WSES Pancreatitis 2019PMC65674622019 WSES guidelines for the management of severe acute pancreatitisWorld Journal of Emergency Surgery(2019)CC BY 4.073
WSES Peptic Ulcer 2020PMC6947898Perforated and bleeding peptic ulcer: WSES guidelinesWorld Journal of Emergency Surgery(2020)CC BY 4.050
WSES-AAST Thoracic Trauma 2025PMC12522690Thoracic trauma WSES-AAST guidelinesWorld Journal of Emergency Surgery(2025)CC BY-NC-ND 4.046
WSES-SICG Elderly Cholecystitis 2017PMC63999452017 WSES and SICG guidelines on acute calcolous cholecystitis in elderly populationWorld Journal of Emergency Surgery(2019)CC BY 4.029

10.3 臺北市到院前緊急救護作業程序手冊

10.4 知識庫怎麼建、怎麼上線

  1. 在開發機用 eval 的三支腳本各自建索引(tintinalli_rag.py build、guidelines_rag.py build、ems_protocol_rag.py build)。
  2. server/scripts/export_kb.py 把三份索引合成 private/kb/kb_passages.jsonl,每行一段 {id, source, lang, title, citation, body},三個來源的段落 id 不重複。
  3. 部署時加 -e triaige_kb_import=true:playbook 把檔案複製到 Spark 的 /srv/triaige/kb/(只有後端使用者讀得到),在容器內執行 python -m triaige_server.kb_import。匯入在單一交易內,檔案裡出現的來源先整批刪除再寫入,所以重複執行不會留下舊段落;英文的 tsv 由資料庫產生,中文的 tsv_zh 在匯入時計算。
  4. 沒加這個參數時,部署不碰知識庫。知識庫是空的時候,智慧體照樣回答,但沒有任何引用。

11. 想深入了解時,去哪裡找?

想知道看這裡
程式分層、每個關注點在哪個檔案、換模型的步驟〈架構說明〉(docs/architecture/README.md)
給評審的正式說明與全部評測結果〈評審報告〉(docs/judges/README.zh-TW.md)
每一項評測的採用標準與原始數字eval/README.md
鑑別診斷的智慧體與搜尋工具server/src/triaige_server/ai/nat_differential.py、llm/prompt_sets/ems_compact/differential.py
知識庫的檢索與匯入server/src/triaige_server/kb.py、kb_import.py、infra/README.md〈知識庫〉
各項背景 AI 功能的規則engine/ai_summary.py、engine/hospital_level.py、ai/followups.py、ai/nurse_notes.py
欄位複查與信心的設計docs/specs/2026-10-14-inline-review/plan.md
API 介面規格與資料規則docs/api/README.md、openapi.yaml、data-model.md
部署與維運儀表板infra/README.md