<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Vardhanam Daga on Medium]]></title>
        <description><![CDATA[Stories by Vardhanam Daga on Medium]]></description>
        <link>https://medium.com/@vardhanam.daga?source=rss-ead06f376cdd------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*4tr3cBr1bZCYTK-GipsRwQ.jpeg</url>
            <title>Stories by Vardhanam Daga on Medium</title>
            <link>https://medium.com/@vardhanam.daga?source=rss-ead06f376cdd------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 00:34:15 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@vardhanam.daga/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[What Piyush Goyal got right about Indian Startups]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@vardhanam.daga/what-piyush-goyal-got-right-about-indian-startups-0a8a72368a57?source=rss-ead06f376cdd------2"><img src="https://cdn-images-1.medium.com/max/634/1*WMH39TvhAcAO8bimrjc6qA.png" width="634"></a></p><p class="medium-feed-snippet">Commerce Minister thinks most Indian Startups are just &#x201C;Dukandaars&#x201D;</p><p class="medium-feed-link"><a href="https://medium.com/@vardhanam.daga/what-piyush-goyal-got-right-about-indian-startups-0a8a72368a57?source=rss-ead06f376cdd------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://medium.com/@vardhanam.daga/what-piyush-goyal-got-right-about-indian-startups-0a8a72368a57?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/0a8a72368a57</guid>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[business]]></category>
            <category><![CDATA[india]]></category>
            <category><![CDATA[economy]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Sun, 06 Apr 2025 18:02:42 GMT</pubDate>
            <atom:updated>2025-04-06T18:02:42.651Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[From Bollywood Setback to 1200 Crore Empire: The Vivek Oberoi Story]]></title>
            <link>https://medium.com/@vardhanam.daga/from-bollywood-setback-to-1200-crore-empire-the-vivek-oberoi-story-6f4e1a1109d7?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/6f4e1a1109d7</guid>
            <category><![CDATA[bollywood]]></category>
            <category><![CDATA[motivation]]></category>
            <category><![CDATA[money]]></category>
            <category><![CDATA[rags-to-riches]]></category>
            <category><![CDATA[gossip]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Sun, 23 Mar 2025 07:03:37 GMT</pubDate>
            <atom:updated>2025-03-23T07:04:24.598Z</atom:updated>
            <content:encoded><![CDATA[<h4>The failed actor who’s richer than Rajnikanth</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*o_QBkm-xPw33Yj8ExPj2XQ.png" /></figure><p>Vivek Oberoi is a failed actor, yet his net worth surpasses that of actors like Ranbir Kapoor, Allu Arjun, and even industry legend Rajnikanth. In fact even when combined, the net worth of these three actors still falls short of Oberoi’s 1200 Crore valuation.</p><p>So how did he make all this wealth?</p><p>This is the story of Oberoi’s entrepreneurial ventures. His diverse portfolio spans real estate, sustainable diamonds, event management, and education, showcasing a strategic approach to wealth creation.</p><h4>Early Exposure to Business</h4><p>Vivek Oberoi’s foundation in business began early. His father, Suresh Oberoi, a Bollywood actor, introduced him to commerce at a young age. At seven, Vivek was tasked with selling perfume bottles, learning about stock management, costing, and sales. This instilled a fundamental understanding of business operations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/286/1*WNU9-zEIwJ4VQxsEYSBqDw.png" /><figcaption>Father, Suresh Oberoi</figcaption></figure><p>By 14, attending Mayo College in Ajmer, his father cut off his allowance, pushing him to earn his own money. Oberoi took on jobs like hosting college events and dubbing English movies into Hindi, earning around ₹30,000 a month. However, his entrepreneurial spirit yearned for more.</p><p>He identified a problem at his college: students had to travel long distances for food if on-campus vendors ran out of supplies. Oberoi seized this opportunity by supplying food items to these vendors at lower prices, taking a 20–30% cut of their total sales. He even offered higher profits to vendors during rainy seasons and holidays, making him a preferred supplier. By 16, Oberoi had made a profit of ₹5–6 lakh.</p><p>Fueled by this success, he ventured into the stock market, learning the basics and applying his own business acumen. Within two years, he made a profit of ₹40–50 lakh. However, his luck turned when he invested in a risky stock, losing all his money in a week. This experience taught him a valuable lesson about risk management and the volatile nature of the stock market.</p><h4>Bollywood Career: Highs and Lows</h4><p>When college ended, Oberoi turned to acting, his “Plan B.” Despite his father’s connections, he struggled for 3–4 years before landing his first movie, “Company,” in 2002. The film was a hit, earning him Filmfare Awards for Best Male Debut and Best Supporting Actor. His second movie, “Saathiya,” was also a success, leading to comparisons with established Bollywood stars.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/455/1*xnkd4qLCbiCgVIpmYc524A.png" /></figure><p>However, his career took a turn on March 29, 2003, when he received a call from Salman Khan, who questioned him about his alleged affair with Aishwarya Rai, who Khan was dating at the time. This incident led to a fallout with Khan, who allegedly used his influence to blacklist Oberoi from Bollywood.</p><p>Directors and producers refused to work with him, and co-actors stopped answering his calls. Oberoi and his family received threats from the underworld, leading to police protection. The lack of opportunities and the pressure affected his performance, and his movies began to flop. From 2003 to 2007, films like “Darna Mana Hai,” “Yuva,” “Deewane Huye Paagal,” “Home Delivery,” and “Fool n Final” failed at the box office. According to the video, in a 22 year Bollywood career, Vivek Oberoi only starred in 30 films, of which 24 were flops. This means that 80% of his films could not recover the money it took to produce them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9kI-lbXL7DdWlXAI.jpg" /><figcaption>Vivek Oberoi &amp; Salman Khan</figcaption></figure><p>This period was marked by financial issues and mental health struggles. Oberoi experienced frustration, pain, anger, and depression. He realized he needed to pivot and return to his entrepreneurial roots.</p><h4>Diversifying into Business</h4><p>Recognizing the instability of the film industry, Oberoi focused on his entrepreneurial ambitions. He understood that relying solely on acting was precarious, and he needed to diversify his income streams. With a business mind honed since childhood and maturity gained through his Bollywood experiences, he began identifying market gaps and opportunities.</p><h4>1. Karrm Infrastructure Private Limited</h4><p>Oberoi recognized the emotional significance of owning a home for middle-class families in India. In 2011, he launched Karrm Infrastructure, a real estate company focused on providing affordable housing. The company has since built and sold thousands of affordable homes.</p><p>What sets Karma Infrastructure apart is its marketing strategy. The company treats families like celebrities during the registration process, providing VIP treatment, including transportation, meals, and even helicopter rides. This customer-centric approach has been successful in attracting and retaining clients.</p><h4>2. B.A.D. Developments</h4><p>Understanding the potential for high profits in the luxury real estate market, Oberoi expanded his business to Dubai, catering to the elite class. B.A.D. Developments focuses on building luxurious homes for the wealthy, tapping into the demand for opulent living spaces.</p><p>Dubai’s tax-free environment further enhances the profitability of this venture. By targeting the elite class and operating in a favorable business climate, Oberoi has generated millions of dollars in revenue from this company.</p><h4>3. Solitario</h4><p>In 2022, Oberoi ventured into the diamond industry with Solitario, a company that produces lab-grown diamonds. Unlike traditional diamond mining, which is environmentally harmful and often involves unsafe labor practices, Isorio offers an ethical and sustainable alternative.</p><p>Lab-grown diamonds are chemically identical to natural diamonds but are produced in a controlled laboratory environment. Oberoi partnered with Ricky Vasandani, who has over a decade of experience in the international jewelry market, to create a company that capitalizes on the growing demand for sustainable luxury.</p><p>Solitario currently has 18 physical stores in India and plans to expand to more cities. The company’s success is driven by the increasing awareness of the environmental and ethical issues associated with natural diamond mining.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WtGLxjLzjHBvYwDPYVQmjQ.png" /><figcaption>Solitario Diamonds</figcaption></figure><h4>4. Mega Entertainment</h4><p>Oberoi’s fourth major company is Mega Entertainment, an event management company operating in India and Dubai. The company specializes in organizing weddings and other events, offering clients a unique experience.</p><p>Mega Entertainment uses the same helicopter marketing strategy as Karma Infrastructure, providing couples with a free helicopter ride. This attention to detail and focus on creating memorable experiences has made Mega Entertainment a popular choice for clients seeking a high-end event management service.</p><h4>5. Other Ventures</h4><p>In addition to his major companies, Oberoi has also founded Swanim University and an education loan platform, providing affordable education loans to students. The education loan platform has a valuation of over ₹3,000 crore. In 2022, he launched a coffee brand called “Aur Coffee,” which competes with established brands like Starbucks.</p><h4>Strategic Investments</h4><p>Oberoi’s early experience in the stock market taught him the importance of strategic investments. He has invested in over 30 companies, including Icolor, Balu Forge, and Infinity Reality, generating crores of rupees in annual returns. One of his early investments, Balu Forge, has grown to a valuation of ₹8,000 crore.</p><h4>The Road Ahead</h4><p>As of 2025, Vivek Oberoi’s net worth stands at $145 million (₹1200 crore). On Ganesh Chaturthi this year Vivek Oberoi gifted Ganesh Ji a 66 karat diamond tilak and bought a Rolls Royce worth 12 Croroes two months after. With his companies poised for IPOs, Oberoi is on track to surpass even the biggest Bollywood superstars in terms of wealth in the coming years.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/493/1*iBzc2QCjBSkE4ei0AnM7Nw.png" /><figcaption>Posing with his Rolls Royce</figcaption></figure><p>His story is a compelling example of how an individual can overcome setbacks and create a diversified portfolio of income through strategic business decisions and investments.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f4e1a1109d7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What does Jada Pinkett Smith have to say about Will Smith’s iconic slapping of Chris Rock]]></title>
            <link>https://medium.com/@vardhanam.daga/what-does-jada-pinkett-smith-have-to-say-about-will-smiths-iconic-slapping-of-chris-rock-f9fb5ef464ad?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/f9fb5ef464ad</guid>
            <category><![CDATA[will-smith]]></category>
            <category><![CDATA[gossip]]></category>
            <category><![CDATA[hollywood]]></category>
            <category><![CDATA[chris-rock]]></category>
            <category><![CDATA[celebrity]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Wed, 19 Mar 2025 11:01:08 GMT</pubDate>
            <atom:updated>2025-03-19T11:01:08.665Z</atom:updated>
            <content:encoded><![CDATA[<h4>“I thought it was a skit”</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/602/1*Ks4U9h6QEtYNYaTKR8lLrA.png" /></figure><p>Everyone remembers the momentous night of the 2022 Oscars when Will Smith walked up to Chris Rock for ridiculing his wife’s baldness and then smacking him in the face. During the ceremony, Chris Rock made a comment about Jada Pinkett Smith appearing in <em>GI Jane</em> — a jab at her bald look — even though her hair loss is due to an autoimmune disorder called alopecia areata. At first, Will laughed at the remark, but when he saw how much it hurt his wife, he abruptly got up, walked toward Chris Rock, and delivered a forceful slap. Then, returning to his seat, he famously declared, “Keep my wife’s name out of your f**ing mouth.”</p><p>Years later, Jada Pinkett Smith reflected on that unforgettable moment:</p><blockquote>“I thought it was a skit. From where I was sitting, you couldn’t really tell — it didn’t look like Will was going to hit Chris. I mean, I’d seen Will in the boxing ring with pro fighters, and he’s a heavy hitter. So when Chris moved, it looked like he ducked or missed the shot, especially when he kept standing and then walked down to the end of the stage. I was thinking, ‘there’s no way he’s going to get hit.’ It wasn’t until Will started walking back to his chair that I realized this wasn’t a skit at all. I was just as foggy as everyone else in that room that night.”</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/969/1*wnvMP3gmfJ7LzSeudPe0vA.png" /><figcaption>Jada Pinkett Smith</figcaption></figure><p>Following the incident, a number of Hollywood celebrities shared their thoughts on that charged evening:</p><h3>Jim Carrey’s Reaction</h3><p>Jim Carrey, known for his bold humor and candid opinions, expressed his disgust over the entire affair. He was particularly critical of the media and Hollywood response — especially the standing ovation given to Will Smith after his Best Actor win. Carrey went on to assert that if he were in Chris Rock’s shoes, he would have sued Will Smith for $200 million. His comments underscored his belief that the slap left a permanent mark on Chris Rock’s career and highlighted the industry’s tendency to mix personal feelings with public drama.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/889/1*lqUhlVbAiyu-WcOmPN0STA.png" /><figcaption>Jim Carrey</figcaption></figure><h3>Chris Rock’s Composure</h3><p>Despite being on the receiving end of one of the most shocking moments in Oscars history, Chris Rock handled the situation with remarkable professionalism. Initially, his wide-eyed expression revealed his shock; yet, he chose not to retaliate or storm off stage. Instead, Rock continued with his presentation, maintaining his composure through an incredibly tense moment. In later reflections, he addressed the incident with humor, acknowledging both the absurdity and personal sting of the slap.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lFukpR1KCaU5p3DcvmrSSw.png" /></figure><h3>Eddie Murphy’s Take</h3><p>Eddie Murphy, adding a lighter note amid the heavy drama, delivered a memorable quip at the Golden Globe Awards when he was honored with the Cecil B. DeMille Award. Murphy joked, “There’s a simple three-step blueprint for success in Hollywood — pay your taxes, mind your business, and keep Will Smith’s wife’s name out of your mouth.” His remark, met with hearty laughs from the audience, served as a reminder that even in the midst of controversy, humor continues to play an important role in processing Hollywood’s most baffling moments.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oUs7NkOi4HJBElIV3sVuuA.png" /><figcaption>Eddie Murphy</figcaption></figure><p>This incident remains one of the most talked-about in recent entertainment history, sparking debates on personal respect and the boundaries of public performance, as well as setting off a chain reaction of candid commentary from some of Hollywood’s most iconic figures.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9fb5ef464ad" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[10 Brilliant AI Insights from Stability AI’s Founder Emad Mostaque]]></title>
            <link>https://medium.com/@vardhanam.daga/10-brilliant-ai-insights-from-stability-ais-founder-emad-mostaque-182905c11a60?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/182905c11a60</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[future-of-ai]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[stable-diffusion]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Mon, 17 Mar 2025 15:04:25 GMT</pubDate>
            <atom:updated>2025-03-17T15:05:34.564Z</atom:updated>
            <content:encoded><![CDATA[<h4>I watched an hour long podcast, so you don’t have to</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*8buFrApovp5A-SI3-89QOw.png" /></figure><p>“In one year, AI will generate complex apps like Uber from scratch”. — Emad Mostaque.</p><p>Let that sink in. The future of AI is not just coming; it’s already here. And leading the charge is Emad Mostaque, the visionary founder of Stability AI, the company behind the AI image model Stable Diffusion. Here are some of his insights from a podcast that you’ll find linked later.</p><p>Insights:</p><ol><li>AI will revolutionize software development. It will create complex apps from scratch within a year.</li><li>Generative AI is expanding. It’s tackling video, code, and 3D assets. Content creation will never be the same.</li><li>AI will augment human creativity. It will empower small teams to rival tech giants.</li><li>Personalized AI will be our trusted collaborator. It will learn from us and anticipate our needs.</li><li>Democratization of AI is crucial. Open-source models and datasets will create a future where AI benefits all.</li><li>AI will eat the world. Industries will be disrupted. Jobs will be transformed. Embrace the change or be left behind.</li><li>Professionals must adapt to the AI landscape. Mastering AI-assisted tools is key to problem-solving and innovation.</li><li>AI models are getting smarter and faster. They’ll run on smartphones for real-time, personalized experiences.</li><li>The future of AI lies in multimodality. Models will seamlessly handle diverse inputs and outputs, revolutionizing human-AI interaction.</li><li>The AI revolution presents challenges. Equal access, ethics, transparency, and accountability require ongoing dialogue.</li></ol><p>In case you are not happy with this summary, you can watch the full podcast here — <a href="https://www.youtube.com/watch?v=VeaT6ucXuMI">https://www.youtube.com/watch?v=VeaT6ucXuMI</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=182905c11a60" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[42% of Young Indians Don’t Want to Marry]]></title>
            <link>https://medium.com/@vardhanam.daga/42-of-young-indians-dont-want-to-marry-cde247a00538?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/cde247a00538</guid>
            <category><![CDATA[arranged-marriage]]></category>
            <category><![CDATA[divorce]]></category>
            <category><![CDATA[lifestyle]]></category>
            <category><![CDATA[marriage]]></category>
            <category><![CDATA[india]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Fri, 14 Mar 2025 09:02:40 GMT</pubDate>
            <atom:updated>2025-03-14T09:02:40.753Z</atom:updated>
            <content:encoded><![CDATA[<h4>Once an eternally cherished institution, marriages now have fewer and fewer takers.</h4><p>According to a recent survey, 42% of young adults in India between 26 and 40 say they do not want to get married. This number shows that many people today are growing more and more afraid of marriage. They worry about long, expensive legal battles and a host of other problems. The old idea of marriage as a lifelong bond built on trust is slowly fading.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Idhoz0g69OU5ufc_" /><figcaption>Photo by <a href="https://unsplash.com/@liquidartiste?utm_source=medium&amp;utm_medium=referral">Liquid Artiste</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>A Crisis of Trust and Legal Battles</h3><p>Many young people in India are turning away from marriage because they fear the legal system. False allegations have led to long and costly court battles. Men worry that even a small mistake might result in huge financial losses. One high-profile case saw a wife file an alimony claim for Rs. 500 crores from her US-based husband, with the names of entire families involved. In another case, the Supreme Court had to settle for Rs. 12 crores. Stories like these create a climate of distrust, and the fear of facing such legal nightmares makes many feel that marriage is simply too risky.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/1*1Piey6rNW82qxkQSidyuuw.png" /></figure><h3>Arranged Marriages in Modern Times</h3><p>In India, arranged marriages are still very common. In fact, a survey shows that even now, 90% of marriages in India are arranged marriages. Families meet through middlemen who introduce potential partners, and both sides share details like education, background, and wealth. However, these marriages come with their own set of problems. There is immense pressure on both families to meet expectations. Discussions about dowry and social status add stress to the process. Arranged marriages are definitely not making it easy for people to sustain the institution of marriage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/792/1*8W0nzot6pLPDbrSAham5TA.png" /></figure><h3>Family Pressure and Domestic Conflicts</h3><p>The problems do not end with legal and financial issues. Family pressure plays a big role in making marriage difficult. After the wedding, a new daughter-in-law often finds herself caught between high family expectations and outdated traditions. Even though many women are well-educated and career-oriented, there is still a strong expectation for them to manage the entire household — cooking, cleaning, and taking care of everyone. The constant meddling of the mother-in-law, father-in-law, and even the daughter’s own family creates conflicts. There is little room for privacy, and personal space becomes a luxury. Such family interference only adds to the growing disillusionment with marriage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/1*hWJVTVd2B2velnz8Zg8RJw.png" /></figure><h3>Love Marriages Are Not Immune</h3><p>While many believe that love marriages are a break from the problems of arranged marriages, they too face significant challenges. Even couples who marry for love find that there are issues beyond emotional compatibility. Many do not get enough time to understand each other’s financial situations, work ethics, or lifestyle choices before they tie the knot. Additionally, staying with extended families often causes intimacy problems. Couples do not have a safe space for sex, which leads to tension and conflict. Without the buffer of family involvement, personal differences and sexual intimacy issues can quickly turn into serious conflicts. As a result, love marriages sometimes end up with as many problems as arranged ones.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/747/1*3sDwGAQ15AdXMQoCq3sY-w.png" /></figure><h3>A Growing Trend: Choosing Singlehood</h3><p>The combined weight of false allegations, expensive legal battles, family interference, and the pressures of traditional expectations has driven many to rethink the idea of marriage altogether. With stories of severe financial losses and relentless family pressures, more young people are finding that staying single is a safer, simpler option. They see marriage not as a fulfilling partnership, but as an institution fraught with risk and disappointment.</p><p>What do you think about these trends? Are we witnessing the end of marriage as we know it in India? Share your thoughts and join the conversation in the comments below.</p><blockquote>Btw, I run a Content Consulting Firm. If you need help with your content needs, reach out at vardhanam@k42consulting.com :)</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cde247a00538" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Distributed Deployment of Qdrant Cluster with Sharding & Replicas]]></title>
            <link>https://medium.com/@vardhanam.daga/distributed-deployment-of-qdrant-cluster-with-sharding-replicas-e7923d483ebc?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/e7923d483ebc</guid>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[qdrant]]></category>
            <category><![CDATA[retrieval-augmented]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Fri, 24 May 2024 06:24:52 GMT</pubDate>
            <atom:updated>2024-05-24T06:24:52.863Z</atom:updated>
            <content:encoded><![CDATA[<h4>Segregating your vector data into multiple nodes to enhance resiliency, scalability, and performance.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/693/1*CkclN5FAKixUUOSfNaKISw.png" /><figcaption>Shot from 2001: A Space Odyssey, the astronaut David Bowman, one by one, removes the distributed modules of the supercomputer HAL, who has gone rogue.</figcaption></figure><h3>Problem Statement</h3><p>In this blog, we are going to address the challenges faced by a single node Qdrant setup. And then we are going to demonstrate how we can overcome it by deploying a distributed node setup. By the end of this blog, you will have both a conceptual understanding of distributed networks as well as the technical know-hows of setting it up.</p><h3>Key Features of a Distributed Deployment Setup in Qdrant</h3><p>To understand what distributed deployment is, it is important to first understand the following features:</p><h3>Single Node Qdrant</h3><p>A single node <a href="https://qdrant.tech/documentation/quick-start/">Qdrant</a> setup uses one server to store and manage all the data and processes. It is less expensive and simpler to set up, but has notable drawbacks. If the server goes down for any reason, such as maintenance or a breakdown, the entire Qdrant service will become unavailable. Furthermore, the performance of the service is limited to what a single server can handle.</p><h3>Qdrant Cluster</h3><p>A Qdrant Cluster is a more advanced setup that involves multiple servers, known as nodes, working together. This arrangement distributes the data and workload among several servers, which offers multiple benefits over a single node setup. It’s more resilient because if one server has an issue, the others can keep the service running. It also allows for scalability, meaning more servers can be added as needed to handle more data or more user requests, thus enhancing overall performance.</p><h3>Cluster Communication</h3><p>In a cluster, the servers communicate using the Raft consensus protocol. This protocol helps keep the servers synchronized, ensuring that they all agree upon any changes or updates before they are made. This coordination is crucial for maintaining data accuracy and consistency across the cluster.</p><p>For operations on individual points though, Qdrant prioritizes speed and availability over strict adherence to this protocol, which allows for faster processing without the complexity of coordinating every detail across all servers.</p><h3>Sharding</h3><p>Sharding is a technique to break down a database into different segments. In Qdrant, a collection can be divided into multiple shards, each representing a self-contained store of points.</p><p>This distribution allows for parallel processing of search requests, leading to significant performance improvements. Qdrant supports both automatic sharding, where points are distributed based on a consistent hashing algorithm, and user-defined sharding, offering more control over data placement for specific use cases.</p><h3>Importance of Distributed Development</h3><p>Distributed development, which involves spreading out data and processing across multiple locations or servers, is essential for creating systems that are reliable and can scale according to demand. In the context of Qdrant, this approach offers several key advantages:</p><p>- <strong>Resilience:</strong> By distributing operations across multiple servers, the system can still function even if one server fails.</p><p>- <strong>Scalability:</strong> It’s easier to handle more data and more users by adding more servers to the system.</p><p>- <strong>Performance:</strong> Distributing the workload helps speed up data processing and retrieval by allowing multiple operations to run in parallel across different servers.</p><h3>How to Launch a Multi-Node Cluster on Qdrant</h3><p>We’ll use Docker Compose to launch a 4-node Qdrant Cluster setup. First create a file called docker-compose.yml and paste the following in it:</p><pre>services:<br>  qdrant_node1:<br>    image: qdrant/qdrant:v1.9.1<br>    container_name: qdrant_node1<br>    volumes:<br>      - ./data/node1:/qdrant/storage<br>    ports:<br>      - &quot;6333:6333&quot;<br>    environment:<br>      QDRANT__CLUSTER__ENABLED: &quot;true&quot;<br>    command: &quot;./qdrant --uri http://qdrant_node1:6335&quot;<br><br><br>  qdrant_node2:<br>    image: qdrant/qdrant:v1.9.1<br>    container_name: qdrant_node2<br>    volumes:<br>      - ./data/node2:/qdrant/storage<br>    depends_on:<br>      - qdrant_node1<br>    environment:<br>      QDRANT__CLUSTER__ENABLED: &quot;true&quot;<br>    command: &quot;./qdrant --bootstrap http://qdrant_node1:6335 --uri http://qdrant_node2:6335&quot;<br><br><br>  qdrant_node3:<br>    image: qdrant/qdrant:v1.9.1<br>    container_name: qdrant_node3<br>    volumes:<br>      - ./data/node3:/qdrant/storage<br>    depends_on:<br>      - qdrant_node1<br>    environment:<br>      QDRANT__CLUSTER__ENABLED: &quot;true&quot;<br>    command: &quot;./qdrant --bootstrap http://qdrant_node1:6335 --uri http://qdrant_node3:6335&quot;<br><br><br>  qdrant_node4:<br>    image: qdrant/qdrant:v1.9.1<br>    container_name: qdrant_node4<br>    volumes:<br>      - ./data/node4:/qdrant/storage<br>    depends_on:<br>      - qdrant_node1<br>    environment:<br>      QDRANT__CLUSTER__ENABLED: &quot;true&quot;<br>    command: &quot;./qdrant --bootstrap http://qdrant_node1:6335 --uri http://qdrant_node4:6335&quot;<br></pre><p>The Docker Compose file defines four services, each corresponding to a Qdrant node in the cluster. Here’s what each section generally specifies:</p><p>Common elements for all nodes:</p><ul><li>image: Specifies the Docker image to use for the container. All nodes use qdrant/qdrant:v1.9.1.</li><li>container_name: Assigns a unique name to each container running a Qdrant node.</li><li>volumes: Maps a local directory (./data/nodeX) to a directory inside the container (/qdrant/storage). This setup is used for data persistence across container restarts.</li><li>environment: Sets environment variables inside the container. QDRANT__CLUSTER__ENABLED: “true” enables cluster mode in each Qdrant node.</li></ul><p>Specifics for individual nodes:</p><ul><li>qdrant_node1</li><li>ports: Maps port 6333 on the host to port 6333 on the container, used for API access to the Qdrant service.</li><li>command: Specifies the command to run inside the container. For qdrant_node1, it initializes with its own URI for cluster communication (http://qdrant_node1:6335).</li><li>qdrant_node2, qdrant_node3, qdrant_node4</li><li>depends_on: Ensures that these nodes start only after qdrant_node1 has started. This dependency is crucial because the subsequent nodes need to connect to the first node for cluster setup.</li><li>command: For these nodes, the command includes both a — bootstrap option pointing to qdrant_node1 (to join the cluster) and a — uri with their own unique URI. This setup is necessary for proper communication within the cluster.</li></ul><p>To launch the cluster, run the following command:</p><pre>docker-compose up</pre><p>Now you can access the cluster via the Qdrant client:</p><pre>from qdrant_client import QdrantClient<br><br># Initialize the Qdrant client<br>client = QdrantClient(host=&quot;localhost&quot;, port=6333)</pre><p>Next, let’s define the collection and the shard_key.</p><pre>collection_name = &quot;sharding_collection&quot;<br>key = &quot;tempKey&quot;<br><br><br># Deleting an existing collection if it exists<br>response = client.delete_collection(collection_name=f&quot;{collection_name}&quot;)<br><br><br># Creating a new collection with specific configuration<br>response = client.create_collection(<br>    collection_name=f&quot;{collection_name}&quot;,<br>    shard_number=6,<br>    sharding_method=models.ShardingMethod.CUSTOM,<br>    vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE),<br>    replication_factor= 2,<br>)<br><br><br># Creating a shard key for the collection<br>response = client.create_shard_key(f&quot;{collection_name}&quot;, f&quot;{key}&quot;)</pre><p>Shard Number implies the number of shards per Shard Key. Replication factor implies the number of times the shards are replicated evenly across all the nodes.</p><p>In this case, since we have defined only 1 Shard Key, the total number of Physical Shards would be 1*6*2 = 12.</p><p>Now let’s input some random vectors into our cluster using the shard key.</p><pre># Counter for generating unique point IDs<br>point_counter = 0<br><br><br># Function to generate a random vector of 768 dimensions with up to 15 decimal points<br>def generate_random_vector():<br>    return [round(random.uniform(0, 1), 15) for _ in range(768)]<br><br><br># Run the loop 1000 times<br>for _ in range(1000):<br>    random_vector = generate_random_vector()<br>    point_counter += 1<br>    response = client.upsert(<br>        collection_name=f&quot;{collection_name}&quot;,<br>        points=[<br>            models.PointStruct(<br>                id=point_counter,<br>                vector=random_vector,<br>            ),<br>        ],<br>        shard_key_selector=f&quot;{key}&quot;,<br>    )</pre><h3>What Happens When We Turn Off a Node?</h3><p>If we have configured our setup to be a 3+ node cluster with a replication factor of at least 2, then even if we stop one node, it’s not going to affect any operations going on in the cluster.</p><p>Let’s test that out.</p><p>First get ids of the containers using:</p><pre>docker ps</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*S56TE9ztibSTmFTB" /></figure><p>Now let’s stop qdrant_node3.</p><pre>docker stop 0b7fac4c224a</pre><p>Next, let’s investigate our collection.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/0*rV2NGUqh209Ni6Wg" /></figure><p>Even though we switched off a node, we can still access all the points we’ve inserted into our collection!</p><h3>Data Distribution between Shards</h3><p>To see how the data is distributed amongst the shards, we need to make a GET request in the following manner.</p><pre>curl localhost:6333/collections/sharding_collection/cluster</pre><p>{“result”:{“peer_id”:2024384091823610,”shard_count”:6,”local_shards”:[{“shard_id”:2,”shard_key”:”tempKey”,”points_count”:135,”state”:”Active”},{“shard_id”:4,”shard_key”:”tempKey”,”points_count”:178,”state”:”Active”},{“shard_id”:6,”shard_key”:”tempKey”,”points_count”:155,”state”:”Active”}],”remote_shards”:[{“shard_id”:1,”shard_key”:”tempKey”,”peer_id”:8555640407930483,”state”:”Active”},{“shard_id”:1,”shard_key”:”tempKey”,”peer_id”:3252676105267795,”state”:”Active”},{“shard_id”:2,”shard_key”:”tempKey”,”peer_id”:3088601394550397,”state”:”Active”},{“shard_id”:3,”shard_key”:”tempKey”,”peer_id”:8555640407930483,”state”:”Active”},{“shard_id”:3,”shard_key”:”tempKey”,”peer_id”:3252676105267795,”state”:”Active”},{“shard_id”:4,”shard_key”:”tempKey”,”peer_id”:3088601394550397,”state”:”Active”},{“shard_id”:5,”shard_key”:”tempKey”,”peer_id”:3252676105267795,”state”:”Active”},{“shard_id”:5,”shard_key”:”tempKey”,”peer_id”:8555640407930483,”state”:”Active”},{“shard_id”:6,”shard_key”:”tempKey”,”peer_id”:3088601394550397,”state”:”Active”}],”shard_transfers”:[]},”status”:”ok”,”time”:0.000067336}</p><p>To know the node by their peer_id, we’ll run:</p><pre>curl http://localhost:6333/cluster</pre><p>{“result”:{“status”:”enabled”,”peer_id”:2024384091823610,”peers”:{“3252676105267795”:{“uri”:”http://qdrant_node2:6335/&quot;},&quot;8555640407930483&quot;:{&quot;uri&quot;:&quot;http://qdrant_node3:6335/&quot;},&quot;2024384091823610&quot;:{&quot;uri&quot;:&quot;http://qdrant_node1:6335/&quot;},&quot;3088601394550397&quot;:{&quot;uri&quot;:&quot;http://qdrant_node4:6335/&quot;}},&quot;raft_info&quot;:{&quot;term&quot;:10,&quot;commit&quot;:40,&quot;pending_operations&quot;:0,&quot;leader&quot;:2024384091823610,&quot;role&quot;:&quot;Leader&quot;,&quot;is_voter&quot;:true},&quot;consensus_thread_status&quot;:{&quot;consensus_thread_status&quot;:&quot;working&quot;,&quot;last_update&quot;:&quot;2024-05-22T13:26:49.305470782Z&quot;},&quot;message_send_failures&quot;:{}},&quot;status&quot;:&quot;ok&quot;,&quot;time&quot;:0.000058492}</p><p>Analyzing the above results, and putting them in a clear format, we get:</p><ul><li>Node1 (current peer) has shards 2, 4, and 6.</li><li>Node 3 has shards 1, 3, and 5.</li><li>Node 2 has shards 1, 3, and 5.</li><li>Node 4 has shards 2, 4, and 6.</li></ul><p>By looking at the above distribution we see that each shard is available on 2 different nodes, and therefore even if one of the nodes fails, the cluster will continue to function.</p><h3>Final Words</h3><p>Multi-node clusters, sharding, and replicas are essential features for production environments. Multi-node clusters distribute the workload and enhance system resilience against individual node failures. Sharding divides data across multiple nodes, facilitating parallel processing that boosts performance and scalability. Replication ensures data availability, even if some nodes fail. Together, these techniques can create a robust and fault-tolerant system capable of reliably handling production-level demands.</p><h3>References</h3><p><a href="https://qdrant.tech/documentation/guides/distributed_deployment/">https://qdrant.tech/documentation/guides/distributed_deployment/</a></p><p><a href="https://github.com/Mohitkr95/qdrant-multi-node-cluster/tree/main">https://github.com/Mohitkr95/qdrant-multi-node-cluster/tree/main</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e7923d483ebc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Multi-Hop Retrieval and Reasoning for Complex Questions Using DSPy, Qdrant, and Llama3]]></title>
            <link>https://blog.stackademic.com/multi-hop-retrieval-and-reasoning-for-complex-questions-using-dspy-qdrant-and-llama3-841580138a81?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/841580138a81</guid>
            <category><![CDATA[vector-database]]></category>
            <category><![CDATA[retrieval-augmented]]></category>
            <category><![CDATA[dspy]]></category>
            <category><![CDATA[qdrant]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Thu, 16 May 2024 06:24:53 GMT</pubDate>
            <atom:updated>2024-05-17T00:33:59.581Z</atom:updated>
            <content:encoded><![CDATA[<h4>Leveraging the no-prompt framework of DSPy for complex LLM question-answering</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4HVzY9fvzNQAvw7yuv-zaw.png" /></figure><h3>What Is a Multi-Hop Question?</h3><p>A multi-hop question is a type of question that requires multiple steps or “hops” to arrive at an answer. Rather than being a straightforward query with a single answer, a multi-hop question involves breaking down the original question into smaller parts, each of which requires its own analysis.</p><p>They typically require critical thinking skills and the ability to connect information from different sources or domains. Multi-hop questions are common in complex problem-solving scenarios and research tasks, where the goal is to assess not only factual knowledge but also the ability to reason and synthesize information.</p><p>Here’s an example of a multi-hop question:</p><p><strong>Texts:</strong></p><p>- Text 1: “The Nile is the longest river in Africa and flows through several countries including Egypt and Sudan.”</p><p>- Text 2: “The ancient city of Thebes was located in Egypt along the banks of the Nile.”</p><p>- Text 3: “Thebes was known for its vast number of temples and was often referred to as the city of a hundred gates.”</p><p><strong>Multi-Hop Question:</strong></p><p>- “Which city known for its many temples was located along the longest river in Africa?”</p><p>How to Answer:</p><p>- First Hop: Identify the longest river in Africa. From Text 1, we learn it’s the Nile.</p><p>- Second Hop: Determine which city known for its many temples was situated along the Nile. From Texts 2 and Text 3, we can conclude that Thebes, known for its temples, was located along the Nile in Egypt.</p><p><strong>Answer:</strong> Thebes</p><h3>Challenges of Creating a Multi-Hop LLM Agent</h3><p>Creating a Large Language Model (LLM) agent for multi-hop question-answering is particularly challenging due to the necessary prompt engineering involved.</p><p>This complex process requires the model to engage in multiple rounds of prompting where the main question must be deconstructed into manageable sub-questions. Each sub-question is then sequentially addressed, gathering the essential information step-by-step.</p><p>This meticulous structuring of prompts is crucial as it guides the LLM to navigate through and gather information from various sources effectively, ensuring a coherent and accurate final answer based solely on the initial, complex inquiry.</p><p>Therefore, in order to create an efficient multi-hop LLM application, one needs to invest a significant amount of time and effort in prompt engineering.</p><p>This process of prompt engineering is often a hit-and-trial method, where the developer has to tweak their prompts iteratively until they are satisfied with the LLM’s responses. Moreover, prompt templates are LLM specific — meaning different LLMs respond correctly to different types of prompting templates.</p><p>All of this makes multi-hop question-answering a rather complicated process.</p><p>Enter <a href="https://github.com/stanfordnlp/dspy">DSPy</a>, a framework specially designed to do away with traditional prompt engineering methodologies.</p><h3>How DSPy Takes Care of Prompt Engineering</h3><p><a href="https://github.com/stanfordnlp/dspy">DSPy</a> has out-of-the-box prompting modules especially designed for various use-cases of LLM question-answering. It prioritizes programming over manual prompting, aiming to streamline tasks that traditionally required intricate prompt crafting or intensive model tweaking.</p><p>The framework introduces structured components like Signatures, Modules, and Optimizers to automate prompting for arbitrary pipelines, making the development process more efficient and effective.</p><h3>Building a Multi-Hop RAG Pipeline with DSPy, Qdrant, and Ollama</h3><p>DSPy has a readymade set of modules which can be used to construct a RAG pipeline that is capable of performing multi-hop question-answering.</p><p>In this tutorial, we’ll use <a href="https://qdrant.tech/">Qdrant </a>as our vector database to store the external information, and we’ll connect it to the LLM Llama3 using <a href="https://ollama.com/">Ollama</a>. Then we’ll use the tools provided by DSPy to build our multi-hop RAG.</p><p>First create a requirements.txt file.</p><pre>dspy-ai<br>qdrant-client<br>ollama<br>wikipedia<br>fastembed<br>langchain</pre><p>Install the modules by running ```pip install -r requirements.txt```</p><p>We’ll use a recursive text character splitter from LangChain to chunk our input documents.</p><pre>from langchain_text_splitters import RecursiveCharacterTextSplitter<br><br><br>text_splitter = RecursiveCharacterTextSplitter(<br>    # Set a really small chunk size, just to show.<br>    chunk_size=512,<br>    chunk_overlap=20,<br>    length_function=len,<br>    is_separator_regex=False,<br>)</pre><p>We’ll use the Wikipedia information on Leonardo DiCaprio as our external document set for the RAG pipeline.</p><pre>from langchain_community.document_loaders import WikipediaLoader<br><br><br>docs = WikipediaLoader(query=&quot;Leonardo DiCaprio&quot;).load_and_split(text_splitter = text_splitter )</pre><pre># List to hold the content of each document<br>doc_contents = [doc.page_content for doc in docs]<br><br><br># List to hold the IDs for each document<br>doc_ids = list(range(1, len(docs) + 1))</pre><pre>doc_contents[0]</pre><blockquote>“Leonardo Wilhelm DiCaprio (; Italian: [diˈkaːprjo]; born November 11, 1974) is an American actor and film producer. Known for his work in biographical and period films, he is the recipient of numerous accolades, including an Academy Award, a British Academy Film Award, and three Golden Globe Awards. As of 2019, his films have grossed over $7.2 billion worldwide, and he has been placed eight times in annual rankings of the world’s highest-paid actors.”</blockquote><p>Next, we’ll add all these documents into the Qdrant Vector DB. By default, Qdrant uses FastEmbed to calculate the embeddings of the text documents.</p><pre>from qdrant_client import QdrantClient<br><br><br># Initialize the client<br>client = QdrantClient(&quot;:memory:&quot;)<br><br><br>client.add(<br>    collection_name=&quot;leo_collection&quot;,<br>    documents=doc_contents,<br>    ids=doc_ids,<br>)</pre><p>Now configure the Qdrant Retriever and Llama3 into DSPy.</p><pre>from dspy.retrieve.qdrant_rm import QdrantRM<br>import dspy<br><br><br>qdrant_retriever_model = QdrantRM(&quot;leo_collection&quot;, client, k=10)<br><br><br>ollama_model = dspy.OllamaLocal(model=&quot;llama3&quot;,model_type=&#39;text&#39;,<br>                                max_tokens=350,<br>                                temperature=0.1,<br>                                top_p=0.8, frequency_penalty=1.17, top_k=40)<br><br><br>dspy.settings.configure(lm= ollama_model, rm=qdrant_retriever_model)</pre><p>You can refer to <a href="https://github.com/ollama/ollama">this</a> to install Ollama. Make sure you have pulled llama3 br running ```ollama pull llama3```</p><p>We’ll first define a DSPy signature which will generate an answer given a context and a question.</p><pre>class GenerateAnswer(dspy.Signature):<br>    &quot;&quot;&quot;Answer questions with short factoid answers.&quot;&quot;&quot;<br><br><br>    context = dspy.InputField(desc=&quot;may contain relevant facts&quot;)<br>    question = dspy.InputField()<br>    answer = dspy.OutputField()</pre><p>Then we’ll define another signature which will help define the intermediate query for the multi-hop.</p><pre>class GenerateSearchQuery(dspy.Signature):<br>    &quot;&quot;&quot;Write a simple search query that will help answer a complex question.&quot;&quot;&quot;<br><br><br>    context = dspy.InputField(desc=&quot;may contain relevant facts&quot;)<br>    question = dspy.InputField()<br>    query = dspy.OutputField()</pre><p>Then we’ll construct a DSPy module that will generate intermediate queries to collect all the relevant context and then use that to answer the user’s questions.</p><pre>from dsp.utils import deduplicate<br><br><br>class SimplifiedBaleen(dspy.Module):<br>    def __init__(self, passages_per_hop=3, max_hops=2):<br>        super().__init__()<br><br><br>        self.generate_query = [dspy.ChainOfThought(GenerateSearchQuery) for _ in range(max_hops)]<br>        self.retrieve = dspy.Retrieve(k=passages_per_hop)<br>        self.generate_answer = dspy.ChainOfThought(GenerateAnswer)<br>        self.max_hops = max_hops<br><br><br>    def forward(self, question):<br>        context = []<br><br><br>        for hop in range(self.max_hops):<br>            query = self.generate_query[hop](context=context, question=question).query<br>            passages = self.retrieve(query).passages<br>            context = deduplicate(context + passages)<br><br><br>        pred = self.generate_answer(context=context, question=question)<br>        return dspy.Prediction(context=context, answer=pred.answer)</pre><p>The `__init__` method in our code sets up several important components:</p><p>- generate_query: For each step, or “hop,” in our process, this component uses a special tool called dspy.ChainOfThought with the GenerateSearchQuery setup to create a search query. dspy.ChainOfThought makes sure that the LLM reasons through the prompts in a step-by-step fashion.</p><p>- retrieve: This component takes the search queries and finds relevant information from the Qdrant database using the dspy.Retrieve module.</p><p>- generate_answer: After gathering all the required information, this dspy.Predict module, configured with the GenerateAnswer setup, is used to formulate the final response.</p><p>In the `forward` method, the process is laid out in a sequence of steps:</p><p>1. We loop through a set number of times, defined by `self.max_hops`.</p><p>2. In each cycle of the loop:</p><p>- A search query is generated using the generate_query component for the current hop.</p><p>- This query is used to fetch the top relevant pieces of information (top-k passages).</p><p>- We collect these passages, ensuring there are no duplicates, and add them to our collection of context information.</p><p>3. After completing all the hops, we use the generate_answer component to create the final answer based on the accumulated context.</p><p>4. Finally, the process returns a prediction that includes both the gathered context and the generated answer.</p><p>Now let’s try asking a multi-hop question to our pipeline:</p><pre># Ask any question you like to this simple RAG program.<br>my_question = &quot;Give me all the co-actors of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?&quot;<br><br><br># Get the prediction. This contains `pred.context` and `pred.answer`.<br>uncompiled_baleen = SimplifiedBaleen()  # uncompiled (i.e., zero-shot) program<br>pred = uncompiled_baleen(my_question)<br><br><br># Print the contexts and the answer.<br>print(f&quot;Question: {my_question}&quot;)<br>print(f&quot;Predicted Answer: {pred.answer}&quot;)<br>print(f&quot;Retrieved Contexts (truncated): {[c[:200] + &#39;...&#39; for c in pred.context]}&quot;)</pre><blockquote>Question: Give me all the co-actors of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?</blockquote><blockquote>Predicted Answer: Jesse Plemons, Tantoo Cardinal, John Lithgow, and Brendan Fraser.</blockquote><blockquote>Retrieved Contexts (truncated): [‘Leonardo DiCaprio, Robert De Niro, and Lily Gladstone lead an ensemble cast, also including Jesse Plemons, Tantoo Cardinal, John Lithgow, and Brendan Fraser. It is the sixth feature film collaboration…’, ‘== Film ==\n\n\n=== As actor ===\n\n\n=== As producer ===\n\n\n== Television ==\n\n\n== Notes ==\n\n\n== See also ==\nList of awards and nominations received by Leonardo DiCaprio\n\n\n== References ==\n\n\n== External link…’, “The duo’s films have been nominated for thirty-one Academy Awards, winning nine. In 2013, the duo was awarded National Board of Review Spotlight award for career collaboration. Scorsese’s work with Di…”, ‘== References ==\n\n\n== External links ==\nGeorge DiCaprio at IMDb…’]</blockquote><p>We can inspect the entire prompting process that went under the hood by running the following command:</p><pre>ollama_model.inspect_history(n=3)</pre><blockquote>Write a simple search query that will help answer a complex question.</blockquote><blockquote>— -</blockquote><blockquote>Follow the following format.</blockquote><blockquote>Context: may contain relevant facts</blockquote><blockquote>Question: ${question}</blockquote><blockquote>Reasoning: Let’s think step by step in order to ${produce the query}. We …</blockquote><blockquote>Query: ${query}</blockquote><blockquote>— -</blockquote><blockquote>Context: N/A</blockquote><blockquote>Question: Give me all the co-stars of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?</blockquote><blockquote>Reasoning: Let’s think step by step in order to Here is a simple search query that can help answer this complex question:</blockquote><blockquote>— -</blockquote><blockquote>Context: N/A</blockquote><blockquote>Question: Give me all the co-stars of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?</blockquote><blockquote>Reasoning: Let’s think step by step in order to produce the query. We need to find a movie where both Leonardo DiCaprio and Robert De Niro appeared, then extract their co-stars from that specific film.</blockquote><blockquote>Query: (Leonardo DiCaprio) AND (Robert De Niro) AND (“co-star” OR “cast list”) -site:imdb.com</blockquote><blockquote>This query uses the following search operators:</blockquote><blockquote>* `(Leonardo DiCaprio)` and `(Robert De Niro)` are exact phrase searches to ensure we’re searching for both actors’ names.</blockquote><blockquote>* `AND` connects these two phrases, requiring them to appear together in a single result.</blockquote><blockquote>* `”co-star” OR “cast list”` is a quoted search that looks for either the words “co-star” or “cast list” (or variations) within the results. This helps us find pages with lists of co-stars from specific movies.</blockquote><blockquote>* `-site:imdb.com` excludes IMDb’s website from our search results, as we’re looking for information not already available on their site.</blockquote><blockquote>By combining these operators and phrases, this query should return a list of movie titles where both Leonardo DiCaprio and Robert De Niro appeared together, along with the names of their co-stars in those films.</blockquote><blockquote>Write a simple search query that will help answer a complex question.</blockquote><blockquote>— -</blockquote><blockquote>Follow the following format.</blockquote><blockquote>Context: may contain relevant facts</blockquote><blockquote>Question: ${question}</blockquote><blockquote>Reasoning: Let’s think step by step in order to ${produce the query}. We …</blockquote><blockquote>Query: ${query}</blockquote><blockquote>— -</blockquote><blockquote>Context:</blockquote><blockquote>[1] «Leonardo DiCaprio, Robert De Niro, and Lily Gladstone lead an ensemble cast, also including Jesse Plemons, Tantoo Cardinal, John Lithgow, and Brendan Fraser. It is the sixth feature film collaboration between Scorsese and DiCaprio, the tenth between Scorsese and De Niro, and the first between Scorsese and both actors overall (they previously all collaborated on the 2015 short film The Audition), and the eleventh and final between Scorsese and composer Robbie Robertson, who died two months prior to the»</blockquote><blockquote>[2] «== Film ==</blockquote><blockquote>=== As actor ===</blockquote><blockquote>=== As producer ===</blockquote><blockquote>== Television ==</blockquote><blockquote>== Notes ==</blockquote><blockquote>== See also ==</blockquote><blockquote>List of awards and nominations received by Leonardo DiCaprio</blockquote><blockquote>== References ==</blockquote><blockquote>== External links ==</blockquote><blockquote>Leonardo DiCaprio filmography at IMDb</blockquote><blockquote>Leonardo DiCaprio at the TCM Movie Database»</blockquote><blockquote>[3] «The duo’s films have been nominated for thirty-one Academy Awards, winning nine. In 2013, the duo was awarded National Board of Review Spotlight award for career collaboration. Scorsese’s work with DiCaprio is considered to be as vital as his work with Robert De Niro.»</blockquote><blockquote>Question: Give me all the co-stars of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?</blockquote><blockquote>Reasoning: Let’s think step by step in order to — -</blockquote><blockquote>Context:</blockquote><blockquote>[1] «Leonardo DiCaprio, Robert De Niro, and Lily Gladstone lead an ensemble cast…»</blockquote><blockquote>Question: Give me all the co-stars of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?</blockquote><blockquote>Reasoning: Let’s think step by step to produce a query. We know that we need to find information about movies where both Leonardo DiCaprio and Robert De Niro have appeared together as actors.</blockquote><blockquote>Query: (Leonardo DiCaprio AND Robert De Niro) site:movies</blockquote><blockquote>This search query uses the following techniques:</blockquote><blockquote>* The parentheses around the names ensure that they are searched for in combination, rather than separately.</blockquote><blockquote>* The “AND” operator is used to require both names to appear in the same movie.</blockquote><blockquote>* The “site:” operator limits the search results to web pages with a URL containing “movies”, which should help us focus on relevant information about movies.</blockquote><blockquote>By using this query, we can find articles or websites that list the co-stars of Leonardo DiCaprio in movies where he has appeared alongside Robert De Niro.</blockquote><blockquote>Answer questions with short factoid answers.</blockquote><blockquote>— -</blockquote><blockquote>Follow the following format.</blockquote><blockquote>Context: may contain relevant facts</blockquote><blockquote>Question: ${question}</blockquote><blockquote>Reasoning: Let’s think step by step in order to ${produce the answer}. We …</blockquote><blockquote>Answer: ${answer}</blockquote><blockquote>— -</blockquote><blockquote>Context:</blockquote><blockquote>[1] «Leonardo DiCaprio, Robert De Niro, and Lily Gladstone lead an ensemble cast, also including Jesse Plemons, Tantoo Cardinal, John Lithgow, and Brendan Fraser. It is the sixth feature film collaboration between Scorsese and DiCaprio, the tenth between Scorsese and De Niro, and the first between Scorsese and both actors overall (they previously all collaborated on the 2015 short film The Audition), and the eleventh and final between Scorsese and composer Robbie Robertson, who died two months prior to the»</blockquote><blockquote>[2] «== Film ==</blockquote><blockquote>=== As actor ===</blockquote><blockquote>=== As producer ===</blockquote><blockquote>== Television ==</blockquote><blockquote>== Notes ==</blockquote><blockquote>== See also ==</blockquote><blockquote>List of awards and nominations received by Leonardo DiCaprio</blockquote><blockquote>== References ==</blockquote><blockquote>== External links ==</blockquote><blockquote>Leonardo DiCaprio filmography at IMDb</blockquote><blockquote>Leonardo DiCaprio at the TCM Movie Database»</blockquote><blockquote>[3] «The duo’s films have been nominated for thirty-one Academy Awards, winning nine. In 2013, the duo was awarded National Board of Review Spotlight award for career collaboration. Scorsese’s work with DiCaprio is considered to be as vital as his work with Robert De Niro.»</blockquote><blockquote>[4] «== References ==</blockquote><blockquote>== External links ==</blockquote><blockquote>George DiCaprio at IMDb»</blockquote><blockquote>Question: Give me all the co-stars of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?</blockquote><blockquote>Reasoning: Let’s think step by step in order to — -</blockquote><blockquote>Context:</blockquote><blockquote>[1] «Leonardo DiCaprio, Robert De Niro, and Lily Gladstone lead an ensemble cast…»</blockquote><blockquote>Question: Give me all the co-stars of Leonardo DiCaprio in the movie in which one of his co-stars was Robert De Niro?</blockquote><blockquote>Reasoning: Let’s think step by step to find out who else starred alongside Leonardo DiCaprio and Robert De Niro.</blockquote><blockquote>Answer: According to [1], the other co-stars were Jesse Plemons, Tantoo Cardinal, John Lithgow, and Brendan Fraser.</blockquote><p>We tried the above workflow with a different set of documents and questions.</p><pre>docs = WikipediaLoader(query=&quot;devops&quot;).load_and_split(text_splitter = text_splitter )</pre><p>We populated the vector store Qdrant with documents related to “devops”. And then we asked the following question:</p><pre>my_question = &quot;&quot;&quot;Given a DevOps environment where automated testing and continuous integration are fully implemented,<br>consider a scenario where a new version of the software is planned for release. First, identify what type of automated<br>tests would likely be run first as part of the CI pipeline. Then, assuming there are failures in these initial tests,<br>explain how the use of Infrastructure as Code (IaC) could potentially impact the resolution of these failures.&quot;&quot;&quot;<br><br><br># Get the prediction. This contains `pred.context` and `pred.answer`.<br>uncompiled_baleen = SimplifiedBaleen()  # uncompiled (i.e., zero-shot) program<br>pred = uncompiled_baleen(my_question)<br><br><br># Print the contexts and the answer.<br>print(f&quot;Question: {my_question}&quot;)<br>print(f&quot;Predicted Answer: {pred.answer}&quot;)<br>print(f&quot;Retrieved Contexts (truncated): {[c[:200] + &#39;...&#39; for c in pred.context]}&quot;)</pre><blockquote>Predicted Answer: The initial automated tests that would likely be run first as part of the CI pipeline are unit tests. These tests verify individual components or units of code work correctly.</blockquote><blockquote>If these initial unit tests fail, Infrastructure as Code (IaC) could potentially impact resolution in several ways:</blockquote><blockquote>1. **Infrastructure consistency**: IaC ensures consistent infrastructure configuration across environments, reducing errors and making it easier to reproduce issues.</blockquote><blockquote>2. **Automated remediation**: With IaC, you can automate the creation of a new environment or restore a previous one if there’s an issue with the current setup.</blockquote><blockquote>3. **Version control for infrastructure**: By managing infrastructure as code, you can track changes and roll back to previous versions if needed.</blockquote><blockquote>By leveraging IaC in this scenario, developers can quickly identify and resolve issues related to infrastructure configuration, allowing them to focus on fixing the root cause of the problem rather than manually configuring environments or troubleshooting.</blockquote><blockquote>Retrieved Contexts (truncated): [‘== Definition ==\nOther than it being a cross-functional combination (and a portmanteau) of the terms and concepts for “development” and “operations”, academics and practitioners have not developed a u…’, ‘There are many tools that fulfill infrastructure automation capabilities and use IaC. Broadly speaking, any framework or tool that performs changes or configures infrastructure declaratively or impera…’, ‘The definitions may be in a version control system, rather than maintaining the code through manual processes.\nThe code in the definition files may use either scripts or declarative definitions, but I…’, ‘=== Continuous configuration automation ===\nAll continuous configuration automation (CCA) tools c…’, ‘== Etymology ==\nIn Lessons Learned in Software Testing, Cem Kaner, James Bach, and Brett Pettichord provided the origin of the term: “The phrase smoke test comes from electronic hardware testing. You …’, ‘In software engineering, CI/CD or CICD is the combined practices of continuous integration (CI) and continuous delivery (CD) or, less often, continuous deployment. They are sometimes referred to colle…’]</blockquote><p>This is the prompting process that went on under the hood:</p><pre>ollama_model.inspect_history(n=3)</pre><blockquote>Write a simple search query that will help answer a complex question.</blockquote><blockquote>— -</blockquote><blockquote>Follow the following format.</blockquote><blockquote>Context: may contain relevant facts</blockquote><blockquote>Question: ${question}</blockquote><blockquote>Reasoning: Let’s think step by step in order to ${produce the query}. We …</blockquote><blockquote>Query: ${query}</blockquote><blockquote>— -</blockquote><blockquote>Context: N/A</blockquote><blockquote>Question: Given a DevOps environment where automated testing and continuous integration are fully implemented, consider a scenario where a new version of the software is planned for release. First, identify what type of automated tests would likely be run first as part of the CI pipeline. Then, assuming there are failures in these initial tests, explain how the use of Infrastructure as Code (IaC) could potentially impact the resolution of these failures.</blockquote><blockquote>Reasoning: Let’s think step by step in order to Here is a simple search query that can help answer this complex question:</blockquote><blockquote>— -</blockquote><blockquote>Context: N/A</blockquote><blockquote>Question: Given a DevOps environment where automated testing and continuous integration are fully implemented, consider a scenario where a new version of the software is planned for release. First, identify what type of automated tests would likely be run first as part of the CI pipeline. Then, assuming there are failures in these initial tests, explain how the use of Infrastructure as Code (IaC) could potentially impact the resolution of these failures.</blockquote><blockquote>Reasoning: Let’s think step by step in order to produce a query that can help answer this question.</blockquote><blockquote>Query: (“continuous integration” OR “CI pipeline”) AND (“automated testing” OR “test automation”) AND (“Infrastructure as Code” OR “IaC”) AND (failure* OR error*) — This search query combines relevant terms related to DevOps, automated testing, and Infrastructure as Code. The use of parentheses helps to group the terms logically, allowing for more precise results.</blockquote><blockquote>This query can help answer the question by providing information on:</blockquote><blockquote>1. What types of automated tests are typically run first in a CI pipeline.</blockquote><blockquote>2. How IaC can impact the resolution of failures or errors that occur during these initial tests.</blockquote><blockquote>3. Strategies and best practices for using IaC to manage infrastructure changes and reduce downtime.</blockquote><blockquote>By searching with this query, you should be able to find relevant articles, blog posts, or documentation that provide insights on how to approach this scenario in a DevOps environment.</blockquote><blockquote>Write a simple search query that will help answer a complex question.</blockquote><blockquote>— -</blockquote><blockquote>Follow the following format.</blockquote><blockquote>Context: may contain relevant facts</blockquote><blockquote>Question: ${question}</blockquote><blockquote>Reasoning: Let’s think step by step in order to ${produce the query}. We …</blockquote><blockquote>Query: ${query}</blockquote><blockquote>— -</blockquote><blockquote>Context:</blockquote><blockquote>[1] «== Definition ==</blockquote><blockquote>Other than it being a cross-functional combination (and a portmanteau) of the terms and concepts for “development” and “operations”, academics and practitioners have not developed a universal definition for the term “DevOps”. Most often, DevOps is characterized by key principles: shared ownership, workflow automation, and rapid feedback.»</blockquote><blockquote>[2] «There are many tools that fulfill infrastructure automation capabilities and use IaC. Broadly speaking, any framework or tool that performs changes or configures infrastructure declaratively or imperatively based on a programmatic approach can be considered IaC. Traditionally, server (lifecycle) automation and configuration management tools were used to accomplish IaC. Now enterprises are also using continuous configuration automation tools or stand-alone IaC frameworks, such as Microsoft’s PowerShell DSC»</blockquote><blockquote>[3] «The definitions may be in a version control system, rather than maintaining the code through manual processes.</blockquote><blockquote>The code in the definition files may use either scripts or declarative definitions, but IaC more often employs declarative approaches.»</blockquote><blockquote>Question: Given a DevOps environment where automated testing and continuous integration are fully implemented, consider a scenario where a new version of the software is planned for release. First, identify what type of automated tests would likely be run first as part of the CI pipeline. Then, assuming there are failures in these initial tests, explain how the use of Infrastructure as Code (IaC) could potentially impact the resolution of these failures.</blockquote><blockquote>Reasoning: Let’s think step by step in order to Here is a simple search query that can help answer this complex question:</blockquote><blockquote>— -</blockquote><blockquote>Context:</blockquote><blockquote>[1] «== Definition ==`</blockquote><blockquote>[2] «Infrastructure Automation»</blockquote><blockquote>[3] `Continuous Integration`</blockquote><blockquote>Question: What types of automated tests are typically run first in a CI pipeline, and how does IaC impact the resolution of test failures?</blockquote><blockquote>Reasoning: Let’s think step by step in order to produce the query. We want to identify what type of automated tests would likely be run first as part of the CI pipeline, considering that DevOps environment where automated testing and continuous integration are fully implemented.</blockquote><blockquote>Query: (CI OR Continuous Integration) AND (“automated test” OR “test automation”) AND (“initial test” OR “first test”) -site:.gov</blockquote><blockquote>This query uses a combination of keywords to search for relevant information. The CI or Continuous Integration terms help narrow down the results to discussions about continuous integration and automated testing in DevOps environments. The additional phrases, such as “automated test”, “test automation”, and “initial test” or “first test”, further refine the search by looking for specific types of tests that are typically run first in a CI pipeline. Finally, excluding government (.gov) sites helps to reduce irrelevant results from academic or research-focused sources.</blockquote><blockquote>This query should return relevant information about which types of automated tests are typically run first in a CI pipeline and how IaC might impact the resolution of test failures.</blockquote><blockquote>Answer questions with short factoid answers.</blockquote><blockquote>— -</blockquote><blockquote>Follow the following format.</blockquote><blockquote>Context: may contain relevant facts</blockquote><blockquote>Question: ${question}</blockquote><blockquote>Reasoning: Let’s think step by step in order to ${produce the answer}. We …</blockquote><blockquote>Answer: ${answer}</blockquote><blockquote>— -</blockquote><blockquote>Context:</blockquote><blockquote>[1] «== Definition ==</blockquote><blockquote>Other than it being a cross-functional combination (and a portmanteau) of the terms and concepts for “development” and “operations”, academics and practitioners have not developed a universal definition for the term “DevOps”. Most often, DevOps is characterized by key principles: shared ownership, workflow automation, and rapid feedback.»</blockquote><blockquote>[2] «There are many tools that fulfill infrastructure automation capabilities and use IaC. Broadly speaking, any framework or tool that performs changes or configures infrastructure declaratively or imperatively based on a programmatic approach can be considered IaC. Traditionally, server (lifecycle) automation and configuration management tools were used to accomplish IaC. Now enterprises are also using continuous configuration automation tools or stand-alone IaC frameworks, such as Microsoft’s PowerShell DSC»</blockquote><blockquote>[3] «The definitions may be in a version control system, rather than maintaining the code through manual processes.</blockquote><blockquote>The code in the definition files may use either scripts or declarative definitions, but IaC more often employs declarative approaches.»</blockquote><blockquote>[4] «=== Continuous configuration automation ===</blockquote><blockquote>All continuous configuration automation (CCA) tools c»</blockquote><blockquote>[5] «== Etymology ==</blockquote><blockquote>In Lessons Learned in Software Testing, Cem Kaner, James Bach, and Brett Pettichord provided the origin of the term: “The phrase smoke test comes from electronic hardware testing. You plug in a new board and turn on the power. If you see smoke coming from the board, turn off the power. You don’t have to do any more testing.”</blockquote><blockquote>== See also ==</blockquote><blockquote>“Hello, World!” program</blockquote><blockquote>Sanity testing</blockquote><blockquote>Shakedown</blockquote><blockquote>== References ==</blockquote><blockquote>== External links ==</blockquote><blockquote>PC Mag’s Definition»</blockquote><blockquote>[6] «In software engineering, CI/CD or CICD is the combined practices of continuous integration (CI) and continuous delivery (CD) or, less often, continuous deployment. They are sometimes referred to collectively as continuous development or continuous software development.»</blockquote><blockquote>Question: Given a DevOps environment where automated testing and continuous integration are fully implemented, consider a scenario where a new version of the software is planned for release. First, identify what type of automated tests would likely be run first as part of the CI pipeline. Then, assuming there are failures in these initial tests, explain how the use of Infrastructure as Code (IaC) could potentially impact the resolution of these failures.</blockquote><blockquote>Reasoning: Let’s think step by step in order to Context:</blockquote><blockquote>* DevOps environment with automated testing and continuous integration implemented</blockquote><blockquote>* New version of software planned for release</blockquote><blockquote>Question: What type of automated tests would likely be run first as part of the CI pipeline, and how could IaC impact resolution if there are failures?</blockquote><blockquote>Reasoning: Let’s think step by step in order to…</blockquote><blockquote>Answer:</blockquote><blockquote>The initial automated tests that would likely be run first as part of the CI pipeline are unit tests. These tests verify individual components or units of code work correctly.</blockquote><blockquote>If these initial unit tests fail, Infrastructure as Code (IaC) could potentially impact resolution in several ways:</blockquote><blockquote>1. **Infrastructure consistency**: IaC ensures consistent infrastructure configuration across environments, reducing errors and making it easier to reproduce issues.</blockquote><blockquote>2. **Automated remediation**: With IaC, you can automate the creation of a new environment or restore a previous one if there’s an issue with the current setup.</blockquote><blockquote>3. **Version control for infrastructure**: By managing infrastructure as code, you can track changes and roll back to previous versions if needed.</blockquote><blockquote>By leveraging IaC in this scenario, developers can quickly identify and resolve issues related to infrastructure configuration, allowing them to focus on fixing the root cause of the problem rather than manually configuring environments or troubleshooting.</blockquote><h3>GitHub</h3><p>You can find the complete code in the GitHub link here:<br>https://github.com/vardhanam/dspy-multihop-qdrant</p><h3>Stackademic 🎓</h3><p>Thank you for reading until the end. Before you go:</p><ul><li>Please consider <strong>clapping</strong> and <strong>following</strong> the writer! 👏</li><li>Follow us <a href="https://twitter.com/stackademichq"><strong>X</strong></a><strong> | </strong><a href="https://www.linkedin.com/company/stackademic"><strong>LinkedIn</strong></a><strong> | </strong><a href="https://www.youtube.com/c/stackademic"><strong>YouTube</strong></a><strong> | </strong><a href="https://discord.gg/in-plain-english-709094664682340443"><strong>Discord</strong></a></li><li>Visit our other platforms: <a href="https://plainenglish.io/"><strong>In Plain English</strong></a><strong> | </strong><a href="https://cofeed.app/"><strong>CoFeed</strong></a><strong> | </strong><a href="https://venturemagazine.net/"><strong>Venture</strong></a><strong> | </strong><a href="https://blog.cubed.run/"><strong>Cubed</strong></a></li><li>Tired of blogging platforms that force you to deal with algorithmic content? Try <a href="https://differ.blog/"><strong>Differ</strong></a></li><li>More content at <a href="https://stackademic.com/"><strong>Stackademic.com</strong></a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=841580138a81" width="1" height="1" alt=""><hr><p><a href="https://blog.stackademic.com/multi-hop-retrieval-and-reasoning-for-complex-questions-using-dspy-qdrant-and-llama3-841580138a81">Multi-Hop Retrieval and Reasoning for Complex Questions Using DSPy, Qdrant, and Llama3</a> was originally published in <a href="https://blog.stackademic.com/">Stackademic</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Use Re-Rankers for Advanced RAG Pipelines Using Qdrant]]></title>
            <link>https://blog.stackademic.com/how-to-use-re-rankers-for-advanced-rag-pipelines-using-qdrant-e8ccbfcfaea1?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/e8ccbfcfaea1</guid>
            <category><![CDATA[qdrant]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[vector-database]]></category>
            <category><![CDATA[retrieval-augmented-gen]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Tue, 30 Apr 2024 11:00:09 GMT</pubDate>
            <atom:updated>2024-05-01T00:17:05.133Z</atom:updated>
            <content:encoded><![CDATA[<h4>A tutorial on implementing Re-Ranking to refine Vector Search Results using Langchain</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*n4pUy3DepUqg1bWWGs2hbA.png" /></figure><h3>What Is a Re-ranker?</h3><p>A Re-ranker is essentially a transformer model that takes a query and a list of documents as input. And it returns the list of the documents as output but now they are re-ranked in relevance to the query. The documents which are most relevant to the query are ahead in the list compared to the ones that are not meaningfully related to the query.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/915/0*hwHPTt6Cv113_Mq4" /></figure><p>This feature is extremely useful especially when feeding external data to an LLM from a corpus of billions of text. A Re-ranker in this scenario would rank the documents with respect to the user query, and send only the top relevant documents to the LLM for generating a response.</p><p>Re-rankers are better than vector searches in figuring out relevancy. This is because in vector searches the documents are first converted into numerical embeddings and then stored in a vector database. This conversion into vector embeddings causes a significant amount of data loss from the actual text to its vector representation.</p><p>Re-rankers, on the other hand, don’t cause any data loss since they take the input as the entire document itself without any kind of conversion into vector embeddings.</p><h3>Why Not Use Only a Re-ranker Instead of Vector Search?</h3><p>So if Re-rankers perform better than vector searches, the question arises: “Why not use them entirely in feeding external data to LLMs instead of using a vector search approach?”</p><p>The reason behind this is that Re-rankers are extremely slow in processing data compared to a Vector DB. Especially if there are millions of documents in the external corpus, it would take several hours for a Re-ranker to rank them. This is because the Transformers model would have to process millions of document query pairs, one by one.</p><p>A vector search, which is based on calculating cosine similarity between the query vector and the document vector, achieves this in a matter of seconds. Vector Databases are essentially designed to facilitate a cosine similarity search at lightning speed.</p><p>That’s why we used a hybrid method combining both Vector Search and Re-ranking.</p><h3>Combining Vector Search and Re-ranking</h3><p>In this method the Vector Search is used to do the heavy lifting, i.e., find documents similar to the query from a large corpus of text.</p><p>Then Re-ranking is applied only on the top documents to refine the results. This way we optimize our search mechanism — the speedy vector search sorts through the millions of documents to give a broad result, while slower albeit more accurate Re-ranker re-arranges the top results to give us a more meaningful response.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/877/0*dSy4nz3jZ0kOOfGi" /></figure><h3>How to Use Re-rankers</h3><p>These are some of the popular re-rankers out there:</p><ul><li>bge-reranker-large</li><li>Jina Reranker</li><li>Cohere Reranker</li></ul><p>We’ll be using the <a href="https://huggingface.co/datasets/ckandemir/amazon-products?row=74">ckandemir/amazon-products</a> dataset from Hugging Face. It contains names and descriptions of about 24k products.</p><p>First, install the dependencies.</p><pre>langchain<br>qdrant-client<br>SQLAlchemy==2.0.1<br>datasets</pre><p>Load the dataset.</p><pre>from datasets import load_dataset<br><br>df = load_dataset(&#39;ckandemir/amazon-products&#39;, split=&#39;train&#39;).to_pandas()</pre><p>Convert it into document format.</p><pre>from langchain.docstore.document import Document<br><br>documents = []<br>for index, row in df.iterrows():<br>    text = f&quot;Product Name: {row[&#39;Product Name&#39;]}\nProduct Category: {row[&#39;Category&#39;]}\nProduct Description: {row[&#39;Description&#39;]}&quot;<br>    document = Document(page_content=text)<br>    documents.append(document)</pre><p>Load the embeddings model.</p><pre>from langchain_community.embeddings import HuggingFaceEmbeddings<br>embeddings = HuggingFaceEmbeddings(model_name  = &quot;BAAI/bge-base-en-v1.5&quot;)</pre><p>Now index all the documents into the vector database <a href="https://qdrant.tech/">Qdrant.</a></p><pre>from langchain_community.vectorstores import Qdrant<br>qdrant = Qdrant.from_documents(<br>    documents,<br>    embeddings,<br>    location=&quot;:memory:&quot;,  # Local mode with in-memory storage only<br>    collection_name=&quot;reranker&quot;,<br>)</pre><p>We’ll make a retriever object that will fetch the top 10 results from the vector database without re-ranking them.</p><pre>retriever = qdrant.as_retriever(search_kwargs = {&#39;k&#39;:10})</pre><p>Next we’ll create another retriever object that will re-rank the results fetched from the vector database:</p><pre>from langchain.retrievers import ContextualCompressionRetriever<br>from langchain.retrievers.document_compressors import CrossEncoderReranker<br>from langchain_community.cross_encoders import HuggingFaceCrossEncoder<br><br>model = HuggingFaceCrossEncoder(model_name=&quot;BAAI/bge-reranker-base&quot;)<br>compressor = CrossEncoderReranker(model=model, top_n=10)<br>compression_retriever = ContextualCompressionRetriever(<br>    base_compressor=compressor, base_retriever=retriever<br>)<br><br></pre><p>Let’s write a function which compares the results of the retrievers with &amp; without reranking.</p><pre>import pandas as pd<br><br>def comparison_df(question):<br>    # Retrieve relevant documents using retriever<br>    retriever_documents = retriever.get_relevant_documents(question)<br>    <br>    # Take top 5 document page contents from retriever<br>    retriever_contents = [doc.page_content for doc in retriever_documents]<br>    <br>    # Retrieve relevant documents using compression_retriever<br>    compression_documents = compression_retriever.invoke(question)<br>    <br>    # Take document page contents from compression_retriever<br>    compression_contents = [doc.page_content for doc in compression_documents]<br>    <br>    # Create a DataFrame with separate columns for each retriever<br>    df = pd.DataFrame({<br>        &#39;without_reranking&#39;: retriever_contents,<br>        &#39;after_reranking&#39;: compression_contents<br>    })<br>    <br>    return df<br></pre><pre>df_comparison = comparison_df(&quot;Give me a list of Toy Figures of Iron-Man&quot;)</pre><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4895c514d94b5ca60ad48e22178b7dfd/href">https://medium.com/media/4895c514d94b5ca60ad48e22178b7dfd/href</a></iframe><p>Code to implement Jina Reranker. In the above code, just replace the compressor.</p><pre>from langchain_community.document_compressors import JinaRerank<br><br>compressor = JinaRerank()<br>compression_retriever = ContextualCompressionRetriever(<br>   base_compressor=compressor, base_retriever=retriever<br>)</pre><p>Similarly, code to implement Cohere Ranker.</p><pre>from langchain_cohere import CohereRerank<br><br>compressor = CohereRerank()<br>compression_retriever = ContextualCompressionRetriever(<br>   base_compressor=compressor, base_retriever=retriever<br>)</pre><h3>Final Words</h3><p>It’s quite a straightforward process to connect the Re-ranker retriever to an LLM to develop a RAG pipeline:</p><pre>from langchain.chains import RetrievalQA<br>from langchain_openai import OpenAI<br><br>llm = OpenAI(openai_api_key=&quot;YOUR_API_KEY&quot;)<br><br>chain = RetrievalQA.from_chain_type(<br>   llm=llm, retriever=compression_retriever<br>)<br><br>chain.invoke(&quot;Your query goes here&quot;)</pre><h3>Stackademic 🎓</h3><p>Thank you for reading until the end. Before you go:</p><ul><li>Please consider <strong>clapping</strong> and <strong>following</strong> the writer! 👏</li><li>Follow us <a href="https://twitter.com/stackademichq"><strong>X</strong></a><strong> | </strong><a href="https://www.linkedin.com/company/stackademic"><strong>LinkedIn</strong></a><strong> | </strong><a href="https://www.youtube.com/c/stackademic"><strong>YouTube</strong></a><strong> | </strong><a href="https://discord.gg/in-plain-english-709094664682340443"><strong>Discord</strong></a></li><li>Visit our other platforms: <a href="https://plainenglish.io/"><strong>In Plain English</strong></a><strong> | </strong><a href="https://cofeed.app/"><strong>CoFeed</strong></a><strong> | </strong><a href="https://venturemagazine.net/"><strong>Venture</strong></a><strong> | </strong><a href="https://blog.cubed.run/"><strong>Cubed</strong></a></li><li>More content at <a href="https://stackademic.com/"><strong>Stackademic.com</strong></a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e8ccbfcfaea1" width="1" height="1" alt=""><hr><p><a href="https://blog.stackademic.com/how-to-use-re-rankers-for-advanced-rag-pipelines-using-qdrant-e8ccbfcfaea1">How to Use Re-Rankers for Advanced RAG Pipelines Using Qdrant</a> was originally published in <a href="https://blog.stackademic.com/">Stackademic</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Set Up Open Devin, the Open Source AI Software Engineer]]></title>
            <link>https://medium.com/superteams-ai-blog/how-to-set-up-open-devin-the-open-source-ai-software-engineer-610adcd5a874?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/610adcd5a874</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[devin]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Tue, 16 Apr 2024 11:06:53 GMT</pubDate>
            <atom:updated>2024-04-17T07:49:15.087Z</atom:updated>
            <content:encoded><![CDATA[<h4>Create entire Software Stacks with just a single Natural Language Prompt</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*npk4hEsPY3RSA7cm6WWimA.png" /></figure><p>“Over the last 10–15 years, almost everybody who sits on a stage like this would tell you that it is vital that your children learn computer science; everybody should learn how to program. In fact, it is almost exactly the opposite. It is our job to create computing technology such that nobody has to program, and that the programming language is human. Everybody in the world is now a programmer. This is the miracle of AI.” — Jensen Huang, CEO of NVIDIA</p><h3>What Is Open Devin?</h3><p>Open Devin is a completely autonomous AI agent that can create entire software stacks starting from just a single user prompt. It has been inspired by <a href="https://www.cognition-labs.com/introducing-devin">Devin</a>, the cutting-edge proprietary AI software engineering tool.</p><p>Like Devin, Open Devin is designed to navigate the complexities of software engineering by leveraging a combination of tools such as a shell, code editor, and web browser. By harnessing the power of LLMs, Open Devin can autonomously handle the complete software development lifecycle, from understanding user requirements and writing code to testing and deployment.</p><p>This AI-driven approach to software development allows for the creation of intricate applications with reduced human input, thus unlocking new opportunities for swift innovation.</p><p>Through the power of open-source collaboration, Open Devin aspires to replicate, enhance, and innovate upon the original Devin model. The project’s goal is to guide the progress of open code models and demonstrate the potential of autonomous AI agents in executing complex engineering tasks and actively collaborating with users on software development projects.</p><h3>How to Set It Up</h3><h4>Requirements</h4><p><strong>Conda env with python 3.11</strong></p><pre>conda create -n opendevin python=3.11</pre><pre>conda activate opendevin</pre><p><strong>Docker</strong></p><p>You can install Docker by running the following commands:</p><pre># Add Docker&#39;s official GPG key:<br><br>sudo apt-get update<br><br>sudo apt-get install ca-certificates curl<br><br>sudo install -m 0755 -d /etc/apt/keyrings<br><br>sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc<br><br>sudo chmod a+r /etc/apt/keyrings/docker.asc<br><br># Add the repository to Apt sources:<br><br>echo \<br><br> &quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \<br><br> $(. /etc/os-release &amp;&amp; echo &quot;$VERSION_CODENAME&quot;) stable&quot; | \<br><br> sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null<br><br>sudo apt-get update<br></pre><pre>sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin</pre><p><strong>Node.js</strong></p><p>Run these commands to install Node.js.</p><pre># installs NVM (Node Version Manager)<br>curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash<br><br># download and install Node.js<br>nvm install 20<br><br># verifies the right Node.js version is in the environment<br>node -v # should print `v20.12.2`<br><br># verifies the right NPM version is in the environment<br>npm -v # should print `10.5.0`</pre><p><strong>Poetry</strong></p><p>First install pipx.</p><pre>sudo apt update<br>sudo apt install pipx<br>pipx ensurepath<br>sudo pipx ensurepath --global # optional to allow pipx actions with --global argument</pre><p>Then install Poetry.</p><pre>pipx install poetry</pre><h3>Build the Project</h3><p>First download the repository.</p><pre>git clone https://github.com/nnilayy/OpenDevin.git<br>cd OpenDevin</pre><p>Then build:</p><pre>make build</pre><h3>Set Up the LLM</h3><p>We’ll use <a href="https://ollama.com/">Ollama</a> to set up our LLM.</p><p>Install Ollama.</p><pre>curl -fsSL https://ollama.com/install.sh | sh</pre><p>Start the server.</p><pre>ollama serve</pre><p>This will start a Ollama server at <a href="http://localhost:11434/">http://localhost:11434</a>.</p><p>If you get an error like this:</p><pre>Error: listen tcp 127.0.0.1:11434: bind: address already in use</pre><p>It just means the server is already running.</p><p>Stop the server and run it again:</p><pre>sudo systemctl stop ollama</pre><p>Let’s use the Mistral-7B LLM.</p><pre>ollama pull mistral:7b</pre><p>Now open the config.toml file and paste the following in it.</p><pre>LLM_API_KEY=&quot;ollama&quot;<br>LLM_MODEL=&quot;ollama/mistral:7b&quot;<br>LLM_EMBEDDING_MODEL=&quot;local&quot;<br>LLM_BASE_URL=&quot;http://localhost:11434&quot;<br>WORKSPACE_DIR=&quot;./workspace&quot;</pre><p>The Workspace_Dir is the folder that will be created by Open Devin to save all the software tasks it’s given to perform.</p><p>Now open the makefile and go to the run: section (#Run the app). There, add — host 0.0.0.0 to the following line:</p><pre>@cd frontend &amp;&amp; echo &quot;$(BLUE)Starting frontend with npm...$(RESET)&quot; &amp;&amp; \<br>npm run start -- --port $(FRONTEND_PORT) --host 0.0.0.0</pre><p>This will ensure that the front end of Open Devin will be exposed to users who are accessing it from external routes.</p><h3>Run Open Devin</h3><pre>make run</pre><p>This will launch the front end at the following address:</p><p>&lt;server-ip&gt;:3001</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*DCgKRNtJvm7D-y30" /></figure><p>Enjoy building your very own software stack!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=610adcd5a874" width="1" height="1" alt=""><hr><p><a href="https://medium.com/superteams-ai-blog/how-to-set-up-open-devin-the-open-source-ai-software-engineer-610adcd5a874">How to Set Up Open Devin, the Open Source AI Software Engineer</a> was originally published in <a href="https://medium.com/superteams-ai-blog">Superteams.ai</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building RAG Powered Audio-Only Chatbot for Mobile Phone Reviews — Using Mistral-7B, WhisperSpeech…]]></title>
            <link>https://blog.stackademic.com/building-rag-powered-audio-only-chatbot-for-mobile-phone-reviews-using-mistral-7b-whisperspeech-024e8ed61b12?source=rss-ead06f376cdd------2</link>
            <guid isPermaLink="false">https://medium.com/p/024e8ed61b12</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[vector-database]]></category>
            <dc:creator><![CDATA[Vardhanam Daga]]></dc:creator>
            <pubDate>Thu, 11 Apr 2024 06:44:27 GMT</pubDate>
            <atom:updated>2024-04-12T00:47:04.930Z</atom:updated>
            <content:encoded><![CDATA[<h3>Building RAG Powered Audio-Only Chatbot for Mobile Phone Reviews — Using Mistral-7B, WhisperSpeech, and Qdrant</h3><h4>A talking chatbot for investigating your pdf documents</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*TICxFq-Zk84GfGluAc1TCA.png" /></figure><h3>How Voice-to-Voice RAG Works</h3><p>Voice to Voice RAG (Retrieval-Augmented Generation) chatbots are an exciting advancement in conversational AI. Moving away from old-school text-generating chatbots, voice chatbots can facilitate more natural and interactive human-machine interaction.</p><p>By playing upon the power of voice input and output, along with RAG techniques, these chatbots can deliver intelligent and contextually-aware responses to user queries.</p><p>Here’s how the workflow of a Voice-RAG looks like:</p><p>1. User uploads documents to create a knowledge base.</p><p>2. Documents are processed, split into chunks, and stored in a Vector Database.</p><p>3. User asks a question using voice input.</p><p>4. Automatic Speech Recognition (ASR) model converts voice to text.</p><p>5. Similarity search on the Vector Database retrieves relevant context.</p><p>6. Original query and retrieved context are combined to create an augmented query.</p><p>7. Large Language Model (LLM) generates a response based on the augmented query.</p><p>8. Text to Speech (TTS) model converts the generated response into voice output for the user.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*HvSDBaoYT6qC44yu" /><figcaption>Voice-to-Voice RAG Workflow</figcaption></figure><h3>Tech Stack Used in This Blog</h3><ul><li><a href="https://www.gradio.app/docs/interface">Gradio</a> is used to build the user interface, allowing users to easily upload documents, record voice queries, and receive voice responses.</li><li><a href="https://github.com/openai/whisper">OpenAI Whisper</a>, a state-of-the-art Automatic Speech Recognition (ASR) model, accurately transcribes the user’s voice query into text.</li><li><a href="https://qdrant.tech/documentation/">Qdrant</a>, a high-performance Vector Database, stores the processed document chunks and helps with fast similarity searches to retrieve relevant context.</li><li><a href="https://huggingface.co/mistralai/Mistral-7B-v0.1">Mistral-7B</a>, the powerful Large Language Model (LLM), generates coherent and contextually relevant responses based on the augmented query.</li><li><a href="https://github.com/collabora/WhisperSpeech">Whisper Speech</a>, a Text to Speech (TTS) model, synthesizes natural-sounding speech from the generated text response, providing the final voice output to the user.</li></ul><h3>Let’s Code</h3><p>Create a requirements.txt file and paste the following in it:</p><pre>transformers<br>accelerate<br>bitsandbytes<br>gradio<br>langchain<br>pypdf<br>qdrant-client<br>sentence-transformers<br>torch<br>torchaudio<br>openai-whisper</pre><p>Now install the dependencies using the following command:</p><pre>pip install -r requirements.txt</pre><p>Spin up a Jupyter Notebook in your Python environment, and import all these modules. We’ll be using LangChain as our framework for handling all the data. It is an efficient and robust framework that takes care of a lot of underlying coding work by abstracting it into seamless modules.</p><pre>from transformers import (<br>AutoTokenizer,<br>AutoModelForCausalLM,<br>BitsAndBytesConfig,<br>pipeline<br>)<br><br>import torch<br>import torch.nn.functional as F<br><br>import os<br><br>from langchain.llms import HuggingFacePipeline<br>from langchain_community.document_loaders import PyPDFLoader<br>from langchain.text_splitter import RecursiveCharacterTextSplitter<br>from langchain_community.vectorstores import Qdrant<br>from langchain.embeddings import HuggingFaceEmbeddings<br><br>import gradio as gr<br><br>import whisper<br>from whisperspeech.pipeline import Pipeline<br><br>import uuid</pre><p>Next we’ll write a function to generate a text generation pipeline using Mistral-7B. We’ll use a quantized version of the model and reduce the precision to 4-bit. This will improve speed and efficiency of our pipeline.</p><pre>def load_llm():<br><br>    #Loading the Mistral Model<br>    model_name=&#39;mistralai/Mistral-7B-Instruct-v0.2&#39;<br>    tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)<br>    tokenizer.pad_token = tokenizer.eos_token<br>    tokenizer.padding_side = &quot;right&quot;<br><br>    bnb_config = BitsAndBytesConfig(<br>        load_in_4bit=True,<br>        bnb_4bit_quant_type=&quot;nf4&quot;,<br>        bnb_4bit_use_double_quant=True,<br>        bnb_4bit_compute_dtype=torch.bfloat16<br>    )<br><br><br>    model = AutoModelForCausalLM.from_pretrained(<br>        model_name,<br>        quantization_config=bnb_config,<br>    )<br><br>    # Building a LLM text-generation pipeline<br>    text_generation_pipeline = pipeline(<br>        model=model,<br>        tokenizer=tokenizer,<br>        task=&quot;text-generation&quot;,<br>        temperature=0.2,<br>        repetition_penalty=1.1,<br>        return_full_text=True,<br>        max_new_tokens=1024,<br>        device_map = &#39;auto&#39;,<br>    )<br><br><br>    return text_generation_pipeline</pre><p>Next we’ll define a text splitter to chunk the user uploaded documents into smaller chunks.</p><pre>def text_splitter():<br>    # Simulate some document processing delay<br>    text_splitter = RecursiveCharacterTextSplitter(<br>        chunk_size=512,<br>        chunk_overlap=20,<br>        length_function=len,<br>        is_separator_regex=False,<br>    )<br>    return text_splitter</pre><p>We’ll then write a function to upsert the user uploaded files into the <a href="https://qdrant.tech/">Qdrant</a> vector database. This function is capable of taking multiple pdf files as input. It then spits the texts in these documents into smaller chunks, then generates vector embeddings for these chunks before finally adding it to the vector DB.</p><pre>def add_pdfs_to_vectorstore(files):<br><br>    saved_files_count = 0<br>    documents = []<br>    for file_path in files:<br>        file_name = os.path.basename(file_path)  # Extract the filename from the full path<br>        if file_name.lower().endswith(&#39;.pdf&#39;):  # Check if the file is a PDF<br>            saved_files_count += 1<br>            loader_temp = PyPDFLoader(file_path)<br>            docs_temp = loader_temp.load_and_split(text_splitter=textsplitter)<br>            for doc in docs_temp:<br>                # Replace all occurrences of &#39;\n&#39; with a space &#39; &#39;<br>                doc.page_content = doc.page_content.replace(&#39;\n&#39;, &#39; &#39;)<br>            documents = documents + docs_temp<br><br>        else:<br>            print(f&quot;Skipping non-PDF file: {file_name}&quot;)<br>            <br>    global qdrant<br>    <br>    qdrant = Qdrant.from_documents(<br>        documents,<br>        HuggingFaceEmbeddings(),<br>        location=&quot;:memory:&quot;, <br>    )<br><br>    return f&quot;Added {saved_files_count} PDF file(s) to vectorstore/ You can begin voice chat&quot;</pre><p>Then we’ll write the function to create an augmented query from the user’s input query. This is done performing a similarity search on the VectorDB to retrieve the relevant context. Then this context+query is passed onto the LLM for generating the response.</p><pre>def answer_query(message):<br>    context_docs = qdrant.similarity_search(message, k= 10)<br>    context = &#39; &#39;.join(doc.page_content for doc in context_docs)<br><br>    template = f&quot;&quot;&quot;Answer the question based only on the following context:<br>        {context}<br><br>        Question: {message}<br>    &quot;&quot;&quot;<br><br>    result = llm(template)<br><br>    answer = result[0][&quot;generated_text&quot;].replace(template, &#39;&#39;)<br><br>    return answer</pre><p>We’ll load all the models (ASR, TTS, LLM).</p><pre>whisper_model = whisper.load_model(&quot;base&quot;)<br>whisper_speech_model = Pipeline(s2a_ref=&#39;collabora/whisperspeech:s2a-q4-tiny-en+pl.model&#39;)<br>llm = load_llm()<br>textsplitter = text_splitter()</pre><p>We’ll now write a function to transcribe the input audio into text so that it can then be passed downstream to the VectorDB and the LLM. This function takes the audio location as the input.</p><pre>def transcribe(audio):<br>    <br>    result = whisper_model.transcribe(audio)<br>    return result[&quot;text&quot;]</pre><p>Then we’ll create a function to convert the LLM’s final response into speech. The output file is saved in a temporary location which is automatically deleted later on.</p><pre>def generate_and_play_audio(text):<br>    # Construct the directory and filename<br>    directory = &#39;/var/tmp/gradio/&#39;<br>    filename = str(uuid.uuid4()) + &quot;/audio.wav&quot;<br>    file_location = os.path.join(directory, filename)<br>    <br>    # Ensure that the directory exists<br>    os.makedirs(os.path.dirname(file_location), exist_ok=True)<br>    <br>    # Generate the audio file from text and save to the specified location<br>    whisper_speech_model.generate_to_file(file_location, text, lang =&#39;en&#39;, cps=15)<br><br>    # Return the location of the saved audio file for playback<br>    return file_location</pre><p>This is the code for the Gradio UI:</p><pre>with gr.Blocks() as demo:<br>    <br>    with gr.Row():<br>        upload_files = gr.File(label=&quot;Upload pdf files only&quot;, file_count=&#39;multiple&#39;)<br>        success_msg = gr.Text(value=&quot;&quot;)<br>    <br>    with gr.Row():<br>        audio_inp = gr.Audio(sources=&quot;microphone&quot;, type=&#39;filepath&#39;)<br>        trans_out = gr.Textbox()<br>    <br>    with gr.Row():<br>        btn_audio = gr.Button(&quot;Submit Audio&quot;)<br>    <br>    with gr.Row():<br>        model_response = gr.Textbox(label= &quot;Model Response&quot;, lines = 20)<br>        audio_out = gr.Audio(label=&quot;AI response in Voice&quot;)<br>        <br>    with gr.Row():<br>        clear_btn = gr.Button(&quot;Clear All&quot;)<br>        <br>    <br>    upload_files.upload(add_pdfs_to_vectorstore, upload_files, success_msg)<br>    transcribe = btn_audio.click(fn=transcribe, inputs=audio_inp, outputs=trans_out)<br>    answer_gen = transcribe.then(fn=answer_query, inputs= trans_out, outputs= model_response)<br>    answer_gen.then(fn=generate_and_play_audio, inputs= model_response, outputs= audio_out)<br>    clear_btn.click(fn= lambda: (None,&quot;&quot;,&quot;&quot;,None), inputs= None, outputs= [audio_inp, trans_out, model_response, audio_out])<br><br>demo.queue().launch(server_name= &quot;0.0.0.0&quot;, share=True)</pre><p>Let’s break the code down:</p><p>1. `with gr.Blocks() as demo:` creates a Gradio interface named `demo`.</p><p>2. Inside `demo`, there are several `gr.Row()` components that organize the interface elements horizontally:</p><p>- The first row contains an `upload_files` component for uploading PDF files and a `success_msg` component to display a success message.</p><p>- The second row has an `audio_inp` component for recording audio input and a `trans_out` component to display the transcribed text.</p><p>- The third row has a `btn_audio` component, which is a button to submit the recorded audio.</p><p>- The fourth row contains a `model_response` component to display the generated response from the model and an `audio_out` component to play the AI-generated voice response.</p><p>- The fifth row has a `clear_btn` component to clear all inputs and outputs.</p><p>3. The `upload_files.upload()` method is used to trigger the `add_pdfs_to_vectorstore` function when files are uploaded, passing the uploaded files and updating the `success_msg` component.</p><p>4. The `btn_audio.click()` method is used to trigger the `transcribe` function when the “Submit Audio” button is clicked, passing the recorded audio input (`audio_inp`) and updating the `trans_out` component with the transcribed text.</p><p>5. The `transcribe.then()` method is used to chain the `answer_query` function after the transcription is complete, passing the transcribed text (`trans_out`) and updating the `model_response` component with the generated response.</p><p>6. The `answer_gen.then()` method is used to chain the `generate_and_play_audio` function after the response generation is complete, passing the generated response (`model_response`) and updating the `audio_out` component with the AI-generated voice response.</p><p>7. The `clear_btn.click()` method is used to clear all inputs and outputs when the “Clear All” button is clicked, setting the values of `audio_inp`, `trans_out`, `model_response`, and `audio_out` to `None` or empty strings.</p><p>8. Finally, `demo.queue().launch(server_name= “0.0.0.0”, share=True)` launches the Gradio interface, enabling queuing to handle multiple requests and making it accessible over the network with the `share=True` option.</p><h3>Demonstration of the Gradio UI</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Dqmv5o1m7Vibz8dJ" /></figure><p>Here’s a short <a href="https://www.youtube.com/watch?v=DAJgfzRsfBs">video</a> demonstrating the UI.</p><p>We also took a dataset of cell phone reviews from <a href="https://www.kaggle.com/datasets/grikomsn/amazon-cell-phones-reviews?resource=download">Kaggle</a>. And then we converted this dataset into .txt format using the following code:</p><pre>import pandas as pd<br><br># Load the CSV files<br>df1 = pd.read_csv(&#39;file1.csv&#39;, usecols=[&#39;asin&#39;, &#39;title&#39;])<br>df2 = pd.read_csv(&#39;file2.csv&#39;, usecols=[&#39;asin&#39;, &#39;title&#39;, &#39;body&#39;])<br><br># Merge the dataframes based on &#39;asin&#39;<br>merged_df = pd.merge(df1, df2, on=&#39;asin&#39;, how=&#39;inner&#39;)<br><br># Sample 100 random rows from the merged dataframe<br>random_subset = merged_df.sample(n=100, random_state=1) if len(merged_df) &gt; 100 else merged_df<br><br># Define the text filename<br>text_filename = &#39;output.txt&#39;<br><br># Open the text file for writing<br>with open(text_filename, &#39;w&#39;, encoding=&#39;utf-8&#39;) as f:<br>    for index, row in random_subset.iterrows():<br>        # Construct the line format: file1[title] : file2[title]: file2[body]<br>        line = f&quot;{row[&#39;title_x&#39;]} : {row[&#39;title_y&#39;]}: {row[&#39;body&#39;]}\n&quot;<br>        <br>        # Write the line to the text file<br>        f.write(line)<br><br>print(f&quot;Text file &#39;{text_filename}&#39; was created successfully.&quot;)</pre><p>We then saved it as a PDF file using Google Docs, and used the PDF to do some sample queries.</p><p>Question: How are the reviews of Samsung phones?</p><p>Answer: The context mentions several Samsung phones, including the Galaxy S4, Galaxy S5, Galaxy S6, and Galaxy S6 Edge. The reviews for these phones are generally positive, with many people praising their features, design, and performance. For example, one person says that the Galaxy S6 is a great phone, while another describes it as having a great screen and being good for taking pictures. Another reviewer mentions that the Galaxy S5 has a nice display and is easy to use, while yet another notes that the Galaxy S4 is great but was outdone by newer models like the S5 and S6. Overall, it seems that the Samsung phones receive positive feedback from users.</p><p>Here’s a <a href="https://www.youtube.com/watch?v=4OBvYXJr3Fk">video</a> of the same.</p><p>Here’s another <a href="https://www.youtube.com/watch?v=6_xwpCp5yHo">video</a> demonstrating our chatbot’s answer when asked: “Which phones had disappointing reviews?”</p><h3>GitHub</h3><p>The full code can be accessed here: <a href="https://github.com/vardhanam/RAG_Voice_Chatbot/tree/main">https://github.com/vardhanam/RAG_Voice_Chatbot/tree/main</a></p><p>We also created a Flask-based API for the voice chatbot under the name api.py.</p><p>Here’s how you can launch the Flask server. Run the following in the bash terminal.</p><pre>export FLASK_APP=api.py<br>flask run</pre><p>This will launch an endpoint on <a href="http://127.0.0.1:5000/">http://127.0.0.1:5000</a>.</p><p>You will first have to upload the pdf documents. You can do so by sending post requests to the API in the following manner:</p><pre>curl -X POST \<br>-H &quot;Content-Type: application/json&quot; \<br>-d &#39;{&quot;file_paths&quot;:[&quot;path_to_file1.pdf&quot;,&quot;path_to_file2.pdf&quot;]}&#39; \ <br> http://localhost:5000/upload_pdfs</pre><p>On successful completion of this above request, you should see the following output in your terminal:</p><pre>{&quot;message&quot;:&quot;Added 2 PDF file(s) to vectorstore/ You can begin voice chat&quot;}</pre><p>Then you can send another request to the server with the input query as an audio file and the name of the output audio file in the following manner:</p><pre>curl -X POST \<br>  -H &quot;Content-Type: application/json&quot; \<br>  -d &#39;{&quot;audio_path&quot;:&quot;path_to_input_query.wav&quot;, &quot;output_filename&quot;:&quot;output_filename.wav&quot;}&#39; \<br>  http://localhost:5000/process_audio</pre><p>Upon successful completion of the above request, you will see a message in the terminal that will display the following;</p><pre>{&quot;transcription&quot; : &quot;Your transcribed version of the audio input query&quot;, &quot;response_text&quot;:<br> &quot;Response text generated by the RAG pipeline&quot;, &quot;audio_output&quot;: <br>&quot;path_to_output_audio_file&quot;}</pre><p>Using this backend Flask API, developers can design full-stack voice-to-voice RAG chatbots.</p><h3>Stackademic 🎓</h3><p>Thank you for reading until the end. Before you go:</p><ul><li>Please consider <strong>clapping</strong> and <strong>following</strong> the writer! 👏</li><li>Follow us <a href="https://twitter.com/stackademichq"><strong>X</strong></a><strong> | </strong><a href="https://www.linkedin.com/company/stackademic"><strong>LinkedIn</strong></a><strong> | </strong><a href="https://www.youtube.com/c/stackademic"><strong>YouTube</strong></a><strong> | </strong><a href="https://discord.gg/in-plain-english-709094664682340443"><strong>Discord</strong></a></li><li>Visit our other platforms: <a href="https://plainenglish.io/"><strong>In Plain English</strong></a><strong> | </strong><a href="https://cofeed.app/"><strong>CoFeed</strong></a><strong> | </strong><a href="https://venturemagazine.net/"><strong>Venture</strong></a><strong> | </strong><a href="https://blog.cubed.run/"><strong>Cubed</strong></a></li><li>More content at <a href="https://stackademic.com/"><strong>Stackademic.com</strong></a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=024e8ed61b12" width="1" height="1" alt=""><hr><p><a href="https://blog.stackademic.com/building-rag-powered-audio-only-chatbot-for-mobile-phone-reviews-using-mistral-7b-whisperspeech-024e8ed61b12">Building RAG Powered Audio-Only Chatbot for Mobile Phone Reviews — Using Mistral-7B, WhisperSpeech…</a> was originally published in <a href="https://blog.stackademic.com/">Stackademic</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>