我在記錄 AI 程式碼會話的使用量和成本時,注意到一個奇怪的現象:某次會話完全沒有成本紀錄。我最初以為是測量工具出了問題。
然而,當我直接對同一個 Claude Code 會話執行 agent-cost 時,它在 36.454 秒內成功完成。但透過 spec-lane 轉接器執行相同的測量時,卻在 30.019 秒後失敗了。
作者在使用 AI 程式碼成本測量工具時,發現某次會話沒有成本紀錄,經調查發現是呼叫端設定了 30 秒逾時導致測量失敗。這次事件的教訓是,測量失敗不等於成本為零,遺失紀錄會扭曲數據,因此區分「零」與「未知」至關重要。文章詳細說明了逾時問題、錯誤訊息的模糊性,以及如何透過增加逾時時間和明確錯誤提示來修復此問題。

我在記錄 AI 程式碼會話的使用量和成本時,注意到一個奇怪的現象:某次會話完全沒有成本紀錄。我最初以為是測量工具出了問題。
然而,當我直接對同一個 Claude Code 會話執行 agent-cost 時,它在 36.454 秒內成功完成。但透過 spec-lane 轉接器執行相同的測量時,卻在 30.019 秒後失敗了。
原因很簡單:呼叫端設定了 30 秒的逾時限制。比逾時本身更重要的是之後發生的事情:失敗的測量並沒有產生 $0 的紀錄,而是完全沒有任何測量紀錄。
這個區別成為了這次事件的主要教訓:「測量失敗」不等於「成本為 $0」。未能測量某件事物,與將其測量為零是截然不同的。
同一個會話直接執行成功,但透過轉接器卻失敗了。我首先使用 agent-cost 直接重新執行了 Issue #42 中的會話。
結果顯示:程式碼正常結束,耗時 36.454 秒,JSON 解析成功,並遵循 measure/v1 協定。這次測量雖然超過 30 秒,但正常完成了。
接著,我將同一個會話透過一個從修復前 Git 版本 cca0338... 建構的 AgentCostTelemetryAdapter 執行。這次它在大約 30 秒時停止,並顯示「TelemetryImportFailed Command failed」。
比較結果顯示,直接執行 agent-cost 成功耗時 36.454 秒,修復前的轉接器逾時耗時 30.019 秒,而修復後的轉接器成功耗時 35.410 秒。
修復前的轉接器預設逾時為 30,000 毫秒(30 秒),因此底層測量雖然需要大約 36 秒才能完成,但呼叫端卻在 30 秒後終止了它。
還有另一個問題:錯誤訊息只有「Command failed」。它沒有說明發生了逾時,也沒有指出程序在 30 秒後被停止。
僅憑這條訊息,很難區分是 agent-cost 內部失敗,還是呼叫端施加的逾時導致的。
沒有紀錄不等於零成本紀錄。我想知道測量失敗會留下什麼。為此,我使用了一個單獨的受控重現,並故意設定了很短的逾時。
這與上面用於時間比較的實際會話不同。當 lane calibrate 在測量期間失敗時,結果顯示「CalibrationObservation: 0 cost_ledger: 0」。
它沒有寫入像 { "cost_usd" : 0 } 這樣的紀錄,而是根本沒有任何紀錄。原始碼也符合這種行為:如果 adapter.measure() 失敗,命令會在產生觀察結果和寫入成本分類帳之前返回。
對空的分類帳執行 emit-metrics 會產生「built 0 record(s), coverage.status=no_data」。這裡的「no_data」不代表「測量成本為零」,而是表示沒有可用的測量紀錄。
這一點在數據匯總時非常重要。如果一百個任務中有十個失敗的測量被默默地轉換為 $0,那麼最終的平均值可能會比實際證據支持的要低。零是一個數值,而缺少測量證據則是一種不同的狀態。
修復不僅僅是將 30 秒改為 180 秒。PR #43 將預設逾時從 30 秒更改為 180 秒。
它還增加了 CLI 覆寫選項 --agent-cost-timeout-ms <n>。此選項適用於 calibrate、emit-metrics、next 和 usage-import 這四個命令。
可接受的範圍是從 1 毫秒到 3,600,000 毫秒。逾時錯誤訊息也變得更明確。
例如,一個受控的 200 毫秒逾時現在會報告:「timed out after 200 ms (killed with SIGTERM)」。這使得區分測量命令自身失敗與呼叫端因截止時間而終止它變得容易許多。
這裡仍然存在一個界限:180 秒並非嚴格的實際時間保證。當達到逾時時,實作會發送 SIGTERM 訊號。
如果子程序在收到該訊號後沒有立即終止,它可能會繼續運行超過名義上的逾時時間。
修復後,一次 38 秒的運行成功保存了測量結果。增加逾時只有在測量能夠實際完成並保存其證據時才有用。
我使用 v0.10.1 CLI 和預設的 180 秒逾時,重新運行了另一個歷史會話和 lane 快照。結果顯示程式碼正常結束,耗時 38.01 秒。
這次,程序不僅成功返回,還產生了觀察結果,寫入了成本分類帳,並且指標覆蓋率達到了「complete」。
還有一個歷史 PR 紀錄報告了約 39 秒的成功運行。我將其分開處理:包含確切歷史運行時間的原始日誌已不可用,因此該報告值與獨立重現的 38.01 秒運行結果並非相同的證據。
完成測量並不代表數字是正確的。在檢查修復時,另一個重要的界限浮現了。我在此驗證的是測量過程可以完成、返回協定酬載並保存其結果。
這並不證明以下所有事項:估計的美元金額是正確的、定價目錄是正確的、會話已歸因於正確的任務。
事實上,歷史紀錄和新的重現產生了不同的 token 數量和估計成本。它們也使用了不同的 agent-cost 版本。
我沒有將這種差異的原因納入這次逾時工作的調查範圍。測量完成、成本準確性和任務歸因是獨立的主張,一次成功的運行僅能確立第一個。
「exit 0」仍可能意味著測量不完整。還有一個值得注意的邊緣情況。當測量失敗時,calibrate 會以代碼 2 退出。
然而,usage-import 有不同的約定。在某些測量失敗的情況下,它會記錄「measurement-incomplete matched: false」,並且不寫入分類帳條目,但仍然返回「exit 0」。
因此,這也不是一個安全的等價關係:「exit 0」不等於「測量成功」。退出代碼、測量狀態和持久化證據需要分開解釋。
不要將未知歸結為零。直接的錯誤是 30 秒逾時。對我來說,更有用的教訓是關於狀態表示。
對於測量系統而言,以下這些狀態是不可互換的:零、未知、失敗、未測量。
將所有這些狀態都歸結為零,雖然讓數據匯總變得更容易,但也破壞了實際發生的資訊。
這不僅適用於 AI 程式碼成本,測試結果、評估分數、使用指標和可觀察性管道都可能遇到相同的問題。
我從 Issue #42 中學到的規則仍然是最簡單的描述:「測量失敗」不等於「成本為 $0」。隨著越來越多的工程工作流程自動化,區分「數值為零」和「我們從未獲得數值」變得越來越重要。
參考資料:Issue #42,agent-cost 逾時、PR #43,預設 180 秒 / 逾時覆寫 / 診斷、spec-lane v0.10.1。
關於原始問題中報告的版本說明:Issue #42 將歷史運行時記錄為「lane 0.9.1, cca0338 on main」。
然而,在 Git 中,cca0338... 是 v0.10.0 標籤的去殼提交,並且該修訂版本中的 packages/cli/package.json 報告的版本是 0.10.0。
本文中 30.019 秒的重現是從 cca0338... 原始碼修訂版本建構的。我尚未確定為何歷史可執行檔報告 0.9.1,因此我無法斷定原始事件發生在 v0.10.0 CLI 上。
覺得值得一看?分享給朋友。
以上為 AI 自動翻譯導讀。原文版權歸 DEV Community (Claude Code) 所有, 建議透過「閱讀原文」前往原始網站,以取得最完整資訊並支持原作者。
43 個來源、每 2 小時更新,太多看不完。電子報每週挑最值得看的幾則,附上 Max 的看法。