JavaRush /Курсы /ChatGPT Apps /Product Feed: назначение, модель данных, ключевые поля и ...

Product Feed: назначение, модель данных, ключевые поля и политика

ChatGPT Apps
14 уровень , 1 лекция
Открыта

1. Зачем вообще нужен Product Feed

Если сравнивать с классическим e‑commerce, Product Feed — это нечто среднее между:

  • «витриной» товаров (каталог с ценами, наличием, ссылками и медиа);
  • и техническим контрактом, который описывает, какие именно SKU мерчант готов показать и/или продать через ChatGPT.

OpenAI в своей спецификации прямо говорит, что feed — это единый источник правды о товарах, на который опираются поиск, рекомендации и подготовка данных для чекаута.

В обычном интернет‑магазине пользователь сам ходит по страницам, листает категории, фильтрует и т.д. В AI‑commerce всё наоборот: пользователь просто говорит модели «подбери мне цифровой подарок до 30 долларов другу‑разработчику, который любит настолки» — а ChatGPT уже сам думает, какие именно SKU из вашего Product Feed подходят, в каком порядке их показать и как всё это оформить в виде карточек и последующего Instant Checkout.

Поэтому Product Feed решает сразу несколько задач.

Во‑первых, он даёт ChatGPT структурированные данные для поиска. Модель опирается не только на описание и название товара, но и на категории, теги, цену, доступность, локаль, ограничения по странам.

Во‑вторых, он является источником данных для чекаута. Когда ChatGPT начинает готовить checkout_session, именно из фида берутся ID SKU, цена, валюта, 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) могли экспортировать фид без шаманства.

В типичном варианте:

  • вы размещаете файл или endpoint с Product Feed на своём HTTPS‑сервере;
  • этот адрес регистрируете в портале ChatGPT Merchants;
  • OpenAI периодически забирает этот фид, валидирует и индексирует товары.

Документация подчёркивает, что фид нужно обновлять регулярно (можно даже каждые 10–15 минут), чтобы пользователи видели актуальные цены и наличие, особенно в распродажи и пиковые периоды.

В учебном примере с GiftGenius мы будем работать с форматом JSON, потому что он хорошо заходит TypeScript‑разработчикам. Но важно понимать: на уровне спецификации OpenAI не привязан к JSON, просто для нас это удобнее.

Простейший JSON‑фид мог бы выглядеть так:

[
  {
    "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‑фидом), выглядит так: каждая отдельная конфигурация (размер, вариант подписки, тариф, регион) — это отдельная запись фида, то есть отдельный SKU.

Базовый продукт живёт у вас во внутренней модели, а в фиде вы работаете на уровне 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;
}

// SKU, который пойдёт в Product Feed
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. А в фиде вы отдаёте уже «плоский» список SKU.

Чтобы ChatGPT мог понимать, какие SKU относятся к одному базовому продукту (например, подписка на 1, 3 и 12 месяцев), часто используется группирующее поле вроде item_group_id. Однако это уже архитектурный паттерн, а не жёсткое требование стандарта.

Например:

{
  "id": "gg-coffee-sub-1m-usd",                // SKU подписки на 1 месяц
  "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",                // SKU подписки на 3 месяца
  "item_group_id": "gg-coffee-sub",            // Тот же id-продукта
  "title": "Подписка на кофе — 3 месяца",
  "price": 7900,
  "currency": "usd",
  "enable_search": true,
  "enable_checkout": true
}

Такой подход облегчает и жизнь модели, и жизнь вашего бэкенда при создании заказов: ID SKU становится уникальным ключом, по которому вы всегда можете найти точную конфигурацию, которую купил пользователь.

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) на ваш сайт, а не в Instant Checkout внутри ChatGPT (где уже привязана карта).

Если же enable_checkout = true, то при соблюдении остальных условий (поддерживаемый регион, валюта, валидный ACP backend) товар может быть куплен прямо в ChatGPT одним‑двумя кликами (что сильно повышает конверсию).

Пример «минимально пригодного» объекта GiftGenius для checkout:

{
  "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. Рекомендованные и опциональные поля: как сделать фид «вкуснее»

Обязательные поля — это «чтобы вообще работало». Но если останавливаться только на них, вы получите что‑то вроде минимально валидного CSV для бухгалтерии, а не крутую AI‑витрину.

Рекомендованные поля обычно включают:

  • основной и дополнительные URL изображений;
  • категорию товара (часто на основе таксономии, вроде «gifts > experiences > online courses»);
  • бренд/мерчант‑нейм;
  • атрибуты вроде цвета, размера, материала;
  • флаги adult‑контента, возрастные ограничения и т.п.

Чем богаче вы опишете товар, тем более осмысленные ответы сможет генерировать модель. Например, если вы явно прописываете, что блокнот сделан из переработанной бумаги и поддерживает «разработчиков, переживающих за планету», 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 и отправлять пользователей на ваш сайт для оплаты.

В этом случае вы:

  • публикуете Product Feed с enable_search = true для нужных SKU;
  • оставляете enable_checkout = false до тех пор, пока не завернёте и не сертифицируете ACP‑интеграцию.

ChatGPT тогда сможет включать ваши подарки в ответы для пользователей, показывать карточки и предлагать ссылку «Перейти на сайт GiftGenius», но не будет строить внутренний UI Instant Checkout.

Когда же вы реализуете Agentic Checkout и Delegated Payment, определённые товары можно перевести в режим «готовы для Instant Checkout» — просто установив enable_checkout = true и дополнительно выполнив все требования по данным (наличие цены, валюты, seller URL и т.п.).

На уровне спецификаций именно поля из Product Feed будут использоваться для заполнения полей line_items и суммы в checkout_session.

Таким образом, фид становится рычагом тонкой настройки: какие именно SKU и в каком виде ChatGPT вообще имеет право продавать от вашего имени.

7. Локали, валюты, регионы и мульти‑региональные цены

Думаю вы в курсе, что мир не ограничивается en-US и долларами. В модулях про локализацию мы уже обсуждали, как locale и userLocation влияют на бизнес‑логику. Здесь это выходит на передний план: товары в Германии могут стоить иначе, чем в США, и какие‑то подарки в принципе не могут продаваться в некоторых странах.

Product Feed спецификация учитывает это через несколько механизмов.

Во‑первых, валюта: currency должен быть валидным кодом ISO 4217 (например, usd, eur, gbp).

Во‑вторых, могут использоваться поля, описывающие геозависимую цену и доступность. В документации приводится пример атрибутов вроде geo_price и связанных с ним региональных кодов, основанных на ISO 3166.

Есть два базовых архитектурных подхода.

Подход один: один фид на один регион.

  • product-feed-us-en.json для США;
  • product-feed-de-de.json для Германии;
  • product-feed-br-pt.json для Бразилии.

В каждом фиде все SKU уже приведены к нужной валюте и локали. Простота для ChatGPT, больше работы для вас по поддержанию нескольких фидов.

Подход два: единый фид c 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
}

Конкретная структура мульти‑региональных полей зависит от версии спецификации, но идея одна: фид должен позволять платформе понять, в каких странах SKU существует и сколько он там стоит.

С точки зрения GiftGenius, важно продумать маппинг между:

  • locale и userLocation, которые ChatGPT знает;
  • и той частью фида, из которой нужно брать цены и тексты.

Чаще всего в коммерческих сценариях вы не отдаёте одну запись «на весь мир», а делаете разные SKU на разные страны, чтобы проще было соблюдать налоги, политику и ограничения на товары.

8. Качество данных и политика: без этого Instant Checkout не взлетит

Product Feed — это не только про формат, но и про качество данных и соблюдение политики OpenAI.

В части качества OpenAI явно требует:

  • корректные, стабильные идентификаторы;
  • валидные URL с HTTPS и кодом ответа 200;
  • согласованность цены и валюты;
  • актуальное наличие (не должно быть in_stock товаров, которых на самом деле уже нет).

Также в спецификации есть требования к длине текстов: например, title не должен быть слишком длинным (сотни символов), а description имеет разумный лимит (тысячи символов), чтобы карточки выглядели опрятно и не превращались в роман в трёх томах.

Отдельный блок — Prohibited Products Policy. Это список категорий товаров и услуг, которые нельзя продавать через Instant Checkout и/или ChatGPT вообще: очевидные вещи вроде незаконных товаров, оружия, некоторых медицинских услуг и т.п. Конкретику всегда нужно проверять в актуальной политике, но для нас важно осознать: Product Feed будет проверяться не только на формат, но и на допустимость содержания.

Если ваш каталог содержит неоднозначные категории (например, алкоголь, азартные игры или что‑то, связанное с детьми), к этим разделам стоит относиться с особым вниманием. Часто их проще оставить в режиме enable_checkout = false и продавать только через собственный сайт с полноценной юридической обвязкой.

9. Практика: собираем минимальный Product Feed для GiftGenius

Давайте теперь применим всё это на практике и соберём простой фид для трёх SKU GiftGenius. Представим, что у нас есть:

  1. Эко‑блокнот для разработчика.
  2. Подписка на кофе на 1 месяц.
  3. Подарочный сертификат на курс «TypeScript для взрослых».

Сначала опишем 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-фида
async function buildProductFeed() {
  const json = JSON.stringify(giftGeniusFeed, null, 2);
  await writeFile("public/product-feed.json", json, "utf8");
}

buildProductFeed().catch(console.error);

Понятно, что в реальном проекте вы не будете хранить весь фид в коде; вместо этого данные будут браться из БД. Но для начала полезно собрать хотя бы такой учебный пример, чтобы протестировать пайплайн: генерация → выкладка → валидация.

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, которые уникальны в рамках мерчанта.

Во‑вторых, price указан как десятичное число с бесконечным хвостом. Спецификации и платёжные системы обычно ожидают цену в минимальных единицах (центы, копейки) целым числом, чтобы избежать проблем с плавающей точкой и округлением.

В‑третьих, currency = "usdollars" и availability = "yes" не соответствуют ожидаемым форматам (ISO 4217 и перечень допустимых статусов).

В‑четвёртых, link ведёт на http и локальный домен — ни то ни другое неприемлемо для реального продакшена; спецификация прямо требует HTTPS и публичную доступность.

В‑пятых, флаги enable_search и enable_checkout должны быть булевыми, а не строками. В противном случае парсер OpenAI либо не примет фид, либо приведёт к значению по умолчанию, которое может вас неприятно удивить.

Такие проблемы могут привести как к жёсткой ошибке валидации (фид отклонён), так и к более неприятной ситуации: фид формально принят, но часть SKU игнорируется или работает не так, как вы ожидали. Именно поэтому стоит вкладываться во внутреннюю валидацию ещё на вашей стороне.

11. Типичные ошибки при работе с Product Feed

Ошибка №1: думать о фиде как о "разовом CSV" для импорта.
Иногда команды воспринимают Product Feed как файл, который они один раз сгенерируют «для интеграции» и забудут. В AI‑commerce это не так: фид — живой источник правды, который должен регулярно обновляться. Если вы меняете цены, снимаете товары с продажи, запускаете промо‑акции — всё это должно своевременно попадать в фид. Иначе ChatGPT будет рекомендовать то, чего уже нет, или по старой цене, и пользователи вполне справедливо будут злиться.

Ошибка №2: смешивать модель продукта и SKU.
Популярный анти‑паттерн — пытаться отразить один базовый продукт с кучей опций в одной записи фида с множеством полей «size1/size2/size3» или «duration1/duration2». В результате модель не понимает, что именно продаётся, а ваш ACP‑backend начинает страдать от распаковки этих полей в момент чекаута. Гораздо проще и надёжнее: один SKU — одна запись фида, даже если это вариант в рамках одного продукта.

Ошибка №3: игнорировать локали и регионы.
Разработчики, которые делают первый MVP, часто ставят currency = "usd" и enable_checkout = true для всего подряд, не задумываясь о том, что Instant Checkout в вашем регионе может быть недоступен или какие‑то товары нельзя продавать в отдельных странах по политике или закону. Потом, когда вы выходите на новый рынок, всё начинает ломаться: цены не сходятся, налоги не учитываются. Лучше с самого начала привязывать SKU к регионам и валютам, даже если у вас пока только один рынок.

Ошибка №4: относиться к описаниям как к SEO‑текстам из прошлого.
Часть команд копирует в Product Feed старые описания из своих сайтов, иногда написанные под «ключевики» и роботов. Для ChatGPT это скорее вредно, чем полезно: модель и так умеет писать текст, ей гораздо важнее структурированные, честные и точные факты. Лучше кратко и по делу описывать, чем забивать description маркетинговой водой на пол‑экрана.

Ошибка №5: не валидировать фид самостоятельно.
Полагаться только на валидацию со стороны OpenAI — путь к больным ночам перед дедлайнами. Стоит сделать простой валидатор на своём бекенде или в CI, который проверяет схемы полей, допустимые значения, форматы URL и валют. Это можно сделать даже на TypeScript, используя, например, Zod или собственные проверки. Тогда вы будете ловить проблемы ещё до того, как залили фид в прод.

Ошибка №6: включать в Product Feed «всё подряд».
Иногда хочется заодно засунуть в фид тысячи SKU, чтобы «ну пусть будут, вдруг пригодятся». На практике это затрудняет и отладку, и аналитику, и контроль качества. Гораздо разумнее начать с ограниченного поднабора: только те категории и SKU, за которыми вы готовы следить и которые реально хотите продавать через ChatGPT. Остальное можно держать в discovery‑режиме или вообще обойтись без интеграции.

Ошибка №7: не синхронизировать Product Feed и ACP‑backend.
Фид и ACP‑API — две стороны одной медали. Если в фиде появился новый SKU, а ваш backend ещё не умеет его продавать (или наоборот, SKU убрали из фида, но backend всё ещё верит, что он существует), вы получите рассинхронизацию, сложные баги и сложные тикеты в саппорт. Хороший тон — иметь единую доменную модель каталога и использовать её и для генерации фида, и для обработки чекаута.

1
Задача
ChatGPT Apps, 14 уровень, 1 лекция
Недоступна
Минимальный Product Feed как публичный JSON endpoint
Минимальный Product Feed как публичный JSON endpoint
1
Задача
ChatGPT Apps, 14 уровень, 1 лекция
Недоступна
Feed Builder: из “продуктов и вариантов” в плоский список SKU + policy gating
Feed Builder: из “продуктов и вариантов” в плоский список SKU + policy gating
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ