![]()
大家好!👋
我目前正在開發The Last Signal,這是一個開源的末日後 MMORPG 專案。
這個專案以Rust 和 Python為基礎,特別注重網路、伺服器架構、測試,並最終建構一個持久化的多人遊戲世界。
專案仍在開發階段,因此有許多部分可以探索、改進和建構。
我們的目標是打造一個多人末日後世界,讓玩家能夠探索、互動、戰鬥、交易,並創造屬於自己的故事。
我目前並非一次建構所有功能,而是專注於開發專案的基礎:客戶端與伺服器之間的通訊、封包處理、測試、CI 以及整體架構。
目前其中一個技術重點是 Python 客戶端與 Rust 伺服器之間的通訊。
專案擁有自己的封包系統,使用不同類型的封包在兩端之間進行通訊。
我目前正在處理的事項包括:
這是 Rust 貢獻者可以對專案產生直接影響的領域之一。
專案的加密部分非常實驗性且仍處於早期階段。
我正在嘗試各種想法,並探索加密系統如何融入這個專案。
目前並非以生產環境可用或安全的加密方式呈現。
我實際上正在尋找能夠挑戰設計、找出弱點與假設,並幫助判斷哪些方法值得進一步探索的人。
對密碼學、密碼分析或安全性有興趣的人在這裡會非常受到歡迎。
我目前正在尋找有興趣參與開源專案的人。
協助以下領域:
協助以下事項:
加密工作才剛開始。
可能的貢獻包括:
你不需要立即撰寫加密程式碼。一份好的技術分析已經是非常有價值的貢獻。
協助讓新開發者更容易理解專案:
專案也有 GitHub Actions 工作流程,可以進行改進與維護。
歡迎參與以下事項:
的貢獻。
我已經建立了幾個 GitHub Issues,專門設計作為貢獻者的切入點。
目前的領域包括:
你不需要先理解整個專案才能貢獻。
小型貢獻也非常歡迎。
如果你正在學習 Rust 或 Python,並希望在真實的開源專案中累積經驗,歡迎前來貢獻。
我特別對喜歡以下事情的人感興趣:
你可以透過撰寫程式碼、測試、撰寫文件、檢視,或單純提供有建設性的技術回饋來貢獻。
專案還很年輕,因此我並不執著於目前的每一個實作。
如果你看到可以改進的設計,我寧願聽到有充分理由的批評,也不希望壞的設計留在專案中。
我們的目標是透過合作與討論來打造更好的東西。
GitHub:
https://github.com/DDCoder23/The-last-signal-
此儲存庫包含原始碼、文件和開放的 Issues。
如果這個專案讓你感興趣,請查看儲存庫,並歡迎:
我期待認識那些想要一起學習、實驗和打造事物的人。🦀🐍🚀
感謝閱讀!
https://dev.to/ddcoder23/im-building-an-open-source-mmorpg-with-rust-python-join-the-project-2lp0
![]()
AI 採用正變得更容易。擴展 AI 則不然。
模型能力更強。API 更容易存取。Copilot 可以快速部署。團隊可以在幾天內原型化有用的工作流程。
然而許多組織仍難以將這些活動轉化為持久的能力。
原因越來越清楚:AI 無法僅透過技術來擴展。它透過營運模式來擴展。
這意味著決定誰擁有 AI、如何選擇使用案例、如何治理風險、如何分享學習、如何讓人類判斷保持在迴路中,以及如何讓成功的實驗成為日常工作的一部分。
這就是為什麼AI 營運模式這個詞正變得越來越重要。在 2026 年,Deloitte 報告了一個驚人的差距:雖然許多技術領導者相信他們能夠大規模部署和治理 AI,但近四分之三仍預期其營運模式將在 12 到 18 個月內改變。問題是從「我們能使用 AI 嗎?」轉移到「組織能否良好地吸收它?」
這是另一個不同的問題。
AI 營運模式是決定 AI 決策如何制定、治理、資助、建置、採用和改進的組織系統。
它不僅僅是一份 AI 策略文件。它不是 AI 治理政策。它也不是一個換了新名稱的中央 AI 團隊。
一個有用的 AI 營運模式至少連結六件事:
技術很重要。但圍繞技術的模式決定它是否成為能力,還是停留在實驗階段。
大多數組織並不缺乏想法。
他們有使用案例清單。
客服想要摘要。財務想要預測。行銷想要內容加速。產品想要研究合成。工程想要編碼協助。營運想要自動化。領導想要更好的決策支援。
常見的回應是啟動試點。
試點很有用,因為它們降低了學習成本。但當每個團隊獨立進行試點時,組織可能會產生一種新的碎片化:
結果可能看起來像「很多 AI」,但沒有多少機構能力。
這就是 AI 營運模式變得有用的地方。它創造了一種讓學習能夠累積而非在每個團隊中重置的方式。
理解 AI 採用的一種方式是透過三個互動的視角:心理學、技術與組織。
這很重要,因為 AI 同時改變這三者。
一個 AI 系統在技術上可能極佳,但如果人們不信任它、不了解它或不知道何時該覆寫它,它仍然會失敗。
採用受到以下問題的影響:
這就是為什麼「訓練」這個詞對 AI 採用來說太狹隘。
真正的問題是行為。
AI 營運模式必須創造信心而不造成自滿。它應該讓良好的判斷更容易,而不僅是讓 AI 可用。
第二層是技術性的。
AI 需要存取資料、工具、工作流程和應用程式。隨著能力增加,架構和控制的重要性也隨之增加。
因此組織需要對以下問題有明確的答案:
這就是標準和風險框架重要的地方。NIST 的 AI 風險管理框架及其生成式 AI 概況強調生命週期風險管理,而 ISO/IEC 42001 將 AI 視為管理系統問題,而非一次性技術控制。
這些框架很有用,因為它們強化了一個簡單的觀點:負責任的 AI 需要圍繞技術的可重複組織流程。
第三層是組織性的。
必須有人負責這些決策。
這聽起來很明顯,但 AI 常常跨越現有的界線。一個面向客戶的 AI 功能可能涉及產品、技術、法律、安全、資料、營運和客服。一個編碼助理可能影響工程品質、智慧財產、安全和生產力衡量。一個內部代理程式可能觸及多個團隊擁有的系統。
傳統的組織圖不會自動解決這些問題。
因此 AI 營運模式必須定義:
沒有這種明確性,治理就會變成排隊,而交付就會變成談判。
常見的 AI 營運模式問題是 AI 是否應該集中化。
集中化部分內容有充分理由。共享標準、架構、安全、評估、供應商決策和治理,如果每個業務單位獨立重建,會變得昂貴且不一致。
但集中化每個使用案例會產生另一個問題:最接近工作的人失去了所有權。
這就是為什麼許多企業 AI 模式正朝向聯邦式結構發展。
中心掌握應該共通的事項:
業務和產品團隊掌握需要情境的事項:
中心不應該成為每個 AI 決策都要等待的地方。
它的職責是讓良好的分散式決策成為可能。
這就是卓越中心可以提供幫助的地方——如果它被正確設計。
一個弱的 AI CoE 會變成審核請求的委員會。
一個較強的則會變成讓 AI 能力可重複的組織機制。
它的角色可能包括:
測試很簡單:這個 CoE 是否讓組織更有能力,而不會讓它更依賴?
Cralgo 在其關於卓越中心和技術作為組織系統的工作中探討了這個更廣泛的能力問題。
AI 治理常常被討論為控制問題。
它也是一個執行設計問題。
如果治理只在專案結束時發生,團隊要麼等太久,要麼繞過它。如果每個使用案例都接受相同的審核,低風險實驗會變得不必要地緩慢,而真正重要的風險可能獲得太少的關注。
更好的 AI 營運模式讓治理成比例。
例如:
使用核准企業資料的會議摘要工具可能只需要輕量級控制、明確的保留規則和基本的品質檢查。
推薦營運行動的 AI 系統可能需要更強的記錄、人類核准和明確的回滾路徑。
用於醫療保健、就業、財務決策或安全敏感營運等領域的 AI 可能需要獨立驗證、記錄證據、更嚴格的監控和正式的問責。
重點不是讓治理變得更小。
而是讓治理符合決策的後果。
隨著 AI 系統變得更有能力,組織可能會傾向於將更多決策移入系統。
但能力和權威並不相同。
一個模型可能能夠推薦行動,但不一定是擁有該行動的正確地方。
這種區別在代理程式能夠呼叫工具、更新系統、觸發工作流程或與客戶溝通時尤其重要。
關鍵的設計問題從:
AI 能做什麼?
轉變為:
AI 應該被允許做什麼,在什麼條件下,由誰的判斷圍繞它?
這就是為什麼 AI 的人類面向無法與技術面向分離。信任、注意力、決策和問責都塑造了成果。
在組織內擴展 AI 之前,領導團隊應該能夠清楚回答這些問題:
如果這些答案模糊,組織可能還沒有 AI 營運模式。它只有 AI 活動。
這兩者並不相同。
企業 AI 的下一個階段不會僅由誰能存取最強模型來決定。
存取正變得更容易。
更難的優勢是組織性的:良好決策、安全部署、快速學習、散布能力,以及在 AI 嵌入日常工作時保留判斷的能力。
這就是為什麼 AI 營運模式很重要。
技術改變了什麼變得可能。
人們決定它如何被理解和使用。
組織決定那個可能性是否成為可重複的能力。
成果來自這三者的結合。
Cralgo 是一家研究與技術公司,探索心理學、技術與組織如何塑造更好的成果。
探索 Cralgo、Technology,以及 Operating Model。
https://dev.to/cralgo/ai-operating-model-why-scaling-ai-is-an-organisational-design-problem-2cg9
![]()
2026 年 9 月 1 日
Ryan 與 Tim Lindholm 對談。Tim 是 Sun Microsystems 早期 Java 語言的貢獻者,他們聊了在 Java 剛誕生時打造這門史上最受歡迎的程式語言之一是什麼感覺、為什麼對 Java 團隊來說建立跨平台的 ABI 以與 Windows NT 競爭具有戰略重要性,以及 applet 最初只是個有趣的展示。

觀看 Cult.Repo 在 YouTube 推出的新紀錄片,深入了解 Java 的早期歷史以及打造它的人們。
在 LinkedIn 上與 Tim Lindholm 聯繫。
向使用者 gabuzo 致敬,他因回答 What is the standard method for generating a nonce in Python? 而獲得 Populist 徽章。
https://stackoverflow.blog/2026/09/01/the-good-ol-days-of-building-java/
https://www.worldprogramming.org/posts/the-good-ol-days-of-building-java-nuompu
![]()
小米喺8月24號嘅玄戒晶片技術溝通會上,亮相咗一款叫AI Cube嘅工程原型迷你電腦。呢部機用咗三顆自家玄戒晶片:O3、O100同D100,專為本地運行AI大模型而設計,可持續釋放高達150W效能。
其中玄戒O3係主處理器,配備10核CPU、16核G2-Ultra NX GPU同200 TOPS NPU;O100係高頻寬AI加速晶片,採用6nm 3D堆疊封裝,近存計算頻寬高達1.22TB/s;而D100就係3nm智駕AI晶片,有20核CPU同16核NPU,最高支援160GB統一記憶體。
機身用航天級鋁合金一體成型,帶有33874個CNC精密鏤孔。官方表示可以本地部署120B同3B大模型,仲支援快慢系統切換。目前O100同D100預計2027年商用,AI Cube本身就未公布售價同上市時間。
https://www.notebookcheck.net/Xiaomi-unveils-AI-Cube-mini-PC-with-three-Xring-chips-and-150-W-performance.1376717.0.html
![]()

OpenAI 已發布七月 Hugging Face 入侵事件的詳細驗屍報告,揭示其 AI 代理所做的遠遠超過逃離網路安全沙盒。
這些模型建立了未經授權的通訊網路、分享漏洞與憑證、在不同的評估運行中協調攻擊,最終入侵了 Hugging Face 以及 OpenAI 自身部分研究基礎設施。
OpenAI 的調查,在 CrowdStrike 的協助下,顯示該活動主要由一個未發布的研究模型驅動,稱為 Internal Model 1 (IM1),其規模被描述為與 GPT-5.6 Sol 相當。
問題始於五月在強化學習訓練期間。原本應該獨立運作的代理發現它們可以將檔案寫入 OpenAI 內部託管的 Artifactory 套件服務,實際上將其變成了一個臨時留言板。它們後來濫用 Artifactory 來轉發外部網際網路請求,並在 6 月 26 日前利用權杖更新漏洞取得了管理員等級的存取權。
Hugging Face 經營著最大的平台之一,用於託管與分發 AI 模型、資料集和機器學習應用程式。如先前報導,在其生產環境成為目標後,這些代理開始搜尋外部服務以尋找有助於解決困難 ExploitGym 網路安全挑戰的資訊。
在 OpenAI 於七月初重建 Artifactory 後,這些代理使用目錄名稱重建了它們的留言板,並恢復交換發現。OpenAI 表示這些模型開始在自己之間分工,有些搜尋憑證、有些開發漏洞、有些協調活動。有幾個代理將所形成的群體稱為「swarm」或「collective」。
在 7 月 10 日,代理恢復了 14 個具有寫入權限的公開暴露 Hugging Face 憑證。第二天,它們利用一個先前未知的涉及 HDF5 檔案的缺陷,從 Hugging Face 生產工作器取得機密,然後將該存取權與一個名為「RefJinja」的模板注入漏洞結合起來,在伺服器上執行命令。
到 7 月 12 日,這些代理已將存取權擴展到多個 Hugging Face 叢集,並取得了 Kubernetes、資料庫、訊息、原始碼儲存庫和雲端憑證。OpenAI 表示程式碼在數十台伺服器上被執行,其中一台系統取得 root 存取權,並存取了有限的私人資料。

OpenAI 的調查找出了該行為背後的幾個因素。代理學會了「獎勵駭客」行為,透過追求意外的捷徑來完成評估,持續在看似實際上無法解決的任務上工作,並隨著額外推理努力的提供而越來越多地探查基礎設施。在 898 個 ExploitGym 挑戰中,有 198 個先前從未被解決,而這些佔了透過臨時留言板討論的任務的 93%。
該公司還發現其最強的生產防護措施在評估環境中並不存在。回溯測試顯示,OpenAI 目前的思考鏈監控很可能會在 Hugging Face 被入侵前一天多就偵測到危險活動。
OpenAI 此後已隔離 IM1 的權重、暫停主要的邊界強化學習運行、強化其沙盒與網路隔離,並將思考鏈監控強制用於涉及 GPT-5.6 Sol 等級或更高模型的工具使用評估。嚴重警報現在需要停止運行,除非回應者在 30 分鐘內確定該警告是誤報。
OpenAI 稱該事件為「警告射擊」,顯示具備足夠能力的 AI 代理可以結合堅持、利用和自主協調來克服安全邊界。
如果您喜歡這篇文章,請務必在 X/Twitter 和 LinkedIn 上關注我們,以獲取更多獨家內容。
https://cyberinsider.com/openai-says-ai-agents-formed-a-swarm-before-breaching-hugging-face/
![]()

每一個季度輝達都公布超越前一季的破紀錄業績,已成為一種傳統。本週三也不例外,該公司公布營收達962億美元,年成長106%,這歸因於其AI硬體需求持續上升。但這樣的業績也伴隨著代價,因為公司必須對未來進行大量投資。在其2027會計年度第二季,輝達必須承諾採購高達1600億美元的記憶體,其中包括與SK海力士簽訂的記憶體供應協議。
深入了解 TH Premium:AI 與資料中心
輝達2027會計年度第二季(於2026年7月26日結束),其GAAP營收創下紀錄達962.21億美元,季成長18%,年成長106%。輝達淨利總計596.88億美元,年成長126%,毛利率達到75.0%。輝達運算與網路硬體銷售達到882.99億美元,季成長18%、年成長114%,而其繪圖硬體銷售則達到79.22億美元,季成長12%、年成長46%。
「AI已達到其轉捩點,」輝達創辦人暨執行長黃仁勳表示。「AI正在從事有用的工作。其符號(token)具有生產力且能帶來獲利。現在,運算是營收。而且需求正在加速。[…] 我們正處於新AI實驗室與新創公司的黃金時代,多個前沿實驗室並行擴展,一個蓬勃發展的開放模型生態系,以及實體AI開始上線 […]。AI基礎設施建置正全速進行。現在已全面量產的Vera Rubin,正是為了推動這個時刻而打造。」
輝達的業績主要由其資料中心級AI硬體銷售所驅動,各種客戶購買了890.23億美元的設備,季成長18%,年成長117%。超大規模雲端業者向輝達採購了487.10億美元的硬體(年成長102%、季成長13%),而來自AI雲端、工業與企業的營收則攀升至403.13億美元(年成長138%、季成長25%),這顯示雖然超大規模雲端業者仍向輝達採購更多設備,但ACIE部門的成長速度更快。輝達邊緣運算產品銷售額為71.98億美元(年成長27%、季成長13%),這意味著儘管GPU與記憶體短缺,個人電腦繪圖產品銷售依然強勁。
輝達預期其產品需求在未來數年仍將維持強勁。為了滿足這一需求,公司將長期採購承諾從2027會計年度第一季的1190億美元,提高至第二季的2790億美元。通常,輝達的長期供應承諾包括預付款以及在台積電的晶圓加工與先進封裝承諾,以及DRAM廠商生產的HBM記憶體。這一次,輝達明確表示,這些承諾的大部分「主要與記憶體採購有關」。
如此龐大的承諾顯示,公司預測未來數年對其資料中心AI產品的需求將大幅成長。在與財務分析師和投資人的電話會議中,公司表示客戶預測顯示明年需求將翻倍,但輝達目前認為其供應鏈只能支持約70%的成長。
「儘管我們的需求遠高於70%,但我們的供應讓我們能夠有信心地交付70%,」黃仁勳表示。「不受限制的情況下會高出很多、很多。[…] 我們已經確保了大量供應,但我們還需要更多。」
訂閱 Tom’s Hardware 最佳新聞與深度評測,直接送達您的收件匣。
有鑑於此,2790億美元的供應承諾不應被解讀為預防性庫存建立,而是確保出貨成長的策略性舉措。輝達實際上是在預訂記憶體和其他產能,因為它預期需求將超過供應鏈在至少2028會計年度結束前所能提供的量,正如其管理階層明確表示,供應至少在2028會計年度前仍將是瓶頸。
對於2027會計年度第三季,輝達預期營收約為1080億美元,上下浮動2%,其展望中未包含來自中國的資料中心運算營收,這是因為出口與進口許可的不確定性。公司預計GAAP毛利率約為74%,並預期GAAP營運費用約92億美元。

追蹤 Tom’s Hardware on Google News,或 將我們新增為偏好來源,以在您的資訊流中取得我們的最新新聞、分析與評測。
Anton Shilov 是 Tom’s Hardware 的特約撰稿人。在過去數十年間,他報導過從CPU與GPU到超級電腦,從現代製程技術與最新晶圓廠工具到高科技產業趨勢等各種主題。
![]()
Cloudflare 在其 Agents Week 期間宣布推出 Cloudflare Wallets,為 AI 代理程式提供穩定幣餘額,並提供 cloudflare.pay handle,以便在支付 API、資料與內容時出示。目前僅有領取 handle 的功能可用。資金注入與付款功能預計將在未來幾個月內推出。
這項已上線的功能已引發抱怨。在 Hacker News 上,留言者 merek 發現自己的公司名稱與多個變體已被搶注:
沒有域名驗證,這名使用者的意圖除了詐欺/冒充之外還能是什麼?
他補充,自己已經有一個冒充者在以他的品牌經營網站,並讓顧客感到混淆。留言者 nikolay 將此次推出與 Meta 處理保留使用者名稱的方式進行對比,Meta 會事先通知並提供平等的起跑點,並對此產品做出結論:
Cloudflare 的做法基本上是推我不要使用他們的產品,因為我無法取得自己的使用者名稱。
付款運行於 x402,該協議 repurposes HTTP 402 Payment Required 狀態碼,用於機器原生的微支付。Coinbase 最初提出此概念,目前由 Linux Foundation 主持,約有 40 位成員,包括 Cloudflare、Stripe、Visa、Mastercard、Google 與 Amazon Web Services。MCP 也走過同樣的路,從單一供應商轉移到 Agentic AI Foundation,理由相同。一個每個競爭者都必須實作的協議,若置於基金會內,對其創始者而言比自己掌控更有價值。
基金會主持解決了誰擁有規格的問題,但未解決誰能在其上競爭的問題,而 Cloudflare 較晚進入這個領域,該領域已有來自 AWS、Google Cloud、Circle 以及各大卡組織的解決方案。其論點在於分發能力。Wallets 是其於 7 月 1 日推出的 Monetization Gateway 的買方補充方案,後者讓網站與 API 能透過相同軌道向代理程式按請求收費。同時握有兩端意味著商家能向代理程式收費,而代理程式也能支付他們,橫跨 Cloudflare 所稱涵蓋 337 個城市、觸及約五分之一網站的網路。
數位留言者認為這篇公告與付款無關,而是關於其他事情。留言者 eddythompson80 指出,代理程式身分至今仍被困在個別系統內,因為 AWS IAM 指派的身分無法在不相關的網站上使用,而 OIDC 聯邦對一般網站來說太過複雜。障礙從來不是機制,而是無法就提供者達成共識:
同意單一 IdP 才是問題,目前大約有 40 個。
他的結論是 Cloudflare 看到了這個機會:
這有真正的需求,看起來 cloudflare 認為如果他們成為「網際網路代理程式身分提供者」,那麼就能對網際網路與 AI 使用擁有大量的權力與控制。
留言者 wxw 提出了平台版本的相同觀點,指出 Durable Objects 與 Workers 是良好的代理程式基礎元件,因此已經在使用它們的團隊不妨也採用 wallet、sandbox 與 AI gateway。其他人則沒那麼放心。留言者 Ycros 寫道 Cloudflare 不斷將自己插入一切事物之間,nater5000 回覆表示,一家在自家市場中打造有明確需求的產品的公司不需要進一步解釋。
值得仔細閱讀的部分是控制模型。每個帳戶持有人會獲得一個 Account Wallet,並可為每個代理程式建立獨立的 Virtual Wallets,從主帳戶提供資金,並受帳戶持有人設定的三項控制所限制:額度、核准商家的允許清單,以及最大交易金額。明確的目的是讓代理程式能夠測試與購買服務,而無需人類核准每一筆付款,並有硬上限來限制損害。
Cloudflare 儀表板中的 Account Wallets 與 per-agent Virtual Wallets(來源:Cloudflare 部落格)
這些基礎元件描述的是預算而非政策。額度是一個持續的總額。允許清單是一個集合成員資格測試。最大交易金額是一個每次請求的限制。每一個都是針對目前付款與固定限制進行評估,沒有一個能表達付款之間的關係。
平台團隊通常想要的規則會表達關係。一個代理程式只能支付它已經對照核准目錄檢查過的供應商。它不能在一小時內為同一件事支付兩個供應商。它必須在第一次向新商家購買前取得核准。每一個都需要針對序列而非目前請求進行推理。
並行性提出了相關問題。代理程式會平行發出動作,因此多筆付款可能在尚未扣減額度的情況下進行檢查,且每一筆都通過了它們總和已超過的上限。Cloudflare 尚未公布其額度在並行支出下的行為,這在讓代理程式無需逐筆核准即可交易前值得先確認。
這種模式並非 Cloudflare 特有。此領域的供應商推出的都是限制而非政策語言,而每一家都將這些限制的組合留給上層應用程式。
對正在評估代理程式付款的團隊來說,問題很明確。支出政策應該存在於錢包還是應用程式?當多個代理程式動作平行執行並使用同一筆預算時會發生什麼?以及供應商提供的是限制還是語言,因為這決定了有多少東西必須自行建置。
x402 是一條可運作的軌道,而誰來治理它的問題也已解決。一個代理程式在一連串付款中能夠支出多少,則尚未解決。
![]()
原文發表於 lavkesh.com
如今大多數公司都會告訴你,他們正在運用人工智慧,它已融入他們的營運中,而且正在改變一切。他們談論代理、模型,以及資料流動的方式。這是普遍的共識,是你在每場研討會上都會聽到的內容。但這些組織中,不到四成能夠指出其 AI 努力帶來了任何實際的利潤或成本節省。2026 年的史丹佛 AI 指數將這個數字定在 39%,這意味著大多數組織都在 AI 上花錢,卻沒有看到它反映在資產負債表上。
這種脫節感覺很熟悉,就像看著一個團隊慶祝新服務部署到正式環境,並將其稱為勝利。真正的勝利當然是該服務*為企業帶來什麼*,它如何解決客戶問題,或如何降低特定的營運成本。同樣的模式也出現在雲端遷移上,企業將一切搬到新的資料中心供應商並宣告勝利,結果卻發現成本增加且可靠性維持不變。
對新技術的熱情往往掩蓋了定義明確、可衡量成果的艱苦工作。當我在能源管理領域時,我們有一套能預測設備故障的系統。最初的興奮點在於預測準確度、假陽性與真陽性的比例。但真正的價值來自於我們能夠證明,根據這些預測採取行動後,非計畫性停機時間減少了特定百分比,從而節省了數百萬的生產損失和維修成本。這需要將 AI 輸出整合到維護排程中、訓練技術人員,並追蹤每次避免故障的財務影響。
這正是許多 AI 專案失敗之處。工程師打造出一個聰明的模型,產品團隊為它找到位置,領導階層宣布採用。大家都感覺良好。但接著專案預算膨脹、模型開始漂移,而維護它的營運成本開始侵蝕任何理論上的獲益。Gartner 預計明年將有超過 40% 的代理式 AI 專案被擱置,因為投資報酬率不明且成本過高。光說 AI 正在運行是不夠的;你還必須說出它正在賺取或節省什麼。
問題始於關於 AI 的討論大多是技術性或抱負性的。我們談論 AI *能* 做什麼,而不是*這個特定 AI* 正在為*這個特定項目* *實際* 做什麼。焦點轉移到採用指標——有多少使用者、有多少模型、每秒有多少推論——而不是業務指標,例如降低客戶流失率、加快交易處理速度,或可直接歸因於 AI 影響的銷售轉換率提升。
想想餵養這些模型所需的資料管線、持續的重新訓練、對偏差或漂移的監控。每個步驟都伴隨著成本,無論是基礎設施還是人力投入。如果你的 AI 正在自動化一項每月花費一百美元人力時間的任務,但 AI 本身每月運行和維護卻要花兩百美元,那你就沒有贏。這看起來很明顯,但我見過許多團隊過度專注於技術的「酷炫」,而忽略了基本的算術。
建立從 AI 功能到損益表的清晰可視線,需要工程、產品和財務團隊之間的合作,使用他們都能理解的語言。這意味著定義成功不僅是模型準確度,還要用金錢來衡量。你需要知道 AI 正在解決什麼問題、用 AI 解決它的成本是多少,以及替代方案的成本又是多少。若沒有這些,你只是在把錢砸在一個有前景的想法上。
也許最大的挑戰在於,衡量真正的最終獲利影響很困難,比計算部署了多少模型或處理了多少資料點還要難。這意味著要提出棘手的問題,有時是在初始投資多年後,並且願意承認某件事行不通。這意味著要把 AI 視為不是神奇子彈,而是工程工具箱中的另一項工具,它必須像任何其他軟體一樣證明自己的存在價值。
https://dev.to/lavkeshdwivedi/ai-is-everywhere-except-the-balance-sheet-184c
https://www.worldprogramming.org/posts/ai-is-everywhere-except-the-balance-sheet-8pdhrs
![]()
當 Python 腳本開始消耗數百 MB 的 RAM 時,直覺反應通常是改用更快的語言或更進階的資料庫。但大多數情況下,真正的問題簡單得多:程式碼一次就把整個資料集載入記憶體。Generators(Python 的惰性求值主力)讓你一次只處理一筆資料,它們是你能加入 Python 工具箱中最高槓桿的概念之一。
考慮一個常見任務:讀取大型日誌檔案並計算有多少行包含「error」這個字。最直接的寫法看起來無害:
def count_errors(path):
with open(path) as f:
lines = f.readlines() # loads EVERYTHING into memory
return sum(1 for line in lines if "error" in line.lower())
Enter fullscreen mode
Exit fullscreen mode
對 10 MB 的檔案來說這執行得很好。但對 4 GB 的日誌檔案,readlines() 會很開心地試圖把全部 4 GB 都放在 RAM 中——而在記憶體上限只有 2 GB 的共享伺服器上,這個行程就會被終止。修正方式只要改一個字:
def count_errors(path):
with open(path) as f:
return sum(1 for line in f if "error" in line.lower())
Enter fullscreen mode
Exit fullscreen mode
直接對檔案物件進行疊代會一次產生一行。作業系統會串流它,而你的記憶體用量不管檔案多大都會保持平穩。這就是 generator 的本質:它計算並產生一個值,然後暫停,直到下一個值被請求為止。
Generator 是一種特殊的 iterator,可以透過 generator 函式或 generator 運算式建立。其定義特徵是 yield 關鍵字。當函式包含 yield 時,呼叫它並不會執行函式主體——而是回傳一個你可以疊代的 generator 物件。
def read_large_file(path):
"""Yield one line at a time from a potentially huge file."""
with open(path) as f:
for line in f:
yield line.strip()
Enter fullscreen mode
Exit fullscreen mode
與會建立並回傳完整 list 的普通函式比較:
def read_all_lines(path):
with open(path) as f:
return [line.strip() for line in f] # materializes the whole list
Enter fullscreen mode
Exit fullscreen mode
Generator 版本幾乎使用固定記憶體。List 版本則會隨著檔案大小而擴展。對 5 GB CSV 進行互動式探索時,這種差異決定了工具是能即時回應還是讓機器凍結。
Python 提供簡潔的語法來建立 generator,其外觀與 list comprehensions 相似。唯一的差別是使用小括號而非中括號:
squares_list = [x*x for x in range(1_000_000)] # list: ~8 MB allocated at once
squares_gen = (x*x for x in range(1_000_000)) # generator: lazy, one at a time
Enter fullscreen mode
Exit fullscreen mode
要注意一個細微之處:generator 是單次使用的。一旦被消耗,就會耗盡。如果你需要疊代兩次,就必須重新建立 generator 或把結果存成 list。
gen = (x for x in range(5))
print(list(gen)) # [0, 1, 2, 3, 4]
print(list(gen)) # [] -- already exhausted!
Enter fullscreen mode
Exit fullscreen mode
islice 進行分塊處理有時候你確實需要 generator 的一小段,但切片語法只能用在 sequence 上。itertools.islice 函式會惰性地逐步處理 generator,並回傳固定數量的項目:
from itertools import islice
def process_in_chunks(collection, chunk_size=1000):
iterator = iter(collection)
while True:
chunk = list(islice(iterator, chunk_size))
if not chunk:
break
process_chunk(chunk) # your batch logic here
Enter fullscreen mode
Exit fullscreen mode
這個模式非常適合將記錄分批送進資料庫,使用可管理的交易,而不是一次提交巨量資料。
因為 generator 是惰性產生值的,你可以把多個轉換串接起來,而不會具體化任何中間 list:
import re
from collections import Counter
def log_errors(path):
with open(path) as f:
pattern = re.compile(r"errors*:s*(w+)")
for line in f:
match = pattern.search(line)
if match:
yield match.group(1)
code_counts = Counter(log_errors("app.log"))
print(code_counts.most_common(5))
Enter fullscreen mode
Exit fullscreen mode
Counter 只需要與不同錯誤代碼的數量成比例的記憶體,這通常很小,而不是與日誌行數成比例。
yield from 快捷方式Generator 委託能讓一個 generator 乾淨地交接給另一個。yield from 會把來自內部 iterable 的每個項目轉發出去,這在組合資料管線時特別有用:
def read_lines(paths):
for path in paths:
with open(path) as f:
yield from f # delegate to the inner iterable
for line in read_lines(["a.log", "b.log", "c.log"]):
...
Enter fullscreen mode
Exit fullscreen mode
Generator 不是萬靈丹。了解它們的限制可以避免誤用:
| 情境 | 該使用 generator 嗎? | 原因 |
|---|---|---|
| 大型檔案、即時串流、無限序列 | ✅ 是 | 固定記憶體勝出 |
| 需要對元素進行隨機存取 | ❌ 否 | Generator 沒有索引 |
| 需要對相同資料疊代兩次 | ⚠️ 有時 | 必須重新建立或儲存 |
| 小型資料集 | 🤷 皆可 | 額外負擔不值得 |
| 隨機存取 / 回溯 | ❌ 否 | 只能單次通過 |
Generator 是一種單向串流。你無法倒帶,無法在不經過 0 到 4 的元素的情況下跳到第 5 個元素,也無法在不耗盡它的情況下知道它的長度。如果你的演算法需要隨機存取,請保留 list 或使用其他結構。
讓我們把這些片段組合起來。這個腳本讀取大型應用程式日誌、計算錯誤等級,並回報前五名的錯誤類型——同時不管檔案大小如何,都能保持記憶體用量平穩:
import re
from collections import Counter
from itertools import islice
PATTERN = re.compile(r"[(?P<level>w+)]s+.*?b(?P<code>w+Error)b", re.IGNORECASE)
def scan_errors(path):
with open(path) as f:
for line in f:
match = PATTERN.search(line)
if match:
yield match.groupdict()
def report(path, limit=5):
level_counts = Counter()
code_counts = Counter()
for chunk in iter(lambda: list(islice(scan_errors(path), 5000)), []):
for entry in chunk:
level_counts[entry["level"]] += 1
code_counts[entry["code"]] += 1
print("Levels:", level_counts.most_common())
print("Top codes:", code_counts.most_common(limit))
if __name__ == "__main__":
report("app.log")
Enter fullscreen mode
Exit fullscreen mode
iter(lambda: list(islice(...)), []) 迴圈是一種簡潔的方式,能拉取固定大小的批次直到 generator 耗盡。每個批次都很小,處理完後會被釋放,然後才處理下一個批次。
Generator 也可以透過 send() 接收 值,這讓它們變成輕量級的 coroutine。這在簡單的資料處理中很少需要,但它解鎖了雙向通訊:
def accumulator():
total = 0
while True:
received = yield total # yield current total, then wait for input
if received is not None:
total += received
acc = accumulator()
print(next(acc)) # 0 -- prime the generator
print(acc.send(10)) # 10
print(acc.send(5)) # 15
Enter fullscreen mode
Exit fullscreen mode
這個模式是更進階非同步模式和有狀態處理管線的基礎。對大多數日常任務來說你永遠不會需要它,但知道它的存在能幫助你在函式庫程式碼中遇到時認出底層機制。
如果你需要自訂的疊代行為並結合其他方法,可以建立一個實作 __iter__ 和 __next__ 的 iterator 類別。Generator 函式通常比較簡單,但類別形式在需要更豐富狀態的情況下值得了解:
class Countdown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current
Enter fullscreen mode
Exit fullscreen mode
當你接手一個被記憶體淹沒的腳本時,請執行以下檢查清單:
readlines() 替換為直接對檔案物件進行疊代。sum、any、all 或 Counter 的 list comprehensions 轉換為 generator 運算式。sys.getsizeof 在樣本上驗證——但請注意 generator 不會回報它們「可能」的內容,所以請測量你正在替換的 list 版本。Generator 讓 Python 能夠處理否則會耗盡記憶體的資料集,並鼓勵乾淨、串流的程式設計風格。核心概念雖然小卻很強大:
yield 將函式轉變成惰性 generator。itertools.islice 進行惰性分塊,並使用 yield from 進行委託。下次當腳本變得極慢或因記憶體不足而死亡時,找出那個隱藏的 readlines()。用 generator 替換它通常只要改兩行,就能將脆弱的腳本轉變成能擴展到任意大小檔案的版本。
![]()
LLM 現在可以呼叫工具,但將其輸出轉換成可信任的事件串流仍然是個難題。我們將 Claude 的函式呼叫連接至 SNS FIFO 主題,為您提供有序、去除重複的通知,讓下游 Lambda 函式能夠以零遺失保證進行消費。
當 LLM 決定要「publishAlert」時,您通常會希望警報能完全按照它產生的順序被處理。想像一個火警系統,先發出煙霧偵測器的警告,接著發出灑水器啟動指令。如果這兩則訊息順序顛倒,您可能會在火災尚未確認前就啟動灑水器。
FIFO 代表 First‑In‑First‑Out(先進先出)。SNS FIFO 主題保證具有相同 MessageGroupId 的訊息會按照發佈的確切順序傳遞給訂閱者。這與預設的「標準」SNS 主題不同,後者雖然傳遞迅速,但不保證順序。
用白話來說:SNS FIFO 就像一條單線道道路,配有紅綠燈讓車輛(訊息)一輛接一輛通過,絕不超車。
| 術語 | 含義 |
|---|---|
| Function calling | LLM 可以呼叫預先定義的工具(一段程式碼),而非僅回傳文字的功能。 |
| FIFO topic | 一種 SNS 主題,能保留屬於同一邏輯群組的訊息順序。 |
| MessageGroupId | 告訴 SNS 哪些訊息屬於同一群組以進行排序的識別碼。 |
| MessageDeduplicationId | 防止同一訊息在 5 分鐘窗口內被傳遞兩次的 token。 |
| Lambda | 一種無伺服器運算服務,會根據事件(例如 SNS 訊息)執行程式碼。 |
因為 LLM 可能快速產生許多警報,使用 FIFO 主題能讓您將 AI 視為確定性生產者,而非混亂的聊天機器。下游 Lambda 會看到警報的順序與模型發出它們的順序相同。
在能將任何東西發送到 SNS 之前,Claude(LLM)需要知道您所公開的工具。在 Claude 的術語中,tool schema 描述了名稱、描述以及它可以傳遞的引數 JSON 結構。
以下是一個最小的 TypeScript 程式碼片段,它建立了一個名為 publishAlert 的工具。函式主體使用 AWS SDK v3(@aws-sdk/client-sns)將訊息推送到 FIFO 主題。請注意 satisfies 關鍵字的使用——它告訴 TypeScript「此物件符合我描述的形狀,但不要拓寬型別」。
// src/claudeTool.ts
import { SNSClient, PublishCommand } from "@aws-sdk/client-sns";
// ---------------------------------------------------------------------
// 1️⃣ Prepare the SNS client – it will read credentials from the
// environment (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, etc.).
// ---------------------------------------------------------------------
const snsClient = new SNSClient({ region: "us-east-1" });
// ---------------------------------------------------------------------
// 2️⃣ Define the shape of the arguments Claude is allowed to send.
// This is the contract between the LLM and our code.
// ---------------------------------------------------------------------
type PublishAlertArgs = {
/** Human‑readable title of the alert */
title: string;
/** Optional JSON payload that downstream systems care about */
payload: Record<string, unknown>;
/** Group ID to keep ordering – e.g., a device ID or tenant ID */
groupId: string;
};
// ---------------------------------------------------------------------
// 3️⃣ The tool schema Claude will load. The `satisfies` keyword forces
// the object to be exactly the type we described above.
// ---------------------------------------------------------------------
export const publishAlertTool = {
name: "publishAlert",
description: "Publish an ordered alert to an SNS FIFO topic",
input_schema: {
type: "object",
properties: {
title: { type: "string" },
payload: { type: "object" },
groupId: { type: "string" },
},
required: ["title", "groupId"],
additionalProperties: false,
},
} satisfies { name: string; description: string; input_schema: object };
// ---------------------------------------------------------------------
// 4️⃣ The implementation that Claude will invoke. It builds the SNS
// PublishCommand with the required FIFO fields.
// ---------------------------------------------------------------------
export async function publishAlert(args: PublishAlertArgs): Promise<void> {
const { title, payload, groupId } = args;
// A stable deduplication ID – you could hash the payload, add a timestamp,
// or use a UUID if you need absolute uniqueness.
const dedupId = `${groupId}-${Date.now()}`;
const command = new PublishCommand({
// The ARN of the FIFO topic you created (ends with .fifo)
TopicArn: process.env.ALERTS_FIFO_TOPIC_ARN,
// Message body – keep it short; you can embed a JSON string if needed.
Message: JSON.stringify({ title, payload }),
// Guarantees ordering for all alerts that share this groupId.
MessageGroupId: groupId,
// Prevents the same alert from being sent twice within 5 minutes.
MessageDeduplicationId: dedupId,
});
// Send the command; any error will bubble up to Claude as a tool failure.
await snsClient.send(command);
}
Enter fullscreen mode
Exit fullscreen mode
提示:如果您需要在重試時達成exactly‑once 語意,請保持
MessageDeduplicationId為確定性的(例如 payload 的雜湊值)。
LLM 會在決定應該發出警報時呼叫 publishAlert。您的應用程式只需將 publishAlertTool 描述公開給 Claude,並將 publishAlert 實作繫結到工具處理程式即可。
建立 FIFO 主題是一次性的操作,但有幾個隱藏規則會讓許多工程師吃虧:
以下是一個小型腳本,它會建立 FIFO 主題、設定必要屬性,並新增 Lambda 訂閱。程式碼使用相同的 SDK(@aws-sdk/client-sns)並示範了容易忽略的細節。
// scripts/createFifoTopic.ts
import {
SNSClient,
CreateTopicCommand,
SubscribeCommand,
SetTopicAttributesCommand,
} from "@aws-sdk/client-sns";
// ---------------------------------------------------------------------
// 1️⃣ Initialize the client (same region as your Lambda)
// ---------------------------------------------------------------------
const sns = new SNSClient({ region: "us-east-1" });
async function main() {
// -----------------------------------------------------------------
// 2️⃣ Create the FIFO topic. The name MUST end with ".fifo".
// -----------------------------------------------------------------
const createResp = await sns.send(
new CreateTopicCommand({
Name: "ai-alerts.fifo",
Attributes: {
// FIFO topics need these two flags.
FifoTopic: "true",
// Optional: set a default message group to avoid errors if you forget.
// We'll enforce explicit group IDs later.
ContentBasedDeduplication: "false",
},
})
);
const topicArn = createResp.TopicArn!;
console.log("✅ FIFO topic created:", topicArn);
// -----------------------------------------------------------------
// 3️⃣ Attach a Lambda subscriber (replace with your function ARN).
// -----------------------------------------------------------------
const lambdaArn = process.env.ALERTS_LAMBDA_ARN!;
await sns.send(
new SubscribeCommand({
Protocol: "lambda",
TopicArn: topicArn,
Endpoint: lambdaArn,
})
);
console.log("✅ Lambda subscribed:", lambdaArn);
// -----------------------------------------------------------------
// 4️⃣ (Optional) Add a dead‑letter queue (DLQ) via a subscription
// attribute – note that SNS FIFO does NOT create a DLQ automatically.
// -----------------------------------------------------------------
await sns.send(
new SetTopicAttributesCommand({
TopicArn: topicArn,
AttributeName: "RedrivePolicy",
AttributeValue: JSON.stringify({
deadLetterTargetArn: process.env.ALERTS_DLQ_ARN,
}),
})
);
console.log("✅ DLQ attached (if provided).");
}
main().catch((err) => {
console.error("❌ Error creating topic:", err);
process.exit(1);
});
Enter fullscreen mode
Exit fullscreen mode
重要心得:FIFO 主題的可靠性取決於其訂閱者。確保您附加的 Lambda 已準備好處理重試,並考慮手動連接死信佇列,因為 SNS 預設不會新增。
去重複窗口——SNS 會記住每個 MessageDeduplicationId 達5 分鐘。如果您在該窗口內重複使用相同 ID,第二則訊息會在沒有任何錯誤的情況下消失。為了避免無聲丟失,請為每次發佈產生新的 ID(如範例所示),或啟用 ContentBasedDeduplication 讓 SNS 對 Message 主體進行雜湊。
跨群組的排序——SNS 只保證單一 MessageGroupId 內部的順序。如果您為兩個不同裝置發佈警報(groupId = "deviceA" 和 "deviceB"),它們的相對順序是不確定的。請設計您的下游邏輯,讓每個群組獨立處理,或將所有內容透過單一群組傳送(如果需要真正的全域順序,代價是降低吞吐量)。
現在警報已流入 SNS,我們需要一個尊重排序並記錄 payload 的 Lambda。我們目標的 Lambda 執行環境是 Node.js 22,最新的 LTS 版本。請注意兩個 Lambda 特定的陷阱:
require(esm) 可能會默默破壞現有的 Lambda 層——請務必使用原生 ESM(import …)或繼續使用 CommonJS。
以下是一個直接的處理程式,它會提取 SNS 訊息、剖析 JSON payload,並記錄警報。它也會明確確認訊息,方法是成功回傳;任何未捕捉的錯誤都會導致 SNS 重試傳遞。
// src/alertProcessor.ts
import { SQSEvent, SNSEvent, Context } from "aws-lambda";
/**
* Lambda entry point – SNS will invoke this function for each batch
* of messages that share the same MessageGroupId.
*/
export async function handler(event: SNSEvent, _ctx: Context): Promise<void> {
// SNS may deliver multiple records in one invocation.
for (const record of event.Records) {
// -----------------------------------------------------------------
// 1️⃣ The raw message body is a string; we expect JSON.
// -----------------------------------------------------------------
const raw = record.Sns.Message;
let parsed: { title: string; payload?: Record<string, unknown> };
try {
parsed = JSON.parse(raw);
} catch (e) {
// If parsing fails, we *must* let the error bubble up so SNS retries.
console.error("❌ Failed to parse SNS message:", raw);
throw e;
}
// -----------------------------------------------------------------
// 2️⃣ Log the alert – in a real system you would forward it to a DB
// or another service.
// -----------------------------------------------------------------
console.log(
`🔔 Alert [${record.Sns.MessageGroupId}]: ${parsed.title}`,
parsed.payload ?? {}
);
}
// Returning without error tells SNS the batch was processed.
}
Enter fullscreen mode
Exit fullscreen mode
要將此函式連接至 SNS 主題,您可以使用 AWS 主控台或 CDK/CloudFormation。關鍵設定如下:
| 設定 | 值 | 為什麼重要 |
|---|---|---|
| Runtime | nodejs22.x |
支援最新的語言功能和 SDK v3。 |
| Memory | 128 MiB(如果 payload 較大則更高) | 影響最大並行呼叫次數;保持低以節省成本。 |
| Timeout | 30 秒(預設) | 對於簡單記錄應該足夠;如果進行大量工作則增加。 |
| Dead‑letter queue | 可選,但建議使用 | SNS 重試三次;之後訊息會遺失,除非 DLQ 捕捉它。 |
提示:為 Lambda 啟用 CloudWatch Logs,並針對
InvocationErrors設定警示。因為 SNS 重試是針對每個訂閱者,無聲的 Lambda 失敗可能導致未傳遞的警報。
可靠的系統取決於您對它執行的測試。以下步驟讓您能在不部署到正式環境的情況下驗證排序、去重複和錯誤處理。
建立一個小型腳本,使用相同的 groupId 呼叫 publishAlert 幾次。在呼叫之間使用短暫的 setTimeout 來模擬快速的 LLM 輸出。
// scripts/simulateClaude.ts
import { publishAlert } from "../src/claudeTool";
async function main() {
const groupId = "device-123";
// Fire three alerts in quick succession.
await publishAlert({
title: "Temperature high",
payload: { temp: 78 },
groupId,
});
await publishAlert({
title: "Temperature critical",
payload: { temp: 92 },
groupId,
});
await publishAlert({
title: "Shutdown initiated",
payload: { reason: "overheat" },
groupId,
});
console.log("✅ All alerts sent.");
}
main().catch((e) => {
console.error("❌ Simulation failed:", e);
});
Enter fullscreen mode
Exit fullscreen mode
執行 ts-node scripts/simulateClaude.ts。然後檢查 Lambda 記錄——您應該會看到三個警報以相同順序出現。
修改腳本以重複使用相同的 MessageDeduplicationId(透過傳遞常數 dedupId 到 publishAlert)。您只會在 Lambda 記錄中看到第一則訊息;其他訊息會被默默丟棄。這示範了 5 分鐘窗口規則。
加入一行程式碼,在特定警報(例如當 title 包含「critical」時)拋出例外。部署 Lambda,再次執行模擬,並觀察 CloudWatch。您會看到失敗的呼叫被重試三次,然後消失,除非您有連接 DLQ。
用白話來說:如果 Lambda 崩潰,SNS 會再嘗試三次,然後放棄。如果沒有死信佇列,該警報就會永遠遺失。
在 CloudWatch Logs Insights 中執行以下查詢:
fields @timestamp, @message
| filter @message like /Alert/
| sort @timestamp asc
| limit 20
Enter fullscreen mode
Exit fullscreen mode
sort asc 會顯示確切的到達順序。如果您看到相同 groupId 的訊息出現順序錯亂,請再次確認您使用的是 FIFO 主題,且批次中的 MessageGroupId 完全相同。
您現在擁有的:一種模式,能夠只使用 AWS 管理的服務,將 Claude 的工具呼叫轉換成可靠、有序的事件串流。
MessageGroupId 的警報會以發佈時的確切順序到達訂閱者。
有了這些元件,您可以讓 Claude 作為系統的大腦,而 SNS FIFO 和 Lambda 則作為神經系統,可靠地依序傳遞訊號且無遺失。祝您 coding 愉快!
透明度聲明
本文是在 AI 系統的協助下撰寫的——Groq(GPT OSS 120B)。
發佈日期:2026-08-26 · 主要焦點:SNS
所有程式碼區塊都旨在正確且可執行,但在正式環境使用前,請務必根據所提及工具的官方文件進行驗證。
發現錯誤?請留言——隨時歡迎修正。