CodeGym /课程 /ChatGPT Apps /Product Feed:用途、数据模型、关键字段与政策

Product Feed:用途、数据模型、关键字段与政策

ChatGPT Apps
第 14 级, 课程 1
可用

1. 为什么需要 Product Feed

如果与传统电子商务相比,Product Feed 介于以下两者之间:

  • 商品“橱窗”(带价格、库存、链接和媒体的目录);
  • 以及一个技术契约,用来描述商家准备通过 ChatGPT 展示和/或售卖的具体 SKU。

OpenAI 在其规范中明确指出,feed 是关于商品的单一事实来源,搜索、推荐和结账数据准备都基于它。

在普通网店里,用户自己浏览页面、翻看分类、做筛选等。AI 电商中则相反:用户只需对模型说“给我为一位喜欢桌游的开发者朋友挑一份不超过 30 美元的数字礼物”——ChatGPT 会基于你的 Product Feed 自行决定哪些 SKU 合适、以什么顺序展示,并将其整理为卡片与后续的 Instant Checkout。

因此,Product Feed 同时解决多项任务。

首先,它为 ChatGPT 提供结构化的搜索数据。模型不仅依赖商品名称与描述,还会参考分类、标签、价格、可用性、语言区域、国家/地区限制等。

其次,它是结账的数据来源。当 ChatGPT 开始准备 checkout_session 时,SKU ID、价格、货币、seller URL 及其他商业信息都来自 feed。

最后,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 服务器上托管 Product Feed 文件或 endpoint;
  • 在 ChatGPT Merchants 门户中登记该地址;
  • OpenAI 定期拉取 feed,进行校验并索引商品。

文档强调需要定期更新 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 内部,GiftProduct 与 GiftSkuFeedItem 可以是一对多关系。而在 feed 中,你输出的是“扁平化”的 SKU 列表。

为了让 ChatGPT 理解哪些 SKU 属于同一基础产品(例如 1、3、12 个月的订阅),通常会使用分组字段,如 item_group_id。不过这是一种架构模式,而非强制标准。

示例:

{
  "id": "gg-coffee-sub-1m-usd",                // 1 个月订阅的 SKU
  "item_group_id": "gg-coffee-sub",            // 你的产品 ID
  "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",            // 同一产品 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_stock、out_of_stock 等) 可能展示不可用商品
enable_search
商品是否可用于搜索 若非 true,商品不会出现在结果中
enable_checkout
是否支持 Instant Checkout 下单 仅做 discovery/link‑out

重要细节:enable_search 与 enable_checkout 在逻辑上划分工作模式。

若 enable_search = true、enable_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
}

category 与 brand 等附加属性不仅能改进搜索结果,还有助于分析:你可以观察哪些类目经由 ChatGPT 的转化更好,哪些较差。

可选字段通常对应更特定的场景(例如我们稍后要谈的价格地理参数,或自定义元数据)。应随项目成熟度按需补充,而非为“打勾”而加。

6. 商务标志与 discovery‑only 模式

让我们再次明确 enable_search 与 enable_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 中的字段将用于填充 checkout_session 的 line_items 与总额。

因此,feed 成为精细化操控的杠杆:哪些 SKU、以何种方式,ChatGPT 才有权代表你进行销售。

7. 语言区域、货币、地区与多地区定价

你当然知道,世界不止有 en-US 与美元。在本系列的本地化模块中,我们已讨论 locale 与 userLocation 如何影响业务逻辑。这里它更为关键:德国与美国的定价可能不同,某些礼物在一些国家/地区甚至不可售。

Product Feed 规范通过若干机制来应对这些情况。

首先,货币:currency 必须是有效的 ISO 4217 代码(例如 usd、eur、gbp)。

其次,可以使用描述地理相关价格与可用性的字段。文档给出了类似 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 + 地理字段。

在每条记录中保存价格数组或附加属性:

{
  "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 所知的 locale 与 userLocation;
  • 与 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: "面向开发者的在线课程,终于把泛型学明白。",
    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,看看一个形式上几乎能跑、实际上会出问题的 feed 示例:

{
  "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 且为本地域名——两者都不适用于真实生产;规范明确要求 HTTPS 与公开可访问。

第五,enable_search 与 enable_checkout 应为布尔值,而非字符串。否则 OpenAI 的解析要么拒绝该 feed,要么按默认值处理,结果可能令你意外。

这类问题可能导致严格校验错误(feed 被拒),也可能造成更糟的情况:表面上 feed 被接受,但部分 SKU 被忽略或行为与预期不同。因此应在你这一端先做好内部校验。

11. 使用 Product Feed 的常见错误

错误 1:将 feed 当作一次性的“导入 CSV”。
有的团队把 Product Feed 当作一次性“为集成而生成”的文件,然后就不管了。在 AI 电商里并非如此: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,而你的后端还不会卖它(或反之,SKU 已从 feed 移除,但后端仍认为它存在),就会出现不同步、复杂 bug 与海量支持工单。最佳实践是拥有统一的领域模型,同时用于生成 feed 与处理结账。

1
任务
ChatGPT Apps, 第 14 级, 课程 1
已锁定
最小化的 Product Feed 作为公共 JSON 端点
最小化的 Product Feed 作为公共 JSON 端点
1
任务
ChatGPT Apps, 第 14 级, 课程 1
已锁定
Feed Builder:将“产品和变体”展开为扁平的 SKU 列表 + 策略门控
Feed Builder:将“产品和变体”展开为扁平的 SKU 列表 + 策略门控
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION