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:
- It hallucinated — confidently recommending restaurants that don't exist, hotels at the wrong address, or flights that aren't real.
- 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
- A short survey: traveler count, profile, preferences (food, history, nature, nightlife, pace).
- The LLM produces a structured day-by-day skeleton (JSON) made of typed slots that describe intent, not specific facts.
- 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.
- Validation: anything the resolver can't back with real data is dropped or flagged. The model doesn't get to fill the gap.
- 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)