![]()
在原本運作良好的向量查詢中加入 WHERE tenant_id = 42,會發生兩種情況之一:查詢變慢,或是返回的資料列比你要求的還少。這兩種現象背後是相同的事實——近似索引與過濾器無法同時套用——而導致致命問題的選擇性是可以事先計算出來的。
B-tree 索引和 GIN 索引可以結合:Postgres 會從每個索引建立位元圖並進行 AND 運算。HNSW 索引無法參與其中,因為它不會產生一組符合的資料列——它產生的是有序串流,最接近的排在最前面,而這個排序正是它的全部價值。你無法將一個排序與位元圖進行交集運算後還保有排序。
因此規劃器必須做出選擇。它要嘛走訪圖形,之後再捨棄不符合過濾器的資料列(後置過濾),要嘛先找出通過過濾器的資料列,再為它們全部計算距離(前置過濾)。這兩種方式有不同的成本,更重要的是,會產生不同的結果。
Postgres 使用其成本模型在兩者之間選擇,而它對近似最近鄰居掃描的成本模型接近猜測。它沒有描述圖形在找到十個通過你過濾器的資料列之前會檢查多少資料列的統計資訊,因為這個數量取決於你的查詢落在向量空間的哪個位置。因此規劃器使用結構上缺乏資訊的估計值來選擇,有時會選到無法回答你查詢的執行計畫。這是在 Postgres 中唯一一種從應用程式覆寫規劃器是正常行為而非壞味道的情況。
這是你對明顯查詢預設會得到的結果:
SELECT id, content
FROM chunks
WHERE tenant_id = 42
ORDER BY embedding <=> $1
LIMIT 10;
Enter fullscreen mode
Exit fullscreen mode
HNSW 掃描會讓 hnsw.ef_search 個候選保持存活,並依距離順序返回它們;過濾器會套用在這個串流上。令 s 為過濾器的選擇性——它通過資料表的分數。如果過濾器與向量空間中的位置無關,預期的倖存者數量為:
survivors ≈ ef_search × s
To get k results: ef_search ≥ k / s
Assumptions: the filter is uncorrelated with the embedding
distribution; ef_search candidates are the only rows examined;
hnsw.ef_search has a hard maximum of 1000.
Enter fullscreen mode
Exit fullscreen mode
在預設 ef_search = 40 且過濾器通過資料表一半的情況下,你預期有二十個倖存者,而你要求十個。沒問題。在過濾器每千分之一列通過的情況下,你預期有 40 × 0.001 = 0.04 個倖存者,這在實務上代表查詢完全沒有返回任何結果,而索引運作完全符合設計。
在 pgvector 0.8.0 之前,在掃描內沒有補救方法:你只會得到倖存的資料列數量,無聲無息,且不會提示答案不足。0.8.0 加入了疊代掃描,它會使用較大的候選集合重新掃描,直到達到限制或耗盡預算為止:
SET LOCAL hnsw.iterative_scan = strict_order; -- pgvector 0.8.0+
SET LOCAL hnsw.max_scan_tuples = 20000; -- the budget it stops at
Enter fullscreen mode
Exit fullscreen mode
strict_order 保證結果會以真正的距離順序返回;relaxed_order 較快,可能會讓結果稍微偏離順序,如果之後無論如何都會執行重新排序器,這通常是可以接受的。兩者都無法消除底層成本——在高度選擇性過濾器上的疊代掃描需要做大量工作才能找到少數幾列。
將公式放入表格中,問題的形狀立刻顯現。對於 k = 10:
| Filter passes | Description |
|---|---|
| 50% of rows | ef_search of 20 is enough. The default of 40 has margin. Nothing to do. |
| 10% of rows | ef_search ≥ 100. Query cost roughly 2.5× the unfiltered one. Still comfortable. |
| 2% of rows | ef_search ≥ 500. Roughly 12× the work of the default, and latency you will notice. |
| 1% of rows | ef_search ≥ 1000 — exactly the maximum pgvector allows. You are at the edge with no margin for an unlucky query. |
| 0.1% of rows | ef_search would need to be 10,000. Not reachable. The post-filter plan cannot answer this query correctly, at any setting, ever. |
這就是懸崖:它不是逐漸退化,而是在頂-10 查詢百分之一選擇性處的硬牆,一般而言位於 s = k / 1000。在它之下,索引不是變慢——而是無能為力,而疊代掃描會把這種無能從錯誤答案轉變成緩慢答案。
該推導中的一個假設值得一提,因為它經常是錯誤的。它假設過濾器與向量位置無關。租戶過濾器通常大致無關。語言、文件類型或日期的過濾器則有強烈相關性——所有德文區塊在嵌入空間中都彼此靠近——這時倖存者要嘛聚集在候選集合中(優於公式),要嘛完全不在其中(糟得多)。公式是正確的規劃工具;你自己的測量才是正確的決策工具。
另一個執行計畫完全忽略向量索引:使用 B-tree 找出符合的資料列,為每個計算距離,排序,取十個。召回率精確為 100%,因為沒有任何近似。
-- Force it, to see what it costs:
SET LOCAL enable_indexscan = off; -- disables the HNSW ordered scan
SET LOCAL enable_bitmapscan = on;
EXPLAIN (ANALYZE, BUFFERS)
SELECT id FROM chunks WHERE tenant_id = 42
ORDER BY embedding <=> $1 LIMIT 10;
Limit
-> Sort
Sort Key: ((embedding <=> '[...]'::vector))
Sort Method: top-N heapsort Memory: 27kB
-> Bitmap Heap Scan on chunks
Recheck Cond: (tenant_id = 42)
-> Bitmap Index Scan on chunks_tenant_idx
Index Cond: (tenant_id = 42)
Enter fullscreen mode
Exit fullscreen mode
這個執行計畫的成本是 s × N 次各有 d 個維度的距離計算,加上堆積提取。在 N = 10,000,000、s = 0.001 且 d = 1536 時:一萬列、一千五百萬次乘加,個位數毫秒的運算。一萬個分散資料列的堆積提取才是真正的成本,而且在暖機狀態下仍可能低於一百毫秒。
因此後置過濾器完全無法回答的執行計畫,是前置過濾器能精確且快速回答的計畫。懸崖和交叉點是同一個地方,這是個方便的巧合,也是本頁最有用的資訊。
將兩種成本設為相等並求解。精確計畫的成本約為 sNd。後置過濾計畫需要 ef_search ≈ k/s,且每個候選會展開約 m 個鄰居,因此成本約為 (k/s)md:
s N d = (k / s) m d
s² = k m / N
s* = sqrt(k m / N)
k = 10, m = 16, N = 10,000,000:
s* = sqrt(160 / 10,000,000) = sqrt(1.6e-5) = 0.0040 → 0.40%
k = 10, m = 16, N = 1,000,000:
s* = sqrt(160 / 1,000,000) = 0.0126 → 1.26%
Assumptions: distance computation dominates both plans; heap access
costs are ignored, which flatters the exact plan; graph traversal
cost is linear in ef_search and m.
Enter fullscreen mode
Exit fullscreen mode
在 s* 之下,不要使用向量索引。在它之上,才使用。這個數字會隨著你的資料表大小移動,而平方根意味著它移動緩慢——從一百萬列成長到一千萬列只會讓它從約 1.3% 移動到約 0.4%。
這代表實務規則是:選擇超過資料表百分之幾的過濾器應該透過提高 ef_search 的向量索引;選擇低於百分之一的過濾器應該跳過它。規劃器不會可靠地為你做出這個選擇,因為它對 ANN 掃描的成本模型只是個佔位符,所以你應該明確地做出選擇。
依過濾欄位進行分割。 如果你的過濾器幾乎總是同一個欄位,將它設為分割鍵並為每個分割區建立一個 HNSW 索引。每個分割區的索引只包含符合的資料列,因此對它的掃描是未過濾的,上面的運算完全不適用。這是最乾淨的修正,也是具有真正運作成本的修正,因為它會讓你的索引數量倍增。
CREATE TABLE chunks (
id bigint GENERATED ALWAYS AS IDENTITY,
tenant_id int NOT NULL,
embedding vector(1536) NOT NULL,
content text NOT NULL
) PARTITION BY LIST (tenant_id);
CREATE TABLE chunks_t42 PARTITION OF chunks FOR VALUES IN (42);
CREATE INDEX ON chunks_t42 USING hnsw (embedding vector_cosine_ops);
部分索引,用於少數熱門值。 索引本身的 WHERE 子句。適合兩三個大型租戶或單一 status = 'active' 述詞;超過幾十個就無法實用,因為每個都需要完整的 HNSW 建置。
CREATE INDEX chunks_active_hnsw ON chunks
USING hnsw (embedding vector_cosine_ops)
WHERE deleted_at IS NULL;
在交叉點之下強制使用精確計畫。 在 (tenant_id) 上建立複合 B-tree,並為該查詢停用索引掃描,或是撰寫查詢讓 ANN 索引無法套用——例如對計算出的運算式排序。在小的已過濾集合上進行精確搜尋不是後備方案;在 s* 之下,它才是正確的計畫。
不在清單中的一件事:將過濾欄位加入 HNSW 索引。pgvector 不支援多欄位 HNSW 索引,也沒有任何運算子類別能讓它有意義。如果某個教學建議這麼做,那個教學是在描述不同的引擎。
無論你採取哪種路線,你首先需要的數字是實際的選擇性,而它是一個查詢而非假設。過濾器很少是均勻的:少數租戶持有大部分語料,而長尾幾乎沒有,因此平均選擇性為百分之五可能隱藏著一千個坐在 0.01% 的客戶,他們看到空的結果而其他人都沒問題。
-- The distribution of selectivity across the filter values you
-- actually use. Look at the bottom decile, not the mean.
WITH n AS (SELECT count(*)::numeric AS total FROM chunks)
SELECT tenant_id,
count(*) AS rows,
round(100.0 * count(*) / (SELECT total FROM n), 4) AS pct_of_table,
-- ef_search needed for a top-10 query, from k/s:
ceil(10.0 * (SELECT total FROM n) / count(*)) AS ef_search_needed
FROM chunks
GROUP BY tenant_id
ORDER BY ef_search_needed DESC
LIMIT 20;
Enter fullscreen mode
Exit fullscreen mode
該輸出中任何 ef_search_needed 高於 1000 的項目,都是後置過濾計畫無法服務的過濾值,而此類資料列的計數會告訴你答案是每個查詢的 ef_search、分割策略,還是將小型租戶送到精確路徑、大型租戶透過索引的路由規則。最後這個選項值得考慮:兩個計畫都是正確的,因此依每個請求在它們之間選擇是一種合理的優化,而不是駭客行為。
最後,讓團隊驚訝的互動是:Postgres 列層級安全性原則會變成 WHERE 子句,這意味著啟用 RLS 會在一夜之間把應用程式中每個向量查詢都變成後置過濾的查詢,具有單一租戶的選擇性。這在多租戶檢索的列層級安全性中有涵蓋,並包含洩漏測試。
https://dev.to/multigrid/filtering-and-vector-search-in-one-query-5085
https://www.worldprogramming.org/posts/filtering-and-vector-search-in-one-query-wki9iv
![]()
在 Android 上實現裝置端 AI 的困難之處不在於撰寫推論呼叫,而是相同的呼叫必須在數千種系統單晶片與驅動程式組合上執行。其中有些能優雅地加速你的模型,有些會在不告知的情況下退回 CPU,還有少數會產生錯誤的數值。有效的策略是在執行階段探測並記住結果。
在 iOS 上,你只需針對單一廠商的少數幾代晶片。而在 Android 上,你必須面對多家晶片廠商、各自多個世代,以及由裝置製造商按照自己的時程所出貨的驅動程式堆疊。兩支搭載相同旗艦晶片的手機,可能因為其中一支使用較舊的 GPU 驅動程式而表現不同。
由此導出的規則是:永遠不要依據裝置型號字串來決定是否加速。依裝置名稱建立的白名單會在一個版本週期內過期,無法涵蓋你出貨後才推出的裝置,而且它們是在有實際測量可用的情況下仍做出的猜測。應該在裝置上實際嘗試一次,並快取結果。
大致上有三種可用的抽象層級,選擇正確的層級主要取決於你需要多少控制權:
哪些加速路徑目前有效、哪些已被棄用而改用廠商 SDK,已改變過多次且仍持續變化。請將你選擇的 delegate 視為建置的參數,而非 Android 的既定事實,並在每次主要平台版本發布時重新檢查。以下的探測程式碼設計成只需修改一行就能更換 delegate。
無論你選擇哪種執行環境,模式都相同:嘗試建構加速的直譯器、執行固定的輸入、與 CPU 參考值比對,並計時兩者。如果建構拋出例外、數值差異超過容忍範圍,或加速路徑實際上並未更快,則使用 CPU。
enum Accel { NNAPI_OR_VENDOR, GPU, CPU }
data class ProbeResult(val accel: Accel, val medianMs: Double, val valid: Boolean)
fun probe(context: Context, modelBytes: ByteBuffer): Accel {
val golden = loadGoldenInputOutput(context) // fixed input + expected output
val results = mutableListOf<ProbeResult>()
// Always establish the CPU reference first: it is the tie-breaker
// for both correctness and speed.
val cpu = timeRun(modelBytes, Accel.CPU, golden)
results += cpu
for (accel in listOf(Accel.NNAPI_OR_VENDOR, Accel.GPU)) {
val r = try {
timeRun(modelBytes, accel, golden)
} catch (t: Throwable) {
// Delegate construction failing is normal, not exceptional.
ProbeResult(accel, Double.MAX_VALUE, valid = false)
}
results += r
}
val best = results
.filter { it.valid }
.minByOrNull { it.medianMs } ?: cpu
// Require a real margin. A 5% win is not worth a second code path.
return if (best.medianMs < cpu.medianMs * 0.8) best.accel else Accel.CPU
}
Enter fullscreen mode
Exit fullscreen mode
在功能首次被使用時,於背景執行緒執行此探測一次——不要在應用程式啟動時執行,因為那時它會與其他所有工作競爭啟動預算。將判斷結果以你的應用程式版本、模型版本與 OS build number 為鍵值持久化儲存,並在這三者任一改變時重新探測。系統更新可能會新增或移除可用的驅動程式,而你的快取答案不能比它活得更久。
探測中正確性這一半是最常被整合忽略的部分,卻也是能抓住最嚴重 bug 類型的那一部分:一個能執行、速度快、但結果錯誤的 delegate。
使用 SoC 識別碼與 OS build 來記錄探測結果。幾週後,這些記錄會成為你自己安裝基礎唯一準確的地圖,其價值遠超過任何公開的相容性矩陣。
與其設計一個必須在所有地方都能運作的體驗,不如定義兩到三個等級,讓探測來為裝置指派等級:
| 等級 | 描述 |
|---|---|
| accelerated | 探測找到有效且明顯更快的路徑。完整功能:更大的模型、更長的上下文、即時處理。 |
| cpu-capable | 沒有加速,但 CPU 推論能在互動預算內完成。較小的模型、批次處理或依需求執行而非即時。 |
| unsupported | CPU 推論太慢,或記憶體不允許載入模型。功能被隱藏或改由遠端提供。隱藏它是誠實的做法;一個需要九秒的功能比沒有功能更糟糕。 |
透過實際測量來決定,意味著隨著你的安裝基礎變化,等級指派仍能保持正確,也意味著在你推出後才發布的新手機能自動獲得良好的體驗。這也為你提供了一個乾淨的地方來放置緊急停止開關:如果某個 delegate 在部分使用者群上被發現有問題,你可以透過遠端旗標將該群組降級到 CPU,而不是推出緊急版本。此模式與 模型與提示的機能旗標 中描述的模式相同。
onTrimMemory。在背景 session 中持續保留模型是導致應用程式被殺掉、然後被怪罪冷啟動變慢的常見原因。如果 unsupported 等級退回至託管模型,則這兩條路徑在呼叫端必須可以互換——Multigrid 在各提供者之間暴露單一 API,並提供每次請求的成本與延遲,這讓遠端分支保持為單一實作,而非針對每個可能路由到的廠商各有一個。
https://dev.to/multigrid/on-device-ai-on-android-delegates-npus-and-fragmentation-2o2p
![]()
生產日誌是你能擁有的最佳訓練資料,也是最危險的。它們是真實分布中的真實輸入——但充滿了你目前模型的輸出,而這正是你絕對不能用來訓練的內容。
日誌傾印不是資料集。百分之九十的生產流量是模型已經在正確執行的事,訓練這些內容不會教會你任何原本沒有的知識。值得納入的範例,是那些攜帶目前模型所缺乏資訊的案例。
選擇給了你輸入。目標則是另一個問題,而且只有三種來源,依品質與成本由高到低排序。
| 目標來源 | 描述 |
|---|---|
| 人類編輯的輸出 | 如果你的產品已經有審核步驟則免費,若沒有則極為昂貴。品質最高,也是唯一能反映使用者真正想要什麼、而非模型認為他們想要什麼的來源。 |
| 更強模型(已過濾) | 前沿模型的回答,僅在通過驗證器或評分標準時保留。便宜且可擴展。會繼承教師的盲點,並受限於教師的使用條款——見 /learn/fine-tuning-licenses。 |
| 你自己模型的輸出 | 免費,但未經過濾幾乎總是錯誤的。你無法透過模仿自己來學習原本沒有的行為。只有在有嚴格外部過濾器時才合理——例如通過的單元測試、已對帳的交易。 |
直覺是把一切都正規化:去除空白、統一大小寫、統一日期格式、將樣板內容模板化。大部分都要抵抗。推論時的輸入會以日誌中同樣混亂的方式呈現,而只在乾淨輸入上訓練的模型,處理混亂輸入時會表現更差。
真正需要做的事:
max_tokens 而非結束序列 token 停止的完成,都是在教導模型在中途句子停止。請根據結束原因而非長度來過濾。以隨機抽樣分割後,出現 400 次的模板化請求會同時出現在訓練集與測試集。你的評估會因此測量到記憶而誤報為泛化,數字會非常漂亮,直到生產環境與其不符為止。
請在分割之前先去重,並根據分組鍵而非單列來分割——依租戶、文件、工作階段、模板 ID 來分割。如果兩個範例有可能來自同一個底層事物,它們就應該屬於分割的同一側。
隨機分割也會讓模型在下個月資料上訓練,卻在上個月資料上測試。對於任何輸入分布會漂移的情況——而產品流量總是會漂移——請依時間分割:在截止時間之前的所有資料用於訓練,之後的所有資料用於測試。得到的數字會較低,但才是能預測生產環境的那一個。
這是專屬於日誌衍生資料的陷阱,而且它很安靜。你的日誌包含目前模型的輸出。如果你拿來訓練並部署,下個月的日誌就會包含新模型的輸出,然後你又拿來訓練。每一個世代都是在擬合前一個世代,而不是擬合使用者真正想要的內容。
可見的症狀是收窄:輸出變得更一致、避險消失、模型發展出語言上的抽搐,而稀有但有效的回應形式則完全消失。這與 Shumailov 等人在 2024 年《Nature》論文中描述的合成資料動態相同,只是透過日誌管線的後門進入。
防禦方式是硬性規則而非警覺:只有當目標來自模型外部——人類編輯、通過的測試、已對帳的交易、不同的模型——時,範例才能進入資料集。將來源記錄為一個欄位,並讓訓練作業拒絕沒有來源的列。
最後一步是機械性的,也是許多執行在無聲中失敗的地方。有兩個規則。
使用基礎模型自己的聊天模板。 不是看起來像的那個。特殊 token、角色標記與空白字元都很重要,如果訓練時使用的模板與服務堆疊套用的模板不同,適配器就會被要求在格式偏移中進行無謂的泛化。在啟動執行前,請渲染一個範例並印出可見的特殊 token。
在提示上遮罩損失。 許多訓練腳本預設會計算整個序列的損失,因此模型同時被訓練去預測你的指令以及它的答案。對於指令微調,你幾乎總是想要僅完成部分的損失:
tokens <|system|> You are ... <|user|> Summarise ... <|assistant|> The report ... <|eot|>
labels -100 -100 -100 ... -100 -100 -100 ... The report ... <|eot|>
________________ masked ________________/ ____ supervised ____/
Enter fullscreen mode
Exit fullscreen mode
結束回合的 token 必須位於受監督的區域內。如果遮罩它,模型就永遠不會被訓練如何停止,這會產生最常見的「微調搞壞了一切」報告:一個正確回答後卻不斷持續下去的模型。
https://dev.to/multigrid/building-a-fine-tuning-dataset-from-production-logs-e95
https://www.worldprogramming.org/posts/building-a-fine-tuning-dataset-from-production-logs-y3ppn0
![]()

發佈於 2026 年 8 月 5 日,東部時間晚上 8:00
住在明尼蘇達州鄉村的 Brian Burgess 在 IT 領域工作了 10 年,之後才找到他對消費者科技寫作的熱情。
Brian 在 2000 年取得電腦與網路科技學位。他擔任過各種 IT 職位,包括技術支援、為 IBM 安裝路由器、資料庫管理,以及其他網路管理相關角色。
他已經擔任個人科技記者 18 年,撰寫過數千篇關於 Microsoft 產品與服務、Android、iOS、串流媒體等主題的文章。他曾為知名科技網站撰稿,包括 XDA、InformationWeek、How-To Geek、Byte、groovyPost 等。
當他離開鍵盤時,你會聽到他在彈吉他、戶外工作,以及觀看《星艦迷航記》。
你是否曾好奇為什麼你的筆電運行起來比預期還熱?你可能認為只是硬體在努力執行你正在使用的應用程式。但其實 Windows 本身也是原因之一——即使在高效能系統上也是如此。
不幸的是,Microsoft 加入了你可能不想要的 diagtrack 服務,這可能會讓你的筆電運行更熱,並可能比你預期更早故障。幸運的是,它可以被停用,我將說明它是什麼以及如何關閉它,讓你的機器能多使用幾年。

Microsoft 以在 Windows 中加入你真的不想要或不需要的應用程式和功能而聞名。例如,我經常 批評 Copilot —— 但那是容易的目標。我可以稍後再談,因為它是正面功能的特性,可以輕易停用。另一方面,診斷追蹤服務 (Diagtrack) 是公司最早在 Windows 7 中加入的底層服務,用於系統使用的診斷追蹤。
這是一項你可能不知道的服務,它在背景執行並定期收集使用資料並傳回總部,這可能會造成 CPU 使用率高峰並產生更多熱量——特別是筆電。筆電受影響最大,因為它們的冷卻系統比桌上型系統有限。Diagtrack 本身可能不會單獨造成過度發熱。然而,當與 SysMain 等服務結合時就會如此。
該服務會喚醒、傳送崩潰傾印、應用程式使用訊號和其他診斷資料給 Microsoft。當它這麼做時,它會與其他程序和相關任務一起運行,通常會在 工作管理員 中顯示為 CPU 和磁碟高峰。它通常一天執行一次,通常在啟動後,這時風扇會運轉,筆電也會開始變熱。
它會收集你 Windows 10 或 11 系統上的作業系統和應用程式層級使用情況。它也會收集你的裝置和硬體驅動程式狀態、Wi-Fi 使用、周邊設備細節、應用程式和功能使用、系統健康與錯誤、效能指標,以及手寫和輸入規格。所以 Diagtrack 需要做很多工作來收集你系統上的所有遙測資料,當全部結合起來時,就可能造成筆電過熱。

如果你正在閱讀這篇文章並準備 停用這項服務以提升效能,你可能會好奇為什麼看不到它以及要在哪裡關閉它。Microsoft 實際上在 2015 年將這項服務重新命名為「連接的使用者體驗與遙測」。這基本上是公司對 Diagtrack 的美化更名,因為 Diagtrack 對懷疑自己活動被追蹤的使用者有負面聯想。
更令人厭煩的是,公司並沒有公開宣布這次更名,而是當時被一些科技偵探發現。這讓社群對這個模糊的遙測追蹤服務更名更加懷疑。更糟糕的是,Windows 10「Threshold 2」將這項服務重新開啟給那些已經在系統上停用它的使用者。這確實是公司的一個糟糕舉動。
既然 Microsoft 把遙測追蹤服務搞得這麼糟糕,而且因為它讓你的筆電運行更熱並縮短其壽命,是時候停用它了。有幾種方法可以關閉它,你可以選擇最適合你的方式。
最直接的方法是按 Windows 鍵 -> 輸入 services.msc -> 按 Enter。找到 連接的使用者體驗與遙測 -> 按右鍵 -> 停止服務 -> 設定為 已停用 -> 套用 -> 確定。
也可以透過登錄檔關閉它,前往:HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindowsDataCollection 並將 AllowTelemetry DWORD 設定為 0。如果不存在,你可以建立該值並將其設定為 0。完成後重新啟動你的筆電。
如果你執行的是 Windows Pro 或更高版本,也可以透過群組原則停用它:電腦設定 -> 系統管理範本 -> Windows 元件 -> 資料收集與預覽組建,並將其設定為停用。
也可以立即停止它,方法是以 系統管理員身分執行 PowerShell 並執行以下指令:
Stop-Service -Name DiagTrack -Force
Set-Service -Name DiagTrack -StartupType Disabled
對大多數使用者來說,透過 Services.msc 關閉它是最簡單的,停用後,你將為你的筆電注入更多生命。不僅能幫助它避免過熱並停止風扇不斷旋轉,還應該能提升整體 Windows 使用體驗的效能。
連接的使用者體驗與遙測(以前稱為 Diagtrack)不會收集你在筆電上做的任何事或在系統上輸入的內容,例如你傳給別人的訊息或你開啟了哪些應用程式。然而,它正透過讓它運行得比應有更熱並縮短其壽命來傷害你的筆電。它對你的 Windows 裝置運作並非關鍵,而且既然它讓裝置運行更熱,就沒有理由不停用它。
![]()
📝 原文(日文)發表於 forge.workstyle.tech。
當你想把錄下的聲音轉換成另一個人的聲音時,第一個浮現的問題是:
「聲音」究竟是什麼?
即使說出相同的詞句,不同的說話者會產生不同的聲音。即使是同一位說話者,根據所說內容的不同也會產生不同的聲音。再加上語調變化,就會更加不同。換句話說,語音是一種由多個獨立資訊混合而成的訊號——至少包括:誰在說話(說話者身分)、說了什麼(內容)、以及怎麼說的(韻律)。
語音轉換(VC)的核心挑戰就在這裡。如果你單純地處理語音來替換說話者身分,內容和語調往往也會跟著改變。在這篇文章中,我們將說明我們採用作為「聲音設計」應用程式後端的 Seed-VC 如何解決這個問題——透過使用四個模組分離並處理資訊,同時逐步講解實際的模型載入與推論程式碼。
Seed-VC 的核心思想是:「不要讓單一大型模型包辦一切。」而是按類型分解語音的組成要素,將每個要素分配給專用模組,最後再將它們重新組合起來。啟動時的模型載入流程如下:
model, semantic_fn, f0_fn, vocoder_fn, campplus_model, mel_fn, mel_fn_args = load_models(a)
進入全螢幕模式
退出全螢幕模式
雖然回傳了七個元件,但可以歸納為四個功能層:
semantic_fn) — 提取內容(說了什麼)作為語意特徵campplus_model) — 將說話者身分(誰在說話)編碼成單一向量嵌入model.cfm) — 以擴散模型根據上述兩者生成梅爾頻譜圖vocoder_fn) — 將梅爾頻譜圖轉換回可聽見的波形每個角色——「提取語意」、「提取說話者」、「繪製頻譜圖」、「轉換成聲音」——都乾淨地分離開來。這種分工就是我們能夠只替換說話者身分,同時保持其他一切不變的原因。讓我們依序來看每個步驟。
在內容提取上,我們使用語音辨識模型 Whisper 的編碼器。我們不使用解碼器(轉錄)。而是直接取用其中間表示(一序列語意特徵)作為特徵向量。
s_alt = _semantic(torchaudio.functional.resample(src_t, _S["sr"], 16000))
進入全螢幕模式
退出全螢幕模式
一個關鍵點:輸入在處理前會重新取樣到16kHz。由於 Whisper 是為 16kHz 音訊所設計,即使主要轉換模型以 44.1kHz 運作,我們在語意提取前總是會降採樣到 16kHz。產生的序列幾乎不包含音高或音色資訊——它代表的是與所說內容對齊的表示。這是我們之後能夠自由替換說話者身分的先決條件。
注意:Whisper 有一個限制——一次只能處理最多 30 秒的音訊。較長的音訊需要進行分塊處理。這個限制本身曾是個重大陷阱(詳見我們的另一篇文章:「語音轉換中『說話變慢』臭蟲的元兇是 Whisper 的 30 秒限制」)。
說話者身分提取由CAMPPlus這個說話者嵌入模型負責。它接收音訊,計算 fbank 特徵,並輸出一個單一的 192 維向量。
feat = torchaudio.compliance.kaldi.fbank(w16, num_mel_bins=80, dither=0, sample_frequency=16000)
feat = feat - feat.mean(dim=0, keepdim=True)
return _S["campplus_model"](feat.unsqueeze(0)).squeeze().detach().cpu().numpy()
進入全螢幕模式
退出全螢幕模式
「說話者身分 = 單一向量」這件事對我們的「聲音設計」應用程式至關重要。因為向量可以相加、混合或內插,我們會預先從 18 位說話者的乾淨錄音計算嵌入作為「錨點」,然後根據滑桿輸入使用加權平均來混合它們。
w = design_weights(slider_values, bank, **kw)
emb = (w[:, None] * bank.embeddings).sum(axis=0)
進入全螢幕模式
退出全螢幕模式
我們為「年齡」、「音高」、「沙啞度」等可解釋軸定義滑桿,計算權重 w,然後對錨點嵌入進行加權平均。這種「透過混合聲音來設計」的操作之所以可行,正是因為說話者身分被模組化為獨立的向量。如果說話者身分與內容糾纏在一起,混合就會破壞所說的詞句。
一旦我們取得語意特徵(內容)和說話者嵌入(身分),就會進入合成階段。這就是擴散模型(CFM:Conditional Flow Matching;以 DiT 實作)登場的地方。它從隨機噪聲開始,逐步生成以輸入為條件的梅爾頻譜圖。
vt = _S["model"].cfm.inference(cat, torch.LongTensor([cat.size(1)]).to(dev),
mel2, style, None, STEPS, inference_cfg_rate=CFG)
vt = vt[:, :, mel2.size(-1):]
進入全螢幕模式
退出全螢幕模式
觀察引數可以看出這個階段如何整合先前模組的輸出:
cat — 語意特徵(內容)。提示音訊(pc)與目標條件(cond)的串接style — 來自步驟 2 的說話者嵌入(= 混合後的設計嵌入)mel2 — 提示音訊的梅爾頻譜圖。生成後,我們會裁剪前 mel2.size(-1) 幀,只保留新內容STEPS / inference_cfg_rate — 擴散步數與無分類器引導的強度模型以分離的引數接收內容(cat)與說話者身分(style)。它將它們解釋為指令:「用這個說話者的聲音繪製這個內容。」如果你固定其中一個並改變另一個,只有預期的屬性會改變。這種分離設計直接反映在推論介面上。
length_regulator 與 F0「怎麼說的」——韻律(速度與音高變化)則有些不同。它無法完全與內容解耦,因此不使用專用模組,而是作為內容與說話者身分之間的連接點來處理。
首先是速度(持續時間)。來自 Whisper 的語意序列需要被拉伸以符合所需的梅爾幀數。這由 length_regulator 負責。
cond, *_ = _S["model"].length_regulator(s_alt, ylens=torch.LongTensor([mel.size(2)]).to(dev),
n_quantizers=3, f0=None)
進入全螢幕模式
退出全螢幕模式
透過傳入目標幀長(ylens),語意序列會被調整到所需的持續時間。接著是音高(F0)。在 44.1kHz F0 條件模型中,length_regulator 可以接受 f0 引數,得以進行韻律控制,例如將載音的音高範圍向目標說話者的範圍偏移。
lf[F0_alt > 1] = lf[F0_alt > 1] - m_alt + m_ori # 將載音 F0 偏移至目標中位數
shifted = torch.exp(lf)
cond, *_ = _S["model"].length_regulator(S_alt, ylens=tgt_len, n_quantizers=3, f0=shifted)
進入全螢幕模式
退出全螢幕模式
這是一個簡單的操作:在對數域中依中位數差進行偏移。韻律並未被視為獨立模組,而是作為注入的參數。這反映了一種務實的妥協——嘗試完全解耦往往會導致不自然的結果。
擴散模型生成的是梅爾頻譜圖——一種聲音的「藍圖」。最後一步,將它轉換成人類能聽見的波形,由聲碼器 BigVGAN 負責。
wav = _S["vocoder_fn"](vt.float()).squeeze().detach().cpu().float().numpy().reshape(-1)
進入全螢幕模式
退出全螢幕模式
雖然只是一行程式碼,但這一步對音質影響很大。即使使用相同的梅爾頻譜圖,不同的聲碼器也會產生不同的聲音。我們的 44.1kHz 模型能夠輸出「真正的寬頻」,正是因為 BigVGAN 是以高取樣率訓練的(詳見我們的另一篇文章:「22.05kHz 與 44.1kHz」)。
以下是實作與操作這個四層架構時的一些重要心得:
length_regulator 注入的條件參數是務實的解決方案。強行完全解耦往往會產生不自然的偽影。whisper(語意)+ campplus(說話者)+ CFM/DiT(擴散梅爾生成)+ BigVGAN(聲碼器)
cat)與說話者身分(style)——這種分離設計直接反映在推論介面上length_regulator 注入
![]()
我曾經認為電子郵件是 AI 的可怕戰場。
太雜亂、太人性化、充滿 2017 年的轉寄郵件,以及公司裡沒人知道是哪個軟體產生的 HTML。
後來我花時間閱讀信箱自動化的討論串,特別是 r/openclaw 上關於郵件流程的一篇好文,終於搞懂了模式:
如果你不再讓模型扮演郵件伺服器的角色,電子郵件其實是 AI 非常好的應用場景。
這聽起來很明顯。但許多信箱自動化仍然在做以下事情:
這不是智能。
這是昂貴的失憶症。
更好的模式很簡單:
這樣的區分讓我的信箱工作流程變得更便宜、更容易除錯,也遠比以前穩固。
OpenClaw 工作流程討論中的一則留言,比大多數文件都說得更好:
如果你的工作流程在達到 LLM 使用上限時就停止運作,那 LLM 很可能做得太多了。
這原本是在談程式碼代理人,但它完全適用於信箱自動化。
如果你的郵件管線需要仰賴模型來記住信箱狀態、去除重複事件、處理重試,或每次執行都重新檢查路由規則,那你就是建錯系統了。
模型擅長判斷。
它們不擅長當管理員。
人類體驗郵件是混亂的。
機器不是。
每封郵件到來時都帶有有用的結構:
FromToReply-ToSubject這很重要,因為許多路由決策根本不該交給 LLM。
如果發票永遠都要寄到 [email protected],GPT-5 就不該每天早上重新發現這條規則。
如果客服郵件永遠落在特定別名上,程式碼就該確定性地路由它。
如果某個討論串已經處理過,你的 worker 應該從資料庫知道,而不是從提示詞知道。
把 GPT-5、Claude Opus 4.6、Grok、Qwen 或 Llama 用在真正需要推理的部分:
所有重複性工作:
這種架構不像「AI 信箱代理人」那麼炫目。
但它也是下個月還能繼續運作的架構。
這部分徹底改變了我對信箱管線的看法。
Google 公開了 Gmail API 方法的配額成本。
history.list = 2 個配額單位messages.list = 5 個配額單位messages.get = 20 個配額單位threads.get = 40 個配額單位messages.send = 100 個配額單位這些數字不是 trivia。
它們是設計提示。
Google 正在告訴你應該這樣做:
而不是這樣:
如果你的工作流程每分鐘醒來一次,就叫前沿模型檢查所有未讀郵件,那你不是在打造自動化。
你是在打造一張持續的帳單。
對 Gmail 來說,模式很直觀:
users.watch 訂閱收件匣變更
history.list 取得變更的訊息 IDPOST https://www.googleapis.com/gmail/v1/users/me/watch
Content-Type: application/json
{
"topicName": "projects/myproject/topics/mytopic",
"labelIds": ["INBOX"],
"labelFilterBehavior": "INCLUDE"
}
進入全螢幕模式
退出全螢幕模式
import { google } from "googleapis";
const gmail = google.gmail({ version: "v1", auth });
async function processMailboxChange(startHistoryId: string) {
const history = await gmail.users.history.list({
userId: "me",
startHistoryId,
historyTypes: ["messageAdded"]
});
const messageIds = new Set<string>();
for (const item of history.data.history ?? []) {
for (const added of item.messagesAdded ?? []) {
if (added.message?.id) messageIds.add(added.message.id);
}
}
for (const id of messageIds) {
const msg = await gmail.users.messages.get({
userId: "me",
id,
format: "metadata",
metadataHeaders: ["From", "To", "Subject", "Reply-To"]
});
const headers = Object.fromEntries(
(msg.data.payload?.headers ?? []).map(h => [h.name!, h.value!])
);
const subject = headers.Subject || "";
const to = headers.To || "";
const from = headers.From || "";
if (to.includes("[email protected]")) {
await routeToAccountsPayable(id);
continue;
}
if (from.endsWith("@trustedvendor.com") && subject.includes("Invoice")) {
await routeToAccountsPayable(id);
continue;
}
await sendToLLMForClassification({ id, subject, from, headers });
}
}
進入全螢幕模式
退出全螢幕模式
重要的不是程式碼風格。
重要的是操作順序:
Microsoft Graph 有相同的架構,只是用 delta query 而不是 Gmail history。
GET https://graph.microsoft.com/v1.0/me/mailFolders/{id}/messages/delta
進入全螢幕模式
退出全螢幕模式
你需要保留:
@odata.nextLink 來分頁@odata.deltaLink 給下一次同步週期那個 token 就是你的記憶。
你的 worker 應該擁有它。
而不是模型。
async function syncOutlookFolder(deltaUrl?: string) {
const url = deltaUrl ?? "https://graph.microsoft.com/v1.0/me/mailFolders/inbox/messages/delta";
const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` }
});
const data = await res.json();
for (const msg of data.value ?? []) {
if (msg.toRecipients?.some((r: any) => r.emailAddress?.address === "[email protected]")) {
await routeToSupport(msg);
continue;
}
await classifyIfNeeded(msg);
}
if (data["@odata.nextLink"]) {
return syncOutlookFolder(data["@odata.nextLink"]);
}
if (data["@odata.deltaLink"]) {
await saveDeltaLink(data["@odata.deltaLink"]);
}
}
進入全螢幕模式
退出全螢幕模式
相同的模式。
不同的 API。
這是我最喜歡的例子,因為區分非常乾淨。
import PostalMime from "postal-mime";
export default {
async email(message, env, ctx): Promise<void> {
const subject = message.headers.get("subject") || "";
const from = message.from || "";
const to = message.to || "";
if (to === "[email protected]") {
await message.forward("[email protected]");
return;
}
if (subject.includes("Invoice") && from.endsWith("@vendor.com")) {
await message.forward("[email protected]");
return;
}
const parsed = await PostalMime.parse(message.raw);
const llmResult = await classifyEmail({
subject,
from,
to,
text: parsed.text,
html: parsed.html
});
if (llmResult.label === "support") {
await message.forward("[email protected]");
}
}
};
進入全螢幕模式
退出全螢幕模式
第一個 if 陳述式,比很多「自主代理人」展示還要做更多有用的事。
| 選項 | 最適合的用途 |
|---|---|
| Gmail API | 使用 users.watch 推送通知、history.list 增量同步,以及在呼叫 LLM 前的配額感知篩選 |
| Microsoft Graph Mail API | 資料夾層級的 delta 同步、使用 @odata.nextLink 與 @odata.deltaLink 的持久信箱狀態,以及選擇性分類 |
| Cloudflare Email Workers | 直接在入站郵件上執行自訂邏輯,包含標頭、原始 MIME,以及 forward()、reply()、setReject() 等動作
|
| OpenClaw | 自託管編排,包含 cron、webhook、工具、記憶體,以及圍繞實際模型呼叫的多代理人路由 |
| n8n / Make / Zapier | 快速的無程式碼或低程式碼編排,適合希望在加入 LLM 步驟前先有規則、重試與整合的團隊 |
這些工具都不是行銷意義上的「AI 原生」。
這正是它們有用的原因。
公平地說,電子郵件在實務上並不乾淨。
你還是得面對:
這就是為什麼純規則不夠。
但這也是為什麼純 LLM 管線是個錯誤。
正確的模式是硬邊界搭配軟性後備機制:
這種混合架構沒有「完全自主信箱代理人」那麼性感。
但這才是大人打造生產環境自動化的方式。
這就是經濟面變得惱人的地方。
如果你的工作流程不斷把同樣的路由決策送給模型,你就是在付錢讓模型一次又一次重新發現你自己的商業邏輯。
這是偽裝成 AI 問題的糟糕架構問題。
對那些整天在 n8n、Make、Zapier、OpenClaw 或自訂 Node worker 中執行代理人的團隊來說,按 token 計費會讓情況快速惡化。
你最後看著使用量儀表板,而不是在出貨。
這正是我喜歡確定性編排優先、LLM 呼叫其次模式的原因,也說明了為什麼固定費率的 API 存取對自動化密集的工作負載如此吸引人。
使用 Standard Compute,你可以保留工作流程已經習慣的 OpenAI 相容 API 形態,卻不用把每次分類、重試和長討論串都當成計費事件。它是現有 SDK 與 HTTP 用戶端的即插即用替代方案,背後是 GPT-5.4、Claude Opus 4.6 與 Grok 4.20 的動態路由,價格則是可預測的月費。
當你的自動化 24/7 持續執行,而重點是要同時停止照顧信箱和 token 計量器時,這一點非常重要。
如果我從頭開始打造信箱自動化,這是我信任的堆疊:
這就是整個轉變。
別再讓模型當迴圈。
讓模型回答問題。
在那之後,一切都變得更便宜。
一切也都變得更好。
![]()
事先揭露:我開發了本文所介紹的工具。它是
免費且採用 Apache-2.0 授權,所以我的興趣是「讓人們覺得這個工具有用」勝過
「讓人們付費給我」。
讓我走上這條路的失敗經驗應該很多人都有過。我給代理一個
多步驟的目標:重構這個模組、更新 README、加入測試。一切
都進行順利,直到第 4 步——我才發現它在一開始就誤讀了第 1 步。
那時檔案已經被寫入了。沒有計畫可以修正,因為計畫只存在於
模型的腦海中。只剩下需要復原的東西。
這就是核心問題:計畫是工作階段的副作用,而不是你可以檢查和編輯的成品。這篇文章要談的是我最終採用的設計決定——讓計畫成為你先核准的東西,而不是你只能期待的東西。
這個工具以唯讀方式讀取你的程式庫,然後回傳一個有序的任務清單。
每個任務都帶有四項後設資料:執行器(Claude Code、Codex 或
OpenCode)、模型、思考強度,以及模式。這不是裝飾——
這四項才是任務實際執行的方式。你可以改寫任何提示、增加
或刪除任務、重新連接依賴關係(task 4 depends on task 2),或是更改
單一任務所使用的模型。已完成的作業會保持完成狀態。你在編輯時不會有任何東西需要反覆呼叫
AI。
很自然的問題是「為什麼不直接使用計畫模式?」有兩個原因。
第一,計畫模式是在之後會執行的工作階段內進行規劃——計畫只是建議,模型有可能偏離它。而在這裡,計畫是由一個
獨立的過程產生,這個過程在物理上無法寫入你的程式庫。它的探索
是嚴格唯讀的;任何會寫入的指令會在核准提示出現前就被拒絕,所以不存在「允許一次」可以點擊通過。變更
屬於執行器,而非規劃器。
第二,逐任務分配。一個安全性重構和一個 README 更新不應該
使用相同的模型。規劃器會在整個計畫中公開地做出這個組合決策,在你花費任何執行 token 之前——而且你可以
覆蓋其中任何部分。
我最在意的部分發生在後續。代理不擅長為自己評分
——更糟的是,它們會在無法編譯的建置上宣布成功。因此在這裡
只有當獨特的完成標記出現在
執行器的輸出中,並且旁邊保留了結束代碼作為獨立證據時,任務才會被標記為完成。
模型永遠不是決定因素。如果工作階段結束並聲稱工作已完成
卻沒有出現標記,它就會大聲失敗。
如果你看過代理說「完成了」然後打開一個仍然有問題的檔案,
那就是整個動機。
規劃器仍然是 LLM,有時候會寫出不好的計畫。這裡的論點不是
它永遠正確——而是一個你能看到並編輯的壞計畫只花一分鐘,而一個你看不到的壞計畫會花掉一個下午。完成標記只證明
工作階段已結束並聲稱工作完成,而非程式碼是正確的。
另外:TUI 在每個平台都需要 tmux(在 Windows 上,這代表需要 WSL)。CLI
和 VS Code 擴充功能則可以原生執行,不需要它。
npm install -g ordewell && ordewell
Enter fullscreen mode
Exit fullscreen mode
把它指向一個你很熟悉的程式庫,然後閱讀它回傳的計畫。那第一個
計畫就是整個論點。
很樂意回答任何問題,包括「為什麼不直接做 X」。
![]()
Claude Code 雖然能寫出不錯的 Laravel PHP 程式,但每次對話都以通才模式開始。它不知道你的專案有三百個應該縮減為三十個的遷移檔、不知道兩個檔案外的 @foreach 正在造成 N+1 問題,也不知道你的 Modal 遵循特定模式。你得不斷重複解釋相同的上下文。
LaraClaude 將這些上下文打包成斜線指令。它是一個 Claude Code 外掛,內建超過三十種 Laravel 專長,每一種都是一個 /lc: 指令。一次安裝後,你就擁有已經懂 Laravel 的稽核、鷹架與清理工具。以下是我最常使用的幾個。
LaraClaude 透過 Claude Code 的外掛系統安裝。一次加入市場,之後安裝,之後就能收到更新:
/plugin marketplace add edulazaro/laraclaude
/plugin install laraclaude@edulazaro
進入全螢幕模式
退出全螢幕模式
也可以直接從 GitHub 安裝:
/plugin install github:edulazaro/laraclaude
進入全螢幕模式
退出全螢幕模式
你需要有 Claude Code 與一個 Laravel 專案。大多數功能這樣就夠了;少數需要連接實際資料庫的功能還會需要 Docker。
大多數功能預設只產生唯讀報告,只有當你加上 fix 時才會修改檔案,所以請先查看報告。/lc:find-n-plus-one 會掃描你的 Blade 視圖、Livewire 元件與控制器,找出在迴圈中存取關聯的程式碼,追溯到建立集合的查詢,並告訴你該加入哪個確切的 with()。
/lc:find-n-plus-one
進入全螢幕模式
退出全螢幕模式
/lc:security-audit 是我在任何接手專案時都會執行的另一個指令。它會尋找 SQL 注入、XSS、大量賦值以及儲存在版本庫的密碼等問題,而且大多數可修正的功能在真正修改前都會先提供預覽旗標。
/lc:security-audit # 產生報告
/lc:security-audit fix --dry-run # 預覽修正內容
/lc:security-audit fix # 套用修正(需確認)
進入全螢幕模式
退出全螢幕模式
每一個長期維護的 Laravel 應用程式都會累積遷移檔的垃圾:一個 create 後面跟著二十個 add_column 與 change_column 檔案。/lc:consolidate-migrations 會依照資料表分組,判斷每個資料表是否適合合併,並將 ALTER 操作折回原本的 create 檔案,同時不碰資料遷移。
/lc:consolidate-migrations # 分析
/lc:consolidate-migrations fix --dry-run
進入全螢幕模式
退出全螢幕模式
它拒絕在正式環境資料庫上執行,並且在刪除任何東西前都會詢問,這正是你希望重寫 schema 歷史的工具該有的行為。/lc:dead-code 是它在程式碼端的夥伴:找出未使用的類別、方法、路由與視圖。
這些產生器會先閱讀你的專案現有寫法,而不是吐出制式樣板。/lc:volt-component 會產生一個 Livewire Volt 單檔案元件,包含 PHP 區塊、驗證規則、@text() 字串,並只有一個根元素。
/lc:volt-component UserProfile
進入全螢幕模式
退出全螢幕模式
/lc:generate-crud 範圍更廣,能為一個模型產生從遷移到視圖的完整堆疊,而 /lc:generate-action 則會建立 Laractions Action 並註冊到模型上。甚至還有 /lc:generate-scraper,它會讀取真實網頁並根據實際標記產生 Larascraper 類別。
當我面對一個還不了解的程式碼庫時,會使用兩個指令。/lc:model-diagram 會產生你的 Eloquent 模型及其關聯的 Mermaid ER 圖,這是最快了解整體關聯的方式。
/lc:model-diagram
進入全螢幕模式
退出全螢幕模式
而 /lc:analyze-model Property 則會完整傾倒一個模型的資訊:它的關聯、cast、scope、observer 以及它發現的問題。當執行階段已經出錯時,/lc:analyze-error 會接收堆疊追蹤並找出根本原因而非表面症狀。
LaraClaude 總共有超過三十種功能,從 /lc:deploy-checklist 到 /lc:api-docs,全部都遵循 Agent Skills 標準,因此它們只是你可以閱讀的 Markdown。它把你一直重複解釋的 Laravel 上下文,變成 Claude Code 可以隨需執行的指令。
👉 GitHub 網址:https://github.com/edulazaro/laraclaude
https://dev.to/edulazaro/turn-claude-code-into-a-laravel-expert-with-laraclaude-4l42
https://www.worldprogramming.org/posts/turn-claude-code-into-a-laravel-expert-with-laraclaude-xtkj6j
![]()
各位,我剛剛發布了兩支相互搭配的影片:認證是如何運作的,以及授權是如何運作的。
當有人說「Auth」時,這兩者經常被混為一談,但理解它們之間的差異,並弄清楚認證和授權在底層是如何運作的,是一項非常重要的技能,尤其是在現今這個 AI 時代。
以下是 YouTube 上的影片
別忘了訂閱,這樣你就不會錯過任何影片
訂閱
Code of Conduct
•
Report abuse
如需進一步操作,您可以考慮封鎖此人並且/或者 檢舉濫用
https://dev.to/shrutikapoor08/how-does-auth-work-10fh
https://www.worldprogramming.org/posts/how-does-auth-work-bxmwvs
![]()
簡介
發佈時間:
2026 年 8 月 5 日 下午 2:30 PDT

Nikita Bier 已卸任 Elon Musk 旗下社群平台 X 的產品主管一職,任期一年多。
Bier 在週三表示,他認為是「傳承火炬的時候了,並將自己降級回原本的狀態:一名貼文者」,並補充他將繼續為公司提供諮詢。
這位連續創業家與 Lightspeed 合夥人在 2025 年 7 月接下產品主管角色。他在週三表示,在任內他監督了 30 項新產品的推出,同時「保護了公眾廣場的完整性」。
當然,Bier 擔任產品主管期間,X 也發生了多起醜聞。他接下產品主管職位僅幾天後,由 xAI(當時為 Musk 擁有的獨立公司)開發的聊天機器人 Grok 開始 自稱「MechaHitler」。Grok 也曾被 X 用戶用來產生 非自願裸露影像,包括兒童性虐待材料,這讓平台陷入法律困境。
「X 是、並將繼續是歷史上最重要的通訊技術。但經營這個應用程式是一份全職 24/7 的工作,現在是我該喘口氣的時候了。」Bier 在週三寫道。
訂閱產業最大科技新聞
https://techcrunch.com/2026/08/05/nikita-bier-steps-down-as-xs-head-of-product/
https://www.worldprogramming.org/posts/nikita-bier-steps-down-as-xs-head-of-product-z75kht