1. 簡介
現代網頁開發技術可做為 AI 用途的雲端往返替代方案。Chrome 已開始提供內建 AI API,讓您使用各種模型,從翻譯用的小型專家模型到功能強大的精簡完整語言模型,應有盡有。這些模型會在使用者裝置上私下執行,您或使用者都不必支付權杖費用。
同時,AI 代理程式也為使用者提供與網路應用程式互動的新方式,透過 WebMCP 讓網路體驗支援代理程式,有助於減少權杖用量,並提供比傳統啟動方式更準確的結果 (傳統方式需要螢幕截圖和 DOM 擷取)。
在本程式碼研究室中,您將使用 Mont-Royal Plein Air,這是一個戶外用品電子商務網站。您將瞭解如何建構及整合內建的 AI API 和 WebMCP,以便:
- 從瀏覽記錄推斷顧客意圖,並使用裝置端模型動態建構推薦內容。
- 公開工具代理程式和瀏覽器助理可使用的工具,以便瀏覽網站、檢查產品和建議,以及管理使用者的購物車。
- (選用) 使用裝置上的小型專家模型,即時翻譯網站內容。
- (選用) 將基本站內搜尋轉換為站內代理,並使用外部代理使用的相同工具。
課程內容
- 如何使用 Prompt API,並強制輸出結構化 JSON。
- 如何註冊 WebMCP 工具,以及思考工具組成和精細度的策略。
- (選用) 如何使用 Translator API,透過裝置端專家模型快速翻譯內容。
- (選用) 如何自行呼叫 WebMCP 工具。
必要條件
- 個人 Google 帳戶和 Google Cloud。
- Google Chrome 150 以上版本,或 Canary 版、開發人員版或 Beta 版,並啟用
#enable-webmcp-testing和#devtools-webmcp-support標記。 - 熟悉 HTML、CSS、JavaScript 和 TypeScript。
- 熟悉 JSON 結構定義。
2. 專案設定
Google 帳戶
如果沒有個人 Google 帳戶,請建立 Google 帳戶。
登入 Google Cloud 控制台
使用個人 Google 帳戶登入 Google Cloud 控制台。
啟用計費功能
如要設定個人帳單帳戶,請在 Cloud Console 中啟用帳單功能。
建立專案 (選用)
如果沒有要用於本實驗室的現有專案,請在這裡建立新專案。
開啟 Cloud Shell 編輯器
- 按一下這個連結,直接前往 Cloud Shell 編輯器。
- 如果系統在今天任何時間提示您授權,請點選「授權」繼續操作。

- 如果畫面底部未顯示終端機,請開啟終端機:
- 點選「查看」。
- 按一下「終端機」。

設定專案
- 在終端機中,使用下列指令設定專案:
範例:gcloud config set project [PROJECT_ID]gcloud config set project lab-project-id-example
- 畫面會顯示以下訊息:
Updated property [core/project].
本機和工作區設定
- 在終端機 (或 Cloud Shell 終端機) 中複製專案存放區,然後前往專案目錄:
git clone https://github.com/GoogleChromeLabs/codelabs mont-royal cd mont-royal - 前往
ecommerce-ai-enhancements/starter資料夾:cd ecommerce-ai-enhancements/starter - 使用
pnpm安裝依附元件:pnpm install - 啟動本機開發伺服器:
開啟瀏覽器,pnpm devhttp://localhost:5173查看「Mont-Royal Plein Air」商店。
(選用) 安裝 WebMCP 檢查器擴充功能
如要更輕鬆地使用 WebMCP,可以安裝 WebMCP Model Context Tool Inspector。安裝完畢後,您需要取得 Gemini API 金鑰才能使用:
- 前往 AI Studio。
- 點按「建立 API 金鑰」按鈕,產生與您在本步驟稍早設定專案相關聯的新 Gemini API 金鑰。
- 開啟 WebMCP 模型內容工具檢查器 (會在側邊面板中開啟),然後按一下「更新 Gemini API 金鑰」按鈕。
- 將 API 金鑰貼到彈出式視窗中,然後儲存。
這個擴充功能含有可使用 WebMCP 的基本代理程式,讓您透過該程式試用網站,不必直接透過開發人員工具呼叫 WebMCP 工具。
3. 網頁上的內建 AI 模型
什麼是 Prompt API?
網頁應用程式可透過 Prompt API,直接存取完全在使用者裝置上執行的多模態小型語言模型。由於推論是在本機執行:
- 零雲端延遲:沒有網路來回行程或後端伺服器排隊。
- 預設為私密:提示和傳遞給提示的任何內容絕不會離開裝置
- 零成本:推論作業會在用戶端硬體上執行,不會產生權杖費用或雲端代管費用。
- 離線功能:即使沒有網路連線,也能穩定運作。
在 Chrome 中,您可以透過全域 LanguageModel 介面存取 Prompt API。
// 1. Set your expected inputs and outputs. This is multimodal, so you can
// include other types here, too
const languages = {
expectedInputs: [{type: "text", languages: ["en"]}],
expectedOutputs: [{type: "text", languages: ["en"]}],
}
// 2. Check availability. Always pass in your expected inputs and outputs,
// as some models may only support some inputs and outputs
const availability = await LanguageModel.availability(languages);
// 'available', 'downloading', or 'unavailable'
// 3. Create an isolated session with system prompt and language constraints
const session = await LanguageModel.create({
...languages,
// Optional: add initial context to your session, like a system prompt
initialPrompts: [
{
role: 'system',
content: 'You are an expert outdoors sales assistant...'
}
]
});
// 4. Define your expected output as JSON Schema
const schema = {
//...
}
// 5. Prompt the model (supports plain text or structured models)
const result = await session.prompt('Recommend a 3-season tent footprint.', {
responseConstraint: schema,
});
練習 1:根據歷程提供的建議
電子商務網站通常會提供「常與這項商品合購」的輪轉介面或追加銷售。如果是戶外活動網站,根據瀏覽記錄建立建議可能更有用。
為此,您將建構三階段的建議管道:
- 歷程分析器:使用提示 API 分析顧客的瀏覽時間軸,嘗試推斷使用者的真實旅遊意圖。
- 產品查詢:從該意圖,您會向虛擬產品後端發出 API 要求,以取得相關項目。
- 產品建議:將這些產品傳回 Product API 進行排名,並傳回與使用者觀看內容最相符的五個產品。
工作 1.1:Prompt API 初始化
您不必在每次想使用 Prompt API 時個別初始化,而是將呼叫集中到單一檔案中,並透過系統提示記憶建立作業,減少對同一代理程式進行多次呼叫的啟動時間。
前往 src/ai/prompt-api.ts 檔案,並檢查第 27 至 58 行的 getPromptSession():
export async function getPromptSession(
systemPrompt: string = '',
options: { signal?: AbortSignal } = {}
): Promise<LanguageModel>
- 重複使用快取的基本工作階段。第 21 行已有快取對應,
baseSessions,以系統提示做為鍵。重複使用基礎模型 (而非建立新模型) 可縮短啟動時間,並沿用核心設定,且每個工作階段不會互相干擾。clone()傳回複製項,通話者可以與複製項互動,包括destroy()複製項,不必捨棄快取基礎。 - 偵測 API 的功能。偵測 API 是否存在,如果不存在,則擲回錯誤。
- 宣告模態和語言。內建模型可支援多模態輸入內容。您需要宣告所需模式和要支援的語言。傳送給 LLM 的所有內容都是英文。
- 建立任何內容前,請先確認是否適用。即使有 API,也可能沒有符合您需求的模型。檢查是否有現有帳戶。如果不是,請擲回錯誤。如果只是尚未下載,請回報下載進度。
- 建立工作階段。設定選項,建立新的 Prompt API 工作階段,並提供系統提示 (如有)
工作 1.2:實作歷程分析器
前往 src/ai/journey-profiler.ts 檔案,並檢查第 42 至 100 行的目標函式:
export async function inferJourneyProfile(
context: ProfilerInputContext,
catalogMap: ReadonlyMap<string, Product>
): Promise<JourneyProfile>
- 使用工作 1 中的函式,產生要使用的新提示工作階段。
- 使用
journeyProfileSchema做為結構化回覆的 JSON 結構定義,提示模型使用提供的提示文字。 - 剖析提示輸出內容,並移除重複的目標類別。
- 以提示的實際結果取代硬式編碼的字串回傳。
- 工作階段結束後,請銷毀工作階段,釋出記憶體。
工作 1.3:實作協同效應重新排序器
前往 src/ai/synergy-reranker.ts 檔案,並檢查第 30 至 71 行的目標函式:
export async function rankComplementaryGear(
profile: JourneyProfile,
candidates: readonly Product[],
currentProduct?: Product | null,
cartProducts?: readonly Product[],
limit: number = 5
): Promise<readonly RecommendedItem[]>
- 使用工作 1 中的函式,產生要使用的新提示工作階段。
- 使用提供的提示文字和生成的結構定義,提示模型。
- 剖析提示輸出內容。
- 使用
assembleRecommendations傳回組裝好的建議清單。 - 工作階段結束後,請銷毀工作階段,釋出記憶體。
驗證建議管道
- 開啟 Chrome
http://localhost:5173/catalog/tent-mont-tremblant-3p。 - 向下捲動至「為你推薦」部分。
- 觀察 5 張隨附卡片如何更新,反映智慧套件配對 (例如地面足跡、睡墊和輕量釘子),而非隨機產品。
- 開啟 Chrome 開發人員工具控制台,檢查兩個推論步驟的即時執行時間。
(選用) 任務 1.4:探索更多內建 AI 模型
此外,還有其他內建 AI 模型可供使用,包括 Translator API 專家模型。這個程式碼集中的元件已連結至服務,可監聽目前語言的變化並要求翻譯,您的工作就是將所有內容連結起來。
前往檔案:src/ai/translator.ts
檢查第 29 至 45 行的目標函式 createTranslator:
export async function createTranslator(
targetLang: SupportedLanguage
): Promise<Translator | null>
- 確認是否支援 Translator API,並確保目標語言不是英文 (內容預設為英文)。
- 建立語言組合 (從英文到目標語言),並確認該組合是否可用。
- 為翻譯人員建立選項,並附加監控器,顯示模型下載進度。
- 傳回已初始化的翻譯人員。
接著,檢查第 50 至 58 行的目標函式 translate:
export async function translate(
text: string,
targetLang: SupportedLanguage
): Promise<string>
- 檢查是否有可用的翻譯人員,並在
getCachedTranslator中傳遞targetLang。如果沒有,請傳回乾淨的文字。 - 如有,請使用翻譯工具翻譯乾淨的文字。
前往檔案:src/ai/translator.ts
檢查第 204 行的目標函式 render:
export async function translate(
text: string,
targetLang: SupportedLanguage
): Promise<string>
- 啟用語言選擇器元件
4. 使用 WebMCP 提升代理程式體驗
什麼是 WebMCP?
隨著使用者開始使用自動和共同瀏覽代理程式,網站必須進行調整。傳統上,代理程式會依賴啟動 (擷取螢幕截圖、擷取 DOM 和無障礙樹狀結構),判斷如何與網站互動。這種做法速度緩慢、容易出錯,而且會浪費使用者權杖。
WebMCP 可讓開發人員直接提供工具給代理程式,與代理程式所在的網頁互動,藉此解決這個問題。支援這些工具的代理程式可以像使用編碼架構中的工具一樣使用這些工具,並根據您的指示提供清楚的結構化輸入內容和回傳值。
// Register a tool directly on document.modelContext
document.modelContext.registerTool({
name: 'get_product_specs',
title: 'Get Product Specs',
description: 'Retrieve technical specifications for the active product.',
inputSchema: {
type: 'object',
properties: {
// ...
},
},
annotations: {
readOnlyHint: true, // Informs the agent this tool causes no side-effects
},
execute: async (input) => {
return {
weight: '1.8 kg',
capacity: '3 persons',
seasons: '3-season',
};
},
});
代理程式連上網頁時,會查詢 document.modelContext.getTools()。每個已註冊的工具都會公開:
name:代理程式執行工具時使用的程式輔助工具 ID (例如'get_product_specs')。title:檢查員和代理商介面使用的人類可讀顯示標籤 (例如'Get Product Specs')。description:純文字說明,告知模型工具的功能和呼叫時機。代理程式會根據這項說明判斷是否應呼叫工具,因此請盡量詳細說明。inputSchema:定義可接受引數的 JSON 結構定義。annotations:行為提示,例如{ readOnlyHint: true },適用於不會造成狀態副作用的唯讀工具。execute:工具叫用時執行的非同步函式。
工作 2.1:建議和產品工具
首先,請註冊工具,讓代理程式擷取您在上一個練習中建立的建議。
前往檔案:src/components/product/ForYouSection.ts
檢查第 71 至 94 行的 registerWebMCPTools():
private registerWebMCPTools(): void
- 確認是否支援 WebMCP。
- 如果是,請註冊該工具。
- 選擇能吸引代理程式選取工具的標題和說明,這裡可以考慮使用提示工程。
- 沒有輸入內容,因此只要加入空白物件 JSON 結構定義即可。
- 這項工具只能讀取資料。
- 在執行函式中,使用
recommendationStore取得目前的建議組合,然後傳回目前的產品 ID 和產品建議組合。 - 新增中止信號並擷取該信號,以免擲回錯誤。確保元件卸載時,工具會正確移除。
前往檔案:src/views/ProductView.ts
- 重複相同程序來註冊
get_current_product工具,這次會傳回完整產品和建議
工作 2.2:購物車導覽匣工具
前往檔案:src/components/cart/CartDrawer.ts
檢查第 83 至 114 行的 registerWebMCPTools():
private registerWebMCPTools(): void
- 註冊
view_cart工具:
inputSchema應為具有單一布林選項openDrawer的物件。- 這個檔案應該只能讀取。
- 在
execute函式中讀取輸入內容、決定是否顯示或隱藏購物車、重新整理recommendationStore,然後傳回購物車摘要
- 註冊
manage_cart工具:
- 其
inputSchema應為包含items的物件,而 是包含productID、add、remove和updateaction列舉值,以及整數quantity的物件陣列。 execute函式應將項目傳遞至this.updateCart
工作 2.3:語言切換工具
進一步運用 WebMCP,向外部代理公開語言工具。
前往檔案:src/components/navigation/LanguagePicker.ts
檢查第 61 至 63 行的 registerWebMCPTools():
private registerWebMCPTools(): void
- 註冊
switch_language工具:inputSchema應具有language屬性,該屬性是SUPPORTED_LANGUAGE_CODES的列舉。- 其
execute函式應使用提供的語言呼叫this.switchLanguage。
工作 2.4:商店導覽工具
讓自主代理程式瀏覽商店、跳轉至產品頁面、瀏覽類別或發起搜尋。
前往檔案:src/components/navigation/SiteHeader.ts
檢查第 155 至 171 行的 registerWebMCPTools():
private registerWebMCPTools(): void
- 確認是否支援 WebMCP。
- 註冊
search工具:- 輸入結構定義會採用
query字串。 - 在
execute中呼叫this.search(input?.query)。
- 輸入結構定義會採用
- 註冊
go_to_catalog工具:- 輸入結構定義接受選用的
activity(ACTIVITIES的列舉) 和category(PRODUCT_CATEGORIES的列舉)。 - 在
execute中呼叫this.goToCatalog(input?.activity, input?.category)。
- 輸入結構定義接受選用的
- 註冊
get_categories_and_activities工具:- 唯讀工具,不含輸入參數。
- 在
execute中呼叫this.getCategoriesAndActivities()。
- 註冊
go_to_product工具:- 輸入結構定義需要
productId字串。 - 在
execute中呼叫this.goToProduct(input?.productId)。
- 輸入結構定義需要
使用 WebMCP 檢查器驗證
- 在 Chrome 中重新載入
http://localhost:5173/catalog/tent-mont-tremblant-3p,然後前往產品頁面。 - 開啟 Chrome 開發人員工具 >「應用程式」>「WebMCP」。
- 您應該會看到 WebMCP 工具:
get_recommendations、get_current_product、view_cart、manage_cart、switch_language、search、go_to_catalog、get_categories_and_activities和go_to_product。 - 按一下其中一個參數,即可查看詳細資料和參數。
- 選擇一個或多個含有參數的工具,然後按一下「執行工具」,即可查看工具的運作情形。
- (選用) 如果您已安裝並設定 WebMCP 模型內容工具檢查器,請開啟該檢查器,它會顯示在 Chrome 的側邊面板中。使用對話介面指示代理程式執行您認為應呼叫其中一項工具的動作,看看代理程式的回應。
5. (選用) 建立現場代理
在網頁中呼叫 WebMCP 工具
WebMCP 工具不僅適用於外部瀏覽器擴充功能或第三方機器人,您自己的應用程式也可以直接呼叫這些工具。透過查詢 document.modelContext.getTools(),用戶端程式碼可以動態探索及執行工具。
你可以使用這項功能建構網站 AI 購物助理,將搜尋列轉換為產品探索工具,根據自然語言輸入內容提供建議。您不必編寫自訂命令式程式碼來協調多個側邊篩選條件,搜尋列可以將自然語言查詢傳遞至 Prompt API,由該 API 決定要叫用哪些網頁內 WebMCP 工具。
如要透過 JavaScript 探索及叫用 WebMCP 工具,請按照下列步驟操作:
// getTools() returns a Promise — it must be awaited.
const tools = await document.modelContext.getTools();
const tool = tools.find(t => t.name === 'list_items');
const json = await document.modelContext.executeTool(tool, args);
const result = JSON.parse(json); // executeTool resolves with a DOMString
工作 3.1:側欄分面工具
將每個目錄側欄的構面公開給 WebMCP,讓代理程式 (和網頁內搜尋助理) 可以透過程式輔助切換篩選條件。
src/components/facets/ 中的每個構面元件,都會在其類別中提供輔助方法,並在 src/utils/filter-schemas.ts 中匯出輸入結構定義:
- 在
src/components/facets/ActivityFacet.ts中:- 使用
activityFilterSchema註冊activity_filter。 - 在
execute中呼叫this.filterActivity(input?.activity, input?.selected)。
- 使用
- 在
src/components/facets/CategoryFacet.ts中:- 使用
categoryFilterSchema註冊category_filter。 - 在
execute中呼叫this.filterCategory(input?.category, input?.selected)。
- 使用
- 在
src/components/facets/ConditionFacet.ts中:- 使用
conditionFilterSchema註冊condition_filter。 - 在
execute中呼叫this.filterCondition(input?.condition, input?.selected)。
- 使用
- 在
src/components/facets/PriceFacet.ts中:- 使用
priceFilterSchema註冊price_filter。 - 在
execute中呼叫this.filterPrice(input?.priceRange || input?.bracket, input?.selected)。
- 使用
- 在
src/components/facets/WeightFacet.ts中:- 使用
weightFilterSchema註冊weight_filter。 - 在
execute中呼叫this.filterWeight(input?.weightRange || input?.bracket, input?.selected)。
- 使用
- 在
src/components/facets/RatingFacet.ts中:- 使用
ratingFilterSchema註冊rating_filter。 - 在
execute中呼叫this.filterRating(input?.minRating || input?.rating, input?.selected)。
- 使用
- 在
src/components/facets/SearchFacet.ts中:- 使用
keywordFilterSchema註冊keyword_filter。 - 在
execute中呼叫this.updateKeyword(input?.keyword)。
- 使用
請記得檢查 WebMCP 支援,並如步驟 2 所學,傳遞 { signal: this.signal } (含 .catch(() => {}))。
工作 3.2:目錄檢視工具
現在請在 document.modelContext 上註冊目錄層級的項目、篩選器重設和語意搜尋工具。
前往檔案:src/views/CatalogView.ts
檢查第 125 至 140 行的 registerWebMCPTools():
private registerWebMCPTools(): void
- 確認是否支援 WebMCP。
- 註冊
list_items工具:- 這個屬性不接受任何輸入參數,且為唯讀。
- 其
execute函式應會呼叫this.getItemsSummary()。
- 註冊
reset_filters工具:- 不接受任何輸入參數。
- 其
execute函式應會呼叫this.resetFilters()。
- 註冊
semantic_catalog_filter工具:- 使用
semanticCatalogFilterSchema。 - 其
execute函式應會呼叫interpretAndApplySemanticFilter(input.query)。
- 使用
工作 3.3:協調語意篩選器代理程式
現在可以開始接線了。這項工作會將搜尋轉換為語意管道,為 semantic_catalog_filter 工具提供支援:
前往檔案:src/ai/catalog-semantic-filter.ts
檢查第 84 至 88 行的 prewarmSemanticFilterSession():
export async function prewarmSemanticFilterSession(): Promise<void>
- 檢查
warmSession是否已存在,如果存在,請提早傳回。 - 使用
getPromptSession()透過SEMANTIC_FILTER_SYSTEM_PROMPT預先啟動 Prompt API 工作階段,並將其儲存在warmSession中。請包裝在try/catch區塊中,這樣如果預先暖機失敗,搜尋建立作業仍可順利回溯。
檢查第 93 至 134 行的 inferSearchFacets():
async function inferSearchFacets(
searchTerm: string,
cachedJourney: JourneyProfile | null
): Promise<{ parsed: SemanticFilterResponse; cacheHit: boolean }>
- 從
warmSession聲明預先暖機的工作階段 (如有),並將warmSession重設為null,或使用getPromptSession(SEMANTIC_FILTER_SYSTEM_PROMPT)建立新的工作階段。 - 使用
semanticFilterSchema做為responseConstraint,以promptText提示模型。 - 剖析傳回的 JSON,使用
cacheKey將剖析結果儲存在永久快取中,並在finally區塊中終止工作階段。
檢查第 139 至 270 行的 applyFacetsViaWebMCP():
async function applyFacetsViaWebMCP(
searchTerm: string,
parsed: SemanticFilterResponse
): Promise<{ appliedFilters: SemanticFilterResult['appliedFilters']; toolsExecuted: string[] }>
- 使用
await document.modelContext.getTools()在document.modelContext上探索已註冊的工具。 - 呼叫
await executeFacet('reset_filters', {})即可重設篩選器,從頭開始。 - 使用
await Promise.all(facetTasks)同時套用有效構面。
檢查第 272 至 316 行的 interpretAndApplySemanticFilter():
export async function interpretAndApplySemanticFilter(
searchTerm: string
): Promise<SemanticFilterResult>
- 呼叫
inferSearchFacets(searchTerm, cachedJourney)推斷搜尋 facet。 - 使用
applyFacetsViaWebMCP(searchTerm, parsed)將推斷的構面套用至目錄。
驗證網頁內代理程式
- 前往
http://localhost:5173/catalog - 在頂端的搜尋列中輸入:
"lightweight 3 season tent for wet hikes" - 觀看 Prompt API 解析要求、叫用
activity_filter(Hiking)、category_filter(Tents) 和condition_filter(Wet),立即將目錄縮小至相符的裝備,不必手動點選核取方塊。
6. 您學到的內容
恭喜!您已將電子商務應用程式轉換為智慧型代理程式優先體驗,完全由裝置端 AI 和標準網頁平台 API 驅動。
您建構的內容:
- Prompt API (裝置端):使用
LanguageModel合成使用者瀏覽時間軸,產生即時JourneyProfile脈絡,並使用結構化 JSON 結構定義 (responseConstraint) 建構rankComplementaryGear協同引擎。 - WebMCP 元件工具:透過
document.modelContext在 UI 元件 (get_recommendations、get_current_product、view_cart、manage_cart) 中註冊的模組化封裝工具。 - 代理程式轉送架構:使用 Chrome WebMCP Inspector 擴充功能測試及驗證工具執行作業。
- 網站內網頁代理程式:直接在瀏覽器中協調用戶端工具,透過網站標題搜尋列,進行多面向的自然語言目錄搜尋。
- 裝置端專用 AI 模型:探討如何使用
Translator進行動態裝置端翻譯。
重點整理
- 零延遲和高隱私權:Gemini Nano 等裝置端模型可消除雲端 API 金鑰、網路延遲和資料外洩疑慮。
- 結構化輸出內容至關重要:搭配使用 JSON 結構定義與
responseConstraint,可將創意文字生成轉換為可靠、型別安全的應用程式邏輯。 - WebMCP 可讓 AI 代理瀏覽網頁:直接在 DOM 中註冊工具,可讓內部輔助功能和外部自主瀏覽器代理執行經過驗證的確定性動作。
- 讓模型提出建議,而非執行動作:將模型限制在已註冊的工具
enum中,並自行調度結果,可確保代理程式行為可供稽核,並防止模型發明動作。