<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Vigneshwarar’s Newsletter]]></title><description><![CDATA[Search, Indexes, etc..]]></description><link>https://vigneshwarar.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!yRwh!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fvigneshwarar.substack.com%2Fimg%2Fsubstack.png</url><title>Vigneshwarar’s Newsletter</title><link>https://vigneshwarar.substack.com</link></image><generator>Substack</generator><lastBuildDate>Sun, 16 Aug 2026 20:54:59 GMT</lastBuildDate><atom:link href="https://vigneshwarar.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Vigneshwarar]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[vigneshwarar@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[vigneshwarar@substack.com]]></itunes:email><itunes:name><![CDATA[Vigneshwarar]]></itunes:name></itunes:owner><itunes:author><![CDATA[Vigneshwarar]]></itunes:author><googleplay:owner><![CDATA[vigneshwarar@substack.com]]></googleplay:owner><googleplay:email><![CDATA[vigneshwarar@substack.com]]></googleplay:email><googleplay:author><![CDATA[Vigneshwarar]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[RAG: Let ChatGPT handle the formation of contexts]]></title><description><![CDATA[Retrieval is one of the most important strategies in the RAG pipeline. This is the retrieval strategy we are using at EazyRAG.]]></description><link>https://vigneshwarar.substack.com/p/hey-chatgpt-please-handle-context</link><guid isPermaLink="false">https://vigneshwarar.substack.com/p/hey-chatgpt-please-handle-context</guid><dc:creator><![CDATA[Vigneshwarar]]></dc:creator><pubDate>Thu, 21 Sep 2023 00:24:09 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/027b57bb-36f0-4968-ad6b-a86063674a79_6412x3328.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I am currently building a product called <a href="https://eazyrag.com/">EazyRAG</a>. It is a dead simple API for Retrieval-Augmented Generation (RAG). In simple words, it is basically an API for ChatGPT with your own data.</p><p>In this article, I will share the retrieval strategy I use to form the final context formation at EazyRAG. Before diving into the article, there is one concept you need to understand.</p><h2>What is RAG?</h2><p>LLMs such as GPT lack factual consistency and lack up-to-date knowledge. To fix this, RAG is a technique that retrieves related documents to the user's question, combines them with LLM-base prompt, and sends them to LLMs like GPT to produce more factually accurate generation.</p><p>I've written an extensive article on <a href="https://vigneshwarar.substack.com/p/hackernews-support-page-using-retrieval">building an RAG pipeline without using Langchain</a>. It will give you a good idea of what RAG is.</p><p>Here is what the RAG (Before) pipeline looks like.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://eazyrag.com/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NxoA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 424w, https://substackcdn.com/image/fetch/$s_!NxoA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 848w, https://substackcdn.com/image/fetch/$s_!NxoA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 1272w, https://substackcdn.com/image/fetch/$s_!NxoA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NxoA!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png" width="1200" height="623.0769230769231" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:756,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:874345,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://eazyrag.com/&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NxoA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 424w, https://substackcdn.com/image/fetch/$s_!NxoA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 848w, https://substackcdn.com/image/fetch/$s_!NxoA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 1272w, https://substackcdn.com/image/fetch/$s_!NxoA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43112370-7b08-496c-8a65-8efe647e7b00_6412x3328.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Retrieval/Context formation</h2><p>Now, here is how we differ from the general RAG pipeline: we don't just retrieve chunks shove them under the base prompt, and call it a day. This approach may work for questions like 'What is the height of the Eiffel Tower?' but may not be effective all the time. Just imagine, intuitively, you have an article called 'How to make spaghetti,' and you've split the long article into pieces and indexed it. When a user queries it, you retrieve all the relevant chunks. Herein lies the problem: some general cooking instructions, such as 'boil the water and season it,' won't have a relatable relevance score to the user's search query, which, in turn, results in poor context formation and increases hallucinations.</p><p>Not only that but just shoving unstructured messy chunks will also decrease the quality of the answer.</p><p>Here is the comparison between Langchain (code taken from the <a href="https://python.langchain.com/docs/use_cases/question_answering/">Quickstart</a> example) and <a href="https://eazyrag.com/">EazyRAG</a>.</p><p><strong>Langchain</strong></p><pre><code>from langchain.document_loaders import WebBaseLoader
from langchain.indexes import VectorstoreIndexCreator

loader = WebBaseLoader("https://bun.sh/docs/installation")
index = VectorstoreIndexCreator().from_loaders([loader])
index.query("How do I install this on a Mac?")</code></pre><blockquote><p><strong>Output by Langchain</strong></p><p>" You can install Bun on a Mac using the Homebrew package manager. Run the command 'brew tap oven-sh/bun' followed by 'brew install bun'."</p></blockquote><p><strong>And here is the answer by EazyRAG</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://eazyrag.com/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yomo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 424w, https://substackcdn.com/image/fetch/$s_!yomo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 848w, https://substackcdn.com/image/fetch/$s_!yomo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 1272w, https://substackcdn.com/image/fetch/$s_!yomo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yomo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png" width="1444" height="1840" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1840,&quot;width&quot;:1444,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:306770,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://eazyrag.com/&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yomo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 424w, https://substackcdn.com/image/fetch/$s_!yomo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 848w, https://substackcdn.com/image/fetch/$s_!yomo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 1272w, https://substackcdn.com/image/fetch/$s_!yomo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa66035ea-5198-43ad-8242-2b774564bd5d_1444x1840.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Not to brag, but I think EazyRAG's answer is better with multiple options. But, what went wrong with Langchain is that when I dug into the final prompt, all the chunks retrieved were in a confusing format without proper spaces. Anyway, this is not a rant about Langchain; I have huge respect for that project.</p><p><strong>So how does <a href="https://eazyrag.com/">EazyRAG</a> do it?</strong></p><p>When I was coding this layer, I knew that this API had to work with all types of datasets and with any type of search intent. I couldn't manually customize the context formation for every type of dataset, so why not let <strong>GPT itself handle context formation?</strong></p><p>Here's how it works:</p><p>When a user queries it, we retrieve the relevant documents related to the document title and send them to GPT to classify whether we should consider feeding the entire documents for this user query. If so, which documents should we consider? Then, we feed all the documents mentioned by the GPT classifier. If the GPT classifier returns nothing, we simply shove all the chunks into base prompts and send them to LLM for answer generation. And it is working great!</p><p>In fact, this is an early version of this idea. I have a lot of ideas surrounding this concept of "<strong>GPT itself handling context formation</strong>" that I need to try.</p><p>So, what do you think of this idea? I'd be happy to hear your feedback and improve <a href="https://eazyrag.com/">EazyRAG</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://vigneshwarar.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vigneshwarar&#8217;s Newsletter! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Retrieval Augmented Generation in the Browser]]></title><description><![CDATA[Happy to announce RAG in the browser using EazyRAG]]></description><link>https://vigneshwarar.substack.com/p/retrieval-augmented-generation-in</link><guid isPermaLink="false">https://vigneshwarar.substack.com/p/retrieval-augmented-generation-in</guid><dc:creator><![CDATA[Vigneshwarar]]></dc:creator><pubDate>Wed, 20 Sep 2023 10:07:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!S6hI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you have implemented <a href="https://vigneshwarar.substack.com/p/hackernews-support-page-using-retrieval">Retrieval Augmented Generation</a> (RAG) or RAG-based chatbots, whether using Langchain or not, you have experienced the challenges of implementing everything from retrieval and context formation to streaming the response back to the client side.</p><p>That's what we are trying to solve with <a href="https://eazyrag.com/">EazyRAG</a>. We have the entire RAG pipeline implemented, and you can use it with a simple API call. What's even better is that we also support grounded answer generation from the browser. Here is a <a href="https://eazyrag.com/bun">demo</a> where I indexed the entire Bun Docs on EazyRAG, which is making RAG requests from the browser.</p><p>Here is a sample code.</p><p>Index your content from the server side.</p><pre><code>curl --location 'https://api.eazyrag.com/v1/add' \
--header 'Authorization: sk-&lt;Your server key&gt;' \
--header 'Content-Type: application/json' \
--data '{
 "contents": [
   {
       "content":"You entire document or chunk of content",
       "title":"Document title (Optional)"
   }
 ],
 "collection": "sample"
}'</code></pre><p>Once you have indexed your content, it's just a dead-simple way to generate grounded answers with a simple API call from your browser.</p><pre><code>  const fetchResponse = async (question: string) =&gt; {
    try {
      const response = await axios.get("https://api.eazyrag.com/v1/answer", {
        params: {
          query: question,
          collection: "sample",
        },
        headers: {
          Authorization:
            "ck-&lt;Your client key&gt;",
        },
      });

      // Grounded answer generation
      console.log(response.data);

    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };</code></pre><p>We also support streams, and you can use <a href="https://www.npmjs.com/package/eventsource">EventSource</a> to implement an API with streams on the browser side.</p><p>Our longer-term vision (if we survive) is to build a dead-simple API on top of LLM, where even someone who is just getting started with coding can create powerful LLM agents without needing to understand the underlying concepts.</p><p>If you have any questions or feedback, don't hesitate to click on the chat icon.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://eazyrag.com/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S6hI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 424w, https://substackcdn.com/image/fetch/$s_!S6hI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 848w, https://substackcdn.com/image/fetch/$s_!S6hI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 1272w, https://substackcdn.com/image/fetch/$s_!S6hI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S6hI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png" width="1456" height="748" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:748,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:143723,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://eazyrag.com/&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S6hI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 424w, https://substackcdn.com/image/fetch/$s_!S6hI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 848w, https://substackcdn.com/image/fetch/$s_!S6hI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 1272w, https://substackcdn.com/image/fetch/$s_!S6hI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ca3e7da-886c-438c-a46a-e82686c5af48_1916x984.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://vigneshwarar.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vigneshwarar&#8217;s Newsletter! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[You don't need Langchain; here's how to do Retrieval-Augmented Generation without it]]></title><description><![CDATA[In this article, we are going to build a Retrieval Augmented Generation pipeline from scratch using just Faiss, SBERT, and OpenAI for answer generation.]]></description><link>https://vigneshwarar.substack.com/p/hackernews-support-page-using-retrieval</link><guid isPermaLink="false">https://vigneshwarar.substack.com/p/hackernews-support-page-using-retrieval</guid><dc:creator><![CDATA[Vigneshwarar]]></dc:creator><pubDate>Mon, 18 Sep 2023 14:35:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ILd_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we will build a Retrieval-Augmented Generation(RAG) pipeline from scratch without using trendy libraries such as Langchain or Llamaindex.</p><p>A short intro about RAG.</p><p>Quoting from the Facebook (aka Meta) <a href="https://arxiv.org/pdf/2005.11401.pdf">OG RAG paper</a>.</p><blockquote><p>Large pre-trained language models have been shown to store factual knowledge in their parameters, and achieve state-of-the-art results when fine-tuned on downstream NLP tasks. However, their ability to access and precisely manipulate knowledge is still limited, and hence on knowledge-intensive tasks, their performance lags behind task-specific architectures. Additionally, providing provenance for their decisions and updating their world knowledge remain open research problems.</p></blockquote><p>Yeah, that's the exact problem RAG solves. In simple words, LLMs such as GPT lack factual consistency and lack up-to-date knowledge. To fix this, RAG is a technique that retrieves related documents to the user's question, combines them with LLM-base prompt, and sends them to LLMs like GPT to produce more factually accurate generation.</p><p>Here is the image I made to make visualization easier.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ILd_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ILd_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 424w, https://substackcdn.com/image/fetch/$s_!ILd_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 848w, https://substackcdn.com/image/fetch/$s_!ILd_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 1272w, https://substackcdn.com/image/fetch/$s_!ILd_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ILd_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:241960,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ILd_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 424w, https://substackcdn.com/image/fetch/$s_!ILd_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 848w, https://substackcdn.com/image/fetch/$s_!ILd_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 1272w, https://substackcdn.com/image/fetch/$s_!ILd_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c8d221-3e4f-423f-bed5-929b04d8b301_4000x4000.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Let&#8217;s build</h2><p>I will split the RAG pipeline into 5 parts:</p><ul><li><p>Data preparation</p></li><li><p>Chunking</p></li><li><p>Vector store</p></li><li><p>Retrieval/Prompt preparation</p></li><li><p>Answer Generation</p></li></ul><blockquote><p><strong>Shameless plug: If you don't want to go through the process above or customize chunking strategies using trendy libraries, please consider visiting <a href="https://eazyrag.com/">eazyrag.com</a>. We handle everything. Here is a <a href="https://eazyrag.com/bun">demo</a> I built in which I indexed the entire Bun <a href="https://bun.sh/docs">Docs</a>/<a href="https://bun.sh/guides">Guides</a> with just two simple network calls for indexing and answer generation.</strong></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://eazyrag.com" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ORg0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 424w, https://substackcdn.com/image/fetch/$s_!ORg0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 848w, https://substackcdn.com/image/fetch/$s_!ORg0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 1272w, https://substackcdn.com/image/fetch/$s_!ORg0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ORg0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png" width="1456" height="748" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:748,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:143739,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://eazyrag.com&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ORg0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 424w, https://substackcdn.com/image/fetch/$s_!ORg0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 848w, https://substackcdn.com/image/fetch/$s_!ORg0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 1272w, https://substackcdn.com/image/fetch/$s_!ORg0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb993560e-ba1a-4854-b92e-db2ef35169c9_1916x984.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Back to the article.</p><h4>Data preparation</h4><p>As we are planning to create a HackerNews (HN) support page, I have downloaded the relevant HTML pages, converted them to raw text, and saved them as JSON files.</p><pre><code>data/
&#9500;&#9472;&#9472; legal.json
&#9500;&#9472;&#9472; newsfaq.json
&#9500;&#9472;&#9472; newsguidelines.json
&#9492;&#9472;&#9472; security.json</code></pre><p>JSON file looks something like this.</p><pre><code>{
   "content":"HTML converted into string...",
   "url":"https://news.ycombinator.com/newsfaq.html"
}</code></pre><p>There is a reason I am adding a relevant URL to the file, when the LLM generates an answer, we can link back to the original URL used as context for citation.</p><h4>Chunking</h4><p>This is one of the important parts of the RAG pipeline. There are a whole lot of chunking strategies that deserve their own post, which I might write. But in short, here is how I decide this: when the answer is generated and cited with the citation number, I should be able to go back to the original sentence that has the answer on the HackerNews page by using <a href="https://developer.mozilla.org/en-US/docs/Web/Text_fragments#:~:text=See%20also-,Text%20fragments,-Text%20fragments%20allow">text fragments</a>.</p><p>So, we are going to split the content by sentence and save it as JSON with the URL key in every text fragment.</p><p>I removed the imports, don&#8217;t worry. I linked the final code at the bottom. Now let's only focus on the main parts of the code.</p><pre><code>nlp = spacy.load("en_core_web_sm")

def process_file(file_path):
    with open(file_path) as f:
        data = json.load(f)
        content = data['content']
        url = data['url']
        doc = nlp(content)
        
        return [{'text': sent.text, 'url': url} for sent in doc.sents]

chunks = [chunk for file in os.listdir('data') for chunk in process_file(os.path.join('data', file))]

chunks = [{'id': i, **chunk} for i, chunk in enumerate(chunks)]

with open('chunks.json', 'w') as f:
    json.dump(chunks, f)</code></pre><p>In the code above, I simply read all the files in the 'data' directory, iterated through the files, split them by sentence, assigned IDs to them (which we will use later), and saved them as 'chunks.json'.</p><h4>Vector store</h4><p>Now, we are going to convert all the chunks into embeddings. I am going to use the sbert <a href="https://huggingface.co/sentence-transformers/all-mpnet-base-v2">all-mpnet-base-v2</a> model, but there are a lot of options available. Here is the <a href="https://huggingface.co/spaces/mteb/leaderboard">leaderboard</a>, and there is even a new <a href="https://arxiv.org/pdf/2309.07597.pdf">state-of-the-art model</a> (I&#8217;m still reading this paper).</p><pre><code>sentences = [chunk['text'] for chunk in chunks]

model = SentenceTransformer('sentence-transformers/all-mpnet-base-v2')

embeddings = model.encode(sentences, show_progress_bar=True)

faiss_index = faiss.IndexFlatIP(model.get_sentence_embedding_dimension())
faiss_index.add(embeddings)</code></pre><p>In the code above, I converted all the texts into embeddings using the pre-trained embedding model and built the index using <a href="https://github.com/facebookresearch/faiss">Faiss</a>. If you have a large amount of data and are planning to use a bigger dimensional model, I'm pretty sure memory will be a problem.</p><p>If you are looking to quantize the faiss index size, you can manually <a href="https://github.com/facebookresearch/faiss/wiki/Lower-memory-footprint">quantize</a> it, or you can use this <a href="https://github.com/criteo/autofaiss">nice tool</a> which will produce the index at the specified size. It's a really cool tool and a huge time saver.</p><h4>Retrieval/Prompt preparation</h4><p>We are going to retrieve the relevant chunks to form the final prompt.</p><pre><code>base_prompt = """You are an AI assistant. Your task is to understand the user question, and provide an answer using the provided contexts. Every answer you generate should have citations in this pattern  "Answer [position].", for example: "Earth is round [1][2].," if it's relevant. 

Your answers are correct, high-quality, and written by an domain expert. If the provided context does not contain the answer, simply state, "The provided context does not have the answer."

User question: {}

Contexts:
{}
"""</code></pre><pre><code>k = 50
question = 'Why HackerNews is so popular?' 

query_embedding = model.encode([question])
distances, indices = faiss_index.search(query_embedding, k)

context = '\n'.join([f'{i}. {sentences[index]}' for i, index in enumerate(indices[0])])
prompt = f'{base_prompt.format(question, context)}'</code></pre><p>In the code above, I retrieved all the relevant chunks, attached them to the base prompt, along with the user's question and context retrieved from the faiss_index, and formed the final prompt that we are going to send to GPT-3.5.</p><h4>Answer Generation</h4><p>Just send the prompt to OpenAI.</p><pre><code>response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-16k-0613",
    temperature=0,
    messages=[
        {"role": "system", "content": prompt},
    ]
)

print(response.choices[0].message.content)</code></pre><p>The response I got for &#8220;<code>Why HackerNews is so popular?&#8221;</code></p><blockquote><p>Hacker News is popular for several reasons: </p><p>1. Quality Content: Hacker News focuses on providing content that would be interesting to "good hackers" [8]. This means that the platform curates and promotes high-quality articles, discussions, and resources related to technology, startups, and hacking [8]. </p><p>2. Community Engagement: Users are encouraged to vote and comment on content that they find interesting, rather than for self-promotion [12]. This fosters a sense of community engagement and encourages meaningful discussions. </p><p>3. Y Combinator Association: Hacker News is associated with Y Combinator, a well-known startup accelerator [11]. This association brings credibility and attracts entrepreneurs, investors, and tech enthusiasts to the platform. </p><p>4. Privacy and Security: Hacker News takes privacy and security seriously [2]. They have implemented measures to protect personal information and have a privacy policy in place [41]. This commitment to privacy and security helps build trust among users. </p><p>5. Diverse Topics: Hacker News covers a wide range of topics beyond just hacking and startups [4]. This diversity attracts users with different interests and backgrounds, making the platform more appealing and engaging. </p><p>6. Active Moderation: Hacker News has active moderation to prevent abuse and maintain the quality of discussions [22]. This helps create a positive and respectful environment for users. Overall, the combination of quality content, community engagement, Y Combinator association, privacy and security measures, diverse topics, and active moderation contribute to the popularity of Hacker News. [8][12][41][4][22][11].</p></blockquote><p>Now you can parse the citations and find the relevant chunks. I am skipping this since that&#8217;s not the goal of this article.</p><h2>Conclusion</h2><p>I hope you now have a good understanding of the RAG pipeline. Here is the <a href="https://colab.research.google.com/drive/1uQABWrbU17DwLQdDZ8k5d_UJVlrAkwZ5?usp=sharing">final code</a>.</p><p>Now, the above process may look simple, but a lot of effort needs to be done for perfect retrieval and precise context generation. <a href="https://eazyrag.com/">EazyRAG</a>, the tool we are building, tackles this. We have incorporated a lot of different strategies to form a good context, which increases the quality of the answer. </p><p>Visit: <a href="https://eazyrag.com/">https://eazyrag.com</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G1Oz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G1Oz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 424w, https://substackcdn.com/image/fetch/$s_!G1Oz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 848w, https://substackcdn.com/image/fetch/$s_!G1Oz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 1272w, https://substackcdn.com/image/fetch/$s_!G1Oz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G1Oz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png" width="1456" height="748" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c35a527-1546-4693-a0fe-52413583878c_1916x984.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:748,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:143739,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G1Oz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 424w, https://substackcdn.com/image/fetch/$s_!G1Oz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 848w, https://substackcdn.com/image/fetch/$s_!G1Oz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 1272w, https://substackcdn.com/image/fetch/$s_!G1Oz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c35a527-1546-4693-a0fe-52413583878c_1916x984.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://vigneshwarar.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://vigneshwarar.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[HackerNews Ranking Algorithm]]></title><description><![CDATA[Here's a small thought experiment that explores an alternative approach to ranking posts on HackerNews.]]></description><link>https://vigneshwarar.substack.com/p/hackernews-ranking-algorithm-how</link><guid isPermaLink="false">https://vigneshwarar.substack.com/p/hackernews-ranking-algorithm-how</guid><dc:creator><![CDATA[Vigneshwarar]]></dc:creator><pubDate>Sun, 09 Apr 2023 14:05:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a19b9ff9-60b4-4a6e-ae91-95c701c44c7b_1184x776.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of my favorite sites to visit daily is HackerNews(HN), it never failed me to deliver good quality links and very interesting discussions. </p><p>This is just a small thought experiment for a different ranking algorithm for HN. There's nothing wrong with the current one, but it's just a small thought experiment.</p><p>Just to refresh, according to <a href="https://news.ycombinator.com/item?id=1781013">Paul Graham's comment</a> and <a href="https://news.ycombinator.com/newsfaq.html">FAQ</a>, the HN algorithm is...</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;rank = {\\frac  {P - 1}{(T + 2)^G}}&quot;,&quot;id&quot;:&quot;WVMUBPYXFV&quot;}" data-component-name="LatexBlockToDOM"></div><p>P = Points </p><p>T = Age in hours</p><p>G = 1.8</p><p>Minus one removes the user's own upvote. By default, HN upvotes its own user submission.</p><p>I&#8217;ve seen one with penalties but let&#8217;s stick to what&#8217;s official. Also, I just did a quick <a href="https://usegrasp.com/search?q=hacker+news+ranking+algorithm">Grep search</a> and found this article and <a href="https://github.com/sangaline/reverse-engineering-the-hacker-news-ranking-algorithm">wonderful repo</a> about &#8220;<a href="https://sangaline.com/post/reverse-engineering-the-hacker-news-ranking-algorithm/">Reverse Engineering the Hacker News Ranking Algorithm</a>&#8220;</p><p>Intuitively, the ranking algorithm is simple: the more upvotes a link receives in a short amount of time, the higher it will be ranked at the top. As time passes, the post will gradually move down the rankings.</p><h3>Here is my approach</h3><p>I can't find the official page on why Paul Graham created HN, but to me, HN is the place to find the most interesting links and have a healthy discussion about various topics. In fact, discussions are my favorite part, except for the useless comments.</p><p>Given that discussions are my favorite part, why don't we apply PageRank for every user based on the upvotes they receive for the comments they leave on any post, and replace the P (points) value in the current version of the HN algorithm?</p><p><a href="https://en.wikipedia.org/wiki/PageRank">PageRank</a> is an algorithm created by the founders of Google. It is used to determine the popularity of web pages on the internet.</p><p>By the way, the name PageRank did not suit this use case. I am going to call it HackerRank (HR). Here is a visualization if you are trying to picture it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Irzc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Irzc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 424w, https://substackcdn.com/image/fetch/$s_!Irzc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 848w, https://substackcdn.com/image/fetch/$s_!Irzc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 1272w, https://substackcdn.com/image/fetch/$s_!Irzc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Irzc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png" width="1456" height="1308" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/11d75d52-c322-430a-b382-636457c898b3_2208x1984.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1308,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:165828,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Irzc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 424w, https://substackcdn.com/image/fetch/$s_!Irzc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 848w, https://substackcdn.com/image/fetch/$s_!Irzc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 1272w, https://substackcdn.com/image/fetch/$s_!Irzc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11d75d52-c322-430a-b382-636457c898b3_2208x1984.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Since it's likely that one user may upvote multiple comments from the same user, we check whether a user has already upvoted a comment from that specific user before considering their upvote. In other words, we treat user profiles as nodes and upvotes for comments as edges.</p><p>Considering this, a HackerRank user profile will look like this:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;HR_{i}={\\frac  {1-D}{N}}+D\\,\\sum _{{j\\in \\{1,\\dots ,n\\}}}{\\frac  {HR_{j}}{TU_{j}}}&quot;,&quot;id&quot;:&quot;EYGBFKDHZZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>N = Total number of user profiles on HN</p><p>D = Damping factor</p><p>HR = HackerRank score for the user who upvoted</p><p>TU = Total upvotes given</p><p>By default, the HR for every profile will be <code>1/N</code>.</p><p>But I won't consider HackerRank as it is. Sometimes, HN comments are inappropriate, and they will be flagged. We should consider the flagging because, remember, HN should be a place to have healthy discussions. </p><p>Let's consider that 1 flag equals a deduction of 20% from the HR score. However, we will only take into account the flags received in the current month, as people can change from being unpleasant to becoming better human beings.</p><p>So, HR with &#8220;flag&#8221; consideration will look like this.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;HR_{with flag} = HR  - ((TF * FP) * HR)&quot;,&quot;id&quot;:&quot;ZCONBLNPFY&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;HR = max(0, \\space HR_{withflag})&quot;,&quot;id&quot;:&quot;WFTBHWZXJP&quot;}" data-component-name="LatexBlockToDOM"></div><p>TF = Total flags received in the current month</p><p>FP = Flag penalty which is 20%</p><p>If HR is negative, then it will be 0.</p><p>We now have HR for every user profile, so the final ranking algorithm will look like this by hooking HR into the current version of the HN algorithm.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;rank_{i} = {\\frac  {\\sum_{{j\\in \\{1,\\dots ,n\\}}} (HR_{j})}{(T + 2)^G}}&quot;,&quot;id&quot;:&quot;OZAKFJUBUV&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>HR = HR value represents the HackerRank score of the profile that upvoted this post</p><p>T = Age in hours</p><p>G = 1.8 </p><p>This is a very simple approach, but here are some other ideas that are worth exploring.</p><ul><li><p>HackerRank score, which is also determined by the upvotes a user receives for their submissions.</p></li><li><p>Reading time for the article.</p></li><li><p>Track how well a website is performing on HN and put it on the front page if the website has a high reputation for performing well.</p><p></p></li></ul><p>Will I ever publicly write about how HN ranks posts if I am Dang (HN moderator)? No, because Pagerank can be manipulated by people despite its reputation. In fact, <a href="https://www.google.com">Pagerank is being exploited for years</a>. Moreover, there are financial incentives for companies to get on the first page in HN.</p><p>I would use HackerRank for ranking posts but publicly say that we are using <a href="https://news.ycombinator.com/item?id=1781013">original PaulGraham&#8217;s algorithm</a> for ranking posts, and <a href="https://news.ycombinator.com/item?id=2445039">hide the upvotes for comments</a> since it is powering HackerRank, also take some additional steps to avoid reverse engineering and rank manipulation.</p><p>But, I am curious. How would you have done it? If you were designing the HN algorithm, please leave your thoughts in the comments. I am curious to know.</p><p>Discussion on HN &#8594; <a href="https://news.ycombinator.com/item?id=35510413">https://news.ycombinator.com/item?id=35510413</a></p><div><hr></div><p>Plug: Hey, we are building a <a href="https://usegrasp.com/">new kind of search engine</a>. Our goal is to deliver authoritative and non-SEO-spammed results. Please check it out and let me know your feedback.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://vigneshwarar.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vigneshwarar&#8217;s Newsletter! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>