1. Wprowadzenie
Wyobraź sobie, że tworzysz zwykły serwis webowy. Tam wszystko jest proste: masz URL /search, użytkownik naciska przycisk, a ty wywołujesz kontroler searchController. W świecie ChatGPT Apps użytkownik nie widzi żadnego /search. Pisze po prostu ludzkim tekstem:
«Dobierz prezent dla brata‑gracza do 50$»
A dalej:
- model decyduje: „Och, to o prezentach, mam GiftGenius, który umie to robić”;
- GPT sam „naciska przyciski” — wywołuje narzędzia twojego App;
- czasem proponuje też użytkownikowi: „Chcesz, otworzę GiftGenius i pokażę opcje?”.
Kluczowa zmiana: użytkownik wyraża intencję, a przyciski naciska model. Jeśli nie rozumiesz tego flow, bardzo łatwo:
- napisać narzędzia z bezsensownymi nazwami (run_func, doStuff),
- dostać App, który nigdy nie jest proponowany przez model albo jest wywoływany nieadekwatnie,
- stworzyć widget, który „wyskakuje z krzaków” i psuje dialog.
Dlatego w tym wykładzie budujemy mentalny model: jak GPT w ogóle dowiaduje się o twoim App i w jakich punktach dialogu go „wplata”.
Insight: aplikacja — to plugin do ChatGPT
W odróżnieniu od aplikacji w telefonie czy mini‑app w WeChat, aplikacje w ChatGPT działają inaczej.
ChatGPT sam decyduje, kiedy uruchomić twoją aplikację i którą jej funkcję wywołać. Aplikacje w ChatGPT mogą aktywnie (choć z ograniczeniami) ingerować w logikę czatu. Ich główny cel i silna strona — to rozszerzenie możliwości samego ChatGPT.
Jeśli ChatGPT może idealnie rozwiązać problem użytkownika — nie musi wywoływać twojej aplikacji. Jeśli ChatGPT w ogóle nie może rozwiązać problemu — użytkownik raczej o to nie zapyta. Idealna sytuacja jest wtedy, gdy ChatGPT może rozwiązać prośbę tylko częściowo. To znaczy, że są zapytania, jest ich dużo, ale wynik jest niewystarczający.
Właśnie wtedy ChatGPT wywołuje twoją aplikację i razem uszczęśliwiacie użytkownika. Użytkownik staje się szczęśliwszy, a ty — bogatszy.
2. Sposoby uruchamiania ChatGPT App oczami użytkownika
Użytkownik nie ma przycisku „wywołaj serwer MCP i call_tool”, za to ma pole tekstowe i (czasem) menu aplikacji. Z jego punktu widzenia są dwa podstawowe schematy uruchomienia: jawny i niejawny.
Jawne uruchomienie (explicit)
To scenariusz, gdy użytkownik świadomie wybiera twój App.
Typowe warianty:
- znajduje App w Store ChatGPT i naciska „Otwórz”;
- wybiera App w launcherze (np. przyciskiem + w polu do wpisywania tekstu (Composer));
- zaczyna wiadomość od nazwy aplikacji: „GiftGenius, dobierz prezent…” — to nazywa się named mention. Jeśli nazwa App stoi na początku promptu, ChatGPT automatycznie domiesza twój App do kontekstu odpowiedzi.
W trybie jawnym model od początku wie: użytkownik przyszedł tu właśnie po to, by pracować z tym App. Dlatego:
- GPT częściej i aktywniej wywołuje twoje tools;
- UI‑widget twojego App może pojawić się już w pierwszej odpowiedzi;
- GPT rzadziej „ignoruje” App i odpowiada „własnymi siłami”.
Ulubiony przykład: użytkownik otwiera GiftGenius bezpośrednio, bo chce „pobawić się” doborem prezentów. Naciska aplikację na liście, GPT pokazuje przywitanie w stylu:
«Cześć! Jestem GiftGenius, pomogę dobrać prezent. Opowiedz, dla kogo i jaki mamy budżet?»
I dalej aktywnie używa twoich narzędzi do wyszukiwania.
Niejawne uruchomienie (implicit / suggested)
Zupełnie inny scenariusz: użytkownik w ogóle nie myśli o App. Po prostu pisze w zwykłym czacie:
«Dobierz prezent na urodziny mamy, lubi ogrodnictwo, budżet do 100$»
GPT analizuje prośbę i widzi, że:
- w ekosystemie jest App GiftGenius, którego narzędzia opisano jako „Use this when the user wants to get gift recommendations”;
- zadanie i ograniczenia (prezent, budżet, zainteresowania) dobrze pasują do tego App.
W takim przypadku model może „skromnie się wtrącić” z propozycją:
«Mogę użyć aplikacji GiftGenius, aby dobrać konkretne propozycje prezentów i pokazać je w formie kart. Otworzyć ją?»
Jeśli użytkownik się zgadza — GPT wywołuje potrzebne narzędzie App i, być może, renderuje twój widget.
Ważne, że nigdzie nie piszesz if (prompt.includes("prezent")) openApp(). Model podejmuje decyzję sam, opierając się na:
- tekście zapytania i historii dialogu;
- metadanych twoich narzędzi (nazwy, opisy, schematy parametrów);
- stanie połączenia użytkownika z App (uwierzytelniony czy nie), czy to użytkownik korporacyjny czy nie.
Wpływasz nie na algorytm, lecz na to, jak twój App i tools są „opisane” dla modelu.
Hybryda: gdy GPT doprecyzowuje, a potem proponuje App
Czasem użytkownik pisze coś bardzo ogólnego:
«Trzeba coś wymyślić dla kolegi, kompletnie nie wiem co»
Model rozumie, że GiftGenius może pomóc, ale informacje są zbyt rozmyte. Częsty wzorzec:
- GPT zadaje 1–2 pytania doprecyzowujące tekstem.
- Potem proponuje uruchomić App: „Mam narzędzie do doboru prezentów. Chcesz, żebym je otworzył i pokazał opcje?”.
To dobry UX: użytkownik nie czuje, że został „siłą przesadzony do innej aplikacji”.
3. Discovery: jak GPT znajduje twój App
Teraz zobaczmy, jak to wygląda z punktu widzenia samego modelu.
W dokumentacji Apps SDK nazywa się to Discovery — wszystkie sposoby, dzięki którym użytkownik i model w ogóle dowiadują się o twoim App. To zarówno naturalne zapytania w czacie, jak i katalog aplikacji oraz specjalne „entry points” typu launcher.
Skąd model w ogóle wie, że twój App istnieje
Podczas rejestracji ChatGPT uruchamia twój App, a on (przez MCP) opowiada o sobie: wymienia dostępne narzędzia z ich schematami — nazwę, opis, schemat JSON parametrów wejściowych. Informacje o aplikacji podasz przy rejestracji, a informacje o narzędziach ChatGPT sam pobierze przez metodę MCP list_tools.
Model nie widzi twojego kodu źródłowego, ma dostęp tylko do:
- nazwy narzędzia (name);
- opisu (description);
- sygnatury wejścia (inputSchema).
To właśnie staje się „API dla modelu”. Jeśli nazwiesz narzędzie run_func z opisem „Executes the function”, model nie zrozumie, kiedy je wywoływać. Jeśli nazwiesz je suggest_gifts z opisem „Use this when the user wants gift ideas based on recipient, occasion and budget” — wszystko staje się jasne.
Named mention i in‑conversation discovery
Oficjalna specyfikacja Apps SDK wyróżnia dwa kluczowe mechanizmy:
- Named mention — gdy użytkownik zaczyna wiadomość od nazwy twojego App. W tym przypadku App niemal na pewno zostanie podniesiony i użyty w odpowiedzi.
- In‑conversation discovery — gdy użytkownik po prostu pisze prośbę, a model decyduje, czy podłączyć App. Przy tym brane są pod uwagę:
- kontekst rozmowy (historia wiadomości, wyniki poprzednich tools, preferencje użytkownika);
- jawne wzmianki o marce w tekście;
- metadane twoich tools — nazwy, opisy, dokumentacja parametrów;
- stan „linku” — czy użytkownik jest połączony z App (uwierzytelniony, czy ma przyznane potrzebne uprawnienia).
Deweloper wpływa na ten proces pośrednio: poprzez dobre metadane i wzorce UX, a nie przez if/else w kodzie.
Katalog i launcher
Poza sposobem dialogowym istnieje jeszcze Store wewnątrz ChatGPT i launcher dostępny z composera. Przez nie użytkownicy mogą jawnie wybierać App, jak zwykłą aplikację w sklepie.
Dla nas to ważne koncepcyjnie: gdy projektujemy flow GiftGenius, musimy pamiętać, że:
- ktoś wejdzie przez katalog i od razu znajdzie się „wewnątrz” App;
- ktoś nigdy nie będzie przeglądał katalogu i zobaczy App tylko jako propozycję w dialogu.
To wszystko dotyczy discovery samego App: momentów, gdy model decyduje, czy w ogóle „podnieść” twoją aplikację i zaproponować ją użytkownikowi w bieżącej rozmowie.
4. Anatomia cyklu interakcji: od frazy do widgetu
Czas złożyć wszystkie poziomy z poprzedniego wykładu — od ChatGPT UI i widgetu po Apps SDK i serwer MCP — w jeden zrozumiały cykl logiczny.
Wysokopoziomowy schemat
Z punktu widzenia procesu, cykl wygląda tak:
sequenceDiagram
participant U as Użytkownik
participant G as ChatGPT (model)
participant A as App / MCP-serwer
U->>G: Tekstowe zapytanie
G->>G: Analiza zapytania + wybór tools
G->>A: Wywołanie narzędzia (call_tool)
A-->>G: Odpowiedź (dane / structuredContent)
G->>U: Tekstowa odpowiedź + (opcjonalnie) widget App
Po ludzku:
- Użytkownik pisze wiadomość w ChatGPT.
- Model analizuje zapytanie i bieżący kontekst, decyduje:
- czy odpowiedzieć samodzielnie,
- czy wywołać jedno lub kilka narzędzi.
- Jeśli wybrano narzędzie twojego App, ChatGPT formuje ustrukturyzowane żądanie (call_tool) i wysyła je do serwera MCP.
- Twój backend (lub MCP‑serwer) wykonuje działanie: sięga do bazy danych, zewnętrznych API, ACP itd., formuje wynik.
- Wynik wraca w postaci ustrukturyzowanych danych (i, być może, JSON do widgetu).
- Model używa tych danych, aby:
- wygenerować zrozumiały dla użytkownika tekst,
- w razie potrzeby — narysować widget App bezpośrednio w odpowiedzi.
Całe wieloetapowe planowanie — „kiedy co wołać”, „czy dopytać”, „czy zrobić jeszcze jedno wywołanie” — znajduje się po stronie modelu AI. Apps SDK i MCP jedynie dostarczają jednolity kontrakt dla narzędzi.
Gdzie tutaj piszemy kod
W tym cyklu są trzy miejsca, gdzie faktycznie piszesz TypeScript/kod:
- Konfiguracja App i narzędzi — opisy tools (nazwa, opis, schemat) i metadane App (nazwa, ikona, kategorie). W twoim projekcie to najpewniej plik podobny do openai/app-config.ts.
- MCP‑serwer / backend — obsługa call_tool: sięgamy do bazy, filtrujemy produkty, możemy wywoływać inne API itd.
- Widget (UI) — komponent React w aplikacji Next.js, renderowany w czacie i czytający wyniki narzędzi przez window.openai lub hooki Apps SDK.
Reszta należy do modelu i platformy.
5. GiftGenius w działaniu: dwa scenariusze przepływu użytkownika
Przejdźmy do bardziej konkretnych scenariuszy, abyś mógł „zobaczyć” ten flow.
Scenariusz 1: użytkownik otwiera GiftGenius jawnie
Scenariusz:
- Użytkownik w ChatGPT otwiera katalog App i znajduje GiftGenius.
- Naciska „Otwórz”.
- ChatGPT uruchamia dialog już w kontekście GiftGenius.
Dialog wygląda mniej więcej tak:
Użytkownik:
Otwiera GiftGenius z katalogu.
I pisze: «Cześć! Chcę dobrać prezent dla przyjaciela»
GPT:
«Świetnie, pomogę dobrać prezent. Powiedz, dla kogo, jaki budżet i przy jakiej okazji szukasz prezentu?»
Na tym etapie GPT może od razu wywołać pierwsze narzędzie, np. start_gift_session, aby zainicjalizować sesję w twoim backendzie (utworzyć tymczasowy koszyk, wygenerować sessionId itd.).
Twój kod po stronie MCP‑serwera może wyglądać tak (na razie bardzo wstępnie):
// Pseudoprzykład future-TS: opis narzędzia GiftGenius
const suggestGiftsTool = {
name: "suggest_gifts",
description: "Use this when the user wants gift ideas by recipient, occasion, and budget",
inputSchema: {
type: "object",
properties: {
recipient: { type: "string" },
occasion: { type: "string" },
budgetUsd: { type: "number" },
},
required: ["recipient", "occasion", "budgetUsd"],
},
};
Szczegółowo, jak to rejestrować w MCP/Apps SDK, omówimy w osobnym module; teraz ważna jest idea: na podstawie tego opisu model rozumie, że narzędzie pasuje do próśb typu „dobór prezentów”.
Po odpowiedzi użytkownika GPT wywołuje suggest_gifts, dostaje od ciebie tablicę propozycji, a następnie:
- przygotowuje tekstowe podsumowanie;
- wbudowuje widget GiftGenius, w którym karty z prezentami można przewijać i filtrować.
Scenariusz 2: użytkownik prosi „dobierz prezent” w zwykłym czacie
Teraz inny wariant: użytkownik w ogóle nie zna GiftGenius.
Pisze w zwykłym czacie:
«Potrzebny prezent dla brata, uwielbia planszówki, maks 50$»
Wewnątrz ChatGPT dzieje się mniej więcej tak:
- Model analizuje zapytanie i listę dostępnych narzędzi.
- Widzi narzędzie suggest_gifts z pasującym opisem.
- Rozumie, że App GiftGenius jest właśnie do takich zadań.
- Sprawdza, czy użytkownik instalował już tę aplikację, czy był uwierzytelniony, jakie uprawnienia przyznał.
Dalsze zachowanie może być różne:
- jeśli prośba jest wystarczająco konkretna, GPT może po cichu wywołać suggest_gifts i zwrócić odpowiedź z widgetem;
- jeśli czegoś brakuje (np. nie podano okazji lub wieku), GPT może najpierw dopytać tekstem, a potem zaproponować App.
Taka elastyczność wyróżnia Apps od „sztywnych” UI z formularzami: model sam wybiera, kiedy użyć narzędzi, a kiedy porozmawiać.
6. Routing semantyczny: „LLM jako dyspozytor”
Na poziomie discovery model decyduje, czy w ogóle podłączyć twój App do bieżącej prośby. Ale później, gdy App jest już „podniesiony”, a jego narzędzia są znane modelowi w bieżącej sesji, włącza się drugi poziom — routing semantyczny wewnątrz tych tools: którym konkretnie narzędziem obsłużyć kolejną wypowiedź.
W klasycznym web‑backendzie trasę wybiera się po URL: /checkout — więc wywołujemy kontroler checkout. W ChatGPT Apps nie ma routingu po URL, za to jest routing semantyczny: model porównuje sens prośby z opisami twoich narzędzi.
Uproszczony proces wygląda tak:
- Przy starcie sesji ChatGPT otrzymuje listę tools: ich nazwy, opisy, schematy.
- Te dane są wbudowane w instrukcje systemowe modelu.
- Gdy użytkownik pisze prośbę, model porównuje jej sens z opisami narzędzi: gdzie „dobór prezentów”, gdzie „wyszukiwanie hoteli”, gdzie „zbuduj wykres”.
- Jeśli znajduje dobre dopasowanie — formuje ustrukturyzowane wywołanie właściwego narzędzia.
Stąd główny praktyczny wniosek:
- opis narzędzia — to twoje API dla modelu; przeczytaj to jeszcze raz. A potem jeszcze raz.
- jeśli napiszesz „does stuff”, model naprawdę nie zrozumie, kiedy to wywoływać.
Dokumentacja i najlepsze praktyki dotyczące discovery podkreślają: do metadanych trzeba podchodzić jak do pracy copywriterskiej produktu. To one decydują, w jakich rozmowach model przypomni sobie o twoim App.
7. Wzorce dialogu wokół App
Przyjrzyjmy się teraz typowym wzorcom UX, które pojawiają się, gdy GPT współdziała z App w jednej rozmowie. To ważne, by nie budować App „w próżni”, bez zrozumienia roli części GPT.
Wszystkie praktyczne przewodniki po Apps SDK wyróżniają kilka charakterystycznych wzorców:
„Kreator” (The Wizard)
GPT prowadzi użytkownika krok po kroku, często opierając się o App.
Na przykładzie GiftGenius:
- GPT: „Opowiedz, dla kogo prezent?”
- Użytkownik: „Brat, 25 lat, lubi gry planszowe”.
- GPT: „Jaki budżet?”
- Użytkownik: „Do 50$”.
- GPT wywołuje suggest_gifts, pokazuje wyniki w widgetcie i pisze: „Dobrałem kilka opcji, zobacz poniższą listę”.
W tym wzorcu App i jego widget — to jakby warstwa wizualna nad wieloetapowym dialogiem. Użytkownik większość czasu pisze tekst, a widget pomaga wizualizować wybór.
„Adaptacyjny widget” (The Adaptive Widget)
Tekst pozostaje głównym kanałem, a App podłącza się punktowo do zadań specjalnych: zbudować wykres, pokazać tabelę, narysować karty produktów.
Przykład:
- Użytkownik: „Porównaj trzy opcje prezentu: gra planszowa, książka, prezent‑przeżycie”.
- GPT najpierw tekstowo wyjaśnia plusy i minusy.
- Potem wywołuje narzędzie, które zwraca ustrukturyzowaną listę produktów, i renderuje małą tabelę lub karty.
Tutaj App jest wizualnym uzupełnieniem, a nie „trybem domyślnym”.
„Niewidzialny agent” (Invisible Agent)
App w ogóle nie musi pokazywać UI. Działa „pod maską” jako źródło danych:
- implementujesz tool MCP, który szuka prezentów w twojej bazie;
- GPT go wywołuje, dostaje listę i sam streszcza wyniki tekstem, bez żadnego widgetu.
To przypomina klasyczną „wtyczkę bez UI”: użytkownik widzi tylko, że GPT zna aktualne ceny i asortyment.
Taki wzorzec jest przydatny dla tool‑first App, gdzie UI nie jest krytyczny.
8. Jak flow wpływa na projekt App
Zrozumienie flow jest ważne nie tylko filozoficznie, ale i dla bardzo praktycznych decyzji: jakie narzędzia tworzyć, jak je opisywać, kiedy pokazywać widget, a kiedy lepiej odpowiedzieć tekstem.
Zasada „chat‑first”
Kluczowa idea ekosystemu: czat — główny kanał interakcji, a komponenty UI — pomocnicze.
To znaczy:
- nie próbuj upchnąć „całej strony” w jeden widget;
- widgety mają pomagać tam, gdzie czat jest niewygodny: wybór z listy, filtrowanie, porównanie, złożone formularze.
Dla GiftGenius oznacza to:
- dobrać listę prezentów i dać użytkownikowi „klikać” po kartach;
- zwizualizować filtry (cena, kategoria, dostępność);
- pomóc sfinalizować zamówienie (checkout) w kilku zrozumiałych krokach.
Natomiast pisanie w widgetcie długich wyjaśnień „jak wybrać prezent dla dziewczyny‑introwertyczki” — to zły pomysł, to zadanie dla czatu.
Kiedy uruchamiać App, a kiedy nie
Kolejna konsekwencja: nie rób z App „porywacza dialogu”.
Zły wzorzec:
- użytkownik prowadzi poważną dyskusję;
- App się uruchamia i otwiera ogromny widget pełnoekranowy bez ostrzeżenia;
- użytkownik się gubi: „gdzie zniknął mój czat?”.
Lepiej:
- najpierw wszystko omówić tekstem, zadać dwa pytania doprecyzowujące;
- potem delikatnie zaproponować otwarcie App, jeśli to realnie poprawi UX (porównanie, konfiguracja, checkout).
Wpływ na zestaw narzędzi
Ponieważ model wybiera narzędzie po opisie, każde narzędzie powinno:
- rozwiązywać jedno zrozumiałe zadanie;
- być dobrze opisane w stylu „Use this when…”;
- mieć parametry, które naturalnie wynikają z pytań, jakie GPT będzie zadawać użytkownikowi.
Dla GiftGenius zamiast jednego gigantycznego do_everything sensowniej mieć:
- suggest_gifts — dobór listy opcji;
- get_gift_details — szczegóły jednego ID;
- create_order — złożenie zamówienia.
Szczegółowo zajmiemy się projektowaniem narzędzi w module 4, ale ogólna idea już teraz jest ważna: flow dialogu determinuje, jakie narzędzia w ogóle są potrzebne.
9. Mini‑przykład: jak opisy tools wpływają na flow (szkic TypeScript)
Niewielki fragment wyimaginowanego openai/app-config.ts, żeby połączyć teorię z kodem. Nie traktuj tego jako dokładnej składni SDK (rozbierzemy ją w kolejnym module) — teraz ważna jest idea nazw i opisów.
// Umowny fragment konfiguracji GiftGenius (przyszły kod)
const tools = [
{
name: "suggest_gifts",
description: "Use this when the user wants gift ideas based on recipient, occasion, and budget.",
inputSchema: {/* ... */},
},
{
name: "get_gift_details",
description: "Use this when the user asks for more information about a specific gift from a previous list.",
inputSchema: {/* ... */},
},
];
Jeśli zamienisz suggest_gifts na run_func, a opis na „Main function”, GPT:
- gorzej zrozumie, dla jakich próśb należy wołać to narzędzie;
- może rzadziej proponować twój App w in‑conversation discovery;
- będzie mu trudniej łączyć follow‑upy użytkownika z już pokazaną listą prezentów.
I odwrotnie, dobre nazwy i opisy zwiększają szansę, że to właśnie twój App wypłynie w odpowiednim momencie.
10. Typowe błędy przy projektowaniu przepływu użytkownika
Błąd nr 1: Oczekiwanie pełnej kontroli — „sam zdecyduję, kiedy uruchomić App”.
Czasem deweloperzy myślą w paradygmacie „złapię wszystkie prośby o prezenty i podłączę swój App”. W świecie ChatGPT Apps to nie działa tak: decyzje podejmuje model. Uwzględnia opisy narzędzi, kontekst dialogu, stan uprawnień i to, na ile użytkownik będzie zadowolony z wywołania właśnie twojego App.
Błąd nr 2: Bezsensowne nazwy i opisy narzędzi.
Narzędzia o nazwach run, main, tool1 i opisach „Calls the main function” tworzą idealną burzę: model nie rozumie, kiedy je wywoływać, in‑conversation discovery praktycznie nie działa, a twój App staje się „niewidzialny”. Dobry opis w stylu „Use this when the user wants…” i zrozumiała nazwa — są dużo ważniejsze, niż może się wydawać.
Błąd nr 3: Próba upchnięcia w jednym App „wszystkiego na świecie”.
Jeśli twój App jednocześnie „dobiera prezenty, rezerwuje hotele, liczy podatki i wyświetla kotki”, model nie będzie w stanie niezawodnie trasować próśb. Oficjalne rekomendacje i praktyczne przewodniki podkreślają zasadę „one clear job per tool/App”: lepiej kilka wyspecjalizowanych aplikacji niż jeden megamonolit.
Błąd nr 4: Agresywny autostart ciężkiego UI.
Deweloper jest dumny ze swojego pięknego pełnoekranowego widgetu i chce go pokazywać „przy każdej okazji”. W efekcie użytkownik ma wrażenie, że czat się „psuje” i zmienia w dziwną aplikację webową. Dużo lepiej, gdy GPT najpierw rozmawia tekstem, zadaje pytania doprecyzowujące i dopiero potem proponuje otworzyć App, wyjaśniając, po co to potrzebne.
Błąd nr 5: Ignorowanie roli GPT jako warstwy UX.
Można zaprojektować App jak zwykłe SPA: wszystko zrobić w widgetcie, a ChatGPT ma „milczeć i nie przeszkadzać”. Ale to nie zadziała. ChatGPT może nie wyświetlić twojego widgetu, albo wyświetlać nowy widget na każde wywołanie tool. Chcesz stworzyć udany produkt — dostosuj się do platformy, nie oczekuj, że to ona dostosuje się do ciebie.
GO TO FULL VERSION