標籤: 臺灣

  • 當 AI 夠重要,價值與風險就是一體兩面:談 AI 治理與 ROI

    重點摘要

    • AI 的 ROI「難算又好算」:別只看表面省工,要看頻率質變——一個分析從「一年做一次」變成「一月一次」,價值是跳級的。
    • ROI 要對到競爭本質與戰略目標,不是中階的過程 KPI。
    • 當 AI 夠重要,它的價值與風險就是一體兩面,這不是缺陷,是事實。
    • 治理心法:讓法遵、風險、業務所有人在同一個平台看同樣的問題與機會,達成共識才放行。
    • 底線是主權 AI:公司的資料不能丟到公開 AI 去訓練。

    這是 SAP NOW AI Tour 系列的最後一篇。前面談了方法論、技術、案例,這篇談一個比技術更難、卻真正決定成敗的東西——AI 治理與 ROI。這天聽下來,最深刻的幾段都不是在講模型多強,而是在講「怎麼算它的價值」和「怎麼管它的風險」。

    一、ROI 難算又好算:關鍵在「頻率質變」

    一位銀行高管分享的 ROI 觀點,我覺得每個要替 AI 專案爭預算的人都該聽。他說 AI 的 ROI「難算,但也好算」。

    難算,是因為一個企業要用 AI 做什麼,沒辦法被量化反推;好算,是因為當 AI 對到「三到五年後的巨大競爭優勢」時,那些成本相對就不是重點。他舉了一個企業信用分析的例子,非常經典:

    一開始算 ROI,是「原本一個人要做 36 小時,AI 降到 3 小時」。聽起來省了工,但因為做的人不多,效益看起來普通。後來他們發現算錯了重點——因為過去要花 36 小時,這個分析一年只能做一次;但 AI 只要 3 小時,就能改成一季一次、甚至一個月一次。頻率一變,質就變了:能提早發現客戶信用變好(多給額度)、或提早發現問題(不用等到明年,中間就預警)。他說:「這對銀行是很大的突破,效益沒辦法估量,因為太大了。」

    這就是頻率質變:真正大的效益,往往不在「同一件事做得更快」,而在「快到可以改變做這件事的頻率」。表面的工時 ROI,會嚴重低估它。

    二、ROI 要對到戰略本質,不是中階 KPI

    承上,他的結論是:AI 專案的 ROI,應該對到「你原本要創造的競爭優勢是什麼」,而不是中階的過程指標。製造業的講者也呼應這點——挑 AI 專案的優先順序,是「越能直接反映客戶需求的越優先」(良率、產出、交期),而不是從內部好做的地方開始。

    另一個容易被低估的效益是潛在損失的避免。一家電子大廠提到,AI 最大的價值往往不是看得到的降本,而是「在第一關就攔截一個品質議題,避免整批損失」——這種效益很難寫進試算表,卻可能是最大的。還有橫向複製:一個廠導入成功,就能複製到二十個廠,效益會放大到難以估算。

    三、價值與風險,是一體兩面

    講到治理,那位銀行高管用了兩個會場引用的軍事 AI 案例,把問題講得很透。同一套 AI 影像辨識系統:

    • 故事一:在任務中辨識出前方的威脅,救了一條人命。
    • 故事二:把一個人手上拿的東西誤判成危險物,造成了無法挽回的誤傷。

    同一個系統,兩個極端。只看故事二,你會想「隔天就把系統關掉」;只看故事一,你會繼續用。他的洞察是:當你的 AI 夠重要,它一定同時帶著高價值與高風險——這是一體兩面,不是哪邊做得不夠好。

    四、治理心法:所有人在同一個平台達共識

    既然價值與風險綁在一起,怎麼管?他的答案很簡單,也很難:讓所有人在同一個平台上。

    以他們銀行為例,法遵、風險、業務人員,都在同樣的平台、看同樣的 AI、同樣的問題與機會。沒有共識,就沒辦法離開那個辦公室——因為一定有人覺得「該關掉」,有人覺得「不能關(關掉會出事)」,必須當場喬到共識。這比任何一份治理文件都實在:把對的人放在同一個畫面前,逼出共識。這也呼應全場另一個反覆出現的觀點——AI 治理的重點,是讓 AI「行為有序」地在企業內運行,而不是放任它亂竄。

    五、底線:主權 AI

    如果說全場有一條最強的暗線,那就是主權 AI(Sovereign AI)——這個詞在不同講者口中至少出現了三次。顧問業引用的調查顯示,超過七成的企業領導者認為「AI 在哪裡開發/運算」是選技術的關鍵考量;製造業強調總部集中算力、守住數位主權;而傳產的設備主管講得最白:

    每個公司都有自己的機密,你不會希望把自己的資料丟到公開的 AI 上去訓練。所以你需要的是主權 AI。

    對製造業、金融業這種高度重視資料的產業,這會是董事會問的第一個問題。所以在選型時,「資料留在哪、誰能存取、會不會被拿去訓練」往往比「模型多聰明」更早被決定。

    結語:難的不是技術,是人與治理

    四篇寫到這裡,剛好繞回系列第一篇的結論:數位轉型 80% 卡在組織與人,不是技術。AI 治理也是同一回事——真正難的,不是把模型接起來,而是怎麼算清楚它的價值、管得住它的風險、讓所有人對它有共識。

    把整個系列濃縮成一句話:AI 降低了工具的門檻,卻抬高了「懂業務、會判斷、守得住治理」的人的價值。工具會越來越好用,但會用工具的人和組織,才是差距所在。

    常見問題 FAQ

    怎麼評估 AI 專案的 ROI 才不會低估?

    別只看「同一件事做得更快」省了多少工時,要看「頻率質變」——當一個分析從一年一次變成一月一次,能提早發現機會與風險,價值是跳級的。ROI 應對到競爭本質,而非中階過程 KPI。

    AI 的價值和風險可以分開管嗎?

    很難。當 AI 夠重要,價值與風險是一體兩面。務實的治理是讓法遵、風險、業務在同一個平台看同樣的問題與機會,達成共識才放行。

    什麼是主權 AI(Sovereign AI)?

    指企業掌握「AI 在哪裡開發、運算,資料由誰存取、會不會被拿去訓練」的主導權。對重視資料的產業,公司機密不丟公開 AI 訓練是底線。

    導入企業 AI,最該先想清楚什麼?

    不是先選模型,而是先想清楚資料主權與治理(資料留在哪、誰能存取),以及這個 AI 要對到的競爭本質。技術反而是相對後面的問題。

    📚 本系列:SAP NOW AI Tour 的 4 堂課

  • 傳產與金融怎麼把 AI 落地?三個真實場景

    重點摘要

    • 鋼鐵廠:讓機器狗進約 1,200°C 的高爐巡檢,並用「設備健康指標像人的健康指標」的概念,做動態預知維護。
    • 銀行:把客戶經理變成 AI Agent,靠「下游的下游有訂單」的線索,搶在同業之前打那通電話。
    • 電子代工:信奉「工廠不是實驗場」,所有試錯與優化先在數位孿生裡跑完,再上實體。
    • 三個產業差很遠,但共通點一致:AI 不是取代人,而是把人從危險、重複、來不及反應的地方解放出來。

    這是 SAP NOW AI Tour 系列的第三篇。前兩篇談方法論與技術骨架,這篇講最好看的部分——真實案例。我挑了三個差異很大的產業(鋼鐵、銀行、電子代工),看他們各自怎麼把 AI 落到地上。為尊重分享者,以下用產業代稱、只引用公開分享的內容。

    一、鋼鐵廠:讓機器狗進 1,200 度的高爐

    鋼鐵是典型的「3K 場域」——危險、骯髒、辛苦,再加上傳產普遍的缺工壓力。這家鋼鐵龍頭的設備部門,把 AI 用在兩個地方,我覺得都很有啟發。

    無人化:機器狗、無人機、無人天車

    高爐的高點,溫度約 1,200°C,爐板一旦出問題可能導致熱點甚至爆炸——這種地方不適合人進去。他們的解法是把巡檢路徑寫成程式,讓機器狗去走、去看,背後的資料庫做預知分析。有人問「機器狗為什麼要練爬樓梯?」講者的回答很妙:人也不是天生會走路,是學會之後才會;機器人往前走要耗大量運算在做平衡,如果目的是去收集數據,那就讓它走遍各種路去練。同樣的思路也用在無人天車上——AI 控制吊掛鋼捲時,左右自動防擺,比人操作還穩。

    設備健康指標,就像人的健康指標

    這是我整天聽到最好的一個比喻。買設備時,廠商會告訴你「多久保養一次」,那是固定規範。但設備用久了會慢慢變化,固定規範不一定適用。講者拿人來類比:

    小孩子量身高、體重、頭圍最重要;到了中老年,身高體重沒太大意義,要量三高。設備也一樣——剛買的設備和用了十年的設備,同一個指標代表的意義完全不同,不能用同一套標準看。

    所以他們用 AI(深度學習模型 + 領域專家的特徵工程)把老師傅的經驗變成「智慧健康指標」,在設備出問題前就抓到初期徵兆。核心一句話:用「數據驅動」取代「直覺或規範」。

    二、銀行:把客戶經理變成 AI Agent

    一家大型銀行的企業金融部門問了自己一個尖銳的問題:我們的服務方式會不會被取代?他們的答案是「會」,所以乾脆自己先動手。

    最精彩的是一個「搶先機」的案例。某個企業客戶可能接到一筆訂單——這種公開資訊大家都看得到。但這家銀行的客戶經理,會在早上收到系統提示:「你可能要去拜訪某客戶。」怎麼知道的?因為系統掌握到這個客戶「下游的下游」可能有訂單,照這個模式推斷它有機會接單,再比對它最近的新聞表現。因為它會接單,就可能有備料與資金需求——於是客戶經理提前打了那通電話。結果是:客戶的財務長第一個接到的,是這家銀行打來的。

    更進一步,他們的想像是把客戶經理本身變成一個常駐客戶端的 AI Agent。一個真人沒辦法一天到晚守在客戶那裡待命,但 AI 可以。背後的技術,就是用前一篇談過的協定,把銀行服務嵌進客戶的 ERP 流程裡。這呼應了一個全場反覆出現的觀點:AI 不是要取代你,而是讓你把「人做不到的覆蓋率」補起來。

    三、電子代工:工廠不是實驗場

    一家全球佈廠的電子代工大廠,分享了他們十多年的 AI 進化。最打動我的,是一句很樸素的話:「工廠是每天在生產運行的地方,並不是給你做實驗的地方。」

    所以他們的核心策略是數位孿生:所有的生產設計、AI Agent 的驗證、流程的優化,都先在虛擬世界裡跑完,再上實體。一個模擬若用實體去做實驗可能要兩個月,在數位孿生裡快很多;而且實體還沒蓋,就能先把問題找出來、把良率拉上去。他們也坦白分享了 Agent 的導入節奏:今年初做了第一個 Agent,到年中大概第八個——剛開始導入比較辛苦,但越往後越快,因為 know-how 會累積。這跟前面銀行、鋼鐵的經驗一致:先做最關鍵的那一個,驗證了再放心擴展。

    結語:三個產業,同一個底層邏輯

    把這三個案例疊在一起,會發現它們其實在講同一件事:

    • 方向一致:都是把人從危險(高爐)、重複(守客戶)、來不及反應(品質與訂單)的地方解放出來。
    • 節奏一致:都先做一個最關鍵的 MVP,驗證了再擴展,沒有人一次性全導入。
    • 對人的定位一致:AI 接手「人做不到或不該做」的部分,人回到判斷與經驗的價值上。

    下一篇是系列最後一篇,談一個比技術更難、卻決定成敗的東西——AI 治理與 ROI:當 AI 夠重要,它的價值與風險就是一體兩面,你該怎麼算、怎麼管?

    常見問題 FAQ

    AI 怎麼用在設備維護上?

    用深度學習模型加上領域專家的特徵工程,把老師傅的經驗變成「智慧健康指標」,在設備出問題前抓到初期徵兆,做動態的預知維護,而不是照固定的保養規範。

    為什麼說「工廠不是實驗場」?

    因為工廠每天都在生產,不能拿來反覆試錯。改用數位孿生,把生產設計、AI 驗證、流程優化先在虛擬世界跑完再上實體,可大幅降低風險與時間。

    AI 會取代客戶經理或第一線人員嗎?

    案例顯示的方向是「補覆蓋率」而非取代:AI Agent 常駐客戶端、處理人力做不到的即時與規模,人則回到判斷、經驗與關係經營的價值上。

    導入 AI Agent 一開始就會很有效率嗎?

    不會。實務經驗是「先苦後快」——第一個最辛苦,隨著 know-how 累積,後面越做越快、效益越來越可觀。建議先做一個最關鍵的 MVP。

    📚 本系列:SAP NOW AI Tour 的 4 堂課

  • AI Agent 怎麼接進企業系統?看懂 MCP 與 A2A 兩個關鍵協定

    重點摘要

    • AI 應用正從「單一模型/聊天機器人」走向 Agentic AI(自主規劃、推理、跨系統行動)
    • Agentic AI 有兩個關鍵挑戰:Agent 怎麼連接工具?怎麼跟其他 Agent 合作?由此誕生兩個開放協定。
    • MCP(Model Context Protocol)= 垂直整合:讓單一 Agent 往下接工具與資料源。
    • A2A(Agent-to-Agent)= 水平協作:讓多個 Agent 之間互相委派任務。
    • 資料層上,趨勢是「串接而非搬遷」——地端資料可以留在原地,用連接器接上雲端分析。

    這是 SAP NOW AI Tour 系列的第二篇。第一篇談方法論(為什麼轉型會失敗),這篇換上工程師的眼睛,談技術骨架:當大家都在喊 Agentic AI,到底 AI Agent 是怎麼接進一家企業既有的系統?這一整天聽下來,金融、製造、雲端三方不約而同指向同兩個字母組合——MCP 與 A2A

    一、先看演進:從 Traditional AI 到 Agentic AI

    AI 在企業裡的應用方式,大致經過三個階段:

    1. Traditional AI:單一模型、單一任務(聊天機器人、文件摘要)。
    2. AI chatBot:AI 嵌入應用,輔助人員完成工作。
    3. Agentic AI:AI 自主規劃、推理、行動,並跨系統協作

    到了第三階段,問題就來了:一個 Agent 要做事,得能呼叫工具、讀寫資料;而真實的企業流程往往要好幾個 Agent 接力。於是兩個關鍵挑戰浮現——Agent 如何連接工具?如何與其他 Agent 合作?

    二、兩個開放協定:MCP 與 A2A

    這兩個挑戰,分別由兩個開放協定來解。它們不是競爭關係,而是互補——一個管「垂直」,一個管「水平」。

    維度 MCP(Model Context Protocol) A2A(Agent-to-Agent)
    連接對象 Agent ↔ 工具/資料源 Agent ↔ Agent(雙向協作)
    整合方向 垂直整合(取用工具) 水平協作(分工委派)
    典型用法 Agent 透過 MCP 存取 ERP 資料庫 / API 一個 Agent 透過 A2A 把任務委派給另一個 Agent

    一句話記憶:MCP 讓 Agent 往下接系統,A2A 讓 Agent 之間互相傳接棒。

    三、實際跨系統流程長怎樣

    會場舉了一個很好懂的端到端流程,看完就知道兩個協定是交替使用的:

    • 採購 AgentMCP 查庫存
    • 物流 AgentA2A 被委派去安排出貨
    • 財務 AgentMCP 更新帳務
    • → 完成一條自動化流程

    每個 Agent 用 MCP 往下接自己負責的系統,再用 A2A 把棒子交給下一個 Agent。這就是 Agentic AI「跨系統協作」的具體長相。

    四、資料層:串接,而不是搬遷

    講到 Agent 接資料,現場有個觀眾問了一個很實際的問題:「用 AI 是不是一定要把所有資料都搬上雲?」畢竟資安、上雲成本、地端的第三方系統,都是真實顧慮。

    答案是「不用」。現在的資料雲走的是「串接」而不是「搬遷」——透過連接器(Data Provisioning Agent 這類機制)直接接上地端資料,資料可以留在原地,上層再用 AI 做分析與呈現。對於有資安顧慮、又想用 AI 的企業,這條路很關鍵。一個實際的搭法是:既有系統(ERP/設備系統)→ 連接器 → 雲端的資料模型層(如 Datasphere)+ 報表層(如 SAP Analytics Cloud),最前面再接一層自然語言(Joule),就能「用一句話問、自動跑出分析圖表」。

    五、官方參考架構:把內外 Agent 安全地串起來

    最後一張技術總圖,把上面這些拼成了一個完整的互通架構(這是雲端與 ERP 兩大廠的聯合參考架構):

    • 企業內部的 Agent(Orchestrator + 各種 Custom/Low-Code/Pro-Code Agent)透過 A2A 跟外部雲端的 Agent 協作;
    • 透過 MCP 接到 ERP、資料雲等既有系統;
    • 身份與信任由統一的 Identity Service 治理(authenticate / trust)。

    值得一提的是,雲端廠在大會上一口氣發布了多項與 ERP 深化整合的東西,包括官方的 MCP Server(讓 AI Agent 透過整合套件安全存取 ERP 商業數據)、支援 ABAP 開發者的 AI IDE,以及基於雲端模型平台的 Agentic AI 方案。換句話說,MCP 已經不是概念,而是有官方實作可以開始試的東西。

    結語:協定先行,骨架才穩

    如果你也在規劃企業內的 AI Agent,這篇的重點只有一個:先把「Agent 怎麼接系統、怎麼互相協作」這層協定想清楚,再談上面要跑什麼應用。MCP 負責垂直、A2A 負責水平,資料層走串接不搬遷,身份治理統一——這就是下一代企業 AI 自動化的骨架。下一篇換個角度,看真實的傳產與金融公司,是怎麼把這套東西落到地上的。

    常見問題 FAQ

    MCP 和 A2A 有什麼差別?

    MCP 是讓單一 Agent 垂直連接工具與資料源(例如存取 ERP 資料庫);A2A 是讓多個 Agent 之間水平協作、互相委派任務。實際流程裡兩者交替使用。

    用 AI Agent 一定要把資料搬上雲嗎?

    不一定。可以用連接器「串接」地端資料,讓資料留在原地,再由雲端的分析層處理,兼顧資安與成本。

    什麼是 Agentic AI?

    相對於單一任務的傳統 AI 與輔助型的 chatBot,Agentic AI 能自主規劃、推理、行動,並跨多個系統協作完成任務。

    MCP 現在可以實際使用了嗎?

    可以。雲端與 ERP 大廠已推出官方的 MCP Server,讓 AI Agent 透過整合套件安全存取 ERP 商業數據,並有支援開發者的相關工具。

    📚 本系列:SAP NOW AI Tour 的 4 堂課

  • 數位轉型不是換系統:企業 AI 落地為什麼失敗,又該怎麼做對

    重點摘要

    • 麥肯錫研究指出:數位轉型失敗的主因 80% 在「組織與人」,而不是技術
    • AI 世代的轉型有四大關鍵核心:人員、流程、應用、數據,四者要同步處理,不能只做一個。
    • 轉型有不能跳過的順序:合理化 → 標準化 → 自動化。跳過前段直接自動化,等於把錯的流程加速。
    • 很多企業的「戰情室/儀表板」做完沒人用,是因為它只看落後指標;當員工覺得「自己下載資料用 Excel 更快」,系統就開始死亡。
    • 一句話:數位轉型只是手段,真正的目的是創造價值。

    我參加了一整天的企業 AI 大會,聽了金融、半導體、電子製造、鋼鐵、顧問與雲端平台共六、七家公司分享他們怎麼把 AI 落地。把這些不同產業的經驗放在一起聽,最有趣的發現是:他們講的「成功關鍵」高度一致,而且那個關鍵幾乎都不是技術。這篇是系列第一篇,先談方法論——企業 AI 為什麼會失敗,又該怎麼做對。

    一、先承認:80% 的轉型卡在「人與流程」,不是技術

    會場引用了一份麥肯錫研究:數位轉型失敗的主因在於「組織與人」,而非技術本身。成敗大約 80% 取決於「組織與人」的改變與「方法」的正確性,而「資料」與「內容」是實現價值的核心基石。

    把它拆開來看,組織面的挑戰是:缺乏清晰的轉型願景、組織結構僵化、跨部門協作困難、決策流程緩慢、資源分散。人員面的挑戰是:員工抗拒改變、數位技能不足、人才流失、缺乏主人翁意識、溝通不足導致信任缺失。這些沒有一條是「買哪個 AI 工具」能解的。

    現場有位經營者講得更直接:很多人怕因為跟不上而被淘汰,所以拒絕改變;而真正成功的企業,是想辦法讓「最懂業務的資深人員」被 AI 賦能,而不是被取代。AI 降低了工具門檻,卻抬高了「懂業務、會問對問題」的價值。

    二、四大關鍵核心:人員、流程、應用、數據

    在 AI 世代,數位轉型規劃有四個關鍵核心,每一個都帶著自己的痛點。整理成一張表最清楚:

    核心 三大痛點
    人員 技能隔閡、變革阻力、組織知識流失
    流程 過時流程、跨系統依賴、合規問題
    應用 過度客製、技術債、整合挑戰
    數據 數據孤島、數據品質問題、數據安全與合規

    關鍵在於這四個要同步處理。只把「數據」清乾淨、卻不動「流程」和「人員」,AI 一樣跑不起來;反過來也一樣。多家公司不約而同提到的共通痛點——數據孤島、技術債、缺乏單一真實來源——其實都落在這四個象限裡。

    三、不能跳步:合理化 → 標準化 → 自動化

    一位資深製造業高管分享了一個很樸素但很重要的原則:轉型沒有捷徑,過程必須照順序走——

    1. 先把做事情的順序合理化
    2. 再想辦法標準化
    3. 標準化之後,才能自動化(接著才是 AI)

    為什麼順序這麼重要?因為如果你跳過合理化與標準化、直接自動化,你的標準很可能是錯的——這等於把一個錯的流程加速,是一場無效的轉型。這也呼應了現場另一個觀察:很多人誤以為「拿一個工具來、不需要前面那些步驟,就能把事情做好」,但這從來不會成立。

    對應到角色,轉型會依序需要三種人:BA(業務分析)把現況忠實記錄成流程、SA(系統分析)定義這些需求該用什麼系統滿足、SD(系統設計/開發)實作。順序顛倒,後面全部白做。

    四、為什麼「戰情室」做了沒人用

    一家深耕 SAP 二十多年的整合商,分享了一個我覺得每個做過 BI 專案的人都會心一笑的觀察:傳統的策略支援系統(戰情室、儀表板)會沿著一條曲線慢慢失效。

    階段 作用強度 狀態
    過去 100% 決策利器,報表即時、深受信任
    幾年前 75% 仍具價值,但開始延遲、需人解讀
    現在 40% 內容固定、無法靈活、使用率下降
    不久後 15% 「自己做更快」,轉向替代方案
    未來 5% 報表停更、系統荒廢

    真正的死亡轉折點,發生在「現在 → 不久後」之間:當員工覺得「我自己下載資料、用 Excel 加工更快」,這個系統就開始死亡。幾年後公司又起一個新專案、重做一個新的戰情室,如此不斷循環。

    根因是什麼?傳統戰情室只給你落後指標——告訴你「過去發生了什麼」。但經營者真正面對的世界,不是內部報表,而是外部的快速變化。一句話點破:現在企業經營,最大的風險不在「做錯決策」,而是「太晚知道這世界變了」。所以下一代的決策平台,要從「內部、落後、檢討過去」轉向「外部、領先、預判未來」。

    五、把方法論變成步驟:從經營分析到決策機制

    那實際要怎麼建?現場分享的一套五步驟方法論,把上面這些抽象原則落成了可執行的流程:

    1. 經營分析:先對準企業目標——「企業到底需要什麼」,盤點現有流程與痛點。
    2. 資訊探索:從資料裡看清楚「現在發生了什麼問題、哪些資料必須收集進來」。
    3. 要因分析:用模型與統計方法,找出最重要的影響因子,把它變成你的領先指標
    4. 建立決策引擎:做出預測模型與預警儀表板。
    5. 形成決策機制:導入流程、教育訓練、持續優化,確保它真的被用起來。

    注意第三步「要因分析」才是重點——找出領先指標,而不是把舊的三十幾個 KPI 再畫一次。如果你做數位轉型時,還是只盯著以前那幾張報表看,那不會從根本改變公司的體質。

    結語:轉型是手段,創造價值才是目的

    麥肯錫、BCG、Gartner 對「數位轉型」的定義各不相同,但他們都強調同一件事:要創造價值。多數公司過於聚焦在前半段的「數位化」(導入工具、優化局部流程、提升效率),結果改善了效率、價值卻有限,難以帶動企業成長。真正的數位轉型,是重新設計商業模式與價值交付。

    所以如果只能記一句話,我會記這句:數位轉型只是手段,真正的目的在於創造價值。工具會越來越好用,但真正的差距,落在你有沒有把流程、資料與人,重新組織成一個 AI 跑得動的樣子。

    這是 SAP NOW AI Tour 系列的第一篇(方法論)。接下來幾篇會談技術骨架(MCP 與 A2A 怎麼讓 AI 接進企業系統)、真實落地案例(傳產與金融怎麼做),以及 AI 治理與 ROI。

    常見問題 FAQ

    數位轉型失敗的最主要原因是什麼?

    根據麥肯錫研究,主因是「組織與人」而非技術,成敗約 80% 取決於組織與人的改變、以及方法的正確性,資料與內容則是實現價值的基石。

    為什麼不能直接導入自動化或 AI?

    因為順序是「合理化 → 標準化 → 自動化」。跳過前面直接自動化,等於把一個還沒理順的錯誤流程加速,是無效的轉型。

    為什麼很多 BI 戰情室做完就沒人用?

    因為它只提供「落後指標」、內容固定難以靈活。當員工覺得自己下載資料用 Excel 更快,使用率就會一路下滑到系統荒廢。解法是轉向外部感知與領先指標。

    數位化和數位轉型有什麼不同?

    數位化偏向導入工具、優化局部流程、提升效率;數位轉型則是重新設計商業模式與價值交付。前者改善效率但價值有限,後者才能驅動企業持續成長。

    📚 本系列:SAP NOW AI Tour 的 4 堂課

  • 從自動化到自主化:SAP NOW AI Tour 座談五觀察

    重點摘要

    • 企業 AI 的競爭,正從「誰的工具快」轉向「誰能把 AI 行為有序地放進流程」——人機協作分成三階段:人在迴圈中、人在迴圈上、人當協調者。
    • 餐飲業者提出務實的加薪邏輯:AI 提升 25% 效能,就把待遇提升 25%(5 人月薪 4 萬 → 4 人月薪 5 萬)。
    • 製造業者的答案是「戰略集中化 + 應用邊緣化」:總部集中算力與資料治理,海外廠用「參數包」無痛複製。
    • 顧問業者強調:真正難被複製的不是單一技術,而是跨產業整合能力;做的不是科技本身,而是改善流程。
    • 平台商的結論:資料不必全部搬上雲(用串接而非搬遷),而成功的關鍵其實是一連串「選擇」。

    這是一場以「企業 AI 如何落地」為題的綜合座談,與談者橫跨餐飲、光電製造、科技集團、顧問與平台商。把五個視角放在一起聽,會發現他們其實在講同一件事的不同切面:AI 正從「自動化」走向「自主化」。以下是我在現場記下的五個觀察。

    一、AI 不是要取代你,而是放大你的價值

    座談一開始就定調:多數與談者都同意,AI 帶來的不是「取代」,而是經營模式的變革

    餐飲集團董事長講得最直白:「餐飲業的本質不會改變,但 AI 會帶來經營模式的變革。」他認為這個產業「太幸運」——人與人之間有溫度的交流,本來就不會被 AI 取代,反而能被 AI 放大價值。他舉點餐為例:與其讓客人自己滑手機自助點餐,理想場景是 AI 一眼認出常客、知道他的口味偏好,讓不同的服務夥伴也能交付一樣的感動

    二、餐飲業的加薪邏輯:五成四變四成五

    最讓我記住的一段,是餐飲董事長對「AI 與待遇」的算式。他向董事會、股東、同業溝通的概念叫「五成四變四成五」:

    • 原本 5 個人、平均月薪 4 萬
    • 透過 AI 與科技導入提升效能 → 變成 4 個人、每人平均月薪 5 萬
    • 待遇提升 25%

    他的主張是:如果 AI 能提升夥伴 25% 的效能,就應該把這 25% 回饋到待遇上。對一個長期缺工的產業來說,這不只是成本算式,更是留才與招募的吸引力。而要支撐這件事,背後需要可信賴、精準的底層資訊系統——當門市數量、來客人次累積成海量資料,沒有系統就無法把資料變成更好的經營決策。

    三、製造業的跨國解法:集中化加邊緣化

    光電製造業者面對的是另一種題目:跨國擴張時,如何把品質判斷複製到海外廠?他分享了一個很具體的痛點:光學元件最後常要靠老師傅「目視判斷品味」,這件事很「玄」,而當你要在海外設新廠時,沒有同一批老師傅怎麼辦?

    他們的做法是把老師傅的判斷標準化——用 AI 影像模型即時記錄作業員檢視產品時的角度、停留時間,一旦方式不對就現場提醒。累積資料後做預測與比對,這套機制就能搬到海外廠,降低跨國擴張的品質風險。延伸到組織層級,他畫出一張「未來跨國 AI 頂層設計架構」:

    層級 做法
    戰略集中化 總部建置核心算力,集中治理乾淨的核心資料,對核心智慧財產分級安全管控,守護「數位主權」
    應用邊緣化 海外各廠作為應用端,快速無痛導入由總部打包的微服務「參數包」,把前線操作門檻降到最低

    他用了一句很到位的話收尾:「數據決定智商,治理引領戰略;人才點亮大腦,批判成就卓越。」並提醒:AI 賦能很好,但不能讓所有人各做各的,否則既浪費又有風險——就像飛機機長能在自動駕駛時休息,靠的是「對的系統」,而不是一直手動微調。

    四、整合能力才是護城河

    科技製造集團的代表談「大艦隊」如何協同。他的心法是:AI 不是拿著鎚子到處找釘子——不要看到哪裡就把工具往哪裡敲,而是先找出整個集團最重要的事,再用 AI。

    他們的競爭力主張是:「真正難被複製的,不是單一技術,而是跨產業整合能力。」關鍵在於整合算力、網路、資料、場域與產業 know-how,讓 AI 從「分析工具」進一步成為「營運執行助力」。而支撐這種跨公司、跨事業群整合的,是一套「單一數據真相」。

    顧問業者則把話題拉回本質:「我們要做的不是科技本身,而是怎麼去改善營運、改善業務、改善流程。」他強調關鍵始終在你的資料——先把碎片化的資料匯進系統、治理好,才談得上往上疊應用。對於代理型 AI(Agentic AI)的紅利,他的建議是:資源有限,必須有排序與藍圖,而且「未來是系統整合的世界」,懂業務結構的人,才找得出最適應自己的 AI 應用。

    五、平台商的兩個答案:資料留地端、成功靠選擇

    平台商在觀眾 Q&A 給了兩個很實用的答案。

    問題一:用 AI 一定要把所有資料都搬上雲嗎?

    答案是「不用」。透過資料雲的「串接」機制(而不是把資料整個搬上去),地端資料可以留在原地,上層再用 AI 助理做分析。對於有資安與成本考量、又想用 AI 的企業,這是關鍵的一條路。

    問題二:員工要具備什麼技能、上什麼課才會用?

    最大的差別是:過去要寫程式、做報表再串接,現在這些提示(prompt)已經內建在產品裡——會打字、會用講的,就能用,不太需要特別上課。換句話說,提示工程被產品吸收了,人的價值回到「會問對問題」加上業務判斷。

    而對於「企業如何像自動駕駛一般運作」,平台商的結論很清楚:成功的關鍵在一連串的「選擇」——從哪裡開始、聚什麼團隊、選什麼平台、選哪些流程與資料、找哪些顧問參與。平台本身不是萬靈丹,選對標準流程,AI 才發揮得出來。

    整場的理論收束:人機協作的三階段

    如果要用一張圖總結這場座談,那會是平台商提出的「人類決策 + AI 執行」新運作邏輯。知識圖譜像一個「導遊」,告訴 AI 流程在哪、要取哪個系統、資料在哪;而人與 AI 的協作,會經歷三個階段:

    階段 人的角色
    人在迴圈中(Human-in-the-Loop) 人觸發並監控代理的每個動作
    人在迴圈上(Human-on-the-Loop) 系統觸發代理,人只處理例外
    人當協調者(Human-as-the-Orchestrator) 人退居監督者,跨多個 AI 助理協調指揮

    人從「親自做」走向「監控」、再走向「處理例外」與「協調指揮」——這正是「從自動化到自主化」的具體階梯。而與談者最後那句話,也許是整場最好的註腳:

    人機協作的時代已經來臨——機器不是要取代你,而是你要教會它,如何「行為有序」地在企業內部運行。

    結語:差距落在組織,而不是工具

    回看這五個視角,會發現它們其實在講同一件事的不同切面:方向一致——都指向「AI 從輔助走向自主」;底線一致——資料治理與「讓 AI 行為有序、不亂竄」是所有人的共同前提;對人的重新定位——AI 降低了工具門檻,卻抬高了「懂業務、會問對問題」的價值。

    工具會越來越好用,但真正的差距,落在你有沒有把流程、資料與人,重新組織成一個 AI 跑得動的樣子。

    常見問題 FAQ

    企業導入 AI,一定要把資料全部上雲嗎?

    不一定。可以用資料雲的「串接」機制讓地端資料留在原地,再由上層 AI 做分析,兼顧資安與成本。

    員工要會寫程式才能用企業 AI 嗎?

    多數情況不用。提示(prompt)已內建在產品裡,會用自然語言(打字或講話)就能操作;價值回到「會問對問題」與業務判斷。

    「從自動化到自主化」具體是什麼意思?

    指人機協作的演進:人在迴圈中(觸發監控)→ 人在迴圈上(只處理例外)→ 人當協調者(指揮多個 AI 助理)。

    跨國企業怎麼把 AI 能力複製到海外廠?

    一種做法是「戰略集中化 + 應用邊緣化」:總部集中算力與資料治理,海外廠用標準化的「參數包」快速導入。

  • 我的家庭照顧 14 個 HTML 工具:dementia-care monorepo + 實戰使用指南

    重點摘要

    • dementia-care monorepo 是 14 個 HTML/Python 工具的 personal toolkit:圍繞「家人照顧」這件事,自家用為主,朋友(藥師)+ 社區照護者也用得上。
    • 起源:照失智媽媽 2 年急速進展 + 育兒 2023 年出生女兒,前面有 15 年照爸爸 stroke 失能 secondary 經驗。每天遇到 friction 就寫一個小工具。
    • 上位 mission:「讓整個家忙起來」(ambient engagement,Marx & Cohen-Mansfield 2010 循證概念)—— 工具不是治療,是降低照護者啟動 friction。
    • 共用 spec:純前端、單檔 HTML、0 CDN、0 build、離線可用、繁體中文、大字大按鈕、SVG emoji favicon、GitHub Pages 部署。
    • 5 條自我約束(2026-04-28 後):凍結新 sub-project 60 天 / commit cap 20/天 / 每週一個下午全關 / 0 CDN 機器化守門 / 不主動推工具只分享方法。
    • 跨專案 lessons:純黑白對白內障是錯的 frame、圖書館 ≠ 景點 precision contract、Google Maps fallback default pin 陷阱、Selenium 驗證 self-use 例外、物件 literal 尾逗號讓整頁 blank。

    dementia-care monorepo 是 14 個圍繞家庭照顧的 HTML/Python 工具集,過去半年累積。為什麼會有這個 repo?照失智媽媽,順便做給太太、藥師朋友的太太、社區照護者用 ——「自家工具集 + 經驗分享」,不是 community product。

    這篇是這個 monorepo 的全面整理:14 個工具的分工、起源故事、共用設計原則、5 條自我約束、5 條跨專案踩坑 lessons。給想做類似 personal toolkit 的人參考,也給之後的我自己回頭看為什麼這樣設計。

    為什麼會有這個 monorepo?

    結構上設計給:白天只有你跟長輩、家屬 backup 0、商業 app 都假設你有時間引導。我家 timeline:

    • 15 年照父親 stroke 失能(secondary,媽媽是 primary,2024 過世)
    • 2024 起媽媽輕度失智 → 2 年急速進展到中重度
    • 2023 出生女兒進入 toddler 階段
    • 太太是藥師、有正職,白天無法 backup
    • 過去半年我變 primary caregiver

    每天遇到 friction(媽媽問同樣問題第 50 次 / 居服員交班沒交集 / 回診忘記想問什麼 / 女兒週末沒地方去) —— 直接寫一個小工具,不寫 spec、不開會、不等 backlog。半年累積 14 個。

    上位 mission 是「讓整個家忙起來」。對應的循證概念是 ambient engagement(Marx & Cohen-Mansfield 2010 “Engagement of Persons with Dementia”):環境引發的活動 vs 人引發的活動,失智長輩參與有意義活動的「量」與認知衰退斜率負相關。工具不是治療,是降低照護者啟動 friction —— 讓 engagement 在沒人陪伴的疲累照護日實際發生。

    14 個工具分四大類

    🧠 失智照護生態系(主線資料閉環)

    工具 類型 說明
    陪伴小幫手 v1 互動遊戲 15 個認知訓練遊戲,8 級難度滑桿自動選 10 個顯示
    陪伴小幫手 v2 試驗版 推薦式首頁 + 照護者陪伴指南 + 今日摘要分享
    白板 OCR Bot Telegram Bot 每日白板照 → Gemini 3 Flash(box-index 策略,磁鐵在第幾格)→ iDempiere Z_momSystem
    就診小幫手 Web App 回診前 prep:抓 iDempiere 異常、症狀分類、診間錄音

    👶 兒童 + 親子

    工具 類型 說明
    小朋友學習樂園 學齡前互動 1-6 歲 23 個活動,4 年齡層自適應深度
    週末出遊地圖 親子景點 全台 22 縣市 850+ 景點 + 多點路線規劃
    托嬰幼兒園手冊 方法論 0-6 歲托嬰中心 + 幼兒園選擇方法論(4 種類型對照,評估 SOP)

    📖 生活方法論手冊

    手冊 主題
    care-handbook 長照手冊:找居服員 / 日照 / 喘息 / 機構 / 看護工 / 失智專屬支援系統
    home-handbook 家中照護手冊:13 項物理改動 + 早午晚 SOP + 援手系統 awareness
    home-handbook-classic 家中照護手冊舊版(保留作對照,新版改用 home-handbook)
    garden-handbook 家庭園藝手冊(可食 + 觀葉 + 觀花 + 根莖類,陽台/窗邊/室內)— 對失智長輩是 behavior redirection 工具
    pet-handbook 家中寵物生活手冊(貓/狗/兔/鳥/魚/烏龜)—「會主動靠近的家人」,失智長輩 + 小孩雙受惠
    mindset 心法手冊 — 6 條視角(失智不是失能 / 用加法對抗減法 / 躁動不是無聊 / 動線是功能可及性 / 誠實版優於善意包裝 / 手冊是網狀不是清單)

    🧃 飲食 / 健康

    • health-drinks:**19 款醫療營養品 + 嬰幼兒配方 + 高蛋白補充品**並排比較(180-280ml 容量範圍。三重使用者:Tom 自家、藥師朋友、藥局客戶)

    失智照護主線:資料閉環長什麼樣?

    14 個工具裡 4 個是失智照護核心,串成一條 daily/weekly 閉環:

    [居服員 / 我]
        ↓ 拍白板照傳 Telegram
    whiteboard-ocr-bot
        ↓ Gemini 3 OCR + 人工 confirm
    iDempiere Z_momSystem(每天一筆紀錄)
        ↓ REST API
    mom-clinic-companion
        → 回診前產出「今天要問醫生的 3 件事」

    白板每天記錄媽媽 餐食 / 用藥 / 行為事件 / 睡眠時數。OCR Bot 把照片轉成結構化資料寫進 iDempiere(自家 ERP-as-PHR,Z_momSystem 表 12 欄位)。回診前 mom-clinic-companion 比對「上次回診 → 今天」vs「上上次回診 → 上次回診」兩個 window,抓變化顯著項目給神經科醫師看具體事件,不是「最近狀況不太好」這種模糊描述。

    這條主線運轉半年,媽媽每月回診從「我也不知道要說什麼」變成「上週三晚上她突然找不到回家的路」這種具體 evidence。神經科醫師根據具體事件調藥,比根據家屬情緒描述準確很多。

    共用設計原則 — 為什麼都是單檔 HTML?

    14 個工具共用同一套 spec:

    • 單檔 HTML:HTML + CSS + JS 全塞 `index.html`,不拆檔。對 backup / 修改 / 分享(直接寄一份)極友善。
    • 離線可用:所有資源 inline(SVG favicon、base64 圖、不依賴 CDN)。山區農場、長輩家 wifi 弱 都能跑。
    • 0 CDN 強制:禁止任何 fonts.googleapis / cdnjs / unpkg / jsdelivr / Google Analytics / 外部 script。原因:使用者打開網頁時瀏覽器會從使用者裝置直接發請求到 CDN 伺服器,洩漏 IP + User-Agent + 時間給第三方,違反 COPPA(兒童)/ GDPR-K / 個資法。有專屬 CI workflow `monorepo-cdn-ban.yml` 機器化守門(2026-04 加),違反即擋 push。**Caveat**:`health-drinks` 因為較早期建置仍用 Chart.js + Google Fonts CDN,是 monorepo 唯一例外,計畫之後遷移成 inline。
    • 0 build step:不進 npm、不進 webpack。寫完開瀏覽器看,改完 commit push 30-60 秒 GitHub Pages 部署。
    • 繁體中文 + 大字大按鈕:觸控友善,最小點擊區 48×48px。
    • SVG data URL emoji favicon:離線也有 tab icon。

    低視力對比:原本以為「純黑底 + 純白字 = 最大對比 = 最適合低視力長輩」,後來發現對中度白內障(monorepo 主場景)會因 forward light scatter 引發 halation/glare —— 21:1 是 over-shoot,不是越高越好。Evidence-based 替代:米白底深字(#222 on #f5f5f5)/ 深底淺字(#e8e8e8 on #1a1a1a)/ 字級 ≥ 24px / line-height ≥ 1.6。維持 WCAG AAA(7:1+)但消除極端 glare。

    5 條自我約束(2026-04-28 後加)

    跨 6 domain expert review 共識項。寫進 CLAUDE.md 變強制規則,我自己做時也守:

    1. 凍結新 sub-project 60 天(到 2026-06-30):14 個已過載,主軸佔比 < 35%。6 個月 450+ commits(`git log –since=’2025-11-01’`),「持續產出 = 情緒迴避」紅旗。例外:只允許 archive / 整併 / 刪除。解凍後若仍想開新工具,先在 blog 寫一篇「為什麼這值得開一個工具」,沒寫完不開。
    2. Commit cap 20 / 天 (soft warning):超過 20:pre-commit hook 跳對話框問「今天你媽吃幾餐、女兒抱了你幾次、你笑了幾次」。失智照護者 burnout 是 monorepo 結構性 SPOF —— Tom 倒下 = mom-clinic 朋友家屬可能誤診 = 整個生態系凍結
    3. 每週一個下午全關:不寫 code、不寫 blog、不規劃 feature。陪女兒、發呆、睡覺都行。「讓整個家忙起來」mission 不該包含 Tom 自己一刻不停。
    4. 0 CDN 機器化守門:`.github/workflows/monorepo-cdn-ban.yml` 自動掃所有 *.html。違反即擋 push。不再靠人記得。
    5. 不主動推工具,只分享方法:工具是 personal toolkit,維護優先順序看當下需要。不主動推給陌生使用者(避免讓人對「會被維護」產生錯誤期待)。朋友(藥師)是「資訊交流」不是「使用者」,不發配工具帳號。方法寫成 blog,blog 才是擴散渠道(這篇就是)。

    5 條跨專案踩坑 lessons

    1. 純黑白對白內障是錯的 frame

    「最大對比 = 最適合低視力」是錯的。對白內障(monorepo 主場景)forward light scatter 引發 glare,21:1 反而降可讀性。WCAG 21:1 是 物理可量化(luminance ratio),「適合低視力」是 臨床效果(可讀 + 不疲勞 + 不誘發 glare),兩者不是同一件事。Evidence-based:米白底深字 / 深底淺字 / 字級 24px+ / line-height 1.6。

    2. 圖書館 ≠ 景點:precision contract

    不同 place category 對 precision 容忍度不同。景點(公園 / 山林 / 老街)area centroid 1-2 km 噪音 OK(本身就大);圖書館 = 單一建築,1 km 偏差 = 不同樓棟 = 錯,不能套同一條 fallback 規則。對「single building」類,寧可 entry 數量少(精確) 也不要 area centroid(誤導 user)。

    3. Google Maps fallback default pin 陷阱

    Google Maps geocoding 找不到地址時不會回 error,而是 silent fallback 回最後一個成功 query 的 cached coord。kids-weekend 跑 23 筆 Playwright 有 3 筆全部 fallback 到同一個 [24.9790, 121.4579]。必跑 sanity gate:縣市 bounding box 比對。任何 geocoding pipeline 必須有 downstream sanity check —— 不能信「200 OK + 有 @lat,lng」就當作對的。

    4. Selenium 驗證 self-use 例外 ≠ photo scraping hard violation

    Google Maps Platform ToS 是合約不是法律,enforcement profile 對「自用 / 非商業 / 中等規模」幾乎為零。判斷不是 binary —— 看(1) self-use vs 商業化 (2) 一次性 vs 持續性 (3) 文字 vs 照片 三維度。kids-weekend 圖書館 geocode 落在「self-use + 一次性 + 文字座標」三個都 OK 的格子,屬技術性 ToS issue。但 photo extraction + redistribute 仍是 hard violation(著作權法 §91 §92),商業化應升級付費 API。

    5. 物件 literal 尾逗號讓整頁 blank

    2026-04-21 kids-companion 整頁 blank 事故:新增 IMG 物件忘記前一筆尾逗號,SyntaxError 整頁掛。單檔 HTML 沒 webpack 兜住,JS 一錯整頁 die。寫 lint script (`scripts/lint_places.py`)機器化檢查每筆 entry 結尾。

    為什麼不對外推銷?

    因為這是 tier 2 personal toolkit 不是 community product。三個原因:

    1. 維護順序看自家當下需要:某天我家 schedule 變、媽媽病程變、女兒入學,工具優先順序就變。對外推銷會建立「會被維護」期待,實際上我可能突然停某個工具 —— 對 user 不公平。
    2. SPOF 問題:14 個工具只有我一個 maintainer,我倒下整個 stop。對外推 = 對外承諾,承諾兌現不了 = 信譽損傷。
    3. 方法 vs 工具:方法可以用文字傳承,擴散性高;工具 binding 在我家 schedule + 我家硬體 + 我家數據格式。方法寫成 blog,工具留給有能力 fork 改的人。

    朋友(藥師)是「資訊交流者」不是「使用者」 —— 我跟她討論失智用藥,她跟我討論病人家屬,但我不發給她工具帳號讓她依賴我的伺服器。她想用就 fork,改成她家用。

    給想做類似 personal toolkit 的人的建議

    1. 明確 scope = self-use:這個 frame 鎖死所有設計決定 —— 不做 user account、不做 paywall、不對外推銷、不收 review。Scope 一變,所有 compliance / privacy / 合規 trade-off 全變。
    2. 單檔 HTML 是 personal toolkit 的甜蜜點:0 build / 0 server / 直接寄一份檔案 / 純前端 / 離線 / GitHub Pages 免費部署。技術簡單到不會卡住做事的人。
    3. 0 CDN 是隱私底線:任何外部 fonts / analytics 都洩漏 user IP。家庭應用(兒童 / 醫療 / 失智)不能讓 Google 知道你家在訪問什麼工具。寫 CI workflow 機器化守門,不靠人記得。
    4. 每個工具對應一個 friction:不要先想「我要做什麼工具」,要想「我每天卡在什麼」。卡在交班 → OCR Bot;卡在回診 → mom-clinic;卡在週末 → kids-weekend。
    5. 政府開放資料 > 商業 API scraping:libstat / data.gov.tw / TGOS 對台灣應用是乾淨 source,合規且持久。每個 domain 找對應的政府 source(圖書館 / 醫院 / 學校 / 古蹟)。
    6. self-use 工具不是免責令:Photo extraction、持續性 production scraping、商業化 仍是 hard violation。判斷 framework 看 (1) self-use vs 商業 (2) 一次性 vs 持續性 (3) 文字 vs 照片 三維度。
    7. 給自己自我約束:照護者 burnout 是結構性 SPOF。commit cap、每週全關一下午、凍結新 sub-project,這些不是「強制症」是「對抗持續產出 = 情緒迴避」的 hard rule。

    —— 工具實戰判斷與用法 ——

    三層分工:Handbook、工具、專業

    使用 monorepo 之前,先建立三層分工的觀念:

    作用 對應 monorepo 頻率
    Handbook 認識系統、申請流程、SOP 學習 care-handbook / home-handbook / childcare-handbook 階段性(剛確診、要申請居服員)
    工具 每日操作、降低啟動 friction 陪伴小幫手 / OCR Bot / mom-clinic / kids-weekend 每日 / 每週
    專業 診斷、用藥、急救、法律 神經科 / 精神科 / 1966 / 1925 / 119 / 共照中心個管師 回診 + 突發事件

    實戰原則:剛確診先讀 handbook(2-3 天密集吸收),3 個月後 handbook 慢慢變參考書,工具變每日操作,專業在事件發生時 escalate。

    7 個照顧場景對應工具速查

    場景 主要工具 配合 handbook
    失智剛確診那週 無工具(handbook 為主) home-handbook P0 + care-handbook 申請流程
    居服員每天交班 白板 OCR Bot home-handbook 居家日 SOP
    媽媽情緒不好想做點事 陪伴小幫手 v2(推薦)/ v1(自選)
    回診前一晚 mom-clinic-companion
    週末帶孩子去哪 kids-weekend(住哪 → 路線)
    孩子在家想做活動 kids-companion(2-6 歲 4 年齡層自適應) — (kids-companion 自己分齡)
    第一次申請長照 無工具(handbook 為主) care-handbook 7 步 SOP + 援手系統

    場景 1:失智剛確診那週 — handbook 為主

    剛確診那週不要急著上工具。先做 5 件事(home-handbook P0 章節):

    1. 法律 P0:輔助宣告 / 監護宣告 / 預立醫療決定 — 趁失智長輩仍有意思能力時辦,過了會難辦
    2. 醫療 P0:確認確診醫院 + 預約共照中心 + 申請重大傷病卡
    3. 防走失:愛心手鍊 / GPS / 鄰里通報網
    4. 物理改動 13 項(home-handbook 列清單):防滑地墊 / 衛浴扶手 / 廚房瓦斯總開關 / 大門感應…
    5. 申請長照:1966 → 照管專員到府評估 → 失能等級 → 服務媒合(care-handbook 7 步 SOP)

    這週不要碰工具。一邊吸收 handbook,一邊處理法律醫療 P0,一邊跟家人討論分工。工具是後面 2-3 個月開始有居服員 / 日照排班後才會用得上。

    場景 2:居服員每天交班 — 白板 OCR Bot

    白板 OCR Bot 解決交班斷層:居服員早上來、下午走;家屬晚上接手 — 中間 8 小時居服員紀錄不傳給家屬,神經科回診也說不清楚。

    實際流程:

    1. 家裡放一塊白板,居服員每天用筆寫紀錄(餐食 / 用藥 / 行為事件 / 睡眠)+ 用磁鐵標記固定欄位的選項
    2. 居服員下班前 / 我經過時拍照傳 Telegram bot(`telegram_bot.py`)
    3. Bot 走 `ocr_pipeline.py` → Gemini 3 Flash Preview API,**用 box-index 策略**(磁鐵在第幾格)避開手寫中文字元 OCR — human-as-verifier 設計
    4. 手機收到 bot push 訊息「請確認」,3 秒過目即可。錯了直接改文字回傳
    5. 自動寫入 iDempiere Z_momSystem(每天一筆 row,12 個欄位)
    6. 家屬晚上看 iDempiere 知道白天發生什麼,銜接夜間照護

    另也支援 📝 文字訊息 → 加時間戳(早 / 晚 / 大夜班)append 到當天備註欄;`/status` `/today` 指令查當天/累積狀態。`whiteboard-ocr-bot/index.html` 是純前端 demo 版本(模擬對話流程,不連網不傳資料),正式版要 Python + iDempiere REST API 跑在自家 server。

    關鍵 design:box-index 策略 + human-as-verifier 不是全自動。Gemini OCR 對手寫長輩字跡不一定 100%(尤其用藥名稱),所以白板用固定欄位 + 磁鐵 — Gemini 只要識別「第幾格有磁鐵」這種離散 boolean,不用識別自由手寫,大幅降低錯誤率。

    場景 3:媽媽情緒不好想做點事 — 陪伴小幫手 v2

    陪伴小幫手有 v1 / v2 兩版本並存:

    情境 用 v1 還是 v2?
    媽媽心情好,自己想挑 v1(10 格遊戲卡讓她挑)
    媽媽疲累 / 不擅選擇 / 照護者也累 v2(一鍵推薦「今天一起做這個好嗎」)
    想知道對長輩說什麼話帶遊戲 v2(每遊戲 3 條陪伴指南)
    想記錄今天玩了什麼貼 LINE 給家人 v2(每日摘要一鍵複製)

    v2 推薦邏輯:依時段(早 / 午 / 晚 / 深夜)+ 最近玩過避免重複 + 當前難度自動挑一個遊戲。次要選項「換一個 / 我想自己選」字級縮小、無底色,降低照護者選擇癱瘓 — 是給疲累照護者的設計。

    難度滑桿 1-8 對應方式(`v1 CLAUDE.md` 規格):

    • 1-2 輕度:遊戲篩選後較難(辨識變化小、選項多),語音只朗讀題目
    • 3-6 中度:遊戲難度中等,語音朗讀題目 + hover 選項唸出
    • 7-8 重度:遊戲篩選後最簡單(選項少、對比大),語音朗讀題目 + 所有選項,重複一次

    遊戲庫(`GAME_LIBRARY`)15 個遊戲每個有 `min`/`max` 範圍,`selectGames(level)` 從符合範圍的遊戲中隨機抽 10 個顯示首頁。選擇難度時看當週實際狀況試,不是越難越好 — 失智長輩做不到會挫折,做太簡單會無聊

    場景 4:回診前一晚 — mom-clinic-companion

    失智回診最大的問題是「**最近狀況不太好**」這種家屬模糊描述,神經科沒辦法調藥。mom-clinic-companion 讀 iDempiere `Z_momSystem` 表(白板 OCR Bot 寫入的),把 raw data 歸納成照護者可以記住、可以問的內容。

    實際 4 個 sections(`mom-clinic-companion/index.html` H2):

    1. 🚨 值得跟醫生討論的 — 規則引擎自動比對「上次回診 → 今天」vs「上上次回診 → 上次回診」兩個 window,找變化顯著項目
    2. 💭 這一個月媽媽發生過 — 從白板 OCR Description 欄抓症狀關鍵字
    3. 📋 這次要問醫生 — 從上面兩區一鍵「加進問題」,手動補其他
    4. 🎙️ 診間錄音 — 醫師講話 STT 轉字,回家同步回 iDempiere

    核心設計是回診日期感知:`APP.visits` 是回診日期 array,`computeWindows()` 產生最新兩段比對區間 — 因為實際回診頻率不規則(通常每月,有時兩週),按日曆切會不準。

    場景 5:週末帶孩子去哪 — kids-weekend(MAP 工具)

    kids-weekend 是 monorepo 裡最大的 MAP 工具:全台 22 縣市 851 筆親子景點 + 路線規劃(`STATE_VERSION` 3,單檔 HTML ~700KB)。解決的具體問題是「從家出發 X 公里範圍內,有什麼順路可以串成一日」 —— 媽媽社團、IG 收藏、Google Maps 我的清單,都做不到「按距離 + 順路 + 一鍵多點導航」這件事。

    1 題 wizard 是 deliberate 砍簡 — 從 4 題到 1 題

    2026-04 砍簡前,wizard 有 4 題:住哪 + 天氣 + 年齡 + 範圍。實測發現 user(太太、藥師朋友)80% 都直接 next 跳過後 3 題:

    • 天氣晴雨:家長自己抬頭看,問了多餘
    • 年齡:每筆景點 entry 已有 `ages: [‘0-2′,’2-3′,’3-6’]` 標籤,filter UI 之後再勾就好
    • 範圍:**家庭多在 20 km 內**(自家 + 朋友家實測 4 個月),預設 20 km 一拉就動

    所以剩 1 題:**「住哪?」**(GPS 一鍵 / 縣市 + 區下拉)。設完直接看推薦清單,範圍可拉滑桿改 5-400 km。砍題目比加 feature 更重要 —— personal toolkit 的設計訓練。

    實際 6 步使用流程

    1. 設家 — 第一次選,之後 `localStorage[kidsWeekendState]` 記住。GPS 一鍵會 reverse geocode 成「📍 新北土城」(不顯示醜的經緯度)
    2. 看推薦清單 — 預設 20 km 內景點,室內/戶外/觀光工廠/博物館/公園/海邊/廟宇/老街全混合
    3. 篩 filter — 晴天/雨天/0-2 歲/室內/避開人多/避開假日塞車黑名單
    4. 勾比較籃 — 1-3 個目的地加入比較籃
    5. 看路線預覽 — corridor 演算法找順路景點(預設 5 km corridor,`STATE.preferences.corridorWidthKm`)+ 計算多點總公里 + 拖 ⋮⋮ 換站順序
    6. 一鍵 Google Maps 多段導航 — 直接丟 Maps app(`maps.google.com/dir/?…` URL),不用手動複製貼

    實例(README 範例):「搜尋觀音山設目的地 → IKEA 新莊距路線 0.44 km ➕ 加入 → 五股 ➕ 加入 → 想加林口三井但 5.13 km 擦邊 → corridor 拉到 6 km → 拖 ⋮⋮ 把林口移到第 1 站 → 一鍵 Google Maps」。

    Place precision contract:景點 vs 圖書館 fallback 策略

    kids-weekend 的距離計算 priority(`getPlaceCoords()` line 2354):

    1. 先查 `PRECISE_COORDS[place.id]` — 有就用
    2. 沒有 → fallback `getCoordsFromArea(place.area)` 取「縣市 + 區」中心點(`TAIWAN_DISTRICTS` lookup,286 個區 centroid)
    3. 都沒有 → null,distance filter 排除

    但圖書館不能 fallback 區中心(本文上方「跨專案 lesson 2」)。圖書館是單一建築,1 km 偏差 = 不同樓棟 = 錯。所以 2026-04-30 圖書館 wave A→C 擴點時,**沒有精確 coord 的圖書館直接 drop,不入庫**(reject 連江縣文化處 / 桃園兒童文學館 / 高雄新興閱覽室 3 筆,因為 Google Maps fallback 到 default pin)。

    Metadata flag 系統 — 怕感冒 / 怕塞 / 失智注意

    每筆景點除了基本欄位(name / area / ages / types / hours / website),還帶 metadata flag 給推薦邏輯參考:

    Flag 含意 影響
    `elder_friendly: true` 長輩友善(平緩、無障礙、有座位) 失智 + 親子混合家庭優先推薦
    `weekend_jam: true` 假日塞車黑名單(陽明山 / 九份 / 淡水) 勾「避開塞車」會排除
    `dementia_caution: true` 失智長輩慎入(動物園 / 大型賣場 / 高 crowd 易迷路) 混合家庭手動觀察
    `crowd: ‘low|mid|high’` 人潮 enum UI「🤧 避開人多景點」剔除 high

    851 筆景點怎麼累積 — 5 wave + 圖書館 wave A→C

    景點不是一次抓進來的,分 wave 增量。每 wave 對應「家附近還缺什麼類型」的 surface gap:

    Wave 主題 +景點
    v3.11 base 親子館 / 公園 / 觀光工廠 主軸 ~770
    v3.12 0-2 歲友善 補嬰幼兒場域(托嬰中心 / 兒童美術館) +8
    v3.13 觀光工廠 DIY 體驗 + 雨天首選 +12
    v3.14 露營區 Glamping + 渡假農場 +10
    v3.15 雲嘉南高屏 南台灣覆蓋補齊 +14
    圖書館 wave A→C(2026-04-30) 縣市總館 + 親子閱覽室 + 文學/繪本 +33

    圖書館 wave 走獨立 pipeline:libstat 國家圖書館抓政府公開資料 → OSM Overpass strict verify(`amenity=library` POI 全台 853 個)→ Google Maps Selenium geocode 補不足 → 縣市 bbox sanity 過濾 → 通過才入庫。三條 source 各補不同覆蓋率,合規(政府開放資料 0 ToS)+ 精確(building-level coord)。

    每個 wave 的關鍵 lesson:**對應實際 user gap,不盲目擴量**。盲目擴點會稀釋信號(user 搜「週末去哪」跳出一堆樓上閱覽室,反而難用)。圖書館 wave 砍 46 筆閱覽室因為「樓上小空間 ≠ destination」,只進 33 筆 high-value。

    場景 6:孩子在家想做活動 — kids-companion

    kids-companion 是 2-6 歲兒童平板學習 app,核心設計是「自適應深度 (Adaptive Depth)」 —— 同一內容,不同年齡,不同深度。4 個年齡層各有版本:

    • toddler(幼幼班 1-2 歲):選項 2、語音題目+選項重複、目標字 140px、無拖拉
    • small(小班 3-4 歲):選項 2-3、語音題目+選項、目標字 120px
    • middle(中班 4-5 歲):選項 3-4、語音題目+hover、目標字 100px、可拖拉
    • large(大班 5-6 歲):選項 4-6、只朗讀題目、目標字 80px

    使用流程:設角色 emoji + 年齡層(toddler/small/middle/large) → 首頁活動卡 → 系統依年齡層自動調選項數 / 字級 / 互動方式。設計哲學在 brain memory `project_kids_companion_philosophy.md`。

    跟陪伴小幫手 v1/v2 關鍵差異:Web Speech API pitch 設定不同。kids-companion `pitch: 1.2`(高頻活潑感吸引兒童);陪伴小幫手 v1/v2 都已校正成 `pitch: 0.95`(老年聽力 presbycusis 高頻損失,低頻反而清楚)。同 API 不同設定,因為使用者生理不一樣。

    場景 7:第一次申請長照 — care-handbook 7 步 SOP

    長照申請新手最大的痛點:不知道要打給誰、要準備什麼、評估會問什麼。care-handbook 直接給 7 步 SOP:

    1. 打 1966(長照專線,免費)→ 報長輩姓名 + 縣市 + 失智症
    2. 等照管專員到府評估(通常 1-2 週內)
    3. 準備評估會問的:長輩 ADL/IADL 量表自評 + 失智診斷書 + 重大傷病卡(如有)
    4. 失能等級判定(2-8 級)→ 對應給付額度
    5. 服務媒合(居服員 / 日照 / 喘息)→ 排面試
    6. 居服員 / 日照面試 SOP:重點問題、紅旗信號、簽約注意事項(handbook 列詳細 checklist)
    7. 失智專屬支援:申請共照中心 + GA07 家屬訓練諮商給付碼 + 巷弄失智據點(這條在 care-handbook 獨立章節,大多家屬不知道)

    handbook 不取代 1966,是讓你打 1966 之前知道要問什麼。直接打 1966 也可以,但你會發現照管專員講的有些聽不懂(BA / CA / GA01-07 給付碼),先看 handbook 心裡有底再打。

    場景 8:選托嬰中心 / 幼兒園 — childcare-handbook

    childcare-handbook 是托嬰中心 + 幼兒園選擇方法論手冊(0-6 歲),不是「找最便宜」「找最近」這種比價工具,而是教**怎麼系統性評估** —— 在報名截止前知道「該看哪些點、該準備哪些東西、該追蹤哪些時間」。

    4 種托育類型(0-2 / 2-6 歲分流)

    • 托嬰(0-2 歲)3 類型:公托 / 準公共 / 私立
    • 幼兒園(2-6 歲)4 類型:公幼 / 非營利 / 準公共 / 私立

    5W1H 評估方法論(Who / What / When / Where / Why / How)

    Handbook H1「🎯 5W1H 評估方法論」拆 5 個 H2:你家是誰 / 選哪一類 / 什麼時候動 / 距離與動線 / 決策框架。每個維度有具體 checklist。

    核心 family mode:`sandwich`(三明治世代) — 全域狀態 `STATE.familyMode` 有 4 個值:`normal` / `sandwich`(同時照顧失智長輩 + 幼兒)/ `dual_income` / `single_parent`。**Tom 家是 sandwich**,工具設計 deliberately 給三明治世代設想:選離長輩家近 vs 離公司近的 trade-off、晚接送對失智長輩晚餐 SOP 的影響、公幼接送時間跟長輩日照時間怎麼對齊。

    state(`localStorage[childcareHandbookState]`):`childAge` enum + `familyMode` enum + `favorites` 收藏園所類型 + `checklist` 文件 / 行動完成度。可匯出匯入 JSON。

    場景 9:陽台種菜 / 觀葉 / 觀花 — garden-handbook

    garden-handbook 是家庭可食 + 觀葉 + 觀花 + 根莖類種植手冊,涵蓋陽台、窗邊、室內盆栽。每個 plant 一個 entry,**統一 10-section 結構 + 5W1H 總覽 + 購物籃匯入**。

    為什麼 garden 在失智照護 monorepo 裡?

    因為 repo 上位 mission「讓整個家忙起來」(ambient engagement)—— 用植物讓家裡有生長中的東西、每天互動的動作、可採可賞的成果。對失智長輩,種植是 behavior redirection 的有效工具:她躁動時遞她澆水器,「來,我們去澆花」是個比「坐下休息」更不抗拒的指令,因為她可以「做有意義的事」。

    10-section 結構 + 5W1H + 規劃模式

    每個 plant entry 統一格式:

    • 5W1H 5 秒總覽:`renderPlantOverview()` 從 meta + sections 自動抽 6 行摘要(怎麼種 / 多久收成 / 適合哪些家)
    • 10-section 結構:選盆 / 選土 / 種法 / 澆水 / 採光 / 病蟲害 / 採收 / 留種 / 失敗訊號 / 跟其他植物搭配 — 每株都這 10 段
    • 規劃模式:設定頁 toggle 開啟,filter 按「家庭模式 / 季節 / 採光」推薦對應 plant
    • 購物籃匯入:一鍵把該 plant 需要的盆/土/工具加入購物清單(連到 brain memory `feedback_starter_kit_ordering.md`「基礎設施先,活體後」原則)

    state:`localStorage[gardenHandbookState]` — 最愛 / 購物籃 / 規劃模式 / 照護級數 / memos,可匯出匯入 JSON。

    場景 10:讓家有「會主動靠近的成員」 — pet-handbook

    pet-handbook 是家中寵物生活手冊,按 6 個物種分類:**貓 / 狗 / 兔 / 鳥 / 魚 / 烏龜**。每物種下有多個 topics(親訓 / 飼料 / 醫療 / 訓練)。

    跟 garden 的 frame 區別 — 寵物是會主動靠近的家人

    核心定位:寵物是會主動靠近你的家人。跟植物不一樣 —— 他會自己跳上你腿、用頭頂你手、發出呼嚕聲。他不是被動被照顧的對象,**是家庭成員**。

    對失智長輩尤其重要 —— 當她大腦退化、溝通困難,一個會自己靠近的生命,是「她還被需要、她還存在」的證明。garden 是 ambient(植物在那裡),pet 是 active(寵物來找你)—— 兩者並用補不同層次的 family vitality。

    對小孩:寵物從小同住的孩子發展(empathy / 責任感 / motor skills)有 evidence-based 好處。混合家庭(失智長輩 + 幼兒 + 寵物)是 monorepo 主場景之一。

    場景 11:照護判斷迷茫時 — mindset(6 條視角)

    mindset 是「心法手冊」 — 不是 SOP、不是 checklist,是一位失智照護者面對新狀況時,腦袋裡跑的判斷視角。中英雙語(zh + en),開源歡迎其他家屬補充。

    6 條視角

    • 視角 1:失智不是失能 — 她不是壞了,是用不一樣的方式運轉
    • 視角 2:用加法對抗減法 — 認知衰退是減法,加新刺激抵銷
    • 視角 3:躁動不是無聊 — 行為背後通常有具體 trigger(尿急、肚子餓、燈太亮)
    • 視角 4:動線是功能可及性 — 她做不到不一定是失能,可能是動線設計
    • 視角 5:誠實版優於善意包裝 — 不要編故事騙她,她感受得到
    • 視角 6:手冊是網狀不是清單 — 沒有「按順序做完」這種事

    caveat 自註:Handbook 自己寫了「⚠️ 不要把任何視角當絕對」 —— 「這 6 條視角是我寫家中照護手冊時用的判斷方式,不是失智照護的真理」。比如「視角 2 加法對抗減法」跟主流的「懷舊治療(Reminiscence Therapy)」(用過去記憶喚起情感連結)有衝突。Tom 在文章明文承認這個衝突。

    這個工具不解決具體問題,而是在其他工具給不了答案時,**回頭問:我用什麼 frame 在想這件事?** Handbook 是網狀的,在失智路上某些時刻會用上。

    場景 12:長輩 / 病人 / 嬰兒選營養品 — health-drinks

    health-drinks 是19 款醫療營養品 + 嬰幼兒配方 + 高蛋白補充品的並排比較工具(180-280ml 容量範圍)。**不是市售飲料**,是給病人 / 長輩 / 嬰兒喝的營養補充品(葡勝納 / 完膳 / 安素 / S-26 / 倍速益 / 康健等)。

    三重使用者

    • Tom 自家 — 失智媽媽吞嚥退化階段選低糖高蛋白配方
    • 藥師朋友 — 跟客戶解釋「葡勝納原味跟菁選香草」差別時要快速比成分
    • 藥局客戶 — 拿出手機看比較表自己挑(藥師沒空講)

    資料流:拍包裝 → AI 擷取 → 手填 drinks.js

    每加新飲品的流程:

    1. 藥局買回來拍包裝側標籤
    2. AI(Gemini / Claude)從圖片擷取營養成分
    3. **手填**到 `data/drinks.js`(brain memory `health-drinks-data-entry.md` 「拍標籤說『加進去』就全填,包含微量元素,不可自行省略」原則 — `feedback_nutrition_label_fulldata.md` lesson)
    4. UI 並排比熱量 / 糖 / 鈉 / 蛋白質 / 脂肪 / 維生素 / 礦物質

    monorepo 唯一 CDN 例外:health-drinks 較早建置仍用 Chart.js + Google Fonts CDN(Noto Sans TC)。圖表呈現用 Chart.js 4,字體用 Noto Sans TC。違反 monorepo 0 CDN 強制規定 —— 計畫之後遷移成 inline,但目前留著作為「歷史包袱」example。新工具不准走這條路。

    何時不該用工具,直接找專業

    工具看到「預期外的 pattern」就停用,改找專業。具體訊號:

    訊號 該找誰 為什麼
    突然拒食 ≥ 3 天 神經科 / 急診 可能是 UTI / 吞嚥退化 / 譫妄,不是「沒胃口」
    行為驟變 24 小時內 急診先排除 UTI 中老年 UTI 常表現為譫妄不是發燒
    跌倒 119 / 急診 頭部撞擊、髖關節骨折看似輕微會延遲爆發
    照顧者撐不住 1925 安心專線 / 共照中心個管師 Burnout / 預期性悲傷有專業 evidence-based 支援
    小孩發燒 ≥ 39°C 連 2 天 兒科 / 急診 tools 不會幫你看川崎 / 流感 / 腸病毒

    原則:工具是 baseline 操作,異常事件外溢就 escalate。不要用「我家工具上看了沒問題」當不去看醫生的理由。

    工具互鎖:資料閉環怎麼運作

    14 個工具裡不是每個都獨立。失智照護核心 4 個工具串成 daily/weekly 閉環:

    每天:
    [居服員 / 我] 寫白板 → 拍照傳 Telegram
        ↓
    [白板 OCR Bot] Gemini OCR + confirm
        ↓
    [iDempiere Z_momSystem] 每天一筆紀錄
    
    每月:
    [mom-clinic-companion] 拉一個月紀錄
        ↓
    產出回診清單 → 神經科看具體 evidence
        ↓
    醫師調藥決定寫回 iDempiere
    
    每月共照中心月聚:
    [care-handbook 援手系統] 個管師有資料看可以諮詢
        ↓
    社工 / 物理治療 介入決定

    關鍵設計:資料只進 iDempiere 一次,各工具讀同一個 source。不是 OCR Bot 一個資料庫、mom-clinic 另一個資料庫 — 那會分裂。所有寫入收斂到 iDempiere,所有讀取從 iDempiere 出來。

    iDempiere 是台灣 open source ERP,我把它當 PHR (Personal Health Record) 用。對家庭規模 overkill,但有 Z_table 自訂 + REST API + audit log 的 enterprise 級資料管理,這條主線運轉半年沒掉資料。

    不是處方,是 invitation

    這套工具不是處方。每家狀況不同 — 有的家有外籍看護工、有的家三代同堂家屬 backup 充足、有的家在偏鄉服務不完整。我家是「白天 solo + 配偶藥師有正職 + 兒女幼小 + 父母 secondary 經驗 15 年」這個極窄 niche,所以工具 design 偏向「降低 solo 啟動 friction」。

    如果你家狀況跟我接近,這套工具開箱可用;不接近,把它當「一個照護者怎麼設計自家工具」的 reference,fork 改成你家用的。原始碼在 GitHub,部署在 tm731531.github.io/dementia-care

    有相關問題歡迎在 blog 留言 — 工具不主動推,但方法 / 經驗 / 踩過的坑歡迎交流。

  • iDempiere Plugin 開發完整指南:踩遍台灣統一發票的 10 個坑

    重點摘要

    • 我們用兩天為 iDempiere 12.0 從零開發了台灣統一發票 OSGi Plugin,踩了至少 7 個主要的坑
    • 最燒時間的 bug:SeqNoGrid 缺失導致 Grid View 在按「新增」時拋出 IndexOutOfBoundsException——官方文件完全沒提
    • EventHandler 模式是 iDempiere 12 的正確驗證方式,ModelValidator 不透過 OSGi DS 登錄根本不執行
    • 2Pack ZIP 結構、事件主題比較、雙 JVM 部署問題——每一個都能讓你白白浪費半天

    這篇文章記錄了我們為 iDempiere 12.0 從零開發台灣統一發票(統一發票)與營業稅申報 Plugin 的完整過程。如果你正在開發 iDempiere Plugin,這篇文章能幫你少掉至少一天的除錯時間。

    為什麼要做這個 Plugin?

    台灣的統一發票制度獨特而嚴格:每兩個月一期的雙月申報週期、財政部核配的字軌號碼(如 AA01234567)、三聯式(B2B)和二聯式(B2C)的不同計稅方式、以及嚴格的 FLOOR 取捨規定。

    這些都是 iDempiere 標準功能完全沒有覆蓋的。既有的 C_Invoice 系統不知道什麼是「字軌」,不知道進項折讓要在哪一期申報,更不知道 401 申報表長什麼樣子。所以我們做了這個 Plugin。

    系統架構概覽:四張表對應四個階段

    iDempiere Plugin 開發的核心是理清業務模型。台灣統一發票有清楚的生命週期,我們用四張資料表對應:

    財政部核配字軌
          │
          ▼
    TW_InvoicePrefix      ← 字軌管理(AA、AB 等,號碼範圍、有效期)
          │ 開立發票時
          ▼
    TW_Invoice_Prefix_Map ← 每張發票的字軌號碼對應(含買方統一編號)
          │ 如有退貨/折讓
          ▼
    TW_InvoiceAdjustment  ← 銷項/進項折讓(方向、期別、超期申報)
          │ 期末
          ▼
    TW_TaxStatement       ← 401 申報表(銷項稅、進項稅、留抵、應納稅額)

    技術層面:OSGi bundle(Equinox),2Pack 管理 dictionary,AbstractEventHandler 做 PO 事件驗證,服務層純 Java 方便單元測試。最終成品:87 個測試全部通過,4 張 TW_* 資料表,4 個 iDempiere 視窗。

    把台灣稅法翻成 Java 程式碼

    稅額計算:FLOOR,不是 ROUND

    這是財政部的明確規定,一律捨去,不四捨五入。聽起來簡單,但在邊界值差一塊錢,申報出去就是對不上帳:

    // 二聯式(B2C):含稅金額已知,反推銷售額和稅額
    BigDecimal saleAmount = grossAmount
        .divide(new BigDecimal("1.05"), 0, RoundingMode.FLOOR);
    BigDecimal taxAmount = saleAmount
        .multiply(new BigDecimal("0.05"))
        .setScale(0, RoundingMode.FLOOR);
    
    // 注意:taxAmount ≠ grossAmount - saleAmount
    // 財政部規定:用前者(先算銷售額,再乘 5%)

    字軌狀態機:單向前進

    字軌狀態只能往前走,不能回頭:I(未啟用)→ A(使用中)→ C(已用完)。這是台灣稅法要求,已啟用的字軌必須被追蹤,不能撤回。

    // EventHandler 在 PO_BEFORE_CHANGE 攔截
    if ("A".equals(oldStatus) && "I".equals(newStatus))
        throw new AdempiereException("使用中字軌不可降回未啟用(台灣稅法)");
    if ("C".equals(oldStatus))
        throw new AdempiereException("已用完字軌不可再變更狀態");

    雙月申報期別計算

    // 從發票月份算期別
    int period = (month - 1) / 2 + 1;  // 1=1-2月, 2=3-4月 ... 6=11-12月

    七個真實踩坑紀錄

    坑 1:事件主題比較,一個字毀掉一切

    這個 bug 讓狀態驗證完全靜默失效了很久。症狀是:程式碼看起來完全正確,但驗證從來不觸發。

    // 錯誤 — 永遠不會觸發
    if (topic.endsWith("po_before_change")) { ... }
    
    // 正確
    if (IEventTopics.PO_BEFORE_CHANGE.equals(topic)) { ... }

    iDempiere 的 topic 格式是 org/adempiere/po/PO_BEFORE_CHANGE(全大寫),endsWith 配對小寫後綴當然不匹配。靜默失效最可怕——不報錯,只是所有驗證都沒執行。規則:事件主題永遠用 IEventTopics 常數。

    坑 2:ModelValidator 是個陷阱

    Validator 類別一開始實作了完整的 ModelValidator 介面(initialize、modelChange、docValidate、login…),程式碼寫得很整齊,但驗證從來不執行。

    原因:ModelValidator 需要透過 ModelValidationEngine.addModelValidator() 主動登錄。單純 implements ModelValidator + @Component 什麼都不會發生。

    正確的 iDempiere 12 Plugin 驗證模式:

    // *Validator.java    → 純靜態方法,不實作任何介面
    // *EventHandler.java → extends AbstractEventHandler,OSGI-INF/*.xml 登錄為 DS 服務
    
    // EventHandler 捕捉 OSGi 事件,呼叫 Validator 的靜態方法做驗證
    @Component(immediate = true, service = IEventHandler.class)
    public class InvoicePrefixEventHandler extends AbstractEventHandler {
        @Override
        protected void doHandleEvent(Event event) {
            String topic = (String) event.getProperty(IEventTopics.EVENT_TOPIC);
            if (IEventTopics.PO_BEFORE_CHANGE.equals(topic)) {
                String err = InvoicePrefixValidator.validateStatusTransition(...);
                if (err != null) throw new AdempiereException(err);
            }
        }
    }

    坑 3:2Pack ZIP 打包方式,犯了兩次

    iDempiere 的 PackIn 解壓 ZIP 到 /tmp/,預期路徑是 /tmp/tw_invoice_system/dict/PackOut.xml

    第一次:ZIP 裡多了 2pack/ 前綴層。第二次:用了 zip -j(junk paths),把所有目錄剝掉,路徑變成 /tmp/PackOut.xml/dict/PackOut.xml——把文件名當目錄了。

    # 正確打包方式
    mkdir -p /tmp/b/tw_invoice_system/dict
    cp PackOut.xml /tmp/b/tw_invoice_system/dict/
    cd /tmp/b && zip -r 2Pack_1.0.10.zip tw_invoice_system/
    
    # 永遠要驗證結構
    unzip -l 2Pack_1.0.10.zip

    坑 4:SeqNoGrid 缺失 → Grid View 崩潰(最燒時間)

    這是整個過程中最「無辜」的 bug——不是邏輯錯誤,是 XML 少了兩個欄位。所有 73 個 AD_Field 元素都缺少 <SeqNoGrid> 和正確的 <IsDisplayedGrid>

    iDempiere 12 的 Grid View 渲染器在初始化行編輯器時需要 SeqNoGrid 做排序依據,全部 NULL 導致:

    java.lang.IndexOutOfBoundsException: Index: 2
        at GridTabRowRenderer.editCurrentRow

    任何視窗,只要在 Grid 模式下按「新增」,必爆。這個 bug 在官方文件裡完全沒有提到。修復:補上這兩個欄位。

    <SeqNo>10</SeqNo>
    <SeqNoGrid>10</SeqNoGrid>        <!-- = SeqNo,顯示欄位 -->
    <IsDisplayedGrid>Y</IsDisplayedGrid>
    
    <!-- 隱藏欄位(SeqNo=0)-->
    <SeqNoGrid>0</SeqNoGrid>
    <IsDisplayedGrid>N</IsDisplayedGrid>

    坑 5:兩個 JVM 搶 Port,Deploy 進錯的那個

    症狀很奇怪:OSGi telnet console 顯示 bundle ACTIVE ✅,但 Web Console 找不到這個 bundle ❌。

    最後發現機器上跑著兩個 iDempiere JVM:

    JVM 擁有 Port 說明
    JVM-A(舊的)8080/8443Web 瀏覽器連這個
    JVM-B(新的)12612OSGi telnet 連這個

    deploy.sh 透過 telnet 把 bundle 裝進了 JVM-B,但使用者看的 Web Console 是 JVM-A。原因是 idempiere-server.sh 有 restart loop,systemctl restart 啟動了新 JVM,但舊 JVM 沒死。

    # 診斷方法
    ps aux | grep java | grep -v grep | wc -l  # > 1 就是這個問題
    
    # 修復:kill 兩個 JVM,等 30 秒讓 port 釋放,再 restart
    sudo kill <pid1> <pid2>
    sleep 30
    sudo systemctl restart idempiere

    坑 6:AD_Field UUID 衝突

    2Pack 重裝時,iDempiere 已為新建的 Tab 自動插入標準欄位(AD_Client_ID、AD_Org_ID、IsActive)。當 PackIn 再次嘗試用不同 UUID 插入同一個 (tab_id, column_id) 組合時,違反了 UNIQUE(ad_tab_id, ad_column_id) 約束,拋出 POSaveFailedException

    解法:對這類「系統可能已存在」的標準欄位,PackOut.xml 使用固定的 placeholder UUID。PackIn 遇到重複就 UPDATE 而不是 INSERT。升版 UUID 策略:已存在的 field → 保留原 UUID;新增的 field → 才用新的 uuid4。不要為了「整齊」換掉既有 UUID。

    坑 7:清除 DB 做全新安裝——FK 刪除順序

    當要做「完整卸載 → 清 DB → 重裝」的驗證時,刪資料的順序錯了好幾次。

    正確順序:AD_Field → AD_Tab → AD_Window,每一步都有 FK 指向下一個。特別注意:AD_PreferenceAD_Menu 也會 FK 到 AD_Window,忘記刪這兩個就卡住。另外:ad_package_imp 記錄了 2Pack 安裝歷史,不清掉的話 Incremental2PackActivator 判定「已安裝過同版本」就跳過不執行。

    如果重來一次,我們會怎麼做

    1. 先建立 PackOut.xml 驗證腳本

    每次 2Pack 安裝後自動跑這些 SQL,出問題立刻知道,不用等到 UI 爆炸:

    -- SeqNoGrid 是否設定
    SELECT tablename, count(*) FILTER (WHERE seqnogrid > 0) ok
    FROM ad_table JOIN ad_tab ... JOIN ad_field ...
    WHERE tablename LIKE 'TW_%' GROUP BY tablename;
    
    -- _UU 欄位是否 updateable
    SELECT columnname, isupdateable FROM ad_column
    WHERE tablename LIKE 'TW_%' AND columnname LIKE '%_UU';

    2. 把 ZIP 結構驗證寫進 Maven build

    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <executions>
        <execution>
          <phase>verify</phase>
          <goals><goal>exec</goal></goals>
          <configuration>
            <executable>bash</executable>
            <arguments>
              <argument>-c</argument>
              <argument>unzip -l resources/META-INF/2Pack_*.zip | grep -q "dict/PackOut.xml"</argument>
            </arguments>
          </configuration>
        </execution>
      </executions>
    </plugin>

    3. 每次 commit 前跑 deploy.sh –check

    加一個 dry-run 模式,只驗證 JAR 可部署、OSGi console 可連線、bundle 存在,不實際更新。讓這個檢查成為 commit hook。

    給下一個要做 iDempiere Plugin 的人

    iDempiere 的文件很少,很多行為只有讀原始碼才能理解。以下是花最多時間搞懂的六件事:

    # 規則 說明
    1ModelValidator 不是 OSGi 服務@Component 不會讓它跑起來,要用 EventHandler
    2SeqNoGrid 是 Grid View 必備欄位缺了不報錯,只在按「新增」時崩潰
    32Pack ZIP 結構有嚴格要求打包後一定要 unzip -l 驗證,絕不用 zip -j
    4_UU 欄位必須 IsUpdateable=Y否則 UUID 永遠 NULL
    5IEventTopics 常數不要用字串字面量比較 topic,靜默失效
    6Incremental2PackActivator 記住安裝歷史同版本不重裝,升版要改 ZIP 檔名

    後記:實作兩個流程(又踩了三個坑)

    文章發完當天,隨即著手實作原本標注為「計劃中功能」的兩支 SvrProcess

    • GenerateTaxStatementProcess — 聚合 TW_Invoice_Prefix_Map 的銷售資料、折讓,產生 TW_TaxStatement 申報記錄
    • ExportTaxReportProcess — 讀取 TW_TaxStatement,輸出財政部格式 CSV

    同時也需要把這兩個流程透過 2Pack 登錄到 iDempiere 的 AD_Process / AD_Menu,讓使用者可以從選單觸發。這一輪又多踩了幾個坑。

    坑 8:AD_Process_Para 的 AD_Process_ID 必須明確寫入

    2Pack 的元素處理器(ElementHandler)有一個隱藏的不一致性

    AD_Tab 時,把它放在 <AD_Window> 元素內,Tab 的 AD_Window_ID 會自動繼承父元素——不需要重複宣告。大多數巢狀元素都這樣工作。

    AD_Process_Para 不同。ProcessParaElementHandler 呼叫 filler.autoFill() 處理子元素,但不從父 <AD_Process> 讀取 context 填入 AD_Process_ID

    結果:2Pack 安裝過程看起來正常執行,沒有任何錯誤訊息,但 Process Para 根本沒有存入。直到手動查 DB 才發現空的。真正的錯誤需要翻 PostgreSQL log:

    tail -f /var/log/postgresql/postgresql-16-main.log
    # ERROR: null value in column "ad_process_id" violates not-null constraint

    修正:每個 <AD_Process_Para> 元素內都必須顯式宣告 AD_Process_ID

    <AD_Process_Para type="table">
      <AD_Process_ID reference="uuid" reference-key="AD_Process">{process-uuid}</AD_Process_ID>
      <Name>Statement Year</Name>
      ...
    </AD_Process_Para>

    坑 9:FieldLength NOT NULL(但 iDempiere log 不說)

    修好 AD_Process_ID 之後,再次安裝,再次失敗,再次查 PostgreSQL log:

    ERROR: null value in column "fieldlength" violates not-null constraint

    FieldLengthad_process_para 資料表中是 NOT NULL 欄位,但如果 PackOut.xml 沒有提供,iDempiere 的 log 只會說 Failed to save ProcessPara——沒有欄位名稱,沒有 SQL,什麼都沒有。

    不同 Reference 型別的預設長度:

    AD_Reference_ID 型別 FieldLength
    11Integer10
    17List1
    10String實際最大長度

    教訓:2Pack 的錯誤訊息有時候刻意模糊。遇到 Failed to save 之類的通用錯誤,直接去查 PostgreSQL log,那裡才有真相。

    坑 10:iDempiere 物理表在 adempiere schema,不在 public

    寫完 clean_reinstall.sh(一個用來清除所有 TW_* 字典並重新部署的腳本)後,發現 DROP TABLE 完全沒作用:

    DROP TABLE IF EXISTS TW_InvoicePrefix;  -- 執行成功,但表還在

    原來 iDempiere 12.0 把物理表建在 adempiere schema,而不是 public。用 information_schema.tables WHERE table_schema='public' 查詢,一張 TW_* 表都找不到。

    正確用法:

    -- 確認表存在
    SELECT tablename FROM pg_tables WHERE schemaname='adempiere' AND tablename ILIKE 'tw_%';
    
    -- 刪除表
    DROP TABLE IF EXISTS adempiere.TW_InvoicePrefix;
    DROP TABLE IF EXISTS adempiere.TW_Invoice_Prefix_Map;

    這也影響 psql 互動查詢——連線後預設 search_path 如果不含 adempiere,直接 SELECT * FROM TW_InvoicePrefix 會找不到表。

    SvrProcess 實作要點

    SvrProcess 的標準結構很直覺——prepare() 讀參數、doIt() 做事。幾個需要注意的地方:

    • 不要呼叫 ps.setAD_Client_ID():那是 PO 類別的 protected 方法,不是 PreparedStatement 的方法。在 SvrProcess 裡用 getAD_Client_ID() 取值,直接 ps.setInt(1, getAD_Client_ID())
    • DB.prepareStatement() 而不是 JDBC 直接連線:iDempiere 的 DB class 管理連線池和事務,不要繞過它。
    • 記得 DB.close(rs, ps):在 finally block 釋放資源。

    clean_reinstall.sh — 開發期間的救命工具

    開發期間反覆修改 PackOut.xml,每次都要手動清資料庫重裝,非常繁瑣。寫了一個腳本自動化整個流程:

    1. 依 FK 順序刪除所有 TW 字典(Window_Access → Process_Access → Field → Tab → Menu → Window → Process_Para → Process)
    2. Drop 物理表(adempiere.TW_*
    3. 清除後設資料(Column → Table → Sequence → Element → Reference → EntityType)
    4. 清 AD_Package_Imp_Detail / AD_Package_Imp(注意:Detail 要先刪,因為有 FK)
    5. 呼叫 deploy.sh 重新部署

    FK 刪除順序是最麻煩的部分——錯一個順序就會碰到 FK 違規,整個腳本失敗。從失敗中整理出來的正確順序如上。

    最終成果(v1.0.11)

    Bundle:    tw.idempiere.invoice.tax v1.0.0 (2Pack v1.0.11)
    Tests:     89 個,全數通過
    Tables:    4 張 TW_* 資料表
    Windows:   4 個 iDempiere 視窗
    Processes: 2 個(GenerateTaxStatement + ExportTaxReport)
    Fields:    73 個 AD_Field(含正確 SeqNoGrid)
    Menu:      7 個項目(1 父選單 + 4 視窗 + 2 流程)
    Status:    ACTIVE,Grid View 正常,流程可從選單觸發
  • 認知與社交情緒發展:思考力、專注力、情緒調節指南

    🧠 孩子的認知、社交、情緒發展正常嗎?本文整理 0-6 歲認知與社交情緒發展里程碑,包含 Parten 遊戲階段理論、情緒調節四步驟,以及專注力發展對照。

    (閱讀全文…)

  • 托嬰、托幼、幼兒園完整指南:選園、適應期、分離焦慮

    🏫 托嬰中心、保母、幼兒園怎麼選?本文完整比較台灣各類托育選項、選園必查事項、入園準備清單,以及分離焦慮處理與適應期陪伴技巧。

    (閱讀全文…)

  • 語言發展里程碑:0-6歲寶寶說話能力完整追蹤

    🗣️ 孩子幾歲會說話?詞彙量夠不夠?本文整理 0-6 歲語言發展里程碑,幫助你追蹤孩子的語言進度,了解何時需要評估,以及如何促進語言發展。

    (閱讀全文…)