設計開發人員工具:AI 輔助功能中的有效權杖用量

發布日期:2026 年 1 月 30 日

建構效能 AI 輔助功能時,主要的工程挑戰是讓 Gemini 順利處理在開發人員工具中記錄的效能追蹤記錄。

大型語言模型 (LLM) 的運作範圍是「脈絡窗口」,也就是一次可處理的資訊量上限。這項容量是以權杖為單位。以 Gemini 模型來說,一個符記約為一組四個字元。

效能追蹤記錄是龐大的 JSON 檔案,通常包含數百萬位元組。傳送原始追蹤記錄會立即耗盡模型的脈絡窗口,導致無法提出問題。

為提供成效 AI 輔助功能,我們必須建構一個系統,盡可能提供大量實用資料給大型語言模型,同時盡量減少權杖用量。在這篇網誌中,您可以瞭解我們使用的技術,並將這些技術套用至自己的專案。

調整初始情境

偵錯網站效能是一項複雜的工作。開發人員可以查看完整追蹤記錄瞭解脈絡,也可以專注於核心網頁指標和追蹤記錄的相關時間範圍,甚至深入瞭解詳細資料,專注於個別事件 (例如點擊或捲動) 及其相關呼叫堆疊。

為輔助偵錯程序,開發人員工具的 AI 輔助功能必須符合這些開發人員歷程,且只使用相關資料,提供與開發人員專注事項相關的建議。因此,我們並非一律傳送完整追蹤記錄,而是建構 AI 輔助功能,根據您的偵錯工作分割資料:

偵錯工作 最初傳送給 AI 輔助功能的資料
討論效能追蹤記錄 追蹤記錄摘要:以文字為主的報表,內含追蹤記錄和偵錯工作階段的概略資訊。包括網頁網址、節流條件、主要成效指標 (LCP、INP、CLS)、可用洞察資訊清單,以及可用的 CrUX 摘要。
討論成效洞察 追蹤記錄摘要,以及所選成效洞察的名稱。
討論追蹤記錄中的工作 追蹤摘要,以及所選工作所在的序列化呼叫樹狀結構。
討論網路要求 追蹤摘要,以及所選要求金鑰和時間戳記
產生追蹤註解 所選工作所在的序列化呼叫樹狀結構。序列化樹狀結構會指出選取的工作。

系統幾乎都會傳送追蹤記錄摘要,為 AI 輔助功能的基礎模型 Gemini 提供初步脈絡資訊。如果是 AI 生成的註解,則會省略。

將工具提供給 AI

開發人員工具中的 AI 輔助功能會做為代理。也就是說,根據開發人員的初始提示和分享的初始背景資訊,Gemini 可以自主查詢更多資料。為了查詢更多資料,我們為 AI 輔助功能提供了一組可呼叫的預先定義函式。這類模式稱為「函式呼叫」或「工具使用」

根據先前列出的偵錯歷程,我們為代理定義了一組細微函式。這些函式會根據初始環境深入探究重要細節,類似於人類開發人員進行效能偵錯的方式。函式集如下:

函式 說明
getInsightDetails(name) 傳回特定成效洞察的詳細資訊 (例如,LCP 遭到標記的原因)。
getEventByKey(key) 傳回單一特定活動的詳細屬性。
getMainThreadTrackSummary(start, end) 傳回指定界限內主要執行緒活動的摘要,包括由上而下、由下而上和第三方摘要。
getNetworkTrackSummary(start, end) 傳回指定時間範圍內的網路活動摘要。
getDetailedCallTree(event_key) 傳回效能追蹤記錄中特定主執行緒事件的完整呼叫樹狀結構
getFunctionCode(url, line, col) 傳回資源中特定位置定義的函式原始碼,並附上效能追蹤記錄中的執行階段效能資料。
getResourceContent(url) 傳回網頁使用的文字資源內容 (例如 HTML 或 CSS)。

嚴格限制資料擷取作業只能透過這些函式呼叫進行,可確保只有相關資訊會以明確定義的格式進入脈絡視窗,進而提高權杖用量。

代理程式作業範例

讓我們看看實際範例,瞭解 AI 輔助功能如何使用函式呼叫來擷取更多資訊。在「為什麼這個要求速度緩慢?」的初始提示後,AI 輔助功能可以逐步呼叫下列函式:

  1. getEventByKey:擷取使用者選取特定要求的詳細時間細目 (TTFB、下載時間)。
  2. getMainThreadTrackSummary:檢查要求應啟動時,主要執行緒是否忙碌 (遭到封鎖)。
  3. getNetworkTrackSummary:分析是否有其他資源同時爭用頻寬。
  4. getInsightDetails:檢查「追蹤摘要」是否已提及與此要求相關的洞察資訊,指出要求是瓶頸。

結合這些呼叫的結果後,AI 輔助功能就能提供診斷結果,並提出可執行的步驟,例如建議使用 getFunctionCode 改善程式碼,或根據 getResourceContent 最佳化資源載入作業。

不過,擷取相關資料只是其中一半的挑戰。即使函式提供精細資料,這些函式傳回的資料也可能很大。以 getDetailedCallTree 為例,getDetailedCallTree 可以傳回含有數百個節點的樹狀結構。在標準 JSON 中,這會是許多 {}, 只是為了巢狀結構!

因此,我們需要一種格式,既要夠密集,能有效運用權杖,又要夠結構化,讓 LLM 能夠瞭解及參照。

序列化資料

讓我們繼續以呼叫樹狀結構為例,深入瞭解我們如何解決這項挑戰,因為呼叫樹狀結構占效能追蹤資料的大宗。如需參考,以下範例顯示 JSON 格式的呼叫堆疊中單一工作:

{
  "id": 2,
  "name": "animate",
  "selected": true,
  "duration": 150,
  "selfTime": 20,
  "children": [3, 5, 6, 7, 10, 11, 12]
}

如下列螢幕截圖所示,一個成效追蹤記錄可能包含數千個這類事件。每個小色塊都是使用這個物件結構表示。

DevTools 中記錄的效能追蹤記錄中的呼叫堆疊

這種格式很適合在開發人員工具中以程式輔助方式使用,但對 LLM 來說卻很浪費資源,原因如下:

  1. 多餘的鍵:呼叫樹狀結構中每個節點都會重複使用 "duration""selfTime""children" 等字串。因此,如果將含有 500 個節點的樹狀結構傳送至模型,系統會針對每個鍵耗用 500 次權杖。
  2. 詳細清單:透過 children 個別列出每個子項 ID 會耗用大量權杖,特別是會觸發許多下游事件的工作。

為所有用於 AI 輔助成效的資料導入權杖效率格式,是逐步完成的過程。

第一次疊代

我們開始為「成效」頁面開發 AI 輔助功能時,首先著重於運送速度。我們採用的權杖最佳化方法很基本,就是從大括號和半形逗號中移除原始 JSON,產生如下格式:

allUrls = [...]

Node: 1 - update
Selected: false
Duration: 200
Self Time: 50
Children:
   2 - animate

Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children:
   3 - calculatePosition
   5 - applyStyles
   6 - applyStyles
   7 - calculateLayout
   10 - applyStyles
   11 - applyStyles
   12 - applyStyles

Node: 3 - calculatePosition
Selected: false
Duration: 15
Self Time: 2
URL: 0
Children:
   4 - getBoundingClientRect

...

但這個第一版只比原始 JSON 略有改善。但仍會明確列出具有 ID 和名稱的節點子項,並在每行前面加上重複的描述性鍵 (Node:Selected:Duration: 等)。

最佳化子節點清單

為進一步最佳化,我們移除了節點子項的名稱 (上例中的 calculatePositionapplyStyles 等)。由於 AI 輔助功能可透過函式呼叫存取所有節點,且這項資訊已位於節點標題 (Node: 3 - calculatePosition) 中,因此不需要重複提供這項資訊。這讓我們得以將 Children 摺疊成簡單的整數清單:

Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children: 3, 5, 6, 7, 10, 11, 12

..

雖然這項做法比以往有顯著進步,但仍有進一步的優化空間。查看上一個範例時,您可能會發現 Children 幾乎是連續的,只缺少 489

原因是在第一次嘗試時,我們使用深度優先搜尋 (DFS) 演算法,從效能追蹤記錄序列化樹狀資料。這導致同層級節點的 ID 不是連續的,因此我們必須個別列出每個 ID。

我們發現,如果使用廣度優先搜尋 (BFS) 重新建立樹狀結構的索引,我們就能取得連續 ID,進而進行其他最佳化。現在我們不必列出個別 ID,而是可以透過單一精簡範圍 (例如原始範例中的 3-9),代表數百名兒童。

最終節點標記 (含最佳化 Children 清單) 如下所示:

allUrls = [...]

Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children: 3-9

減少索引鍵數量

節點清單最佳化完成後,我們接著處理多餘的金鑰。我們首先從先前的格式中移除所有鍵,結果如下:

allUrls = [...]

2;animate;150;20;0;3-10

雖然這種做法的權杖用量較少,但我們仍需指示 Gemini 如何解讀這項資料。因此,我們第一次將呼叫樹狀結構傳送給 Gemini 時,加入了以下提示:

...
Each call frame is presented in the following format:

'id;name;duration;selfTime;urlIndex;childRange;[S]'

Key definitions:

*   id: A unique numerical identifier for the call frame.
*   name: A concise string describing the call frame (e.g., 'Evaluate Script', 'render', 'fetchData').
*   duration: The total execution time of the call frame, including its children.
*   selfTime: The time spent directly within the call frame, excluding its children's execution.
*   urlIndex: Index referencing the "All URLs" list. Empty if no specific script URL is associated.
*   childRange: Specifies the direct children of this node using their IDs. If empty ('' or 'S' at the end), the node has no children. If a single number (e.g., '4'), the node has one child with that ID. If in the format 'firstId-lastId' (e.g., '4-5'), it indicates a consecutive range of child IDs from 'firstId' to 'lastId', inclusive.
*   S: **Optional marker.** The letter 'S' appears at the end of the line **only** for the single call frame selected by the user.

....

雖然這種格式說明會產生權杖費用,但這是靜態費用,整場對話只需支付一次。但先前最佳化作業帶來的節省金額,已超過這筆費用。

結論

使用 AI 建構內容時,請務必盡量減少權杖用量。我們將原始 JSON 轉換為專用的自訂格式,使用廣度優先搜尋重新建立樹狀結構索引,並使用工具呼叫依需求擷取資料,大幅減少 Chrome 開發人員工具中的 AI 輔助功能消耗的符記數量。

啟用成效追蹤的 AI 輔助功能前,必須先完成這些最佳化作業。否則,由於脈絡視窗有限,模型無法處理大量資料。但最佳化格式可讓效能代理程式維持較長的對話記錄,並提供更準確、符合情境的答案,不會因雜訊而不知所措。

希望這些技巧能啟發您,在設計 AI 應用程式時,重新審視自己的資料結構。如要在網頁應用程式中開始使用 AI,請參閱 web.dev 上的「瞭解 AI」