DEV Community

Cover image for How I built an AI travel planner that doesn't hallucinate places or flights
Emir Eid
Emir Eid

Posted on

How I built an AI travel planner that doesn't hallucinate places or flights

I'm Emir, a software engineer, and for the past few months I've been building Rotavi, an AI travel planner — solo. I want to share the one architectural decision the whole product is built around, because it's the thing most "AI trip planner" demos get wrong: the model is not allowed to invent facts.

The problem

Every AI travel tool I tried did two things badly:

  1. It hallucinated — confidently recommending restaurants that don't exist, hotels at the wrong address, or flights that aren't real.
  2. It ignored visas — especially transit visas, where a cheap layover can leave you stuck at the airport because you needed a visa you didn't know about.

Both come from the same root cause: letting a language model act as a source of facts.

The core idea: separate reasoning from facts

The fix is boring but effective. The LLM only structures the plan; it never supplies facts.

  • The model decides the shape of the trip — how many days, the rhythm, what kind of place fits each slot, the narrative flow.
  • Every factual detail — place names, ratings, addresses, flight options, links — comes from authoritative APIs, not the model's memory.

So the model never "recalls" a restaurant. It outputs something like "day 2 afternoon: a well-rated traditional restaurant near the old town" — an intent — and a real query to a places API fills that slot with a real, currently-open venue. If the API returns nothing, the slot stays empty instead of getting invented.

The pipeline, concretely

  1. A short survey: traveler count, profile, preferences (food, history, nature, nightlife, pace).
  2. The LLM produces a structured day-by-day skeleton (JSON) made of typed slots that describe intent, not specific facts.
  3. A resolver layer fills each slot from real sources: a places API for venues, a flight-search API for routes, currency data, and so on.
  4. Validation: anything the resolver can't back with real data is dropped or flagged. The model doesn't get to fill the gap.
  5. Render: day-by-day itinerary, one-tap map links, a PDF, currency notes.

The mental model that helped me: treat the LLM like a creative director, not an encyclopedia.

Keeping API cost sane

Two things did most of the work:

  • Cache aggressively. The same city/query resolves to the same real data for many users — cache it instead of re-hitting the API. It kept the monthly bill tiny.
  • Use a small/cheap model where it's enough. The structuring task doesn't need a frontier model; a fast, cheap one (I use Gemini Flash) handles it well. The "no hallucination" guarantee comes from the architecture, not the model size — which is the whole point.

Visas: the same philosophy, taken further

Transit-visa rules are multi-conditional: your passport, the layover country, whether you leave airside, what other visas you already hold. That's exactly the kind of thing LLMs state confidently and get wrong. So it's a structured rule engine over authoritative data, not the model guessing.

Honest scope: the visa/transit engine currently covers the Turkish passport — that's my own reality and where I could verify the rules. Broadening it is on the roadmap.

Stack & solo notes

For the curious: Next.js + Supabase, a fast LLM (Gemini Flash) for structuring, plus search/places APIs for the real data.

Being solo, the meta-lesson is the usual one: ruthlessly narrow scope, one priority per week, and lean on AI for code and content speed — while never trusting it for facts.

Try it / tell me where it breaks

It's live and free, currently 39 countries / 400+ cities across 4 continents: https://rotavi.app/en?utm_source=devto&utm_medium=referral&utm_campaign=backlink

I'd genuinely love feedback from this crowd — especially on the resolver/validation approach and where you'd push the architecture. Happy to go deeper on any part in the comments.

Top comments (0)