<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Emir Eid</title>
    <description>The latest articles on DEV Community by Emir Eid (@decreeid).</description>
    <link>https://dev.to/decreeid</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4008038%2Fa6528a70-1e93-4fd8-b4f0-9a8cda856774.png</url>
      <title>DEV Community: Emir Eid</title>
      <link>https://dev.to/decreeid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/decreeid"/>
    <language>en</language>
    <item>
      <title>How I built an AI travel planner that doesn't hallucinate places or flights</title>
      <dc:creator>Emir Eid</dc:creator>
      <pubDate>Mon, 29 Jun 2026 11:31:33 +0000</pubDate>
      <link>https://dev.to/decreeid/how-i-built-an-ai-travel-planner-that-doesnt-hallucinate-places-or-flights-38n2</link>
      <guid>https://dev.to/decreeid/how-i-built-an-ai-travel-planner-that-doesnt-hallucinate-places-or-flights-38n2</guid>
      <description>&lt;p&gt;I'm Emir, a software engineer, and for the past few months I've been building &lt;strong&gt;Rotavi&lt;/strong&gt;, 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: &lt;strong&gt;the model is not allowed to invent facts.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Every AI travel tool I tried did two things badly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It hallucinated&lt;/strong&gt; — confidently recommending restaurants that don't exist, hotels at the wrong address, or flights that aren't real.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It ignored visas&lt;/strong&gt; — especially &lt;em&gt;transit&lt;/em&gt; visas, where a cheap layover can leave you stuck at the airport because you needed a visa you didn't know about.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both come from the same root cause: letting a language model act as a source of facts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea: separate reasoning from facts
&lt;/h2&gt;

&lt;p&gt;The fix is boring but effective. The LLM only &lt;strong&gt;structures&lt;/strong&gt; the plan; it never supplies facts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model decides the &lt;em&gt;shape&lt;/em&gt; of the trip — how many days, the rhythm, what kind of place fits each slot, the narrative flow.&lt;/li&gt;
&lt;li&gt;Every factual detail — place names, ratings, addresses, flight options, links — comes from &lt;strong&gt;authoritative APIs&lt;/strong&gt;, not the model's memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the model never "recalls" a restaurant. It outputs something like &lt;em&gt;"day 2 afternoon: a well-rated traditional restaurant near the old town"&lt;/em&gt; — 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeline, concretely
&lt;/h2&gt;

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

&lt;p&gt;The mental model that helped me: treat the LLM like a creative director, not an encyclopedia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping API cost sane
&lt;/h2&gt;

&lt;p&gt;Two things did most of the work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache aggressively.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a small/cheap model where it's enough.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Visas: the same philosophy, taken further
&lt;/h2&gt;

&lt;p&gt;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 &lt;strong&gt;structured rule engine over authoritative data&lt;/strong&gt;, not the model guessing.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Stack &amp;amp; solo notes
&lt;/h2&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it / tell me where it breaks
&lt;/h2&gt;

&lt;p&gt;It's live and free, currently 39 countries / 400+ cities across 4 continents: &lt;strong&gt;&lt;a href="https://rotavi.app/en?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=backlink" rel="noopener noreferrer"&gt;https://rotavi.app/en?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=backlink&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>ai</category>
      <category>webdev</category>
      <category>saas</category>
    </item>
  </channel>
</rss>
