# Så bygger du en AI-reseassistent som tipsar om riktiga platser

> En concierge-app för resor är en platsdatabas plus ett AI-anrop som väljer ur den. Här är koden, plankravet och hur du slipper påhittade platser.

Source: https://northerngo.com/sv/guider/ai-reseassistent/
Language: sv
Updated: 2026-08-15

---
**En concierge-app för resor byggd i NorthernGo består av två delar: en samling platser du lagrar med `window.NorthernGoDB.save()`, och ett anrop till `window.NorthernGoAI.generate()` som förvandlar resenärens önskemål till ett urval ur den samlingen. Modellen känner inte din ort, så det är förankringen i dina egna poster som gör tipsen verkliga. Inbyggd AI kräver Premium eller Pro.**

### Vad en concierge-app för resor faktiskt är

Skalar man bort inramningen är en AI-reseassistent en liten applikation med tre rörliga delar: ett förråd av platser, ett formulär där någon berättar vad hen är på humör för, och ett anrop till en språkmodell som väljer ur förrådet och motiverar sitt val. Det är hela formen.

Det intressanta beslutet är inte vilken modell du använder. Det är att bestämma vad modellen får hitta på och vad den måste läsa ur din data. Sätter du den gränsen fel levererar du en självsäker lögnare: be en modell om "dolda restauranger i Lycksele" och du får trovärdiga namn, trovärdiga öppettider och trovärdiga gatuadresser, varav inget behöver existera. Resenären kör dit och hittar en parkeringsplats.

Sätter du gränsen rätt har du något som är värt att publicera — din egen lokalkännedom, hämtad och formulerad av en modell som är väldigt bra på att formulera och väldigt dålig på att minnas småorter. Den här guiden bygger den andra varianten.

### Platsposterna kommer först, inte AI:n

Innan du skriver en enda prompt: bestäm hur en plats ser ut som post. Varje fält du utelämnar är ett fält modellen kommer att lockas fylla i för dig.

En form som fungerar täcker det folk filtrerar på, plus det de egentligen är ute efter:

```javascript
const places = [
  {
    id: crypto.randomUUID(),
    name: 'Ansia',
    area: 'Lycksele',
    category: 'friluft',
    season: 'sommar',
    priceLevel: 1,
    openingNote: 'Obemannat. Lugnast före 10:00.',
    why: 'Badplats vid älven som campinggästerna går förbi utan att stanna.'
  }
];
```

Fältet `why` är det som betyder något. Det är meningen bara någon på plats kan skriva, och skälet till att den färdiga appen är bättre än en allmän chattbot. Modellens uppgift är att välja och formulera om den, aldrig att uppfinna den.

### Steg 1: Lägg in platserna i databasen

Varje app som genereras i NorthernGo har redan en Supabase-databas i PostgreSQL kopplad via `window.NorthernGoDB`, utan anslutningssträng att klistra in och utan tabell att definiera. Att skriva in grunddatan är en loop:

```javascript
async function seedPlaces() {
  for (const place of places) {
    try {
      await window.NorthernGoDB.save('places', place);
    } catch (err) {
      console.error('Kunde inte spara', place.name, err);
    }
  }
}
```

Kör den en gång. Därefter finns kollektionen och `get('places')` returnerar den. [Hela databas-API:t är fyra metoder brett](/sv/guider/connect-supabase/) — save, get, delete och inloggningsanropen — vilket räcker för den här appen och är värt att läsa innan du utökar datamodellen.

I en riktig driftsättning: lägg inläsningen bakom en adminvy i stället för att skicka den som en loop som körs vid sidladdning. En loop som körs vid varje sidladdning dubblerar hela din platslista vid varje besök.

### Steg 2: Be modellen välja, inte minnas

Så till AI-anropet. Signaturen är `generate(prompt, isJson, base64Img)`. Skickar du `true` som andra argument tolkas svaret som JSON och du får tillbaka ett objekt, vilket är precis vad du vill här — du ber om ett urval, inte om löpande text.

```javascript
async function recommend(preferences) {
  const all = (await window.NorthernGoDB.get('places')) || [];

  const prompt = [
    'Du är en lokal guide. Välj högst tre platser ur JSON-listan nedan.',
    'Använd ENDAST poster ur listan. Hitta aldrig på en plats, en adress eller en öppettid.',
    'Passar ingenting i listan: returnera en tom picks-array.',
    'Svara som JSON: { "picks": [{ "id": "...", "pitch": "..." }] }',
    '',
    'Resenären vill: ' + preferences,
    'Tillgängliga platser: ' + JSON.stringify(all)
  ].join('\n');

  return await window.NorthernGoAI.generate(prompt, true);
}
```

Tre saker i den prompten gör verkligt arbete. Att be om `id` i stället för `name` gör att du kan slå upp posten i stället för att lita på texten. Att låta den returnera en tom array när inget passar ger den ett legitimt sätt att säga nej, vilket är det enda pålitliga alternativet till att hitta på. Och att lägga listan i prompten gör att rekommendationen begränsas av din data i stället för av modellens träning.

### Steg 3: Kontrollera svaret innan du renderar det

Det här är steget de flesta genomgångar hoppar över, och det är skillnaden mellan en demo och en app. SDK:ns `generate()` fångar sina egna fel och returnerar `null` — den kastar inte. Missar du det renderas ett misslyckat anrop som en tom panel utan förklaring.

Utöver det: en modell som blivit tillsagd att inte hitta på saker hittar ändå på saker ibland. Så kontrollera id:na mot vad du faktiskt har:

```javascript
async function showRecommendations(preferences) {
  const all = (await window.NorthernGoDB.get('places')) || [];
  const result = await recommend(preferences);

  if (!result || !Array.isArray(result.picks)) {
    showMessage('Kunde inte nå guiden just nu. Visar allt i stället.');
    renderPlaces(all);
    return;
  }

  const byId = new Map(all.map(p => [p.id, p]));
  const verified = result.picks
    .filter(pick => byId.has(pick.id))
    .map(pick => ({ ...byId.get(pick.id), pitch: pick.pitch }));

  if (verified.length === 0) {
    showMessage('Inget i guiden matchar det ännu.');
    renderPlaces(all);
    return;
  }

  renderPlaces(verified);
}
```

Lägg märke till vad reservvägen gör: den faller tillbaka på din egen ofiltrerade lista i stället för på en felskärm. En reseapp som visar alla fyrtio platser när AI:n inte svarar är fortfarande en användbar reseapp.

### Steg 4: Låt resenären spara sitt urval

Utan inloggning skriver varje besökare till samma kollektion och ser allas sparade resor. Konton knyter posterna till den inloggade:

```javascript
await window.NorthernGoDB.register(epost, losenord);
await window.NorthernGoDB.login(epost, losenord);

if (window.NorthernGoDB.getToken()) {
  await window.NorthernGoDB.save('itineraries', {
    id: crypto.randomUUID(),
    day: '2026-07-14',
    placeIds: verified.map(p => p.id)
  });
}
```

Spara id:na, inte kopior av platsposterna. När du rättar en öppettid nästa vår följer rättningen med i varje sparad resa i stället för att förra årets fel bevaras.

En app med inloggning behöver också ett synligt sätt att radera kontot — det är [GDPR artikel 17 och inte en trevlig extrafunktion](/sv/guider/gdpr-compliant-app-building-eu/), och `window.NorthernGoDB.deleteAccount()` hanterar inloggningsposten och datan tillsammans.

### Steg 5: Publicera där resenären kan nå den

Publicera från **Mina projekt**. Var appen hamnar beror på planen: en egen domän på Pro om du kopplat en, annars en adress på `<subdomän>.northerngo.com` på Premium och Pro, annars reservadressen `https://northerngo.com/?app=<projektId>`. Projekt på Gratis hamnar alltid på reservadressen.

Just för resor betyder subdomänvägen mer än man tror. Appar publicerade på en subdomän eller egen domän får en service worker, så appskalet laddar fortfarande på en telefon utan täckning. `get()` kan visa senast synkade resor plus köade sparningar; inloggning och AI i appen kräver fortfarande uppkoppling. Gamla öppettider kan synas tills nästa lyckade synk — säg det i gränssnittet. [Mönstren för offline först](/sv/guider/offline-first-web-apps-pwa/) är värda att använda här.

### Vad det kostar

Två skilda budgetar, och att blanda ihop dem är den vanliga faktureringsöverraskningen.

Att bygga appen i editorn drar molngenereringar: fem i månaden på Gratis, 25 på Premium för 179 SEK / $19, 50 på Pro för 299 SEK / $29. Att generera lokalt på ditt eget grafikkort är obegränsat på samtliga planer.

Resenärer som använder den färdiga appen drar en annan budget. Den inbyggda AI-proxyn har ett tak per projekt och dygn — 500 textanrop, 100 genererade bilder och 300 talanrop — plus en kortsiktig gräns på 15 anrop per minut. Textanropen körs på Gemini 3.1 Flash Lite. För en guide med några hundra besökare om dagen är det gott om marginal; för något i verklig skala är det ett tak du bör känna till före lanseringsdagen.

### Begränsningar

- **Ingen karta, ingen geokodning, ingen positionering.** Det finns ingen inbyggd kartkomponent och ingen platsuppslagning. Resenären berättar var hen är genom att skriva eller välja bland dina områden. Behöver du en riktig karta lägger du till ett tredjepartsbibliotek i exporterad kod, du slår inte på en funktion.
- **Inbyggd AI kräver Premium eller Pro.** På Gratis är AI-agenterna uttryckligen instruerade att inte bygga in anrop till `window.NorthernGoAI`, och proxyn avvisar dem vid körning om du lägger in dem för hand. Gratis är för att bygga och skicka ut de delar som inte är AI.
- **Modellen har inget minne mellan anropen.** Varje `generate()` står för sig. Uppföljande frågor ("något billigare än det") fungerar bara om du skickar med de tidigare turerna i den nya prompten.
- **Ingen tillgänglighet i realtid.** Ingenting här kontrollerar om en restaurang är öppen nu eller om ett rum är ledigt i kväll. Den rekommenderar ur dina poster, som är lika aktuella som du senast gjorde dem.
- **Tipsen blir aldrig bättre än `why`-fälten.** Tjugo platser med tunna enradsnoteringar ger tjugo tunna rekommendationer. Det här är ett kurateringsarbete med ett AI-lager, inte det omvända. Byggare som utlovar en färdig reseprodukt ur en enda mening [säljer något annat](/sv/alternativ/lovable/).

### Felsökning

**AI-panelen är tom och konsolen är ren.** `generate()` returnerade `null`. Den sväljer sina egna fel, så lägg till den uttryckliga `if (!result)`-grenen från steg 3 och logga inuti den. På Gratis är `null` det förväntade svaret — proxyn nekade anropet.

**Den rekommenderar platser som inte finns i databasen.** Svaret renderades utan kontroll. Be om id, slå upp varje id, kasta det som inte känns igen. Formuleringen i prompten löser inte det här på egen hand.

**Rekommendationerna struntar i önskemålen.** Oftast är platslistan för stor för modellen att resonera över. Filtrera i JavaScript först — på område, säsong eller kategori — och skicka urvalet i stället för hela kollektionen.

**Sparade resor dyker upp hos fel resenär.** Det är det förväntade beteendet utan inloggning. Poster som skrivs utan session lagras på appnivå och delas av alla.

**Det fungerar i editorn men inte i den publicerade appen.** Kontrollera vilken adress du testar. Ett projekt på Gratis omdirigeras alltid till reservadressen `?app=`, och den inbyggda AI:n är blockerad där oavsett var appen servas ifrån.

## Vanliga frågor

### Kan en AI-appbyggare göra en reseapp som verkligen kan min ort?

Bara om du förser den med kunskapen. Språkmodellen har ingen tillförlitlig information om små orter och hittar på adresser och öppettider om den ombeds minnas dem. Mönstret som fungerar är att lagra dina egna platsposter i appens databas och skicka med listan i varje prompt, så att modellen väljer och formulerar i stället för att minnas.

### Varför returnerar min AI-reseapp ingenting alls på gratisplanen?

Inbyggda AI-funktioner är blockerade på Gratis. AI-proxyn avvisar anropet eftersom projektets ägare ligger på gratisplanen, och eftersom window.NorthernGoAI.generate fångar sina egna fel och returnerar null visar appen ett tomt resultat i stället för ett fel. Premium eller Pro krävs för AI inuti en publicerad app.

### Hur hindrar jag AI:n från att hitta på restauranger och öppettider?

Instruera den att bara välja ur en medskickad lista, be om post-id i stället för namn, och kontrollera sedan varje id mot databasen innan du renderar. Formuleringen i prompten minskar påhitten men tar inte bort dem; det är id-kontrollen som gör det omöjligt för en påhittad plats att nå skärmen.

### Fungerar reseappen offline när jag är utomlands utan surf?

Delvis. En app publicerad på en NorthernGo-subdomän eller egen domän får en service worker, så gränssnittet laddar fortfarande utan uppkoppling. get() visar senast synkade resor plus köade sparningar; inloggning och AI i appen kräver fortfarande uppkoppling.

### Kan jag lägga till en karta med resenärens position?

Inte som en inbyggd funktion. Det finns ingen kartkomponent och ingen geokodning eller positionstjänst i plattformen, så resenären anger var hen är genom att skriva eller välja bland de områden du definierat. En riktig karta innebär att du exporterar källkoden och lägger till ett kartbibliotek själv, vilket går på Premium och Pro via ZIP-export.

---

## Related

- [Så lagrar du data i en AI-byggd app med Supabase](https://northerngo.com/sv/guider/lagra-data-med-supabase/)
- [Så bygger du en webbapp som fungerar utan internet](https://northerngo.com/sv/guider/offline-appar-med-pwa/)
- [Bygga GDPR-säkra appar: en praktisk checklista för EU-grundare](https://northerngo.com/sv/guider/bygga-gdpr-saker-app/)
- [Lokal AI eller moln-AI i appbyggare: kostnad, integritet och hastighet](https://northerngo.com/sv/guider/lokal-ai-eller-moln-ai/)

---

NorthernGo är en AI-driven plattform för att bygga produktionsklara webbappar utan kod. Lokal AI-generering via WebGPU är obegränsad och gratis, och du äger all genererad källkod. https://northerngo.com/
