[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-flink-operator-115-turns-status-into-signals-zh":3,"article-related-flink-operator-115-turns-status-into-signals-zh":31,"series-tools-9245621b-7a5a-4d39-8f3f-b2915953db91":82},{"id":4,"slug":5,"title":6,"content":7,"summary":8,"source":9,"source_url":10,"author":11,"image_url":12,"cover_image":12,"category":13,"language":14,"translated_content":11,"related_article_id":15,"keywords":16,"key_takeaways":23,"views":27,"created_at":28,"published_at":29,"topic_cluster_id":30},"9245621b-7a5a-4d39-8f3f-b2915953db91","flink-operator-115-turns-status-into-signals-zh","Flink Operator 1.15 把狀態變訊號","\u003Cp data-speakable=\"summary\">Flink Operator 1.15.0 把\u003Ca href=\"\u002Fnews\u002Fperfect-match-season-4-couples-reality-check-zh\">狀態\u003C\u002Fa>、logging、metrics 和 recovery 變成更好用的 ops 訊號。\u003C\u002Fp>\u003Cp>我跑 Flink on Kubernetes 也一陣子了，最煩的從來不是它會不會掛，而是它明明快掛了，卻還一直裝沒事。deployment 看起來綠的，job 其實還沒 ready；savepoint 明明做過了，cleanup 卻卡在半路；FlinkSessionJob 刪掉了，finalizer 還像在等一個永遠不會回來的人。這種問題很少一次炸開，通常是慢慢堆，堆到你半夜只想把整套 operator 砍掉重來。我看到這種 release notes 時，第一個反應不是興奮，是先看它有沒有真的碰到這些痛點。\u003C\u002Fp>\u003Cp>這次讓我停下來的來源是 Apache Flink 的 \u003Ca href=\"https:\u002F\u002Fflink.apache.org\u002F2026\u002F05\u002F26\u002Fapache-flink-kubernetes-operator-1.15.0-release-announcement\u002F\">Flink Kubernetes Operator 1.15.0 release announcement\u003C\u002Fa>。它沒有只講版本號，反而直接點出 Conditions、Logback、內建 metrics reporter、Flink 2.2 相容性，還有一串 savepoint 與 session job 的修正。我也對照了 \u003Ca href=\"https:\u002F\u002Fnightlies.apache.org\u002Fflink\u002Fflink-kubernetes-operator-docs-main\u002F\">operator docs\u003C\u002Fa>、\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fapache\u002Fflink-kubernetes-operator\">GitHub repo\u003C\u002Fa>，以及 Kubernetes 的 \u003Ca href=\"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Foverview\u002Fworking-with-objects\u002Fconditions\u002F\">Conditions\u003C\u002Fa> 和 \u003Ca href=\"https:\u002F\u002Fkubectl.docs.kubernetes.io\u002Freferences\u002Fkubectl\u002Fkubectl-wait\u002F\">kubectl wait\u003C\u002Fa>。\u003C\u002Fp>\u003Ch2>別再把 deployment status 當成一坨 JSON\u003C\u002Fh2>\u003Cblockquote>The operator now exposes a standard Kubernetes Condition in the status field of FlinkDeployment resources. The Running condition gives tooling a consistent, machine-readable signal of whether the deployment is up and running, directly usable with kubectl wait, GitOps controllers, and any tool that speaks Kubernetes conditions.\u003C\u002Fblockquote>\u003Cp>翻譯一下就是：它終於開始用 Kubernetes 團隊看得懂的語言講話了。這件事很土，但很重要。自訂 status 欄位給人看可以，給\u003Ca href=\"\u002Fnews\u002Fdynaflip-robot-perception-motion-representation-zh\">機器\u003C\u002Fa>看就很容易出事。因為每個 controller 都會長出自己的語意，最後你寫的不是 automation，是一堆猜測字串的 shell 腳本。\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780048998271-jmzt.png\" alt=\"Flink Operator 1.15 把狀態變訊號\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>我以前真的踩過這種坑。兩個 controller 各自說自己 ready，結果一個是「資源已建立」，另一個才是真正可用。你只要維護過這種東西，就會開始討厭 free-form status。Condition 的好處不是漂亮，是一致。它讓 \u003Ccode>kubectl wait\u003C\u002Fcode> 能直接等，也讓 GitOps controller 不必硬猜。\u003C\u002Fp>\u003Cp>實操上我會這樣做：把 readiness gate 從字串比對改成 Condition。只要下一個 job 要等 FlinkDeployment 起來，就直接盯 \u003Ccode>Running\u003C\u002Fcode>。如果你用 Argo CD、Flux，或只是 CI pipeline，也一樣，別再用 \u003Ccode>grep\u003C\u002Fcode> status 文字。你要的是可預期的 contract，不是祈禱。\u003C\u002Fp>\u003Cul>\u003Cli>機器判斷用 Conditions。\u003C\u002Fli>\u003Cli>人類排障看 logs。\u003C\u002Fli>\u003Cli>不要把兩者混在一起，然後叫它 observability。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Logging 不是小事，尤其你公司早就定了 Logback\u003C\u002Fh2>\u003Cp>這版多了 Logback 支援，安裝時可以用新的 \u003Ccode>logging.framework\u003C\u002Fcode> Helm value 選擇。release announcement 也寫得很直白：chart 會帶 \u003Ccode>logback-operator.xml\u003C\u002Fcode> 和 \u003Ccode>logback-console.xml\u003C\u002Fcode>，而且可以像原本的 Log4j2 properties 一樣改。\u003C\u002Fp>\u003Cp>這種改動看起來很小，但只要你待過有平台規範的公司，就知道它有多煩。今天是 operator，明天是另一個 Java service，後天又來一個 chart 想自己玩一套 logging。最後你花掉的時間不是在做產品，是在調整基礎設施去配合別人的預設值。這種工最沒成就感，但最常見。\u003C\u002Fp>\u003Cp>白話講，這版是讓 operator 沒那麼死抱著某一套 logging 方案。你如果整個平台早就標準化在 Logback，就不用為了它特別開例外。這不只是美觀問題，還會影響 appender、routing、以及你們內部既有的 log 收斂方式。\u003C\u002Fp>\u003Cp>我自己的做法是：先決定 logging framework，再裝 chart。不要先上線再補救。把 \u003Ccode>logging.framework\u003C\u002Fcode> 寫進 base values，然後清楚標出 operator log 跟 console output 各改哪個檔案。你如果團隊裡還在 Log4j2 跟 Logback 亂切，這版正好拿來收斂。\u003C\u002Fp>\u003Cp>相關設定可以直接對照 \u003Ca href=\"https:\u002F\u002Fnightlies.apache.org\u002Fflink\u002Fflink-kubernetes-operator-docs-main\u002F\">Flink Kubernetes Operator docs\u003C\u002Fa>，不要只看 release note 摘要就自己猜。\u003C\u002Fp>\u003Ch2>Metrics 有沒有真的能用，差別在有沒有先幫你補齊\u003C\u002Fh2>\u003Cp>1.15.0 直接把 \u003Ccode>flink-metrics-dropwizard\u003C\u002Fcode> reporter 打包進去，不用你自己手動補 JAR。公告也提到 metrics 文件重寫過，會講清楚 operator scope 的 metric 名稱、\u003Ccode>kubernetes.operator.metrics.*\u003C\u002Fcode> 前綴，還有 Prometheus 的完整設定方式。更實際的是，現在文件把所有暴露的 metrics 集中列出來了。\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780048992737-b9hp.png\" alt=\"Flink Operator 1.15 把狀態變訊號\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>我很吃這種改法，因為 metrics 文件通常是很多專案默默失敗的地方。你會拿到一串名字，偶爾有範例，然後剩下的就靠自己 reverse engineer。那不叫 observability，那叫尋寶。當文件把 lifecycle、job status、blue-green deployment、state snapshot、autoscaler 這些東西講清楚，團隊省下來的不是一兩分鐘，是一堆猜測跟對帳時間。\u003C\u002Fp>\u003Cp>翻成白話就是：它想讓監控這件事變得可預期。內建 reporter 少掉一個手動步驟，重新整理過的文件則讓你更容易把 operator metrics 接到 Prometheus 或你們現有的監控系統。你如果曾經跟同事解釋「這個 metric 有，但就是沒出現在 dashboard」，你就知道這有多實際。\u003C\u002Fp>\u003Cp>實操上，我會先盤點團隊真的會拿來告警的 metrics，再對照文件上的名稱與 prefix，不要繼續沿用那些已經漂掉的舊 dashboard。若你用 Prometheus，就把 operator-scoped 的設定模式直接套進 values。若你以前還要自己補 Dropwizard reporter，先確認這版已經內建，別再做重複包裝。\u003C\u002Fp>\u003Cul>\u003Cli>先列出真的有 alert 的 metrics。\u003C\u002Fli>\u003Cli>不要假設 chart 已經幫你帶齊 reporter。\u003C\u002Fli>\u003Cli>Dashboard 以文件為準，不要以記憶為準。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Flink 2.2 相容性不是加分題，是升級能不能過的門檻\u003C\u002Fh2>\u003Cp>公告說 Operator 1.15.0 已經完整驗證 Apache Flink 2.2，支援 2.2.x、2.1.x、2.0.x、1.20.x、1.19.x。這個矩陣我最在意，因為版本支援往往就是升級計畫能不能成立的分水嶺。\u003C\u002Fp>\u003Cp>我看過很多團隊卡在一個很尷尬的位置：應用 runtime 想升，operator 或 chart 卻還沒跟上。結果升級被拆成兩個 project，兩邊都慢。清楚的相容性矩陣至少能把這種鬼打牆減少一半，平台團隊也能直接回答「這版能不能一起上」。\u003C\u002Fp>\u003Cp>也就是說，它不是幫你省測試，而是幫你少掉一層 compatibility fog。你還是要驗證，但不必從零開始猜。\u003C\u002Fp>\u003Cp>我會這樣落地：如果你現在在 1.19 或 1.20，先拿這個矩陣對齊下一次升級，再碰 production。若你已經在試 2.2，operator version 也要一起 pin 進同一個 change set，這樣驗證才有意義。最後，把這張矩陣寫進內部平台文件，因為真的沒人會把 release notes 看第二次。\u003C\u002Fp>\u003Ch2>Savepoint 修正的重點不是 bug，而是你能不能信它\u003C\u002Fh2>\u003Cp>公告提到一個 race condition：savepoint 或 last-state upgrade 在 JobManager 起得太慢時，可能把 job state 弄丟。還有一個問題是 savepoint history 會在真正成功 dispose file 之前就從 status 刪掉，結果留下 orphaned files。這種 bug 很像鬧鬼，但其實只是順序搞錯。\u003C\u002Fp>\u003Cp>白話一點，這版是在 state 操作上更小心。對有 stateful Flink job 的團隊來說，「status 更新了」跟「artifact 真的處理完了」不是同一件事。這中間的空窗，正是資料遺失故事跟檔案垃圾堆出來的地方。\u003C\u002Fp>\u003Cp>我以前也碰過類似問題，controller 先回成功，底層 storage 卻還沒真的穩住。表面上沒事，等到下一次 maintenance window，舊 artefact 跟半完成狀態才一起冒出來。那時你才會懂，state management 不只是 happy path 正確，而是不能亂報完成。\u003C\u002Fp>\u003Cp>實操上，我會先檢查所有假設「savepoint 記錄消失＝檔案已安全處理」的 automation。如果你有 cleanup job、retention policy、DR script，全部都要確認它們不會太早相信 status。還有，JobManager 起得慢的環境要納進測試矩陣，別只在快機器上驗證。\u003C\u002Fp>\u003Ch2>Session job 刪除不該像綁架案\u003C\u002Fh2>\u003Cp>這版新增一個設定，可以在刪除 \u003Ccode>FlinkSessionJob\u003C\u002Fcode> 時直接取消正在跑的 session job，而不是卡在 finalizer 裡面等到天荒地老。它也改善了 session cluster 暫時不可達時的刪除流程，修掉會卡住的 finalizer，還補回 session cluster recovery 時重建的 JobManager Deployment ownerReferences。\u003C\u002Fp>\u003Cp>我很喜歡這段，因為它讀起來像是有人真的盯著刪除流程卡死過。finalizer 很有用，但一旦變成你忘記鬆開的手煞車，就很煩。cluster 掛了或 unreachable 時，刪除流程應該能優雅退場，不該把安全機制\u003Ca href=\"\u002Fnews\u002Fminimax-m27-turns-agents-into-shipped-work-zh\">做成\u003C\u002Fa>死鎖。\u003C\u002Fp>\u003Cp>翻成白話就是：teardown 終於比較像 teardown，不像你在跟資源談判。這件事很現實，因為刪除不是邊角料。你在救壞掉的 deploy、輪替 workload、清 test cluster 時，刪除流程就是日常。\u003C\u002Fp>\u003Cp>我會這樣做：先決定你的平台到底要不要在刪除時直接 cancel active session jobs，還是要等 cleanup 完成。決定完就寫進 config，不要靠口耳相傳。再來，刪除流程要測兩次，一次在 cluster 正常時，一次在 session cluster 不可達時。你只測 happy path，finalizer 之後一定會回來找你。\u003C\u002Fp>\u003Ch2>可抄的模板\u003C\u002Fh2>\u003Cpre>\u003Ccode># Flink Kubernetes Operator 1.15.0 rollout template\n\n## 1) 安裝值\nlogging:\n  framework: logback   # 如果你們平台標準是 Log4j2，就改成 log4j2\n\nwebhook:\n  create: false        # 只有在你們真的把 webhook 另外管時才關掉\n\n# Metrics：保留 operator-scoped prefix\n# kubernetes.operator.metrics.*\n\n## 2) Readiness gate\n# 用 Kubernetes Conditions，不要解析 status 文字。\n# 範例：\n# kubectl wait flinkdeployment\u002Fmy-job --for=condition=Running --timeout=120s\n\n## 3) Monitoring checklist\n- 確認 flink-metrics-dropwizard 已包含在 chart\n- 把 operator metrics 對應到 Prometheus scrape rules\n- 驗證 lifecycle、JobStatus、autoscaler、snapshot metrics\n- Dashboard 只用文件上列出的 metric 名稱\n\n## 4) Upgrade compatibility\n- 目標 Flink 版本：2.2.x \u002F 2.1.x \u002F 2.0.x \u002F 1.20.x \u002F 1.19.x\n- 驗證 operator 版本：1.15.0\n- 測 upgrade + rollback，包含 slow JobManager startup\n\n## 5) State and savepoint safety checks\n- 驗證 rolling upgrade 時的 savepoint 建立\n- 確認 savepoint history 不會早於 artifact disposal 被移除\n- 檢查 cleanup 後是否留下 orphaned files\n- 稽核所有把 status 當 completion 的 script\n\n## 6) Session job deletion policy\nsessionJobDeletion:\n  cancelOnDelete: true\n\n## 7) Pre-prod validation steps\n- 建立 FlinkDeployment，等待 Running Condition\n- 觸發 savepoint，確認 cleanup 順序\n- 在 session cluster healthy 時刪除 FlinkSessionJob\n- 在 session cluster unreachable 時再刪一次\n- 確認 recovery 時 JobManager Deployment 的 ownerReferences 正確\n\n## 8) Notes for operators\n- logging framework 在所有環境保持一致\n- metrics 文件當成 source of truth\n- 不要只靠 finalizer 決定 user-visible deletion timing\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>這段我會直接丟給平台團隊。它不花俏，但很能防止每季都重演同一批痛點。如果你要看原始 release announcement，就去看官方文章和它底下連的 release notes；我這篇是在幫你翻成能上手的 ops 語言。\u003C\u002Fp>\u003Cp>原始來源是 \u003Ca href=\"https:\u002F\u002Fflink.apache.org\u002F2026\u002F05\u002F26\u002Fapache-flink-kubernetes-operator-1.15.0-release-announcement\u002F\">Apache Flink 的 1.15.0 release announcement\u003C\u002Fa>，再加上 \u003Ca href=\"https:\u002F\u002Fnightlies.apache.org\u002Fflink\u002Fflink-kubernetes-operator-docs-main\u002F\">官方文件\u003C\u002Fa>、\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fapache\u002Fflink-kubernetes-operator\">GitHub repo\u003C\u002Fa>、\u003Ca href=\"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Foverview\u002Fworking-with-objects\u002Fconditions\u002F\">Kubernetes Conditions\u003C\u002Fa> 與 \u003Ca href=\"https:\u002F\u002Fkubectl.docs.kubernetes.io\u002Freferences\u002Fkubectl\u002Fkubectl-wait\u002F\">kubectl wait\u003C\u002Fa>。上面這份模板是我根據官方內容整理出的衍生版本，不是原文照抄。","我把 Flink Kubernetes Operator 1.15.0 的 release notes 拆成一份可直接抄的 ops 模板，重點是 Conditions、logging、metrics、savepoint 與刪除流程。","flink.apache.org","https:\u002F\u002Fflink.apache.org\u002F2026\u002F05\u002F26\u002Fapache-flink-kubernetes-operator-1.15.0-release-announcement\u002F",null,"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780048998271-jmzt.png","tools","zh","698d05e8-fe12-4e4a-a1de-7de25a1aba47",[17,18,19,20,21,22],"Apache Flink","Kubernetes Operator","Conditions","savepoint","observability","Logback",[24,25,26],"用 Kubernetes Conditions 取代字串型 status 判斷","把 logging framework、metrics、savepoint、刪除策略寫成可執行模板","升級前先對照 Flink 2.2 相容性矩陣與刪除\u002F恢復測試",6,"2026-05-29T10:02:50.192906+00:00","2026-05-29T10:02:50.182+00:00","eace24dd-f34d-4b55-845e-5153c759d740",{"tags":32,"relatedLang":41,"relatedPosts":45},[33,35,36,38,39],{"name":18,"slug":34},"kubernetes-operator",{"name":20,"slug":20},{"name":17,"slug":37},"apache-flink",{"name":21,"slug":21},{"name":19,"slug":40},"conditions",{"id":15,"slug":42,"title":43,"language":44},"flink-operator-115-turns-status-into-signals-en","Flink Operator 1.15 turns status into signals","en",[46,52,58,64,70,76],{"id":47,"slug":48,"title":49,"cover_image":50,"image_url":50,"created_at":51,"category":13},"5656a6ab-9e07-41be-9cea-3440fb8846e2","nvidia-lg-ai-collaboration-playbook-zh","Nvidia 和 LG 把 AI 合作變成模板","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1781056994999-8eng.png","2026-06-10T02:02:46.590133+00:00",{"id":53,"slug":54,"title":55,"cover_image":56,"image_url":56,"created_at":57,"category":13},"e48be66d-d7de-419e-b5fd-805f0784ef15","ollama-best-free-ai-path-2026-zh","Ollama 是 2026 年真正適合工作的免費 AI 路徑","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1781056077878-11pc.png","2026-06-10T01:47:24.632993+00:00",{"id":59,"slug":60,"title":61,"cover_image":62,"image_url":62,"created_at":63,"category":13},"9b53427c-8c2a-4960-a773-f14d4528caae","awesome-production-ml-turns-chaos-into-stack-zh","這份 MLOps 清單把混亂拆成堆疊","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1781055220958-dmar.png","2026-06-10T01:33:14.850634+00:00",{"id":65,"slug":66,"title":67,"cover_image":68,"image_url":68,"created_at":69,"category":13},"d5af1522-28aa-4cfb-8779-1ecf168bc0b5","bentoml-turns-model-serving-into-python-apis-zh","BentoML 把模型服務變成 Python API","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1781054310299-c1gm.png","2026-06-10T01:17:56.193093+00:00",{"id":71,"slug":72,"title":73,"cover_image":74,"image_url":74,"created_at":75,"category":13},"63d8b456-ad6b-475e-86e9-d4677ca226aa","magenta-realtime-2-score-inside-daw-zh","Magenta RealTime 2 讓你在 DAW 裡即時改曲","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1781046204038-8tox.png","2026-06-09T23:02:55.9651+00:00",{"id":77,"slug":78,"title":79,"cover_image":80,"image_url":80,"created_at":81,"category":13},"f60261ff-a42e-4cfb-9f90-97785e633289","open-source-ai-tools-beat-claude-paid-tiers-zh","開源 AI 工具在價值上已經贏過 Claude 付費方案","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1781045266035-on7t.png","2026-06-09T22:47:20.195939+00:00",[83,88,93,98,103,108,113,118,123,128],{"id":84,"slug":85,"title":86,"created_at":87},"855cd52f-6fab-46cc-a7c1-42195e8a0de4","surepath-real-time-mcp-policy-controls-zh","SurePath 推出即時 MCP 政策控管","2026-03-26T07:57:40.77233+00:00",{"id":89,"slug":90,"title":91,"created_at":92},"9b19ab54-edef-4dbd-9ce4-a51e4bae4ebb","mcp-in-2026-the-ai-tool-layer-teams-use-zh","2026 年 MCP：團隊真的在用的 AI 工具層","2026-03-26T08:01:46.589694+00:00",{"id":94,"slug":95,"title":96,"created_at":97},"af9c46c3-7a28-410b-9f04-32b3de30a68c","prompting-in-2026-what-actually-works-zh","2026 提示工程，真正有用的是什麼","2026-03-26T08:08:12.453028+00:00",{"id":99,"slug":100,"title":101,"created_at":102},"05553086-6ed0-4758-81fd-6cab24b575e0","garry-tan-open-sources-claude-code-toolkit-zh","Garry Tan 開源 Claude Code 工具包","2026-03-26T08:26:20.068737+00:00",{"id":104,"slug":105,"title":106,"created_at":107},"042a73a2-18a2-433d-9e8f-9802b9559aac","github-ai-projects-to-watch-in-2026-zh","2026 必看 20 個 GitHub AI 專案","2026-03-26T08:28:09.619964+00:00",{"id":109,"slug":110,"title":111,"created_at":112},"a5f94120-ac0d-4483-9a8b-63590071ac6a","claude-code-vs-cursor-2026-zh","Claude Code 與 Cursor 深度對比：202…","2026-03-26T13:27:14.279193+00:00",{"id":114,"slug":115,"title":116,"created_at":117},"0975afa1-e0c7-4130-a20d-d890eaed995e","practical-github-guide-learning-ml-2026-zh","2026 機器學習入門 GitHub 實用指南","2026-03-27T01:16:49.712576+00:00",{"id":119,"slug":120,"title":121,"created_at":122},"bfdb467a-290f-4a80-b3a9-6f081afb6dff","aiml-2026-student-ai-ml-lab-repo-review-zh","AIML-2026：像課綱的學生實驗 Repo","2026-03-27T01:21:51.467798+00:00",{"id":124,"slug":125,"title":126,"created_at":127},"80cabc3e-09fc-4ff5-8f07-b8d68f5ae545","ai-trending-github-repos-and-research-feeds-zh","AI Trending：把 AI 資源收成一張表","2026-03-27T01:31:35.262183+00:00",{"id":129,"slug":130,"title":131,"created_at":132},"3ce6e6e2-bac5-463e-9f8d-45caabcc61f7","awesome-ai-for-science-research-tools-map-zh","AI 科研工具清單，開始像地圖了","2026-03-27T01:46:50.521945+00:00"]