W dwóch poprzednich artykułach z tej serii najpierw zobaczyliśmy, dlaczego warto zbierać feedback od klientów, a potem jak stworzyć użyteczny formularz feedbacku, żeby zrozumieć, co dzieje się na stronie lub w aplikacji tuż po konwersji.
W tym trzecim artykule schodzimy poziom głębiej. Nie mówimy już tylko o zbieraniu odpowiedzi, ale o tym, jak je przetwarzać.
Bo analiza odpowiedzi z pól otwartych dowolnego formularza zajmuje czas, jeśli nie zostanie zautomatyzowana. Zwłaszcza jeśli przychodzą w kilku językach.
Pełna seria o tym, jak zbierać i wykorzystywać feedback od klientów, ma cztery części:
- Dlaczego zbieranie feedbacku od klientów jest niezbędne.
- Jak stworzyć użyteczny formularz feedbacku.
- Jak używać AI do tłumaczenia i klasyfikowania odpowiedzi otwartych.
- Jak zamienić ten feedback w dashboardy i miesięczną rutynę monitorowania.
Tutaj skupimy się na trzecim punkcie: zbudowaniu workflow z n8n, Google Sheets i Gemini, aby tłumaczyć, klasyfikować i wzbogacać otwarte odpowiedzi z formularzy.
Índice de Contenidos del Artículo
- Jaki problem rozwiązujemy tym workflow
- Co zbudujemy
- Narzędzia, których użyjemy
- Zanim zaczniesz: jak powinien być przygotowany arkusz odpowiedzi
- Workflow w n8n krok po kroku
- Co uzyskujemy na końcu procesu
- Typowe błędy przy automatyzowaniu feedbacku z AI
- Następny krok: zamienić te dane w dashboard
- Najczęstsze pytania
- Do czego służy automatyzowanie odpowiedzi z formularzy za pomocą n8n i AI?
- Jaki problem rozwiązuje ten workflow?
- Jakich narzędzi używa się w workflow?
- Czy trzeba używać dokładnie Gemini?
- Jak powinien być przygotowany arkusz odpowiedzi?
- Dlaczego unikanie duplikatów jest ważne?
- Dlaczego trzeba dawać AI zamknięte kategorie?
- Co zwraca AI w tym przepływie?
- Dlaczego trzeba walidować JSON zwracany przez AI?
- Czy AI zastępuje analizę człowieka?
Jaki problem rozwiązujemy tym workflow
Pytania zamknięte w formularzu są łatwe do analizy.
Jeśli prosisz o ocenę łatwości procesu od jednego do dziesięciu (albo czegokolwiek innego), główny powód decyzji, wiek, kraj albo informację, czy użytkownik miał problemy, każda odpowiedź trafia do ograniczonej liczby zmiennych.
Problem zaczyna się przy odpowiedziach otwartych.
To tam użytkownik własnymi słowami wyjaśnia, co mu się przydarzyło: że nie mógł znaleźć informacji, że płatność budziła wątpliwości, że porównał z inną platformą, gdzie było taniej, że miał problem z kuponem w checkoutcie, że chciał porozmawiać z człowiekiem albo że proces był jasny i szybki.
Taki komentarz jest bardzo wartościowy, ale ma trzy trudności:
- Trzeba go przeczytać.
- Trzeba zrozumieć i zinterpretować kontekst.
- A jeśli jest kilka języków, trzeba go przetłumaczyć albo znormalizować przed porównaniem.
Jeśli masz niewiele odpowiedzi, możesz zrobić to ręcznie. Jeśli zaczyna się pojawiać większy wolumen, różne rynki albo komentarze w pięciu językach, przestaje to być wykonalne.
W przypadku, którego używamy jako przykładu, formularz był przygotowany po hiszpańsku, niderlandzku, francusku, angielsku i niemiecku. Dlatego dodanie warstwy AI miało sens.
Nie chodzi o to, żeby AI podejmowała decyzje za biznes, tylko żeby przygotowała dane:
- Tłumaczyć komentarze.
- Klasyfikować incydenty.
- Wykrywać wzmianki o konkurentach.
- Przygotować dokument Google Sheets do analizy w kolejnym kroku.
Co zbudujemy
Zbudujemy workflow n8n który robi następujące rzeczy:
- Czyta arkusz Google Sheets z odpowiedziami z formularzy.
- Wykrywa, które odpowiedzi są nowe, żeby nie przetwarzać duplikatów.
- Dodaje kontekst kategorii, żeby AI klasyfikowała spójnie.
- Wysyła pola otwarte do LLM (w naszym przypadku Gemini).
- Otrzymuje odpowiedź w JSON.
- Zamienia ten JSON na kolumny we właściwym formacie.
- Zapisuje wynik końcowy w innym arkuszu Google Sheets z wynikami AI.
To nie jest uniwersalny przepis, który można skopiować bez zmieniania czegokolwiek.
Jest dostosowany do konkretnego formularza feedbacku klienta na stronie rezerwacyjnej, ale logikę można przenieść na e-commerce, szkolenie, stronę usługową albo dowolny formularz feedbacku dotyczący zasobu cyfrowego, w którym chcesz klasyfikować odpowiedzi otwarte.
Narzędzia, których użyjemy
Do tego przepływu używamy kilku konkretnych narzędzi:
- n8n, jako narzędzia automatyzacji.
- Google Sheets, jako arkusza wejściowego i wyjściowego.
- Gemini, jako modelu AI do tłumaczenia i klasyfikowania.
- Data Studio, które będzie naturalnym miejscem do wizualizacji danych w następnym artykule.
W tym przypadku używamy Gemini Flash Lite bo zadanie jest stosunkowo lekkie: analiza krótkich komentarzy, wybór kategorii, wykrycie, czy pojawia się konkurent, i zwrócenie JSON. Nie potrzebujemy do tego najmocniejszego modelu, tylko modelu szybkiego, taniego i stabilnego.
W naszym przypadku przewidywany koszt wynosił zaledwie kilka centów dziennie. Wybraliśmy też wersję latest Flash Lite, bo przy przypinaniu starszych wersji, takich jak 2.0 albo 2.5, pojawiały się problemy z dostępnością.
A w zautomatyzowanym przepływie stabilność jest równie ważna jak jakość, jeśli nie ważniejsza.
Temperatura modelu jest ustawiona na 0.1.
To również celowe: tutaj nie szukamy kreatywności, tylko spójności.
Chcemy, żeby podobne odpowiedzi były klasyfikowane w podobny sposób i żeby model respektował format JSON, o który prosimy.
Zanim zaczniesz: jak powinien być przygotowany arkusz odpowiedzi
Jak wyjaśniłem w poprzednim wpisie, przed zbudowaniem workflow potrzebujemy arkusza Google Sheets z oryginalnymi odpowiedziami z formularza.
Może pochodzić bezpośrednio z Google Forms albo może być arkuszem, w którym ujednoliciliśmy odpowiedzi przychodzące z innego systemu, na przykład CRM albo kilku formularzy w różnych językach.
Ważne jest, żeby arkusz miał stabilną strukturę: jeden wiersz na odpowiedź i jedną kolumnę na pytanie.
W tym przykładzie pracujemy z polami powiązanymi z odpowiedziami:
- Record ID (którego używamy, żeby unikać duplikatów).
- Data.
- Rynek (to pięć różnych domen).
I same pola odpowiedzi:
- Łatwość rezerwacji (skala 1–10).
- Powód decyzji (5 możliwości).
- Czy wystąpiły incydenty i szczegóły incydentu.
- Ocena strony.
- Komentarz swobodny.
- Kraj (to nie to samo co rynek, bo Fin może rezerwować na angielskiej stronie).
- Płeć.
- Wiek.
- I czy użytkownik oczekuje odpowiedzi.
Twój arkusz nie musi mieć dokładnie tych samych kolumn. Ważne, żeby był unikalny identyfikator dla każdej odpowiedzi. W tym workflow używamy Record ID, żeby wiedzieć, które wiersze zostały już przetworzone, a które są nowe.

Jeśli pracujesz w kilku językach, warto zachować tę samą strukturę pytań i odpowiedzi we wszystkich z nich, zmieniając tylko tłumaczenie.
Dzięki temu możesz analizować dane zagregowane, a jednocześnie segmentować według języka, kraju albo rynku. Wszystko to widzieliśmy w poprzednim wpisie o tworzeniu formularza.
Workflow w n8n krok po kroku
Pełny workflow jest zorganizowany w dziewięciu głównych nodach:
Co godzinę:
→ Odczytaj źródłowy Sheets.
→ Spakuj źródło.
→ Filtruj nowe ID.
→ Zbuduj kontekst kategorii.
→ Klasyfikuj z Gemini Flash.
→ Parsuj odpowiedź AI.
→ Przygotuj wyniki dla nowego Google Sheet.
→ Zapisz w nowym Google Sheet.

Najpierw opowiem ogólnie, jak działa przepływ, a potem omówimy szczegółowo każdy element.
W tym przepływie n8n uruchamia się z określoną częstotliwością, czyta arkusz odpowiedzi, normalizuje dane, odrzuca rekordy już przetworzone, dodaje kategorie, których ma użyć AI, wysyła pola otwarte do Gemini, interpretuje odpowiedź i zapisuje wzbogacony wiersz w arkuszu końcowym.
Teraz przejdźmy node po node.
Krok 1: Co godzinę
Ten node jest wyzwalaczem workflow.
W przykładzie jest skonfigurowany tak, aby uruchamiać się co godzinę, ale częstotliwość można dostosować do wolumenu odpowiedzi.
Jeśli otrzymujesz dużo odpowiedzi, uruchamianie co godzinę może mieć sens. Jeśli mało, być może wystarczy raz dziennie.
Trzeba go też będzie uruchamiać ręcznie podczas fazy testów.
Podstawowa konfiguracja:
Node type: Schedule Trigger
Rule: every hour
Kluczem jest dostosowanie częstotliwości. Dla feedbacku z formularzy zwykle nie trzeba przetwarzać wszystkiego co minutę.
Krok 2: Odczytaj źródłowy Google Sheets
Ten node czyta arkusz Google Sheets w którym znajdują się oryginalne odpowiedzi z formularza.
W tym przypadku używamy zakładki źródłowej tylko do odczytu.
Ważne: nie oznaczamy wierszy, nie zapisujemy statusów i nie używamy tego arkusza jako operacyjnej bazy danych.
Moglibyśmy to zrobić, ale ponieważ ten arkusz stworzył klient, lepiej go nie ruszać. Jeśli to Twój własny biznes, prawdopodobnie ma sens dodanie drugiego arkusza, zamiast tworzyć kolejny Google Sheet, jak robimy tutaj.
Podstawowa konfiguracja:
Node type: Google Sheets
Operation: Read
Document ID: [ID_DEL_SPREADSHEET_ORIGEN]
Sheet name: [NOMBRE_HOJA_ORIGEN]
Credential: [CREDENCIAL_GOOGLE_SHEETS]
Arkusz źródłowy powinien być jak najczystszy.
Jeśli pochodzi z Google Forms, masz już dość wygodną strukturę. Jeśli pochodzi z CRM albo z kilku formularzy, warto wcześniej ujednolicić odpowiedzi w arkuszu ze spójnymi kolumnami.
Krok 3: Spakuj źródło
Ten node kodu (JS) normalizuje wiersze które przychodzą z arkusza źródłowego i przygotowuje je dla reszty workflow.
W praktyce kopiuje każdy item dokładnie tak, jak jest.
Kod node'a:
// Normaliza las filas del Sheets origen para usarlas despues desde otros nodos.
// El origen es solo lectura, asi que no marcamos nada aqui.
return $input.all().map(item => ({
json: { ...item.json }
}));
Krok 4: Filtruj nowe Record ID
Ten node zapobiega duplikatom.
To jeden z najważniejszych punktów workflow. Gdybyśmy przy każdym uruchomieniu przepływu wysyłali wszystkie odpowiedzi do Gemini, przetwarzalibyśmy te same komentarze raz za razem, wydawali więcej tokenów i zapełniali arkusz końcowy duplikatami.
Żeby tego uniknąć, używamy node'a Remove Duplicates w n8n z operacją Remove Items Processed in Previous Executions. Konfiguracja opiera się na polu Record ID, które musi być unikalne dla każdej odpowiedzi.
Podstawowa konfiguracja:
Node type: Remove Duplicates
Operation: Remove Items Processed in Previous Executions
Value to Dedupe On: {{ $json["Record ID"] }}
To ważne:
Jeśli workflow jest budowany zanim pojawią się odpowiedzi, nie trzeba nic inicjalizować. Pierwsza odpowiedź, która przyjdzie, będzie nowa i zostanie przetworzona.
Jeśli arkusz ma już stare odpowiedzi, gdy aktywujesz workflow (typowy przypadek), warto uruchomić cały przepływ do tego node'a włącznie, zanim podłączysz go do reszty przepływu.
Dzięki temu n8n nauczy się traktować te Record ID jako już widziane i nie wyśle całej historii do AI przy pierwszym uruchomieniu.
Warto też przetestować przepływ bez publikowania go jeszcze: uruchomić raz, sprawdzić, które rekordy przechodzą, uruchomić ponownie i zweryfikować, że się nie duplikują.
Nie klikaj Clear Deduplication Historychyba że chcesz ponownie przetworzyć wszystko.
Krok 5: Zbuduj kontekst kategorii
Tutaj definiujemy kategorie których AI może używać do klasyfikowania odpowiedzi.
Ten punkt jest kluczowy, bo nie chcemy, żeby Gemini wymyślał inną kategorię dla każdego komentarza. Chcemy, żeby klasyfikował w zamkniętych ramach.
W tym przykładzie mamy dwie grupy kategorii: jedną dla incydentów w procesie rezerwacji i drugą dla komentarzy otwartych.
Kategorie dla Q3, incydenty w procesie:
- Płatność / bramka płatnicza.
- Kod rabatowy.
- Nawigacja / UX.
- Nieprawidłowa dostępność.
- Problemy z rezerwacją.
- Inne.
Kategorie dla Q5, komentarze otwarte:
- Satysfakcja / pochwała.
- Promocje / rabaty.
- Obsługa / ludzkie wsparcie.
- Forma płatności / przelew.
- Cena.
- Porównanie z konkurencją.
- Informacje w listingu.
- Polityka anulowania.
- Czas odpowiedzi.
- Brak istotnego komentarza.
- Inne.
W tym przypadku zdecydowaliśmy się zahardkodować kategorie wewnątrz samego node'a kodu, aby uniknąć dodatkowego odczytu z Google Sheets.
To nie jest tylko preferencja techniczna: pomaga zmniejszyć liczbę wywołań API Google Sheets.
Może wydawać się wygodne używać Google Sheets jak małej bazy danych: jeden arkusz na odpowiedzi, drugi na kategorie, trzeci do przeglądania przetworzonych, kolejny do zapisywania wyników.
Ale jeśli przepływ urośnie, możesz trafić na limity wykorzystania, tak jak nam się tutaj zdarzało.
Dlatego w tym przypadku używamy Google Sheets jako wejścia i wyjścia, a nie jako ogólnej bazy danych systemu (która będzie tą, jaką masz w swojej instalacji n8n, domyślnie SQLite).
Kod node'a:
// Categorías hardcodeadas para eliminar una lectura adicional a Google Sheets.
// Si cambias Categorias_Config, actualiza estas listas aquí.
const categoriasQ3 = [
[
'Pago / pasarela',
'Tarjeta rechazada, fallo con Bancontact, Paypal u otro metodo de pago'
],
[
'Codigo descuento',
'Cupon o codigo de descuento invalido que bloquea o impide completar el pago'
],
[
'Navegacion / UX',
'Problemas de usabilidad en la web, ej. volver al listado, botones confusos'
],
[
'Disponibilidad incorrecta',
'Fechas que desaparecen, alojamiento mostrado como disponible pero no lo esta'
],
[
'Problemas con la reserva',
'Reserva equivocada, duplicada o cancelada por error del sistema, demora o ausencia de confirmacion de reserva, email de confirmacion o validacion del propietario'
],
[
'Otro',
'Incidencia que no encaja en ninguna categoria anterior'
],
];
const categoriasQ5 = [
[
'Satisfaccion / elogio',
'Comentarios positivos, felicitaciones, recomendacion del servicio o buena experiencia'
],
[
'Promociones / descuentos',
'Peticiones de codigos promocionales, descuentos para clientes habituales o promociones'
],
[
'Atencion / soporte humano',
'Peticiones de hablar con una persona, chat humano, soporte no automatizado o ayuda comercial'
],
[
'Forma de pago / transferencia',
'Comentarios sobre transferencia, tarjeta, medios de pago disponibles o preferencia de pago'
],
[
'Precio',
'Comentarios sobre subida de precios, coste percibido como alto o comparacion de precio'
],
[
'Comparacion con competencia',
'Menciona explicitamente otra plataforma como Booking.com, Airbnb, Vrbo, etc.'
],
[
'Informacion del listing',
'Falta de fotos, ubicacion/coordenadas poco claras, info de mascotas, descripcion del alojamiento'
],
[
'Politica de cancelacion',
'Plazo de cancelacion gratuita considerado corto o poco flexible'
],
[
'Tiempo de respuesta',
'Quejas sobre lentitud en la respuesta a consultas o soporte'
],
[
'Sin comentario relevante',
"Respuestas vacias de contenido: 'No', 'nada que destacar', 'all good', etc."
],
[
'Otro',
'Comentario con contenido pero que no encaja en ninguna categoria anterior'
],
];
const catsQ3 = categoriasQ3
.map(([cat, desc]) => `- ${cat}: ${desc}`)
.join('
');
const catsQ5 = categoriasQ5
.map(([cat, desc]) => `- ${cat}: ${desc}`)
.join('
');
return $input.all().map(item => ({
json: {
...item.json,
categorias_q3_texto: catsQ3,
categorias_q5_texto: catsQ5,
}
}));
Oczywiście te kategorie nie są uniwersalne. Dla innych biznesów cyfrowych trzeba je dostosować.
Krok 6: Klasyfikuj z Gemini Flash
To jest node, który wysyła pola otwarte do Gemini. Konkretnie analizujemy dwa pola: szczegóły incydentu podczas rezerwacji i końcowy komentarz swobodny.
Model musi zwrócić wyłącznie prawidłowy JSON, bez wyjaśnień, bez markdown i bez dodatkowego tekstu. To fundamentalne, bo następny node oczekuje sparsowania tej odpowiedzi i zamiany jej na kolumny.
Podstawowa konfiguracja:
Node type: Google Gemini
Model: models/gemini-flash-lite-latest
Temperature: 0.1
Credential: [CREDENCIAL_GEMINI]
Użyty prompt:
Jesteś klasyfikatorem feedbacku użytkowników strony do rezerwacji noclegów wiejskich. Musisz przeanalizować dwa pola tekstowe i zwrócić WYŁĄCZNIE prawidłowy JSON, bez dodatkowego tekstu, bez markdown, bez backticków.
Pole Q3 - Issue Detail (incydent podczas rezerwacji): "{{ $json['Q3 - Issue Detail'] }}"
Dozwolone kategorie dla Q3 (wybierz jedną albo użyj dokładnie tekstu "Sin incidencia", jeśli pole jest puste):
{{ $json.categorias_q3_texto }}
Pole Q5 - Comments (komentarz swobodny): "{{ $json['Q5 - Comments'] }}"
Dozwolone kategorie dla Q5 (wybierz jedną albo użyj dokładnie tekstu "Sin comentario relevante", jeśli jest puste albo nie wnosi treści, jak 'No', 'nada', 'all good'):
{{ $json.categorias_q5_texto }}
Dodatkowo:
- Jeśli Q5 wyraźnie wspomina konkurencyjną platformę (Booking.com, Airbnb, Vrbo, Expedia, HomeAway albo inną), ustaw menciona_competidor true i wykrytą nazwę. Jeśli nie, false i pusty ciąg.
- Przetłumacz treść Q5 na hiszpański wiernie i naturalnie w comentario_traducido_es. Jeśli jest puste, zwróć pusty ciąg.
- Dla Q3, oprócz kategorii, podaj w causa_raiz_resumen krótką frazę (maksymalnie 8 słów) po hiszpańsku, która podsumowuje przyczynę techniczną, przydatną do grupowania podobnych incydentów, nawet jeśli są opisane różnie. Jeśli nie ma incydentu, pusty ciąg.
Zwróć dokładnie taki format JSON:
{
"q3_categoria": "",
"q3_causa_raiz_resumen": "",
"q5_categoria": "",
"q5_menciona_competidor": false,
"q5_competidor_detectado": "",
"q5_comentario_traducido_es": ""
}
Prompt robi kilka rzeczy naraz:
- Klasyfikuje i tłumaczy Q3.
- Podsumowuje krótką przyczynę źródłową incydentów.
- Klasyfikuje i tłumaczy Q5.
- Wykrywa, czy wspomniano konkurenta, i tłumaczy komentarz swobodny na hiszpański.
Wszystko to wraca w JSON z ustalonymi polami.
Najważniejsze jest to, że model nie decyduje swobodnie, co ma zrobić. Dajemy mu dozwolone kategorie, dokładny format wyjścia i prosimy, żeby nie dodawał tekstu poza JSON.
Krok 7: Parsuj odpowiedź AI
Ten node zamienia odpowiedź Gemini w użyteczne kolumny.
Najpierw wyciąga tekst zwrócony przez model, czyści ewentualne backticki lub bloki markdown, a potem próbuje przekształcić go w JSON.
Zawiera też warstwę bezpieczeństwa: jeśli AI zwróci coś, czego nie da się sparsować, oznacza wiersz jako Błąd klasyfikacji. Dzięki temu przepływ nie rozsypuje się przez pojedynczą źle sformatowaną odpowiedź.
Dodatkowo wymusza ważną regułę dla naszego przykładu: jeśli Q3 nie ma szczegółów albo użytkownik wskazał, że nie miał problemów, kategoria Q3 zostaje jako Sin incidencia.
To zapobiega sytuacji, w której AI interpretuje komentarz Q5 jak incydent procesu.
Kod node'a:
function extractModelText(json) {
// Caso Gemini n8n actual:
// item.json.content.parts[0].text
if (json?.content?.parts?.[0]?.text) {
return json.content.parts[0].text;
}
// Otros formatos posibles según nodo/modelo
if (typeof json?.text === 'string') return json.text;
if (typeof json?.message === 'string') return json.message;
if (typeof json?.output === 'string') return json.output;
if (typeof json?.content === 'string') return json.content;
// OpenAI/LangChain style fallback
if (json?.message?.content) return json.message.content;
if (json?.choices?.[0]?.message?.content) return json.choices[0].message.content;
return '';
}
function cleanJsonText(raw) {
return String(raw || '')
.replace(/```json/gi, '')
.replace(/```/g, '')
.trim();
}
const items = $input.all();
const originales = $('Construir contexto de categorias').all();
return items.map((item, index) => {
const raw = cleanJsonText(extractModelText(item.json));
let parsed;
try {
parsed = JSON.parse(raw);
} catch (e) {
parsed = {
q3_categoria: 'Error de clasificacion',
q3_causa_raiz_resumen: '',
q5_categoria: 'Error de clasificacion',
q5_menciona_competidor: false,
q5_competidor_detectado: '',
q5_comentario_traducido_es: ''
};
}
const original = originales[index] ? originales[index].json : {};
const q3HadIssues = String(original['Q3 - Had Issues'] || '').trim().toLowerCase();
const q3Detail = String(original['Q3 - Issue Detail'] || '').trim();
if (!q3Detail || q3HadIssues === 'no') {
parsed.q3_categoria = 'Sin incidencia';
parsed.q3_causa_raiz_resumen = '';
}
return {
json: {
'Record ID': original['Record ID'],
'Timestamp': original['Timestamp'],
'Market': original['Market'],
'Q1 - Ease of Booking': original['Q1 - Ease of Booking'],
'Q2 - Decision Driver': original['Q2 - Decision Driver'],
'Q2 - Other (Specify)': original['Q2 - Other (Specify)'],
'Q3 - Had Issues': original['Q3 - Had Issues'],
'Q3 - Issue Detail': original['Q3 - Issue Detail'],
'Q3 - Cluster Causa Raiz': parsed.q3_categoria || '',
'Q3 - Causa Raiz Resumen': parsed.q3_causa_raiz_resumen || '',
'Q4 - NPS Score': original['Q4 - NPS Score'],
'Q5 - Comments': original['Q5 - Comments'],
'Q5 - Cluster Tema': parsed.q5_categoria || '',
'Q5 - Menciona Competidor': parsed.q5_menciona_competidor ? 'Si' : 'No',
'Q5 - Competidor Detectado': parsed.q5_competidor_detectado || '',
'Q5 - Comentario Traducido ES': parsed.q5_comentario_traducido_es || '',
'Country': original['Country'],
'Gender': original['Gender'],
'Age': original['Age'],
'Reply Requested': original['Reply Requested'],
'Fecha Procesado IA': new Date().toISOString()
}
};
});
Jeśli zmienisz nazwę poprzedniego node'a, musisz dostosować tę linię:
const originales = $('Construir contexto de categorias').all();
W n8n referencje po nazwie node'a muszą zgadzać się dokładnie. Dlatego warto używać jasnych nazw i nie zmieniać ich później bez sprawdzenia kodu.
Krok 8: Przygotuj Resultados_IA
Ten node wykonuje końcowe czyszczenie przed zapisaniem danych w arkuszu wyników. Usuwa pola wewnętrzne, które służą tylko podczas procesu, takie jak kategorie w tekście dodane wcześniej do promptu.
Kod node'a:
// Limpia campos internos antes de escribir en Resultados_IA.
return $input.all().map(item => {
const row = { ...item.json };
delete row['_timestamp_unix'];
delete row['_clasificacion_error'];
delete row['_error_message'];
delete row['categorias_q3_texto'];
delete row['categorias_q5_texto'];
return { json: row };
});
Ten krok nie przekształca analizy, ale zostawia wyjście czystsze.
Arkusz końcowy nie musi przechowywać wszystkiego, co było używane wewnętrznie do klasyfikowania, tylko dane, które potem będziemy analizować.
Krok 9: Zapisz Resultados_IA
Ostatni node zapisuje wzbogacony wiersz w nowym arkuszu Google Sheets.
W tym przypadku używamy arkusza o nazwie Resultados_IA i operacji append, aby dodać nowy wiersz dla każdej przetworzonej odpowiedzi.
Podstawowa konfiguracja:
Node type: Google Sheets
Authentication: Service Account
Operation: Append
Document ID: [ID_DEL_SPREADSHEET_RESULTADOS]
Sheet name: [NOMBRE_HOJA_RESULTADOS]
Mapping mode: Auto-map input data
Credential: [CREDENCIAL_GOOGLE_SHEETS]
Arkusz końcowy zawiera zarówno dane oryginalne, jak i pola wygenerowane przez AI. Na przykład:
- Record ID
- Timestamp
- Market
- Q1 – Ease of Booking
- Q2 – Decision Driver
- Q3 – Had Issues
- Q3 – Issue Detail
- Q3 – Cluster Causa Raiz
- Q3 – Causa Raiz Resumen
- Q4 – NPS Score
- Q5 – Comments
- Q5 – Cluster Tema
- Q5 – Menciona Competidor
- Q5 – Competidor Detectado
- Q5 – Comentario Traducido ES
- Country
- Gender
- Age
- Reply Requested
- Fecha Procesado IA

Od tego momentu nie mamy już tylko luźnych odpowiedzi. Mamy wzbogaconą tabelę, z przetłumaczonymi komentarzami, pogrupowanymi incydentami, sklasyfikowanymi tematami i polami gotowymi do użycia na wykresach.
Co uzyskujemy na końcu procesu
Po zakończeniu workflow każda nowa odpowiedź zostaje zamieniona w bardziej użyteczny wiersz do analizy.
Nadal zachowujemy dane oryginalne, ale dodajemy warstwy, które wcześniej wymagały ręcznego przeglądu.
W praktyce uzyskujemy:
- Otwarte komentarze przetłumaczone na hiszpański.
- Incydenty sklasyfikowane według przyczyny źródłowej.
- Komentarze pogrupowane według tematu.
- Wykrywanie wzmianek o konkurentach.
- Datę przetworzenia przez AI.
- Tabelę gotową do podłączenia do Looker Studio.
To nie zastępuje ludzkiego przeglądu. Po prostu usuwa pracę mechaniczną.
Zamiast zaczynać od czytania stu komentarzy w pięciu językach, zaczynasz od tematów, kategorii, częstotliwości i przetłumaczonych komentarzy. Potem możesz już przejrzeć próbki i zdecydować, jakie działania mają sens, jak zobaczymy w następnym i ostatnim wpisie z serii.
Typowe błędy przy automatyzowaniu feedbacku z AI
Przejdźmy przez najczęstsze.
Pozwalanie AI wymyślać kategorie
Jeśli każde uruchomienie tworzy nowe etykiety, później nie porównasz niczego.
Żeby system działał, AI musi klasyfikować w ramach zamkniętej listy albo przynajmniej bardzo kontrolowanej.
Brak walidacji JSON zwracanego przez model
Nawet jeśli poprosisz o konkretny format, czasem może odpowiedzieć źle. Dlatego node parsujący musi czyścić, próbować konwertować do JSON i obsługiwać błędy bez łamania całego przepływu.
Brak sprawdzania duplikatów
Przed opublikowaniem workflow warto uruchomić go testowo i sprawdzić, czy ta sama odpowiedź nie trafia kilka razy do drugiego arkusza.
Node nowych Record ID zapobiega temu, żeby płacić dwa razy za tę samą klasyfikację i zaśmiecać arkusz końcowy.
Używanie Google Sheets jako operacyjnej bazy danych
Google Sheets bardzo dobrze działa jako wejście i wyjście, ale nie warto robić ciągłych odczytów do wszystkiego: kategorii, statusów, kontroli, wyników i kontroli przetworzonych rekordów.
Jeśli przesadzisz, możesz natknąć się na problemy z limitami albo na przepływ bardziej kruchy niż potrzeba.
Publikowanie przepływu bez testów
Najpierw trzeba uruchomić go ręcznie, sprawdzić, jakie dane wchodzą, jakie wychodzą, czy JSON parsuje się poprawnie, czy nie ma duplikatów i czy kategorie są takie, jak trzeba.
Wiara, że AI wykona całą pracę
AI klasyfikuje i tłumaczy, ale biznes nadal musi interpretować.
Częsta kategoria nie zawsze oznacza natychmiastowe działanie. Trzeba ocenić wolumen, wpływ, łatwość wdrożenia i kontekst.
Następny krok: zamienić te dane w dashboard
Po tym workflow mamy już arkusz wyników, który uzupełnia oryginalny arkusz formularza.
Nie tylko wiemy, co odpowiedział każdy użytkownik, ale mamy też pola przygotowane do analizy: kategorie, tłumaczenia, konkurentów, incydenty i datę przetworzenia.
Następny i ostatni krok to:
Przenieść te dane do dashboardu i stworzyć governance procesu monitorowania.
W następnym artykule zobaczymy, jak połączyć arkusze Google z Data Studio, jakie metryki ma sens pokazywać i jak zamienić feedback w miesięczną rutynę monitorowania.
Bo automatyzacja analizy nie ma sensu, jeśli potem nikt nie patrzy na dane, a to często się zdarza.

Dodaj komentarz