CodeGym /課程 /ChatGPT Apps /Product Feed:用途、資料模型、關鍵欄位與政策

Product Feed:用途、資料模型、關鍵欄位與政策

ChatGPT Apps
等級 14 , 課堂 1
開放

1. 為什麼需要 Product Feed

若拿傳統的 e‑commerce 來比較,Product Feed 介於以下兩者之間:

  • 商品的「展示櫥窗」(含目錄、價格、存貨、連結與媒體);
  • 以及一份技術合約,描述商家準備透過 ChatGPT 展示與/或販售的 SKU。

OpenAI 的規格說得很清楚:feed 是關於商品的單一真實來源(single source of truth),搜尋、推薦與結帳資料準備都依賴它。

在一般的網路商店,使用者會自己逛頁面、瀏覽分類、設定篩選條件等。在 AI‑commerce 中卻相反:使用者只會對模型說「幫我找一個 30 美元以內、送給喜歡桌遊的開發者朋友的數位禮物」——接著 ChatGPT 會自行判斷你的 Product Feed 中哪些 SKU 合適、以何種順序呈現,並把它們組成卡片及後續的 Instant Checkout。

因此,Product Feed 一次解決多個任務。

首先,它為 ChatGPT 提供結構化的搜尋資料。模型不僅依賴商品標題與描述,也會考量類別、標籤、價格、可用性、語系、國別限制等。

其次,它是結帳資料的來源。當 ChatGPT 開始準備 checkout_session 時,會直接從 feed 抽取 SKU 的 ID、價格、貨幣、seller URL 與其他商務資訊。

最後,Product Feed 是一份形式化的你與平台之間的合約。你明確告知:「這是 SKU 清單,哪些可以用於搜尋(discovery),哪些還可以透過 Instant Checkout 結帳。」

為了更直觀,先畫一張簡單的示意圖。

flowchart TD
  A[GiftGenius DB] --> B[Feed Builder]
  B --> C["Product Feed (CSV/JSON/...)"]
  C --> D[OpenAI Ingestion]
  D --> E[搜尋索引 + 排名]
  E --> F[ChatGPT/Agent 挑選禮物]
  F --> G["Instant Checkout (ACP)"]

左邊是你的內部資料庫,裡面有「真正」的商品目錄。右邊是呈現給使用者的 ChatGPT。中間是 Product Feed 以及它的接收與索引機制。本講座所做的一切,正位於 A 與 D 之間。

2. Product Feed 的格式與「物理層面」

OpenAI 的規格對檔案格式相當彈性:支援 TSV、CSV、XML 與 JSON。這是刻意設計,好讓多數既有系統(從自研單體到 Shopify)都能不費力地匯出 feed。

典型流程如下:

  • 你在自己的 HTTPS 伺服器上提供一個檔案或 endpoint,內含 Product Feed;
  • 在 ChatGPT Merchants 入口註冊該位址;
  • OpenAI 會定期擷取、驗證並為商品建立索引。

文件強調應定期更新 feed(甚至每 10–15 分鐘也可),以便使用者看到即時的價格與可用性,尤其在特賣與尖峰時段。

在 GiftGenius 的教學範例中,我們會使用 JSON 格式,因為對 TypeScript 開發者較友好。但要理解:OpenAI 的規格層並不綁定 JSON,僅是我們此處較方便。

最簡單的 JSON feed 可能如下:

[
  {
    "id": "gg-coffee-sub-1m-usd",
    "title": "咖啡訂閱 1 個月",
    "description": "每月一盒咖啡豆,適合開發者。",
    "price": 2900,
    "currency": "usd",
    "availability": "in_stock",
    "link": "https://giftgenius.app/gifts/coffee-subscription-1m",
    "image_link": "https://cdn.giftgenius.app/images/coffee-1m.png",
    "enable_search": true,
    "enable_checkout": true
  }
]

實務上欄位會更多,且其中一部分是必填、另一部分是建議或可選。詳細機制我們接下來會拆解。

3. 產品 vs 變體(SKU):如何建模

常見問題之一:「在 Product Feed 中,如何表達一個商品的尺寸、組合、訂閱時長與其他變體?」

Product Feed 規格以一筆筆的紀錄來表示,每筆描述一個可販售的配置。業界建議(也與 OpenAI feed 很契合)的架構模式是:每一種不同的配置(尺寸、訂閱時長、資費、地區)都作為 feed 中的獨立紀錄,也就是一個獨立的 SKU。

基礎產品存在於你的內部模型,至於 feed 層級則以 SKU 為單位運作。

例如你有一個服務,提供 1、3、6 個月的訂閱。就 product feed 而言,這些都是不同的 SKU。若同一服務可以在 20 種條件下購買,那你的 product feed 也應該有 20 個 SKU。

在 TypeScript 中可以大致這樣表達:

// GiftGenius 內部模型
export interface GiftProduct {
  id: string;              // product_123
  name: string;
  description: string;
  baseImageUrl: string;
}

// 會輸出到 Product Feed 的 SKU
export interface GiftSkuFeedItem {
  id: string;              // product_123_usd_1m
  productId: string;       // 參照 GiftProduct.id
  title: string;
  description: string;
  price: number;           // 以最小單位(美分)
  currency: string;        // "usd"
}

在 GiftGenius 內部,GiftProductGiftSkuFeedItem 可以是 1:N 的關係。而在 feed 中,你提供的是「扁平」的 SKU 清單。

為了讓 ChatGPT 理解哪些 SKU 屬於同一個基礎產品(例如 1、3、12 個月的訂閱),常會使用像 item_group_id 這樣的分組欄位。不過這是架構慣例,而非硬性規定。

例如:

{
  "id": "gg-coffee-sub-1m-usd",                // 1 個月訂閱的 SKU
  "item_group_id": "gg-coffee-sub",            // 你的產品
  "title": "咖啡訂閱 — 1 個月",
  "price": 2900,
  "currency": "usd",
  "enable_search": true,
  "enable_checkout": true
}

而 3 個月訂閱:

{
  "id": "gg-coffee-sub-3m-usd",                // 3 個月訂閱的 SKU
  "item_group_id": "gg-coffee-sub",            // 同一個 product id
  "title": "咖啡訂閱 — 3 個月",
  "price": 7900,
  "currency": "usd",
  "enable_search": true,
  "enable_checkout": true
}

此作法能同時讓模型與你的後端在建立訂單時更輕鬆:SKU 的 ID 成為唯一鍵,你可據此精準找到使用者購買的配置。

4. Product Feed 的必填欄位與它們對 UX 的影響

在 Product Feed 規格中,OpenAI 大致把欄位分為三群:必填(required)、建議(recommended)與可選(optional)。

具體名稱與清單請以最新文件為準;出於教學目的,我們先以這個「最小集合」為依據。

欄位 用途 缺少時的影響
id
商家範圍內 SKU 的唯一識別碼 無法唯一識別商品
title
卡片上使用的短標題 模型更難理解這是什麼商品
description
較完整的描述 回答會較空泛,個人化較差
price
以最小單位表示的價格 無法準備結帳
currency
ISO 4217 的貨幣代碼,通常小寫 平台無法理解計價單位
link
商家端商品頁面的 URL 使用者無法前往你的網站
availability
存貨狀態(in_stockout_of_stock 等) 可能顯示不可購買的商品
enable_search
此商品是否可參與搜尋 若非 true,商品不會出現在結果中
enable_checkout
是否可透過 Instant Checkout 購買 僅能 discovery/link‑out

重點提醒:enable_searchenable_checkout 在邏輯上區分了不同模式。

如果 enable_search = trueenable_checkout = false,商品可以出現在結果中,但當使用者想購買時會透過你的 link 前往你的网站,而不是在 ChatGPT 內的 Instant Checkout(信用卡已綁定)。

enable_checkout = true,在其他條件也符合的情況(支援的地區、貨幣、有效的 ACP backend),商品可以直接在 ChatGPT 內一兩下完成購買(轉換率通常會明顯提升)。

「最小可用」的 GiftGenius 結帳物件範例:

{
  "id": "gg-dev-notebook-plain-usd",
  "title": "極簡開發者筆記本",
  "description": "黑色、無橫線、120 頁。適合喜歡手寫規格書的人。",
  "price": 1500,
  "currency": "usd",
  "availability": "in_stock",
  "link": "https://giftgenius.app/gifts/dev-notebook",
  "image_link": "https://cdn.giftgenius.app/images/dev-notebook.png",
  "enable_search": true,
  "enable_checkout": true
}

請注意:即便在範例中我們也加入圖片(image_link)——形式上它可能是建議欄位、非必填,但沒有它 UX 會大幅打折。

5. 建議與可選欄位:讓 feed 更「誘人」

必填欄位只是「讓它跑得起來」。如果只停留在這一步,你得到的會比較像會計用的最小可用 CSV,而不是出色的 AI 展示櫥窗。

建議欄位通常包含:

  • 主要與其他圖片的 URL;
  • 商品分類(常見基於分類樹,例如「gifts > experiences > online courses」);
  • 品牌/商家名稱;
  • 屬性如顏色、尺寸、材質;
  • 成人內容旗標、年齡限制等。

你描述越豐富,模型能生成的回答就越有意義。舉例:若你明確寫出筆記本是用回收紙製成、並「支持關心地球的開發者」,ChatGPT 就能有意識地推薦給尋找環保友善禮物的使用者。

在 GiftGenius 中,我們可以把某個 SKU 的描述擴充如下:

{
  "id": "gg-dev-notebook-plain-usd",
  "title": "開發者環保筆記本",
  "description": "極簡、無橫線,120 頁回收紙。",
  "price": 1500,
  "currency": "usd",
  "availability": "in_stock",
  "link": "https://giftgenius.app/gifts/eco-dev-notebook",
  "image_link": "https://cdn.giftgenius.app/images/eco-dev-notebook.png",
  "category": "gifts > office > notebooks",
  "brand": "GiftGenius Originals",
  "enable_search": true,
  "enable_checkout": true
}

categorybrand 這些額外屬性不僅提升搜尋結果,也有助於分析:你可以觀察哪些分類在 ChatGPT 的轉換較好、哪些較差。

可選欄位往往對非常特定的場景才有用(例如我們稍後會談的區域性價格,或自定義的後設資料)。應該隨著專案成熟度逐步加入,而不是為了「打勾」而加。

6. 商業旗標與僅探索(discovery‑only)模式

讓我們再明確一次 enable_searchenable_checkout 的邏輯,因為這是通往後續 ACP 與 Instant Checkout 章節的關鍵橋樑。

假設你剛開始成為 ChatGPT 商家。你已有禮物目錄,但 ACP backend 與 Delegated Payment 尚在開發。你希望現在就能讓 ChatGPT 找到你的 SKU,並把使用者導向你的网站付款。

此時你可以:

  • 在需要的 SKU 上,將 enable_search 設為 true 並發布 Product Feed;
  • enable_checkout 保持為 false,直到 ACP 整合完成且通過認證。

這樣一來,ChatGPT 能把你的禮物納入回答、顯示卡片,並提供「前往 GiftGenius 網站」的連結,但不會構建內部的 Instant Checkout UI。

等你實作了 Agentic Checkout 與 Delegated Payment 之後,可以把特定商品切換為「可用於 Instant Checkout」——只要把 enable_checkout 設為 true,並且補齊所有資料需求(價格、貨幣、seller URL 等)。

在規格層,Product Feed 中的欄位會用於填充 line_itemscheckout_session 的金額。

因此,feed 變成精細控制的槓桿:決定哪些 SKU、以何種方式,ChatGPT 有權代表你販售。

7. 在地語系、貨幣、地區與多區域定價

想必你很清楚,世界不只 en-US 與美元。在在地化模組中,我們已談過 localeuserLocation 如何影響商務邏輯。這裡更為關鍵:德國的售價可能不同於美國,且某些禮物在部分國家壓根無法販售。

Product Feed 規格透過多種機制來處理這些情況。

其一是貨幣:currency 必須是有效的 ISO 4217 代碼(例如 usdeurgbp)。

其二是可描述地區化價格與可用性的欄位。文件中舉過像 geo_price 及其相關、基於 ISO 3166 的地區代碼等屬性。

有兩個基本的架構做法。

做法一:一個地區對應一個 feed。

  • product-feed-us-en.json:美國;
  • product-feed-de-de.json:德國;
  • product-feed-br-pt.json:巴西。

每個 feed 內的 SKU 都已轉換到對應的貨幣與語系。對 ChatGPT 較簡單,但你需要維護多份 feed。

做法二:單一 feed,內含 geo 欄位。

每筆紀錄內保存價格陣列或額外屬性:

{
  "id": "gg-dev-notebook-multi",
  "title": "開發者環保筆記本",
  "description": "支持你對乾淨程式碼與地球的熱愛。",
  "prices": [
    { "region": "US", "currency": "usd", "price": 1500 },
    { "region": "DE", "currency": "eur", "price": 1400 }
  ],
  "availability_by_region": [
    { "region": "US", "availability": "in_stock" },
    { "region": "DE", "availability": "out_of_stock" }
  ],
  "enable_search": true,
  "enable_checkout": true
}

多區域欄位的實際結構取決於規格版本,但核心概念不變:feed 必須讓平台能理解某個 SKU 在哪些國家存在、在當地售價是多少

對 GiftGenius 而言,重要的是設計以下映射:

  • ChatGPT 所知的 localeuserLocation
  • 以及在 feed 中應採用的價格與文字來源。

在多數商務場景中,你不會釋出一筆「覆蓋全球」的紀錄,而是為不同國家建立不同的 SKU,以便更容易遵循稅務、政策與商品限制。

8. 資料品質與政策:沒有它們,Instant Checkout 起不來

Product Feed 不僅是格式問題,也是資料品質與遵循 OpenAI 政策的問題。

在品質方面,OpenAI 明確要求:

  • 正確、穩定的識別碼;
  • 有效的 HTTPS URL 且回應 200;
  • 價格與貨幣的一致性;
  • 即時的可用性(不應標示 in_stock 但實際缺貨)。

另外,規格對文字長度也有要求:例如 title 不應過長(數百字),description 也有合理上限(數千字),以免卡片過於雜亂、變成長篇小說。

另一塊是Prohibited Products Policy。這是不得透過 Instant Checkout 或 ChatGPT 銷售的品項與服務清單:例如非法商品、武器、部分醫療服務等。細節請以最新政策為準;對我們而言,重要的是:Product Feed 不僅會檢查格式,還會審視內容是否合法可售。

若你的目錄包含灰色地帶(例如酒精、博弈、或與兒童相關的品項),這些類別要格外謹慎。很多時候,把它們維持在 enable_checkout = false 的模式,僅在自家網站、搭配完整法務流程販售,會更省事。

9. 實作:為 GiftGenius 組一個最小可用的 Product Feed

現在把上述概念用在實作上,為三個 GiftGenius 的 SKU 建立一個簡單的 feed。假設我們有:

  1. 開發者環保筆記本。
  2. 咖啡訂閱 1 個月。
  3. 「TypeScript 給大人的課程」禮品券。

先定義用來產生 feed 的 TypeScript 型別:

export interface GiftGeniusFeedItem {
  id: string;
  title: string;
  description: string;
  price: number;         // 以美分
  currency: "usd" | "eur";
  availability: "in_stock" | "out_of_stock";
  link: string;
  image_link?: string;
  enable_search: boolean;
  enable_checkout: boolean;
}

接著在程式中建立一個陣列,放入幾個元素,最後序列化為 JSON:

export const giftGeniusFeed: GiftGeniusFeedItem[] = [
  {
    id: "gg-eco-notebook-usd",
    title: "開發者環保筆記本",
    description: "極簡、無橫線,回收紙材質。",
    price: 1500,
    currency: "usd",
    availability: "in_stock",
    link: "https://giftgenius.app/gifts/eco-dev-notebook",
    image_link: "https://cdn.giftgenius.app/images/eco-dev-notebook.png",
    enable_search: true,
    enable_checkout: true
  },
  {
    id: "gg-coffee-sub-1m-usd",
    title: "開發者咖啡訂閱 — 1 個月",
    description: "每月一盒咖啡豆。讓你趕進度也有精神。",
    price: 2900,
    currency: "usd",
    availability: "in_stock",
    link: "https://giftgenius.app/gifts/coffee-subscription-1m",
    image_link: "https://cdn.giftgenius.app/images/coffee-1m.png",
    enable_search: true,
    enable_checkout: true
  },
  {
    id: "gg-ts-course-gift-usd",
    title: "TypeScript 課程禮品券",
    description: "線上課程,給終於想弄懂 generics 的開發者。",
    price: 9900,
    currency: "usd",
    availability: "in_stock",
    link: "https://giftgenius.app/gifts/ts-course",
    image_link: "https://cdn.giftgenius.app/images/ts-course.png",
    enable_search: true,
    enable_checkout: false // 目前僅 discovery
  }
];

之後可以寫一個簡單工具,每隔 N 分鐘從此結構產生 product-feed.json 並發布到你的 HTTPS 伺服器。

import { writeFile } from "node:fs/promises";
import { giftGeniusFeed } from "./feed-data";

// 最簡單的 JSON feed 產生器
async function buildProductFeed() {
  const json = JSON.stringify(giftGeniusFeed, null, 2);
  await writeFile("public/product-feed.json", json, "utf8");
}

buildProductFeed().catch(console.error);

顯然在真實專案中你不會把整個 feed 寫死在程式裡;資料應從資料庫取得。不過先做出這樣的教學範例可幫助測試整條管線:產生 → 發佈 → 驗證。

10. 反例:一個「糟糕」的 Product Feed 長什麼樣

為了更理解規格與 UX 的需求,看看一個形式上幾乎能跑、但實務上會帶來問題的範例:

{
  "id": "1",
  "title": "禮物",
  "description": "很棒的禮物",
  "price": 12.333333,
  "currency": "usdollars",
  "availability": "yes",
  "link": "http://giftgenius.local/gift/1",
  "enable_search": "true",
  "enable_checkout": "maybe"
}

這裡一眼就能數出好幾個問題。

首先,id = "1" 是不穩定且過於單薄的識別碼。當你遷移資料庫或導入分片時,這類 ID 很脆弱。最好使用語義清晰且足夠長、在商家範圍內唯一的 ID。

其次,price 以有小數尾巴的浮點數呈現。規格與金流系統通常要求用最小單位的整數(如美分、台分),以避免浮點與進位誤差。

第三,currency = "usdollars"availability = "yes" 並不符合預期格式(ISO 4217 與受支援的狀態清單)。

第四,link 指向 http 且為本機網域——兩者在真實的 production 都不可接受;規格明確要求 HTTPS 與公開可存取。

第五,enable_searchenable_checkout 應為布林值,而非字串。否則 OpenAI 的解析器可能拒收,或直接套用預設值,帶來意料之外的結果。

這些問題可能導致嚴重的驗證錯誤(feed 被退件),或更糟的是:形式上被接受,但部分 SKU 被忽略或行為不如預期。因此,非常值得在你方就先做好內部驗證。

11. 常見錯誤與避坑指南

錯誤 #1:把 feed 當成一次性的「匯入用 CSV」。
有些團隊把 Product Feed 視為為了整合而「一次性」產生的檔案,之後就丟著不管。AI‑commerce 不是這樣:feed 是活的真實來源,必須定期更新。價格變動、下架商品、促銷活動——都應即時反映到 feed。否則 ChatGPT 會推薦不存在或舊價格的商品,使用者自然會不滿。

錯誤 #2:混淆產品模型與 SKU。
常見反模式是用一筆 feed 紀錄塞滿一個基礎產品的所有選項,像是「size1/size2/size3」或「duration1/duration2」。結果模型無法理解實際販售的是什麼,你的 ACP backend 也會在結帳時為拆解這些欄位而痛苦。更簡單可靠的方式是:一個 SKU 對應一筆 feed 紀錄,即使它只是同一產品底下的一種變體。

錯誤 #3:忽略語系與地區。
不少在做第一版 MVP 的團隊會把 currency 一律設為 "usd",並對所有商品將 enable_checkout 設為 true,完全沒考慮 Instant Checkout 在你所在區域是否可用、或某些商品在特定國家是否禁售。等到你拓展新市場時,各種問題就會浮現:價格不合、稅費未計。從一開始就把 SKU 綁定到地區與貨幣,會更健康。

錯誤 #4:把描述當作過去式的 SEO 文案。
有些團隊會把網站上舊的、為了「關鍵字」與爬蟲而寫的描述直接複製到 Product Feed。對 ChatGPT 來說,這通常弊大於利:模型本就會寫文案,它更在乎的是結構化、真實且精準的事實。寧可簡潔到位,也不要讓 description 變成滿版的行銷空話。

錯誤 #5:不自行驗證 feed。
完全仰賴 OpenAI 端的驗證,是在死線前自找痛苦。請在你的後端或 CI 做個簡單驗證器,檢查欄位結構、允許值、URL 與貨幣格式。即便只是用 TypeScript 搭配 Zod 或自寫檢查也行。你會在上線前就先攔截問題。

錯誤 #6:把「所有東西」都丟進 Product Feed。
有時會想一次把上千個 SKU 都放進 feed,「以防萬一」。實務上這會讓除錯、分析與品質管控都變難。更明智的做法是從有限子集合開始:只放你準備好維護、也真的想在 ChatGPT 上販售的類別與 SKU。其餘保留在 discovery 模式,甚至先不要整合。

錯誤 #7:Product Feed 與 ACP backend 沒同步。
feed 與 ACP API 是一體兩面。若 feed 出現新 SKU、但你的 backend 還不會賣它(或反之,SKU 已從 feed 移除,但 backend 仍認為它存在),就會產生不同步、難追的 bug 與艱難的客服工單。良好做法是維持單一的網域模型,同時用它來產生 feed 與處理結帳。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION