UX aplikacji z Claude - jak projektować interfejsy AI które działają i budują zaufanie
Seria Claude Code · JSystemsUżytkownik czeka 8 sekund na odpowiedź AI i myśli że coś się zawiesiło. Zamyka zakładkę. Tracisz klienta. Tego da się uniknąć - i pokażemy Ci jak.
Czego się nauczysz z tego artykułu:
Najlepszy model AI w aplikacji z kiepskim UX to przepis na frustrację użytkownika. Aplikacje z LLM mają unikalne wyzwania designu: model odpowiada z opóźnieniem, może się mylić, odpowiedzi są nieprzewidywalnej długości, a użytkownik nie wie jak formulować zapytania. Ten artykuł zbiera lekcje z realnych wdrożeń aplikacji AI - co działa, co nie i dlaczego.
Słowniczek - terminy używane w artykule
Kilka pojęć które warto znać zanim przejdziesz dalej:
- UX (User Experience) - doświadczenie użytkownika. Jak czuje się używając Twojej aplikacji: intuicyjność, szybkość, przejrzystość
- Latencja - czas oczekiwania. Od kliknięcia "wyślij" do pierwszej odpowiedzi
- LLM - Large Language Model (Duży Model Językowy). Claude, GPT i podobne to LLM-y
- RAG - Retrieval Augmented Generation. Technika gdzie model korzysta z zewnętrznych dokumentów jako kontekstu
- Halucynacja - gdy model AI wymyśla nieistniejące fakty z przekonaniem że są prawdziwe
Problem #1: Latencja - użytkownik nie wie czy coś się dzieje
Claude Sonnet odpowiada typowo w 2-8 sekund. Dla użytkownika przyzwyczajonego do natychmiastowych odpowiedzi - to wieczność. Badania UX pokazują że po 3 sekundach oczekiwania użytkownicy zaczynają wątpić czy aplikacja działa.
Przed i po - konkretny przykład:
| ZLY UX (przed) | DOBRY UX (po) |
|---|---|
| Użytkownik klika "Wyślij". Nic się nie dzieje. Nic. Nic. 4 sekundy ciszy. Użytkownik klika ponownie (myśli że nie wysłało). Dostaje dwie odpowiedzi naraz. | Użytkownik klika "Wyślij". Natychmiast pojawia się animacja "Claude myśli...". Po 0.5s - pierwsze słowa odpowiedzi zaczynają się pojawiać jedno po drugim. Użytkownik widzi postęp. |
| Pełna odpowiedź pojawia się nagle po 6 sekundach. Wygląda jak błąd strony. | Odpowiedź płynie przez 6 sekund. Użytkownik czyta już podczas gdy Claude pisze. |
u = db.find(user)
if u and verify(pwd, u.hash):
return token(u)
raise AuthError()
u = db.find(user)
if u and verify(pwd, u.hash):
return token(u)
raise AuthError()
Streaming - kluczowy pattern dla AI
Nigdy nie czekaj na pełną odpowiedź przed wyświetleniem. Streaming daje użytkownikowi sygnał że coś się dzieje i znacząco poprawia perceived performance - postrzeganą szybkość, nawet jeśli całkowity czas jest taki sam.
Poniżej implementacja streamingu w React - krok po kroku:
Krok 1: Stan komponentu przechowuje aktualny tekst i flagę czy Claude wciąż odpowiada.
Krok 2: Otwieramy połączenie strumieniowe z backendem gdy komponent się pojawi.
Krok 3: Czytamy dane ze strumienia w kawałkach i na bieżąco dodajemy do wyświetlanego tekstu.
Krok 4: Migający kursor pokazuje że Claude wciąż odpowiada - znika gdy skończy.
// React + streaming Claude API
// React to biblioteka JavaScript do budowania interfejsów użytkownika
import { useState, useEffect } from 'react';
// TypeScript: { prompt: string } to typ parametru - musi być stringiem
function ChatMessage({ prompt }: { prompt: string }) {
// KROK 1: Stan komponentu
// text = aktualny tekst odpowiedzi (pusty na starcie)
const [text, setText] = useState('');
// isLoading = czy Claude wciąż odpowiada (true = tak, pokazuj kursor)
const [isLoading, setIsLoading] = useState(true);
// KROK 2: Połączenie strumieniowe gdy komponent się pojawi
useEffect(() => {
const stream = async () => {
// Wywołujemy nasz backend który proxy'uje do Claude API
const response = await fetch('/api/claude', {
method: 'POST',
body: JSON.stringify({ prompt }),
});
// KROK 3: Czytamy dane ze strumienia kawałek po kawałku
// response.body.getReader() = czytnik strumienia danych binarnych
const reader = response.body!.getReader();
// TextDecoder zamienia bajty na tekst UTF-8
const decoder = new TextDecoder();
// Pętla czytająca dane ze strumienia
while (true) {
const { done, value } = await reader.read();
if (done) { setIsLoading(false); break; } - // Koniec strumienia
// prev => prev + ... = dodaj nowy fragment do istniejącego tekstu
setText(prev => prev + decoder.decode(value));
}
};
stream();
}, [prompt]); - // Zależność: uruchom gdy prompt się zmieni
return (
<div className="message">
{text}
{/* KROK 4: Migający kursor pokazuje że Claude wciąż odpowiada */}
{isLoading && <span className="cursor-blink">▊</span>}
</div>
);
}
Po wdrożeniu: otwórz DevTools (F12) --> zakładka Network. Wywołaj zapytanie do Claude. Powinieneś zobaczyć request do /api/claude z Type "EventStream" lub "Fetch" który rośnie w czasie - to znak że streaming działa.
Skeleton loading i progress indicators
- Pokaż "Claude myśli..." z animowanymi kropkami przez pierwsze 500ms - użytkownik wie że aplikacja żyje
- Dla długich zadań (analiza dokumentu): progress bar z etapami ("Czytam dokument... Analizuję... Przygotowuję odpowiedź...") - każda zmiana fazy redukuje niepewność
- Optymistyczne UI: pokaż akcję użytkownika natychmiast (np. "Twoja wiadomość"), odpowiedź AI pojawia się gdy jest gotowa
Problem #2: Użytkownicy nie wiedzą co pisać
Puste pole tekstowe z "Zapytaj mnie o cokolwiek" to najgorszy UX dla AI. Użytkownicy paraliżują się - "Co mogę tu wpisać?", "Czy zrozumie moje pytanie?", "Jak to sformułować?". To zjawisko nazywa się blank page syndrome i dotyka nawet zaawansowanych użytkowników.
Przed i po - konkretny przykład:
| ZLY UX (przed) | DOBRY UX (po) |
|---|---|
| Puste pole z placeholder: "Wpisz wiadomość...". Żadnych wskazówek. Użytkownik wpisuje "pomoc" i dostaje długą listę co potrafi aplikacja - ale już jest sfrustrowany. | 4 klikalne przyciski pod polem: "Wyjaśnij ten kod", "Znajdź błędy", "Napisz testy", "Zoptymalizuj". Użytkownik klika jeden i widzi jak działa - efekt "aha, to tak to działa". |
| Placeholder: "Wpisz wiadomość" - mówi co zrobić, nie daje przykładu | Placeholder: "Np: Znajdź błędy w tym kodzie / Co oznacza ten błąd?" - pokazuje konkretny format |
Suggested prompts - zawsze, bez wyjątków
Krok 1: Przygotuj zestaw sugestii dla każdego kontekstu (kod, dokument, ogólny).
Krok 2: Wyświetl je jako klikalne przyciski gdy pole jest puste.
Krok 3: Po kliknięciu - wstaw sugestię do pola lub wyślij od razu. Użytkownik może edytować przed wysłaniem.
// KROK 1: Sugerowane pytania - zmieniaj kontekstowo
const SUGGESTIONS = {
// Tryb "kod" - użytkownik wkleił lub wskazał plik kodu
'code': [
'Wyjaśnij ten kod',
'Znajdź błędy',
'Napisz testy',
'Zoptymalizuj wydajność'
],
// Tryb "dokument" - użytkownik załadował PDF lub tekst
'document': [
'Podsumuj w 5 punktach',
'Jakie są kluczowe ryzyka?',
'Porównaj z poprzednią wersją',
'Przetłumacz na angielski'
]
};
// KROK 2 i 3: Komponent React wyświetlający przyciski z sugestiami
function PromptSuggestions({ context, onSelect }) {
return (
<div className="suggestions">
{/* Dla każdej sugestii - klikalny przycisk */}
{SUGGESTIONS[context].map(s => (
// onSelect(s) = gdy użytkownik kliknie, wstaw sugestię do pola tekstowego
<button key={s} onClick={() => onSelect(s)}>{s}</button>
))}
</div>
);
}
Placeholder jako instrukcja, nie zachęta
Zamiast "Wpisz wiadomość..." --> "Np: Znajdź błędy w tym kodzie / Podsumuj ten dokument / Co oznacza ten błąd?". Placeholder pokazuje konkretne przykłady, nie abstrakcyjne możliwości - użytkownik widzi format i zakres.
Chcesz zbudować kompletną aplikację AI - od Claude API do działającego frontendu?
Szkolenie AI dla programistów - UX aplikacji AI to jeden z modułów. Termin gwarantowany.
Sprawdź termin szkolenia -->Problem #3: Model może się mylić - jak to komunikować
Claude halucynuje. Nie często, ale zdarza się - szczególnie dla danych po jego dacie treningowej lub dla bardzo specyficznych faktów. Ukrywanie tego niszczy zaufanie gdy użytkownik odkryje błąd. Transparentność jest kluczem do długotrwałego zaufania.
Przed i po - konkretny przykład komunikacji halucynacji:
| ZLY UX (przed) | DOBRY UX (po) |
|---|---|
| Claude odpowiada pewnie: "Wydarzenie X miało miejsce 15 marca 2025." Użytkownik sprawdza - to nieprawda. Traci zaufanie do całej aplikacji. | Claude odpowiada: "Nie jestem pewny tej daty - moje dane są do 2024 roku. Według moich informacji wydarzenie X miało miejsce w okolicach marca 2025, ale proszę to zweryfikować." |
| Brak przycisku feedbacku - użytkownik nie może zgłosić błędu | Przyciski pod każdą odpowiedzią - zbierają dane o jakości, poprawiają system prompt |
Zwrot możesz zgłosić w ciągu 14 dni od otrzymania przesyłki. Towar powinien być nieużywany.
- Confidence indicators: "Na podstawie Twoich danych..." (wysoka pewność - mamy dokumenty) vs "Zakładam że..." (średnia) vs "Nie jestem pewny, ale..." (niska - ryzyko halucynacji)
- Source attribution: w RAG zawsze pokaż skąd pochodzi informacja ("Według dokumentu 'Regulamin 2026', str. 12..."). Użytkownik może samodzielnie sprawdzić
- Uncertainty prompting: skonfiguruj Claude żeby przyznawał się do niepewności:
"Jeśli nie jesteś pewny odpowiedzi - powiedz to wyraźnie zamiast zgadywać." - Easy feedback: przycisk po każdej odpowiedzi - zbieraj dane o jakości, używaj do poprawy systemu promptów
Problem #4: Obsługa błędów widoczna dla użytkownika
Techniczne błędy API nigdy nie powinny trafiać bezpośrednio do użytkownika. "anthropic.APIStatusError: 529" nie mówi mu nic użytecznego - tylko wywołuje panikę. Każdy błąd powinien mówić użytkownikowi co ma zrobić, nie co poszło nie tak technicznie.

Przed i po - obsługa błędu rate limiting:
| ZLY UX (przed) | DOBRY UX (po) |
|---|---|
| Pojawia się czerwony komunikat: "anthropic.RateLimitError: 429 Rate limit exceeded. Current request rate: 95 req/min, limit: 100 req/min." Użytkownik nie wie co to znaczy ani co zrobić. | Pojawia się: "Asystent jest bardzo zajęty. Spróbuj za kilka sekund. [Przycisk: Spróbuj ponownie]". Automatyczny retry po 5 sekundach. |
// NIE RÓB tak - techniczny błąd trafia bezpośrednio do interfejsu
catch (error) {
setError(error.message); // "anthropic.APIStatusError: 529" - użytkownik nie wie co to znaczy
}
// RÓB tak - przyjazny komunikat dla użytkownika + techniczne logi dla dewelopera
catch (error) {
if (error instanceof RateLimitError) {
// Zbyt wiele żądań - użytkownik dostaje prostą instrukcję co zrobić
setError('Asystent jest bardzo zajęty. Spróbuj za kilka sekund.');
} else if (error instanceof APIConnectionError) {
// Problem z siecią - sugeruj sprawdzenie połączenia
setError('Problem z połączeniem. Sprawdź internet i spróbuj ponownie.');
} else {
// Nieznany błąd - ogólny komunikat + zaloguj technikalia
setError('Coś poszło nie tak. Odśwież stronę jeśli problem się powtarza.');
// logger.error loguje szczegóły dla dewelopera (widoczne w logach serwera)
logger.error('Claude API error:', error);
}
}
Problem #5: Długie odpowiedzi - czytelność i nawigacja
Claude lubi długie, szczegółowe odpowiedzi. W UI często to problem - użytkownik widzi ścianę tekstu i nie wie gdzie patrzeć. Wzorce które działają:
- Progressive disclosure: pokaż podsumowanie + "Zobacz więcej" dla szczegółów. Większość użytkowników chce skrótu, nie pełnego elaboratu
- Markdown rendering: Claude domyślnie zwraca markdown (tekst z **pogrubieniami**, # nagłówkami, - listami). Musisz go renderować - surowe gwiazdki w UI wyglądają fatalnie. Biblioteki: react-markdown (React), marked.js (vanilla JS)
- Code highlighting: dla odpowiedzi z kodem - syntax highlighting (Prism.js lub highlight.js). Kolorowy kod jest 3× czytelniejszy niż czarno-biały
- Copy button: na każdym bloku kodu - użytkownicy oczekują że mogą skopiować jednym kliknięciem. Bez tego wielokrotnie zaznaczają myszką i klną
# wdrożenie produkcyjne npm run build && \ docker push registry/app:latest
Problem #6: Kontekst konwersacji - zarządzanie historią
- Pokaż rozmowę jako wątki - nie stack scrollowalnych wiadomości gdy jest ich 50. Długa lista wiadomości jest nieczytelna
- Możliwość edycji promptu - "Edytuj i wyślij ponownie" zamiast przepisywania od zera. Oszczędza czas i frustrację
- Restore context - użytkownik wraca po tygodniu, pokaż mu krótkie podsumowanie poprzedniej rozmowy. Nie musi czytać 50 wiadomości żeby wiedzieć gdzie skończył
- Limit długości konwersacji - po X wiadomościach zaproponuj "Zacznij nową rozmowę" żeby nie tracić jakości. Długi kontekst = Claude "zapomina" co było na początku (limit okna kontekstowego)
Wzorzec: Human-in-the-loop dla krytycznych akcji
Human-in-the-loop to pattern gdzie dla ważnych, nieodwracalnych akcji - agent musi uzyskać potwierdzenie od człowieka zanim je wykona. Zasada: im bardziej nieodwracalna akcja, tym silniejsze potwierdzenie potrzebne.
// Komponent React pokazujący prośbę o potwierdzenie akcji agenta
// onConfirm i onReject to funkcje zwrotne (callbacks) wywoływane po kliknięciu
function AgentAction({ action, onConfirm, onReject }) {
return (
<div className="action-approval">
<p>Agent chce wykonać:</p>
{/* action.description = opis konkretnej akcji w czytelnym języku */}
<code>{action.description}</code>
<div className="buttons">
<button onClick={onConfirm} className="btn-approve">
Zatwierdz
</button>
<button onClick={onReject} className="btn-reject">
Odrzuc
</button>
</div>
</div>
);
}
// Używaj tego wzorca gdy agent chce: wysłać email, zapisać do bazy, wywołać zewnętrzne API
Częste błędy przy projektowaniu UX dla AI
Błąd #1: Brak komunikatu ładowania przez pierwsze sekundy
Użytkownik klika i przez 2-3 sekundy nic się nie dzieje - myśli że przycisk nie zadziałał i klika ponownie. Efekt: dwa równoległe zapytania, podwójny koszt API, zdezorientowany użytkownik. Fix: pokaż loader natychmiast po kliknięciu "Wyślij", zablokuj przycisk do momentu odpowiedzi.
Błąd #2: Renderowanie surowego markdownu
Claude zwraca odpowiedź z **pogrubieniami**, ## nagłówkami, blokami kodu. Wyświetlasz je surowo - użytkownik widzi masę gwiazdek i krzyżyków. Wyglądają jak błąd formatowania. Zawsze używaj biblioteki do renderowania markdownu.
Błąd #3: Brak blokady formularza podczas oczekiwania
Użytkownik może wysłać kolejną wiadomość zanim Claude skończy odpowiadać na poprzednią. Prowadzi to do nakładających się odpowiedzi w UI i niespójnego stanu aplikacji. Blokuj pole input i przycisk Wyślij podczas gdy Claude odpowiada - odblokuj po zakończeniu streamingu.
Checklist UX przed wdrożeniem aplikacji z Claude
Przejdź przez tę listę przed każdym wdrożeniem. Każdy niezaznaczony punkt to potencjalna frustracja użytkownika:
- Streaming jest włączony - użytkownik widzi odpowiedź w czasie rzeczywistym
- Loader pojawia się natychmiast po kliknięciu Wyślij
- Są suggested prompts lub przykłady - użytkownik wie od czego zacząć
- Błędy API mają przyjazne komunikaty dla użytkownika (nie kody błędów)
- Markdown jest renderowany - nie surowy tekst z gwiazdkami i kratkami
- Kod ma syntax highlighting i przycisk kopiowania
- Długie odpowiedzi mają progressive disclosure (podsumowanie + "więcej")
- Krytyczne akcje agenta wymagają potwierdzenia (human-in-the-loop)
- Jest mechanizm feedbacku (thumbs up/down lub podobny)
- Stany: loading (ładowanie), success (sukces), error (błąd) są wyraźnie komunikowane
- Mobile działa poprawnie - szczególnie klawiatura nie zasłania pola input
Kiedy Twoja aplikacja AI reaguje natychmiast, prowadzi użytkownika za rękę i komunikuje błędy jak przyjaciel - użytkownicy wracają. Dobry UX zamienia jednorazowych odwiedzających w lojalnych klientów, a Twój produkt wyróżnia się wśród morza przeciętnych aplikacji AI.
5 decyzji UX, które wdrożysz od ręki
Te pięć drobiazgów decyduje, czy użytkownik polubi Twoją aplikację z AI:
- Streaming zawsze. pokazuj odpowiedź na bieżąco - czekanie na pełny wynik w bezruchu zabija wrażenia.
- Podpowiadaj przykładowe zapytania. gotowe „suggested prompts” i placeholder-instrukcja - bez nich użytkownik nie wie, co wpisać.
- Komunikuj, że model może się mylić. przy ważnych akcjach daj łatwe sprawdzenie i cofnięcie (human-in-the-loop).
- Skeleton zamiast spinnera. pokaż zarys odpowiedzi albo postęp - użytkownik widzi, że „coś się dzieje”.
- Nie kumuluj całej historii. podsumowuj starsze tury rozmowy - inaczej rosną koszty i opóźnienie.
Newsletter bloga JSystems
Otrzymuj każdą nową lekcję prosto na swoją skrzynkę
Nowe lekcje pojawiają się co poniedziałek i czwartek. Zapisz się do newslettera bloga JSystems - dostaniesz powiadomienie zaraz po publikacji każdej lekcji.
Szkolenie AI dla programistów - od API do gotowej aplikacji
5 dni - budujesz kompletną aplikację AI z Claude włącznie z frontendem, streamingiem i wdrożeniem. UX aplikacji AI to jeden z modułów szkolenia. Termin gwarantowany.
Komentarze (0)
Brak komentarzy...