JavaRush /Курси /ChatGPT Apps /Архітектура стеку ChatGPT Apps

Архітектура стеку ChatGPT Apps

ChatGPT Apps
Рівень 1 , Лекція 1
Відкрита

1. Вступ

Якщо дивитися на ChatGPT App просто як на «ще один вебсервер», дуже швидко починається архітектурний зоопарк: десь Next.js, десь MCP‑сервер, десь агент, десь commerce‑бекенд. У голові все це легко зливається в один великий «сервер».

Набагато практичніше відразу прийняти, що це — шарований пиріг:

  • згори — ChatGPT UI, який ми не контролюємо, але під який адаптуємося;
  • під ним — наш віджет на Apps SDK (Next.js 16, React 19), який відображається в чаті;
  • ще нижче — MCP‑сервер з інструментами (tools/resources/prompts);
  • за потреби — шар агентів, який оркеструє складні сценарії;
  • і в самому низу — ваші «земні» сервіси: БД, зовнішні API, commerce/ACP (протокол для commerce‑сценаріїв) тощо.

У конспекті курсу цей шлях можна намалювати як ланцюжок:

User ChatGPT Widget Apps SDK MCP Gateway (Auth) Agent Service ACP / Stripe.

Наше завдання зараз — перетворити цей ланцюжок на зрозумілу ментальну модель.

2. Загальна схема стеку

Спершу подивімося на картину цілком, а потім пройдемося шар за шаром.

flowchart TD
    U[Користувач у ChatGPT] --> C["ChatGPT UI\nчат + панель Apps"]
    C --> W["Віджет вашого App (Apps SDK, Next.js)"]
    W --> M["MCP‑сервер (tools/resources/prompts)"]
    M --> AG["Агент(и) (Agents SDK, оркестрація)"]
    AG --> B["Бекенди та ACP\nБД, сервіси, платіжка"]

Важливо помітити кілька речей.

По‑перше, користувач бачить лише два рівні: ChatGPT UI і ваш віджет. Усе, що нижче, — «закулісся».

По‑друге, протокол MCP — це не випадкова абревіатура, а офіційний стандарт, через який Apps SDK спілкується з вашими інструментами. Сервер має вміти перераховувати tools, приймати запити call_tool і повертати посилання на UI‑ресурс для відображення в ChatGPT.

По‑третє, шари Agents і ACP формально не є обовʼязковими. Але в реальних комерційних застосунках вони зʼявляються майже завжди: десь потрібно планувати багатоетапний сценарій, а десь — приймати оплату.

Тепер розберімо кожен шар окремо.

Ключова думка: ChatGPT — це фреймворк

Інтеграція з ChatGPT не «живе» в одному місці — вона розподілена між багатьма точками інтеграції. Для розробника це найбільше схоже на роботу з фреймворком: він сам вирішує, коли й де викликати ваш код. А вам лишається «підставити» правильні речі в правильні місця.

З ChatGPT усе відбувається саме так:

  • віджети — реєструються через mcp-resources, GPT сам вирішує, коли їх показати;
  • mcp‑tools — GPT сам вирішує, коли їх викликати;
  • product feed — його можна додати в модель через mcp‑tool, але типовий варіант — через реєстрацію продавця на сайті;
  • ACP/InstantCheckout — окремий API;
  • авторизація — окремий MCP auth‑сервер.

3. Шар 1 — ChatGPT UI: наш «хост»

ChatGPT UI — це браузерний (і мобільний) інтерфейс OpenAI, у якому користувач веде основний діалог. Тут є звичне поле введення, історія повідомлень, кнопки вибору моделі та вкладка із застосунками (Store/Composer).

Цей шар ми не програмуємо. У нас немає доступу до його коду, DOM і стилів. Проте саме він задає рамки:

  • саме тут користувач «обирає» ваш застосунок — явно (через Store/Composer) або неявно (модель сама запропонує App);
  • саме тут ChatGPT вирішує: відповісти лише текстом, викликати ваш tool, відобразити віджет чи зробити все одразу;
  • саме тут живуть базові UX‑патерни: inline‑віджет, fullscreen‑режим, PiP‑вікно тощо (детально в модулі 8).

З практичної точки зору важливо памʼятати: ChatGPT UI — це наш хост‑застосунок. Ми вбудовуємося в нього, а не навпаки. GPT‑сервер завантажує код вашого віджета до себе, прибирає все зайве — і лише потім підвантажує його у свій чат зі свого домену.

4. Шар 2 — Apps SDK і віджет (Next.js 16 усередині чату)

Наступний шар — це ваш UI‑код, написаний на React/Next.js із використанням Apps SDK.

Ментальна модель проста: це як міні‑SPA, що відображається у вбудованому віджеті в чаті. Але є кілька застережень:

  • ваш код працює в пісочниці: обмежений DOM, свої правила мережевих запитів, особливий обʼєкт window.openai для звʼязку з ChatGPT (про це буде окрема лекція);
  • віджет не контролює потік діалогу: користувач пише в загальний чат, модель вирішує, коли викликати ваш App, а ви відповідаєте лише у своїй «рамці»;
  • Apps SDK бере на себе майже все: синхронізацію стану віджета з історією діалогу, обробку результатів tool, роботу з MCP тощо.

З погляду розробника на Next.js це виглядає доволі звично: у вас є сторінки/компоненти, хуки, пропси. Але замість класичного fetch('/api/...') ви частіше покладатиметеся на інструменти (tools), описані в MCP‑сервері, і на спеціальні хуки Apps SDK (про них — далі в курсі).

Щоб трохи конкретизувати розмову, згадаємо наш проєкт — умовний GiftGenius. Це застосунок, який допомагає підбирати подарунки за параметрами: кому, на яку суму, з якого приводу тощо.

Невеликий фрагмент майбутнього UI (поки без специфіки SDK — просто як ідея):

// GiftSummary.tsx — простий React-компонент нашого застосунку
type GiftIdea = {
  id: string;
  title: string;
  price: number;
};

interface GiftSummaryProps {
  ideas: GiftIdea[];
}

export function GiftSummary({ ideas }: GiftSummaryProps) {
  return (
    <ul>
      {ideas.map((idea) => (
        <li key={idea.id}>
          {idea.title} — ${idea.price}
        </li>
      ))}
    </ul>
  );
}

Пізніше цей компонент отримуватиме ideas не «з повітря», а з результату інструмента MCP‑сервера (ToolOutput). Але на рівні архітектури нам важливіше інше: увесь такий код живе в «другому шарі» й відповідає лише за відображення стану.

5. Шар 3 — MCP‑сервер: світ інструментів і даних

Тепер рухаємося нижче — у серверну частину.

Model Context Protocol (MCP) — це стандарт, який описує, як LLM‑клієнт (ChatGPT, Apps SDK, Agents) спілкується з вашим сервером. Він визначає, які інструменти доступні, які в них схеми input/output, як їх викликати, а також які ще ресурси й промпти можна підвантажувати.

Мінімальний MCP‑сервер для Apps SDK має вміти три речі:

  • повертати список інструментів (List tools) з їх JSON Schema та метаданими;
  • обробляти виклики інструментів (Call tools) — приймати запит call_tool, виконувати бізнес‑логіку й повертати структурований результат;
  • повертати HTML, JS, CSS тощо — за потреби, якщо tool повʼязаний із конкретним віджетом, який потрібно відобразити.

Важливий момент: MCP — це протокол, незалежний від транспорту. Для ChatGPT Apps нас цікавить його HTTP‑варіант із потоковою (streamable) реалізацією. Але деталі транспорту й формату повідомлень — це вже тема MCP‑модуля (рівень 6). Наразі вам достатньо розуміти головне: Apps SDK «знизу» звертається саме до MCP‑сервера, а не до довільних REST‑ендпойнтів.

Архітектурно MCP‑шар часто виглядає як окремий мікросервіс:

flowchart LR
    subgraph App["Ваш ChatGPT App"]
      W["Віджет (Next.js + Apps SDK)"]
      M["MCP‑сервер (@modelcontextprotocol/sdk)"]
    end

    W <-- JSON-RPC over HTTP/SSE --> M
    M --> DB[(Каталог подарунків)]
    M --> EXT[Зовнішні API]

Усередині MCP‑сервера ви вже пишете звичайний TypeScript/Node‑код, використовуєте бази даних, черги, сторонні API тощо. Офіційний TypeScript SDK для MCP бере на себе серіалізацію JSON‑RPC, валідацію схем і маршрутизацію викликів.

Для нашого GiftGenius один з інструментів MCP може називатися, наприклад, search_gifts. На рівні TypeScript це може виглядати як звичайна функція:

// Псевдокод: бізнес-логіка всередині MCP-сервера
export async function searchGifts(params: {
  recipient: string;
  budget: number;
}) {
  // тут ви вже звертаєтеся до БД/каталогу
  const items = await findGiftsInCatalog(params);
  return items.slice(0, 10);
}

Згодом ми обгорнемо її в MCP‑tool з описом схеми. Але головне таке: цей шар — ваш «звичайний» бекенд, тільки той, що спілкується зі світом через MCP.

6. Шар 4 — Agents SDK: мозок складних сценаріїв

Не всім застосункам потрібні агенти. Але щойно сценарій перестає бути «один виклик інструмента — одна відповідь», агентний шар стає дуже корисним.

Агент — це, по суті, керований LLM‑процес, який:

  • читає запит користувача й факти з історії діалогу;
  • планує послідовність кроків: які інструменти викликати, у якій послідовності, з якими аргументами;
  • аналізує результати й може ухвалювати рішення: «перевикликати tool», «попросити в користувача уточнення», «побудувати складнішу відповідь»;
  • інколи зберігає стан між кроками (памʼять, сесії, контрольні точки — це вже рівень 12).

Agents SDK дає структурований спосіб описувати такі сценарії: які tools доступні агенту, як зберігати й відновлювати стан, як обмежувати цикли тощо. Агенти запускаються всередині бекенда й дають змогу використовувати потужність OpenAI так, як вам зручно, — без обмежень віджетів ChatGPT Apps.

У контексті нашого стеку агент зазвичай «сидить» усередині бекенда між MCP‑шаром і вашими доменними API. Він може використовувати зовнішні API, внутрішні функції й MCP‑tools як «руки», а сам займатися «мозком».

Наприклад, сценарій GiftGenius може виглядати так:

  1. Користувач пише «підібери подарунок для мами до 50 доларів».
  2. ChatGPT викликає інструмент search_gifts вашого застосунку.
  3. За search_gifts tool на бекенді відповідає агент, який вирішує спершу уточнити кілька деталей (інтереси, привід).
  4. Користувач описує додаткові побажання.
  5. ChatGPT знову викликає search_gifts tool вашого застосунку — уже з додатковими аргументами.
  6. Агент на сервері може викликати додаткові інструменти (наприклад, перевірити наявність).
  7. Повертає в ChatGPT уже підготовлені варіанти й, за потреби, посилання на віджет для візуалізації.

Пізніше в курсі ми детально розберемо run‑цикл агента, ідемпотентність і безпеку. Але для загальної архітектури важливо інше: агентний шар не є обовʼязковим, проте це потужний «мозок», який знімає з вас частину складної оркестрації.

7. Шар 5 — ACP/Backend: гроші, дані й земні турботи

Найнижчий шар — це ваші звичні сервіси:

  • бази даних (каталоги товарів, користувачі, замовлення);
  • зовнішні API (платіжні провайдери, логістика, сторонні SaaS);
  • спеціалізовані протоколи, такі як ACP (Agentic Commerce Protocol) для commerce‑сценаріїв та Instant Checkout.

ACP описує, як ChatGPT і агенти спілкуються з вашим commerce‑бекендом: запити на підбір SKU, створення кошика, оформлення замовлення, повернення, webhooks про успішні/неуспішні операції тощо.

Для GiftGenius це буде приблизно так:

  • MCP‑tool search_gifts читає з продуктового фіда/БД;
  • агент, обравши конкретний товар, ініціює commerce‑інтент (через ACP);
  • ваш ACP‑сумісний бекенд каже PaymentService: «списуємо гроші», і повідомляє ChatGPT про статус;
  • користувач бачить у ChatGPT, що замовлення оформлено, без переходу на зовнішній сайт.

Тепер, коли ми пробіглися по шарах, подивімося на конкретний наскрізний сценарій.

8. Наскрізний сценарій: як запит користувача проходить через усі шари

Візьмемо запит: «Підбери подарунок для мами до 50 доларів, вона любить читати й чай».

Розкладемо його на кроки.

  1. Користувач пише текст у ChatGPT. Це перший шар — ChatGPT UI. Для користувача все виглядає як звичайний чат.
  2. Модель читає історію діалогу, метадані вашого App (описи, категорії, дозволи) і вирішує, що GiftGenius — доречний кандидат. Згідно з правилами discovery в Apps SDK, модель ураховує і текстові описи tools, і попередній досвід використання, і контекст, і навіть згадки бренду.
  3. ChatGPT або:
    • відразу викликає інструмент вашого App без UI (сценарій tool‑first);
    • або пропонує у відповіді: «Я можу використати GiftGenius, щоб допомогти з вибором подарунка», — і вже тоді викликає ваш tool.
  4. ChatGPT надсилає на MCP‑сервер запит call_tool для інструмента search_gifts. MCP‑сервер, зі свого боку, виконує бізнес‑логіку: звертається до БД/фіда, фільтрує за бюджетом і вподобаннями та повертає JSON зі списком відповідних товарів.
  5. Результат інструмента повертається в ChatGPT. Він може:
    • просто використати його як дані для текстової відповіді («Ось 3 ідеї подарунків…»), не показуючи віджет;
    • або відобразити віджет, передавши ToolOutput у ваш компонент, щоб показати картки товарів.
  6. І лише в цей момент запускається ваш віджет GiftGenius (Apps SDK), а ваш Next.js‑код відображається всередині чату. Віджет може, наприклад, показати форму з уточнювальними полями: «Кому подарунок?», «Бюджет», «Інтереси». Користувач може клікати по кнопках або просто писати далі в чат — модель синхронізуватиме це із застосунком.
  7. Щойно віджету потрібні реальні дані (каталог подарунків), він не робить fetch('https://my-backend/gifts') напряму. Натомість він ініціює виклик MCP tool: ChatGPT знову надсилає на MCP‑сервер запит call_tool для інструмента search_gifts.
  8. Якщо сценарій багатоетапний (потрібно просити уточнення, ранжувати, робити додаткові перевірки наявності, пропонувати альтернативи), агентний шар бере на себе планування, керування робочим процесом і оркестрацію.
  9. Коли користувач вирішує «купити» конкретний товар, ChatGPT ініціює покупку за ACP‑протоколом. Commerce‑бекенд через ACP і Instant Checkout проводить операцію, відповідає про статус, викликає webhooks, а ChatGPT показує користувачеві фінальний результат («Замовлення оформлене, ось чек»).

З погляду розробника добре, що на кожному рівні є чіткі межі відповідальності. Водночас усі шари зʼєднані новими стандартизованими протоколами (MCP, ACP), а не старими набридлими REST‑запитами.

Усе це складається в логічну картину: які є шари та як через них проходить запит. Далі нас цікавитиме «фізична» сторона: як саме ці шари можна розгорнути в коді та інфраструктурі — одним Next‑монолітом чи кількома сервісами (і це не дискусія «моноліт чи мікросервіси»).

9. Next.js‑моноліт чи розділена архітектура

Тепер логічне запитання: «А все це обовʼязково має бути купою окремих сервісів? Можна я просто зроблю один Next.js‑моноліт — і на цьому все?»

Відповідь: можна. У курсі ми рухатимемося від простого до складного. На старті цілком нормально зібрати «майже все» в одному репозиторії й навіть в одному середовищі виконання:

flowchart LR
    U[ChatGPT] --> W["Next.js App (Apps SDK)"]
    W --> M["MCP endpoint (у тому ж Next.js)"]
    M --> DB[(БД/каталог)]

Тобто ваш Next.js‑сервер (API‑рути або окремий сервер) одночасно:

  • віддає UI‑віджет (сторінки/компоненти Apps SDK),
  • реалізує MCP‑ендпойнт (JSON‑RPC поверх HTTP),
  • звертається до БД/зовнішніх API.

Це зручно і в розробці, і для перших версій застосунку: менше рухомих частин, простіше розгортання.

Однак у міру зростання функціональності зʼявляються причини розділити шари:

  • MCP‑сервер потрібно масштабувати окремо (багато «важких» інструментів);
  • фінансовий бекенд живе на своєму домені, регулюється іншими командами й вимагає підвищеного рівня безпеки;
  • агентну логіку можна винести в окремий застосунок із власним моніторингом і SLA.

Тоді картинка починає виглядати ближче до того, що ми вже бачили:

flowchart TD
    U[ChatGPT] --> W[Next.js + Apps SDK]
    W --> MG[MCP Gateway]
    MG --> M1[MCP Gifts Server]
    MG --> M2[MCP Analytics Server]
    M1 --> AG[Agent Service]
    AG --> ACP[Commerce/ACP Backend]

Зʼявляється поняття MCP Gateway — спільний вхід для ChatGPT. Він маршрутизує виклики на різні MCP‑сервери, працює з REST API, керує авторизацією, лімітами запитів (rate limiting, тобто обмеженням частоти запитів) тощо.

Ми почнемо писати приклади з більш монолітного сценарію. Але від самого початку організовуватимемо код так, щоб його можна було відносно безболісно розрізати на частини.

10. Де саме ви писатимете код (і що делегуєте іншим)

Раз ми окреслили, як шари можуть бути зібрані в моноліт або розподілену архітектуру, корисно явно зафіксувати: де саме ви писатимете код, а що залишиться за іншими сервісами чи командами.

З погляду TypeScript/Next.js‑розробника також корисно чітко позначити, які зони ви контролюєте.

У віджеті (Apps SDK + Next.js) ви:

  • пишете React‑компоненти, що відображають стан інструментів і користувацьке введення;
  • використовуєте хуки Apps SDK, щоб читати ToolInput/ToolOutput і стан віджета (widget state);
  • налаштовуєте візуальний режим (inline/fullscreen/PiP, теми, розміри — це буде на рівні 8);
  • взаємодієте з ChatGPT через window.openai для просунутіших сценаріїв (окремий модуль курсу).

У MCP‑сервері ви:

  • описуєте tools/resources/prompts за допомогою MCP SDK;
  • реалізуєте бізнес‑логіку інструментів (по суті — звичайні TypeScript‑функції, що звертаються до БД, API тощо);
  • оптимізуєте схеми та відповіді, щоб моделі було зручно їх читати (менше «галюцинацій», більше структурованості).

В агентному шарі (якщо використовуєте Agents SDK) ви:

  • описуєте, які інструменти доступні агенту й які в нього цілі;
  • налаштовуєте run‑цикл, памʼять, контроль циклів;
  • стежите за тим, щоб агент не робив дурниць і не заходив у нескінченне планування.

В ACP/бекендах ви:

  • або інтегруєтеся з наявними commerce‑сервісами (Stripe, свій магазин із product feedʼом тощо);
  • або проєктуєте новий бекенд, який розуміє ACP і вміє приймати та повертати замовлення.

Важливо: одна й та сама людина рідко повністю «закриває» всі шари в зрілому продукті. Але на етапі прототипу (і в цьому курсі) ми сподіваємося, що ви принаймні розумітимете, де саме «живе» той чи інший код.

11. Як архітектура впливає на UX і політику платформи

Хоча тема UX і політик — це окремі модулі, уже на рівні архітектури важливо розуміти, як обране розділення шарів позначається на UX і вимогах платформи. Тож зробімо кілька зауваг наперед.

По‑перше, sandbox. Віджет не може бездумно «лазити» інтернетом і збирати користувацькі дані — усе йде через контрольовані інструменти та дозволи, описані в MCP/Store. Платформа очікує, що ви чесно опишете, які дані й дії потрібні вашому App, і будуватиме discovery/пропозиції застосунку на цих описах.

По‑друге, UX‑потік. Через те, що модель може тимчасово «забути» про ваш App або, навпаки, надто агресивно його пропонувати, архітектура має бути стійкою до переривань. Якщо агент не встиг завершити довгий робочий процес, а користувач змінив тему, застосунок має пережити це спокійно. Багатоетапні сценарії та оркестрація в курсі будуватимуться саме поверх MCP‑tools і агентного шару.

По‑третє, продажі. Щойно ваш App починає приймати оплату, набирають чинності додаткові вимоги до безпеки, логування, ACP‑контрактів тощо. Те, як ви розділили шари (UI, MCP, Agents, ACP/Backend), сильно вплине на те, наскільки болісно вам буде проходити ревʼю в Store і аудит безпеки.

Перші підсумки

Сподіваюся, ви побудували у себе в голові оглядову карту:

  • верхні шари (ChatGPT UI + Apps SDK) визначають, як користувач бачить і відчуває ваш App;
  • середній шар (MCP) — це стандартний спосіб дати моделі інструменти та дані;
  • агентний і commerce‑шари перетворюють ваш App із «переглядача даних» на повноцінний продукт із логікою та грошима.

На другому рівні ми почнемо з найцікавішого: завантажимо офіційний шаблон Apps SDK на базі Next.js, запустимо його локально й підʼєднаємо до ChatGPT у Dev Mode. Тобто передусім попрацюємо руками з шаром Apps SDK/віджета, а MCP/агенти поки житимуть або як заглушки, або як вбудований бекенд.

Але тримати поточну схему в голові важливо вже зараз. Це як дивитися на монорепо й розуміти, що папка apps/ — це UI, services/mcp — протокол, services/agent — оркестратор, а services/commerce — гроші.

12. Типові помилки в розумінні архітектури стеку

Помилка № 1: вважати, що ChatGPT App = просто «вебхук до мого REST API».
Так інколи роблять зі звички зі світу «ботів»: мовляв, модель просто шле POST‑запити на мій URL, а далі — як вийде. Насправді між моделлю та вашим кодом стоять Apps SDK і MCP. Вам потрібно описати інструменти, їхні схеми та поведінку, а не просто «слухати» довільні HTTP‑запити.

Помилка № 2: змішувати рівні UI та бізнес‑логіки.
Популярний антипатерн — тягнути складну доменну логіку прямо у віджет, а MCP‑шар робити тонкою прокладкою. У результаті UI стає важким, складним для тестування й погано придатним для повторного використання поза ChatGPT. Значно надійніше тримати правила та доступ до даних на рівні MCP/agent, а віджету залишити виключно відображення й просту інтерактивність.

Помилка № 3: ігнорувати MCP і писати «свій протокол».
Іноді виникає спокуса: «Навіщо мені MCP? Я просто повертатиму JSON — і модель сама розбереться». На коротких демках це може раптово «працювати», але ви одразу втрачаєте стандартні можливості discovery, інспекції, авторизації й багатоклієнтської підтримки, які MCP та Apps SDK дають «з коробки».

Помилка № 4: будувати весь App навколо одного шару.
Хтось робить «усе в агенті», навантажуючи його купою responsibilities. Хтось, навпаки, намагається запхнути все в MCP‑tools. Хтось будує гігантський Next.js‑моноліт. Правильніше прийняти, що кожен шар має свою зону відповідальності: UI — відображення, MCP — доступ до даних/дій, агент — оркестрація, ACP/Backend — доменні інваріанти й гроші.

Помилка № 5: недооцінювати вплив архітектури на ревʼю в Store та безпеку.
Якщо у вас один сервер, який одночасно є MCP‑ендпойнтом, ACP‑ресурсом, зберігає секрети й пише все в логи «як є», — перевірка безпеки та політик контенту може стати затяжною. Розділена архітектура з явними межами й протоколами значно спрощує життя на пізніших етапах.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ