<?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: pante5ter</title>
    <description>The latest articles on DEV Community by pante5ter (@pante5ter).</description>
    <link>https://dev.to/pante5ter</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3960224%2F04ba2896-1904-47c7-81cb-e5b7fd9d8488.png</url>
      <title>DEV Community: pante5ter</title>
      <link>https://dev.to/pante5ter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pante5ter"/>
    <language>en</language>
    <item>
      <title>How to stop your RAG assistant from hallucinating (a practical guide)</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Sat, 30 May 2026 18:32:23 +0000</pubDate>
      <link>https://dev.to/pante5ter/how-to-stop-your-rag-assistant-from-hallucinating-a-practical-guide-2imd</link>
      <guid>https://dev.to/pante5ter/how-to-stop-your-rag-assistant-from-hallucinating-a-practical-guide-2imd</guid>
      <description>&lt;p&gt;A RAG (retrieval-augmented generation) assistant is supposed to answer from &lt;em&gt;your&lt;/em&gt; documents, not from the model's imagination. But teams keep shipping bots that confidently invent prices, policies, and features that don't exist. The hallucination usually isn't the model "being creative" — it's a retrieval and prompting problem you can fix. Here's the checklist I actually use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hallucination is usually a retrieval failure, not a model failure
&lt;/h2&gt;

&lt;p&gt;If the right chunk never makes it into the context, the model fills the gap by guessing. So before blaming the LLM, ask: &lt;strong&gt;did retrieval even return the correct passage?&lt;/strong&gt; Most "the AI lied" bugs are really "we fed it the wrong context" bugs. Fix retrieval first; it's where the biggest wins are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chunk for meaning, not for byte count
&lt;/h2&gt;

&lt;p&gt;Splitting documents every N characters cuts sentences in half and scatters one answer across chunks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split on &lt;strong&gt;semantic boundaries&lt;/strong&gt; — headings, sections, list items — not arbitrary lengths.&lt;/li&gt;
&lt;li&gt;Keep chunks focused: one idea per chunk retrieves far more accurately than a wall of mixed topics.&lt;/li&gt;
&lt;li&gt;Add a little &lt;strong&gt;overlap&lt;/strong&gt; so context isn't lost at the seams.&lt;/li&gt;
&lt;li&gt;Attach metadata (source, title, date) to every chunk — you'll need it for filtering and citations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Retrieve better than plain vector search
&lt;/h2&gt;

&lt;p&gt;Pure embedding search misses exact terms (product codes, names, numbers).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;hybrid search&lt;/strong&gt;: combine semantic (vector) with keyword (BM25) so both meaning and exact matches are covered.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;reranker&lt;/strong&gt; to reorder the top candidates before they hit the prompt — it consistently lifts answer quality.&lt;/li&gt;
&lt;li&gt;Tune how many chunks you pass. Too few starves the model; too many buries the answer in noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Make "I don't know" a first-class answer
&lt;/h2&gt;

&lt;p&gt;This single instruction prevents most embarrassing hallucinations: tell the model to answer &lt;strong&gt;only&lt;/strong&gt; from the provided context, and to say it doesn't know when the context doesn't contain the answer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the answer is not in the provided context, say you don't have that information — do not guess.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A bot that admits a gap is trustworthy. A bot that confidently makes something up costs you a customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demand citations and ground every claim
&lt;/h2&gt;

&lt;p&gt;Have the model cite the source chunk for each statement. Two benefits: users can verify, and you can automatically flag answers where the cited text doesn't actually support the claim. If it can't cite, it shouldn't assert.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluate, don't vibe-check
&lt;/h2&gt;

&lt;p&gt;You can't improve what you don't measure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a small &lt;strong&gt;test set&lt;/strong&gt; of real questions with known correct answers.&lt;/li&gt;
&lt;li&gt;Track &lt;strong&gt;groundedness&lt;/strong&gt; (is the answer supported by retrieved context?) and &lt;strong&gt;retrieval hit rate&lt;/strong&gt; (did the right chunk show up?).&lt;/li&gt;
&lt;li&gt;Re-run it on every change to chunking, embeddings, or prompts so you catch regressions before users do.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A reliable default stack
&lt;/h2&gt;

&lt;p&gt;Clean, semantically chunked docs with metadata → hybrid retrieval + reranker → a strict "answer only from context, cite sources, admit unknowns" prompt → an eval set guarding the whole thing. Boring, measurable, and it stops the confident nonsense.&lt;/p&gt;




&lt;p&gt;Done right, a RAG assistant becomes the thing customers trust for accurate answers 24/7 instead of a liability. I build RAG assistants and AI automation that stay grounded in real data as a freelancer — you can see examples at &lt;strong&gt;&lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;&lt;/strong&gt;. Questions about retrieval or grounding? Drop them in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Telegram bot that takes payments: what actually matters</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Sat, 30 May 2026 18:31:04 +0000</pubDate>
      <link>https://dev.to/pante5ter/building-a-telegram-bot-that-takes-payments-what-actually-matters-4884</link>
      <guid>https://dev.to/pante5ter/building-a-telegram-bot-that-takes-payments-what-actually-matters-4884</guid>
      <description>&lt;p&gt;"Just add payments to the bot" sounds like a one-liner. In practice, the happy path is the easy 20% — the other 80% is the edge cases that decide whether you actually get paid and keep customers. Here's what actually matters when a Telegram bot handles money, learned from shipping a few of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two very different ways to charge
&lt;/h2&gt;

&lt;p&gt;There are two models, and picking the wrong one causes most of the pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Telegram's native payments&lt;/strong&gt; (&lt;code&gt;sendInvoice&lt;/code&gt; + a provider token like Stripe). The whole flow stays inside Telegram, the UX is excellent, and you get a clean &lt;code&gt;successful_payment&lt;/code&gt; update. Great for digital goods and simple checkouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External payment link / your own gateway.&lt;/strong&gt; You generate a link, the user pays on a web page, and your backend gets a &lt;strong&gt;webhook&lt;/strong&gt;. More flexible (subscriptions, local providers, complex carts) but you own more of the plumbing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most "sell a product or a subscription" bots, native payments are the right default. Reach for external only when the provider or business model forces it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pre-checkout step is not optional
&lt;/h2&gt;

&lt;p&gt;With native payments, Telegram sends a &lt;code&gt;pre_checkout_query&lt;/code&gt; and &lt;strong&gt;you have ~10 seconds to answer it&lt;/strong&gt;. If you don't &lt;code&gt;answerPreCheckoutQuery(ok=true)&lt;/code&gt; in time, the payment fails — even though the user did nothing wrong.&lt;/p&gt;

&lt;p&gt;This is where you do final validation: is the item still in stock, is the price still valid, is the user allowed to buy. Approve only if everything checks out. Skipping real validation here is how people sell things they can't deliver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat money events as untrusted until verified
&lt;/h2&gt;

&lt;p&gt;Two rules that save you from fraud and angry customers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify webhook signatures.&lt;/strong&gt; Anyone can POST to your webhook URL. If you act on an unsigned "payment succeeded" call, you'll ship goods for payments that never happened. Always verify the provider's signature before trusting the event.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make payment handling idempotent.&lt;/strong&gt; Networks retry. You &lt;em&gt;will&lt;/em&gt; receive the same &lt;code&gt;successful_payment&lt;/code&gt; / webhook twice. Store a unique payment ID and ignore duplicates, or you'll deliver (or refund) twice.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The database is the source of truth, not the chat
&lt;/h2&gt;

&lt;p&gt;A Telegram message can be missed, edited, or arrive out of order. Don't drive business logic off the conversation state alone. Persist every order with an explicit status — &lt;code&gt;pending → paid → fulfilled → refunded&lt;/code&gt; — and let the bot read from that. When a user writes "where's my order?", you answer from the database, not from memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plan for refunds and failures from day one
&lt;/h2&gt;

&lt;p&gt;The unglamorous parts customers judge you on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clear message when a payment &lt;strong&gt;fails&lt;/strong&gt; (and an easy retry), not silence.&lt;/li&gt;
&lt;li&gt;A defined &lt;strong&gt;refund&lt;/strong&gt; path — Telegram supports refunds for native payments; wire it up before you need it.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;admin view&lt;/strong&gt;: who paid, what's unfulfilled, what errored. A bot that takes money but gives the owner no visibility is a support nightmare.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A sane minimum architecture
&lt;/h2&gt;

&lt;p&gt;Bot (webhook mode, not long polling for production) → a small backend that validates and writes to a database → payment provider webhooks landing on a &lt;strong&gt;separate, signature-verified&lt;/strong&gt; endpoint. Keep secrets in env vars, log every money event, and alert on failed payments. That's it — boring on purpose, because boring is what you want around money.&lt;/p&gt;




&lt;p&gt;None of this is hard individually; the value is doing all of it so nothing silently breaks once real money flows. I build Telegram bots with payments, databases and admin panels as a freelancer — you can see examples at &lt;strong&gt;&lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;&lt;/strong&gt;. Happy to answer implementation questions in the comments.&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I get Next.js sites to load almost instantly — a practical checklist</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Sat, 30 May 2026 16:40:15 +0000</pubDate>
      <link>https://dev.to/pante5ter/how-i-get-nextjs-sites-to-load-almost-instantly-a-practical-checklist-3pf4</link>
      <guid>https://dev.to/pante5ter/how-i-get-nextjs-sites-to-load-almost-instantly-a-practical-checklist-3pf4</guid>
      <description>&lt;p&gt;Speed isn't a vanity metric. On real projects, shaving load time directly moves conversion and Google rankings — Core Web Vitals are a ranking signal, and users bounce before a slow page even paints. Here's the checklist I actually run through on Next.js builds, in the order that gives the biggest wins first.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Ship less JavaScript to the client
&lt;/h2&gt;

&lt;p&gt;The single biggest lever. Most "slow React site" problems are really "we hydrated 400KB of JS the user never needed" problems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep components as &lt;strong&gt;Server Components&lt;/strong&gt; by default (App Router). Only add &lt;code&gt;'use client'&lt;/code&gt; where you genuinely need state or browser APIs.&lt;/li&gt;
&lt;li&gt;Push &lt;code&gt;'use client'&lt;/code&gt; &lt;strong&gt;down the tree&lt;/strong&gt;, not up. A whole page doesn't need to be client just because one button is interactive.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;next/dynamic&lt;/code&gt; for anything heavy and below-the-fold (charts, editors, 3D, modals):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GalaxyScene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/GalaxyScene&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GalaxyScene&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Stop layout shift before it starts
&lt;/h2&gt;

&lt;p&gt;CLS is the easiest Vital to wreck and the easiest to fix.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always give &lt;code&gt;next/image&lt;/code&gt; explicit &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; (or &lt;code&gt;fill&lt;/code&gt; + a sized container).&lt;/li&gt;
&lt;li&gt;Reserve space for anything async — ads, embeds, banners.&lt;/li&gt;
&lt;li&gt;Load fonts with &lt;code&gt;next/font&lt;/code&gt; so the swap doesn't reflow text:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Treat images like the heaviest thing on the page (they are)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;next/image&lt;/code&gt; — it gives you AVIF/WebP, correct sizing, and lazy loading for free.&lt;/li&gt;
&lt;li&gt;Mark the hero image &lt;code&gt;priority&lt;/code&gt; so it isn't lazy-loaded; lazy-load everything else.&lt;/li&gt;
&lt;li&gt;Serve dimensions that match the rendered size. A 4000px photo in a 400px slot is wasted bytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Render on the server, cache aggressively
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prefer static rendering / ISR for anything that isn't per-request personalized. A pre-rendered page paints almost instantly.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;fetch&lt;/code&gt; caching and &lt;code&gt;revalidate&lt;/code&gt; instead of refetching on every hit.&lt;/li&gt;
&lt;li&gt;Move third-party scripts to &lt;code&gt;next/script&lt;/code&gt; with &lt;code&gt;strategy="lazyOnload"&lt;/code&gt; so analytics and chat widgets don't block your main thread.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Measure on a throttled mobile, not your laptop
&lt;/h2&gt;

&lt;p&gt;Your machine on fiber lies to you. Run Lighthouse in mobile mode with CPU throttling, and watch the &lt;strong&gt;field data&lt;/strong&gt; in Search Console (CrUX) — that's what Google actually ranks on, not your local numbers.&lt;/p&gt;

&lt;p&gt;A useful habit: set a performance budget (e.g. &amp;lt; 150KB JS on first load) and let CI fail the build if a PR blows past it. It stops slow creep before it ships.&lt;/p&gt;




&lt;p&gt;None of this is exotic. It's just doing the boring things consistently — and the payoff is a site that feels instant, ranks better, and converts more.&lt;/p&gt;

&lt;p&gt;I build Next.js sites, Telegram bots and AI automation as a freelancer — if you want a fast, SEO-ready site, you can see my work at &lt;strong&gt;&lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;&lt;/strong&gt;. Happy to answer Next.js performance questions in the comments.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>performance</category>
      <category>react</category>
    </item>
  </channel>
</rss>
