<?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 Nhi Yen on Medium]]></title>
        <description><![CDATA[Stories by Nhi Yen on Medium]]></description>
        <link>https://medium.com/@yennhi95zz?source=rss-81c441aba61e------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*QdjvRgHyRFD24vnYAyQbCw.jpeg</url>
            <title>Stories by Nhi Yen on Medium</title>
            <link>https://medium.com/@yennhi95zz?source=rss-81c441aba61e------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 13:46:14 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@yennhi95zz/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[The Secret to Developing an App in 48 Hours and Crashing it in the First Week]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://code.likeagirl.io/the-secret-to-developing-an-app-in-48-hours-and-crashing-it-in-the-first-week-d8be2c47922f?source=rss-81c441aba61e------2"><img src="https://cdn-images-1.medium.com/max/2600/0*7t5LG10GqSk_R3wb" width="3346"></a></p><p class="medium-feed-snippet">The Hidden Cost of Building Software Without Engineering</p><p class="medium-feed-link"><a href="https://code.likeagirl.io/the-secret-to-developing-an-app-in-48-hours-and-crashing-it-in-the-first-week-d8be2c47922f?source=rss-81c441aba61e------2">Continue reading on Code Like A Girl »</a></p></div>]]></description>
            <link>https://code.likeagirl.io/the-secret-to-developing-an-app-in-48-hours-and-crashing-it-in-the-first-week-d8be2c47922f?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/d8be2c47922f</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[vibe-engineering]]></category>
            <category><![CDATA[ai-agents-in-action]]></category>
            <category><![CDATA[delivery-management]]></category>
            <category><![CDATA[vibe-coding]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Thu, 13 Aug 2026 12:46:01 GMT</pubDate>
            <atom:updated>2026-08-13T12:46:01.913Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[The Secret to Using Claude Code to Manage Data Engineering]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://code.likeagirl.io/the-secret-to-using-claude-code-to-manage-data-engineering-02961de14ea7?source=rss-81c441aba61e------2"><img src="https://cdn-images-1.medium.com/max/2600/0*7SEvGCHMktw4yS8W" width="5760"></a></p><p class="medium-feed-snippet">Most Data Engineers use Claude in the wrong way.</p><p class="medium-feed-link"><a href="https://code.likeagirl.io/the-secret-to-using-claude-code-to-manage-data-engineering-02961de14ea7?source=rss-81c441aba61e------2">Continue reading on Code Like A Girl »</a></p></div>]]></description>
            <link>https://code.likeagirl.io/the-secret-to-using-claude-code-to-manage-data-engineering-02961de14ea7?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/02961de14ea7</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[claude-code]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Thu, 09 Jul 2026 02:58:29 GMT</pubDate>
            <atom:updated>2026-07-09T02:58:29.847Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[A successful Manager must excel at Multi-tasking]]></title>
            <link>https://code.likeagirl.io/a-successful-manager-must-excel-at-multi-tasking-6a7a2e48ba16?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/6a7a2e48ba16</guid>
            <category><![CDATA[deep-work]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[project-management]]></category>
            <category><![CDATA[productivity-hacks]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Thu, 05 Dec 2024 11:46:01 GMT</pubDate>
            <atom:updated>2024-12-05T11:55:01.496Z</atom:updated>
            <content:encoded><![CDATA[<h4>The Secret to Career Success</h4><p>I have been in the Tech Industry for over seven years. I have worked both in consulting firms and as an in-house employee. From when I was a junior to when I became a senior, and now as a manager, I have observed the people around me and always believed that “a successful manager must be good at multitasking.”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*OgT4uWFNpr4iI-yO" /><figcaption>Photo by <a href="https://unsplash.com/@robertbye?utm_source=medium&amp;utm_medium=referral">Robert Bye</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>What is Multi-tasking?</h3><p>When I typed “multi-tasking” into Google search, the AI ​​instantly helped me define it. (Thanks, Gemini.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8WPlm0u2amoDx1qi8kGZog.png" /><figcaption>Definition of “Multiple-Tasking” (by Gemini)</figcaption></figure><p>Let me highlight some keywords:</p><blockquote>Multitasking is the act of performing <strong>02 or MORE</strong> tasks at the <strong>SAME </strong>time, or rapidly <strong>SWITCHING </strong>between tasks.</blockquote><p>The first promotion from a Junior to a Mid-level engineer, I went from constantly working on my tasks with senior support to doing my tasks while also supporting 1–2 members. It was not so overwhelming. I was able to handle that. Bingo!</p><p>The second promotion, when I became a Senior, changed everything dramatically. I was now managing engineers with responsibility, not just completing tasks. I worked long hours (and sometimes unpaid overtime) to ensure everything was completed as perfectly as possible (I’m a bit OCD).</p><p>Thanks to hard work, I became a Manager responsible for engineering teams, stakeholders, and business owners. After successfully working long hours and completing everything in one go during my second promotion, I tried to apply the same. Here’s how it went👇.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vEz9YwXP1e6_GCuS" /><figcaption>Photo by <a href="https://unsplash.com/@sixthcitysarah?utm_source=medium&amp;utm_medium=referral">sarah b</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>A very small percentage of people in the world are good at Multi-tasking.</h3><p>Even great people don’t choose to multitask.</p><ol><li>Bill Gates’ Mastery of ‘Deep Work’ Fueled His Success (Source: <a href="https://www.businessinsider.com/">https://www.businessinsider.com/</a>)</li><li>Steve Jobs Quote: “Focus comes from saying NO to a thousand things so you don’t go in the wrong direction or do too much.”</li><li>Elon Musk created his own “Time Blocking” Method to boost productivity.</li></ol><p>You and I are probably not a good fit for “Multiple-tasking” either.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*T3357zmCxvt7NPRl" /></figure><p>An average of 900 people die every day trying to multitask while driving. Think before you answer a text or change your Spotify music station.</p><h3>This is the Alternative</h3><p>What I have learned from a job changes as my mindset changes. Here are my practices for improving productivity and quality:</p><p>𝗛𝗮𝗻𝗱𝗹𝗲 𝗠𝗨𝗟𝗧𝗜-𝗧𝗔𝗦𝗞𝗜𝗡𝗚 𝗯𝘆 𝘀𝘂𝗰𝗰𝗲𝗲𝗱𝗶𝗻𝗴 𝗶𝗻 𝗦𝗜𝗡𝗚𝗟𝗘-𝗧𝗔𝗦𝗞𝗜𝗡𝗚 𝗮𝗻𝗱 𝗗𝗘𝗘𝗣-𝗧𝗔𝗦𝗞𝗜𝗡𝗚.</p><h4>What is Single-tasking?</h4><p>It’s exactly what it sounds like. Single-tasking is simply the act of focusing on ONE task at a time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YpVgB3oIAUNStaP1" /><figcaption>Photo by <a href="https://unsplash.com/@krakenimages?utm_source=medium&amp;utm_medium=referral">krakenimages</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4>What is Deep-working?</h4><blockquote>The term was coined by Cal Newport, a computer science professor at Georgetown University and author of “Deep Work: Rules for Focused Success in a Distracted World.” In his book, Newport defines deep work as a state of distraction-free concentration when your brain works at its maximum potential. — <a href="https://asana.com/resources/what-is-deep-work"><em>https://asana.com/resources/what-is-deep-work</em></a></blockquote><h4>How to Practice Single Tasking and Deep Tasking</h4><p>Let’s set a schedule for each hour of the day and stick to it while avoiding distractions like social media, games, and emails. Put your mind in 100% focus mode.</p><p>Something like this, with the main focus on the afternoon.</p><p>𝗠𝗼𝗿𝗻𝗶𝗻𝗴:<br>9:00–9:20: Plan the day<br>9:20–9:30: Check and prioritize emails<br>9:30–10:30: Focus on Task A<br>10:30–11:30: Focus on Task B<br>11:30–12:00: Check and prioritize emails<br>12:00–1:00: Lunch break</p><p>𝗔𝗳𝘁𝗲𝗿𝗻𝗼𝗼𝗻:<br>1:00–2:00: Meetings<br>2:00–2:30: Check and prioritize emails<br>2:30–3:30: Task C<br>3:30–4:30: Meetings<br>4:30–5:00: Check and prioritize emails<br>5:00–6:00: Task D and wrap up the day</p><p>Some tools that support Single-tasking and Deep Work:</p><ul><li>Pomodoro technique: Work for 25–50 minutes, then take a 5–10 minute break.</li><li>Focus apps: Block distractions with tools like Forest, Focus@Will, and Freedom.</li></ul><p>Many creative ways exist to manage multiple projects in software engineering and other fields.</p><p>Got any good tips? Sharing is caring.</p><blockquote>💡Data Migration, Analytics, AI &amp; Automation | Sharing the Journey on <a href="https://medium.com/@yennhi95zz/subscribe">Medium</a> || <a href="https://github.com/yennhi95zz">Github</a> || <a href="https://www.kaggle.com/nhiyen/code">Kaggle</a> || <a href="https://www.linkedin.com/in/yennhi95zz/">Linkedin</a>. 🔔 Follow “Nhi Yen” for future updates!</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6a7a2e48ba16" width="1" height="1" alt=""><hr><p><a href="https://code.likeagirl.io/a-successful-manager-must-excel-at-multi-tasking-6a7a2e48ba16">A successful Manager must excel at Multi-tasking</a> was originally published in <a href="https://code.likeagirl.io/">Code Like A Girl</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 AI for Earning Passive Income]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-and-beyond/how-to-use-ai-for-earning-passive-income-31b9a457ff76?source=rss-81c441aba61e------2"><img src="https://cdn-images-1.medium.com/max/1280/1*xDgMX9GkkYPuP7SyQ3sM2w.jpeg" width="1280"></a></p><p class="medium-feed-snippet">5 Realistic Ways to Make Money With AI</p><p class="medium-feed-link"><a href="https://medium.com/data-and-beyond/how-to-use-ai-for-earning-passive-income-31b9a457ff76?source=rss-81c441aba61e------2">Continue reading on Data And Beyond »</a></p></div>]]></description>
            <link>https://medium.com/data-and-beyond/how-to-use-ai-for-earning-passive-income-31b9a457ff76?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/31b9a457ff76</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[generative-ai-engineers]]></category>
            <category><![CDATA[money-mindset]]></category>
            <category><![CDATA[passive-income]]></category>
            <category><![CDATA[marketing-automation]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Sat, 20 Jul 2024 10:54:13 GMT</pubDate>
            <atom:updated>2024-07-20T10:54:13.308Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Increase Predictions by 50% with Smart Prompting]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://aiadvances.org/increase-predictions-by-50-with-smart-prompting-981385fb10af?source=rss-81c441aba61e------2"><img src="https://cdn-images-1.medium.com/max/2600/0*cGPi5-h0sNDbafZd" width="6960"></a></p><p class="medium-feed-snippet">How to Achieve the Highest Prediction with Prompt Engineering Techniques</p><p class="medium-feed-link"><a href="https://aiadvances.org/increase-predictions-by-50-with-smart-prompting-981385fb10af?source=rss-81c441aba61e------2">Continue reading on AI Advances »</a></p></div>]]></description>
            <link>https://aiadvances.org/increase-predictions-by-50-with-smart-prompting-981385fb10af?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/981385fb10af</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[llmprompt]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[prompt-engineering]]></category>
            <category><![CDATA[openai]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Mon, 01 Jul 2024 00:53:42 GMT</pubDate>
            <atom:updated>2024-07-01T00:53:42.797Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[How to Easily Automate Web Scraping with a Simple Data Pipeline]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/data-and-beyond/how-to-easily-automate-web-scraping-with-a-simple-data-pipeline-917d0a692472?source=rss-81c441aba61e------2"><img src="https://cdn-images-1.medium.com/max/2600/0*Eepae7lGRN7YcyMF" width="5184"></a></p><p class="medium-feed-snippet">LLM for fully automated web scraping, creating an end-to-end data extraction process that streamlines your workflow.</p><p class="medium-feed-link"><a href="https://medium.com/data-and-beyond/how-to-easily-automate-web-scraping-with-a-simple-data-pipeline-917d0a692472?source=rss-81c441aba61e------2">Continue reading on Data And Beyond »</a></p></div>]]></description>
            <link>https://medium.com/data-and-beyond/how-to-easily-automate-web-scraping-with-a-simple-data-pipeline-917d0a692472?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/917d0a692472</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[web-scraping]]></category>
            <category><![CDATA[data-pipeline]]></category>
            <category><![CDATA[kafka]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Thu, 06 Jun 2024 10:58:01 GMT</pubDate>
            <atom:updated>2024-06-06T10:58:03.630Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Web Scraping With 5 Different Methods: All You Need to Know]]></title>
            <link>https://heartbeat.comet.ml/web-scraping-with-5-different-methods-all-you-need-to-know-403a59fceea0?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/403a59fceea0</guid>
            <category><![CDATA[langchain]]></category>
            <category><![CDATA[data-mining]]></category>
            <category><![CDATA[data-extraction]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[web-scraping]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Thu, 29 Feb 2024 12:01:34 GMT</pubDate>
            <atom:updated>2024-02-29T12:01:34.952Z</atom:updated>
            <content:encoded><![CDATA[<h4>Including how to use LangChain and LLMs for web scraping!</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vewcr3nh268dlgyBX_v10w.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@nate_dumlao?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Nathan Dumlao</a> on <a href="https://unsplash.com/photos/spider-web-in-close-up-photography-kME9jbKd--s?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure><h3>Introduction</h3><p>Web scraping automates the extraction of data from websites using programming or specialized tools. Required for tasks such as market research, data analysis, content aggregation, and competitive intelligence. This efficient method saves time, improves decision making, and allows businesses to study trends and patterns, making it a powerful tool for extracting valuable information from the Internet.</p><p>Since I received a lot of positive comments on my last article, I would like to delve into this topic that is of interest to many people. Besides <strong><em>BeautifulSoup, Scrapy, and Selenium</em></strong>, have you considered web scraping using <strong>LLM</strong>? It’s a technique worthy of your curiosity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/433/1*sFV53FmQNtgXPOoHeBHtlw.png" /><figcaption>Web Scraping using 5 Methods (Image by the Author)</figcaption></figure><p><em>👉 Check out my earlier articles for more information:</em></p><ul><li><a href="https://medium.com/nerd-for-tech/4000-freelance-income-exploring-more-than-just-web-scraping-93548fcbc9b6">$4000 Freelance Income: Exploring More Than Just Web Scraping</a></li><li><a href="https://medium.com/nerd-for-tech/before-you-freelance-5-must-know-truths-b79ee99cf729">Before You Freelance: 5 Must-Know Truths</a></li></ul><blockquote>💡I write about Machine Learning on <a href="https://medium.com/@yennhi95zz/subscribe">Medium</a> || <a href="https://github.com/yennhi95zz">Github</a> || <a href="https://www.kaggle.com/nhiyen/code">Kaggle</a> || <a href="https://www.linkedin.com/in/yennhi95zz/">Linkedin</a>. 🔔 Follow “Nhi Yen” for future updates!</blockquote><p><em>👉 Get UNLIMITED access to every story on Medium with just $1/week — </em><a href="https://medium.com/@yennhi95zz/membership"><strong><em>HERE</em></strong></a></p><h3>Let’s start!!!</h3><p>If you know Python but not HTML, you should first understand the basics of HTML.</p><h3>I. Understand Basic HTML</h3><p>HTML is the basic component of web pages. A set of tags is used to structure content on the Internet. Tags are like containers that wrap various elements, defining their structure and appearance on a web page.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/430/1*3Xw1ZTDu_Y7fah7Ho1OUzQ.png" /><figcaption>HTML Elements (<a href="https://www.google.com/url?sa=i&amp;url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FHTML_element&amp;psig=AOvVaw2zGrk7dQ4NMPrOfefnhOwb&amp;ust=1707134317263000&amp;source=images&amp;cd=vfe&amp;opi=89978449&amp;ved=0CBUQjhxqFwoTCMDjvobRkYQDFQAAAAAdAAAAABAE">Wikipedia</a>)</figcaption></figure><h4><strong>1. Structure of HTML</strong></h4><p>An HTML document consists of 2 main parts: header and body.</p><ul><li><strong>The header</strong> contains metadata such as the page title and links to external resources.</li><li><strong>The body</strong> contains the content of the web page, including text, images, and other multimedia elements.</li></ul><p>Here’s a simple HTML template:</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;My First Web Page&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;h1&gt;Hello, World!&lt;/h1&gt;<br>    &lt;p&gt;This is a simple webpage.&lt;/p&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><h4>2. HTML Tags</h4><p>Tags are the heart of HTML. They define different elements on a webpage. Some common tags include:</p><ul><li>&lt;h1&gt; to &lt;h6&gt;: Headings, with &lt;h1&gt; being the largest and &lt;h6&gt; the smallest.</li><li>&lt;p&gt;: Paragraphs of text.</li><li>&lt;a&gt;: Hyperlinks, allowing you to navigate to other pages.</li><li>&lt;img&gt;: Images.</li><li>&lt;ul&gt;, &lt;ol&gt;, &lt;li&gt;: Lists, both unordered and ordered.</li></ul><h4>3. Attributes:</h4><p>Attributes provide additional information about an HTML element. These are always included in the opening tag and specified as name/value pairs. For example, the href attribute in an &lt;a&gt; tag defines the hyperlink&#39;s destination.</p><pre>&lt;a href=&quot;https://www.example.com&quot;&gt;Visit Example&lt;/a&gt;</pre><h4>4. How to Inspect Elements in a Website</h4><p>Most web browsers provide built-in tools for inspecting elements. To open this tool, right-click the web page and select <strong><em>Inspect</em></strong>. Here you can view the HTML code and identify the tags containing the data you want to extract.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1011/1*4I4dJsRE6ZfihITbZ_ZBbA.png" /><figcaption>Inspect option in Google Chrome (Image by the Author)</figcaption></figure><p>Selectors help pinpoint specific elements on a webpage. Common selectors include:</p><ul><li>Element Selector: element selects all instances of the specified HTML element.</li><li>Class Selector: .class selects all elements with the specified class.</li><li>ID Selector: #id selects a unique element with the specified ID.</li></ul><p>For example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1018/1*c6Pd2BJUjOLesGHVkq-YgA.png" /><figcaption>Inspect IMDM website (Image by the Author)</figcaption></figure><h3>II. How to “Web Scrape”</h3><h4>❗Disclaimer</h4><p>This article is not about web scraping for illegal purposes. Make sure you have permission before extracting content. Ways to check include:</p><ol><li>Review the website’s terms of use. Look for mentions of scraping permissions.</li><li>Use APIs when available. APIs provide legal access to data.</li><li>Please contact the website owner to clarify your permission directly.</li></ol><p>OK, assume you are aware of your actions. Let’s start.</p><p>Here’s the URL for <strong>Action Movies of 2022</strong>: <a href="https://www.imdb.com/list/ls566941243/">https://www.imdb.com/list/ls566941243/</a>. I’ll use 05 different methods to scrape [‘Title’, ‘Genre’, ‘Stars’, ‘Runtime’, ‘Rating’] data from this website.</p><pre># Define the URL<br>url = &quot;https://www.imdb.com/list/ls566941243/&quot;</pre><p><em>👉 You can find the entire code in this </em><a href="https://github.com/yennhi95zz/langchain-web-scraping"><strong><em>GitHub Repository</em></strong></a><em>. To begin, please install the required Python packages listed in </em><strong><em>requirements.txt</em></strong><em>.</em></p><h3>Method 1: BeautifulSoup and Requests</h3><p>The first method uses the popular BeautifulSoup and Requests libraries. These tools make it easy to analyze HTML and navigate web page structure. Below is a sample Python code.</p><pre>import requests<br>from bs4 import BeautifulSoup<br>import pandas as pd<br><br># Step 1: Send a GET request to the specified URL<br>response = requests.get(url)<br><br># Step 2: Parse the HTML content of the response using BeautifulSoup<br>soup = BeautifulSoup(response.text, &#39;html.parser&#39;)<br><br># Step 3: Save the HTML content to a text file for reference<br>with open(&quot;imdb.txt&quot;, &quot;w&quot;, encoding=&quot;utf-8&quot;) as file:<br>    file.write(str(soup))<br>print(&quot;Page content has been saved to imdb.txt&quot;)<br><br># Step 4: Extract movie data from the parsed HTML and store it in a list<br>movies_data = []<br>for movie in soup.find_all(&#39;div&#39;, class_=&#39;lister-item-content&#39;):<br>    title = movie.find(&#39;a&#39;).text<br>    genre = movie.find(&#39;span&#39;, class_=&#39;genre&#39;).text.strip()<br>    stars = movie.find(&#39;div&#39;, class_=&#39;ipl-rating-star&#39;).find(&#39;span&#39;, class_=&#39;ipl-rating-star__rating&#39;).text<br>    runtime = movie.find(&#39;span&#39;, class_=&#39;runtime&#39;).text<br>    rating = movie.find(&#39;span&#39;, class_=&#39;ipl-rating-star__rating&#39;).text<br>    movies_data.append([title, genre, stars, runtime, rating])<br><br># Step 5: Create a Pandas DataFrame from the extracted movie data<br>df = pd.DataFrame(movies_data, columns=[&#39;Title&#39;, &#39;Genre&#39;, &#39;Stars&#39;, &#39;Runtime&#39;, &#39;Rating&#39;])<br><br># Display the resulting DataFrame<br>df</pre><p>In each web scraping method, I save the HTML in an imdb.txt file for a clearer view of the targeted HTML elements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/788/1*yxWPLhINzdDgJJf0P4BYbQ.png" /><figcaption>Save HTML content in a txt file (Image by the Author)</figcaption></figure><p>Final Output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/543/1*vHlMkgP8S2k9-8BwFr37zA.png" /><figcaption>Web Scraping using BeautifulSoup and Requests (Image by the Author)</figcaption></figure><h3>Method 2: Scrapy</h3><p>Scrapy is a powerful and flexible web scraping framework. Below is a code snippet showing how to use <strong><em>Scrapy</em></strong>, with explanations in the comments.:</p><pre># Import necessary libraries<br>import scrapy<br>from scrapy.crawler import CrawlerProcess<br><br># Define the Spider class for IMDb data extraction<br>class IMDbSpider(scrapy.Spider):<br>    # Name of the spider<br>    name = &quot;imdb_spider&quot;<br>    # Starting URL(s) for the spider to crawl<br>    start_urls = [&quot;https://www.imdb.com/list/ls566941243/&quot;]<br>    # start_urls = [url]<br><br>    # Parse method to extract data from the webpage<br>    def parse(self, response):<br>        # Iterate over each movie item on the webpage<br>        for movie in response.css(&#39;div.lister-item-content&#39;):<br>            yield {<br>                &#39;title&#39;: movie.css(&#39;h3.lister-item-header a::text&#39;).get(),<br>                &#39;genre&#39;: movie.css(&#39;p.text-muted span.genre::text&#39;).get(),<br>                &#39;runtime&#39;: movie.css(&#39;p.text-muted span.runtime::text&#39;).get(),<br>                &#39;rating&#39;: movie.css(&#39;div.ipl-rating-star span.ipl-rating-star__rating::text&#39;).get(),<br>            }<br># Initialize a CrawlerProcess instance with settings<br>process = CrawlerProcess(settings={<br>    &#39;FEED_FORMAT&#39;: &#39;json&#39;,<br>    &#39;FEED_URI&#39;: &#39;output.json&#39;,  # This will overwrite the file every time you run the spider<br>})<br><br><br># Add the IMDbSpider to the crawling process<br>process.crawl(IMDbSpider)<br># Start the crawling process<br>process.start()</pre><pre>import pandas as pd<br><br># Read the output.json file into a DataFrame (jsonlines format)<br>df = pd.read_json(&#39;output.json&#39;)<br><br># Display the DataFrame<br>df.head()</pre><p>In this demo, I’m using Jupyter Notebook. If you encounter a <strong><em>ReactorNotRestartable</em></strong> error, just restart the kernel and run the code again.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/876/1*0ostaXEaX6_i2XpwfUToJQ.png" /><figcaption>Example: ReactorNotRestartable Error while using Scrapy</figcaption></figure><p>Display the data in a dataframe:</p><pre>import pandas as pd<br><br># Read the output.json file into a DataFrame (jsonlines format)<br>df = pd.read_json(&#39;output.json&#39;)<br><br># Display the DataFrame<br>df.head()</pre><h3>Method 3: Selenium</h3><p>Selenium is often used for dynamic web scraping. Here’s a basic example:</p><pre>from selenium import webdriver<br>from bs4 import BeautifulSoup<br>import pandas as pd<br><br># URL of the IMDb list<br>url = &quot;https://www.imdb.com/list/ls566941243/&quot;<br><br># Set up Chrome options to run the browser in incognito mode<br>chrome_options = webdriver.ChromeOptions()<br>chrome_options.add_argument(&quot;--incognito&quot;)<br><br># Initialize the Chrome driver with the specified options<br>driver = webdriver.Chrome(options=chrome_options)<br><br># Navigate to the IMDb list URL<br>driver.get(url)<br><br># Wait for the page to load (adjust the wait time according to your webpage)<br>driver.implicitly_wait(10)<br><br># Get the HTML content of the page after it has fully loaded<br>html_content = driver.page_source<br><br># Parse the HTML content with BeautifulSoup<br>soup = BeautifulSoup(html_content, &#39;html.parser&#39;)<br><br># Save the HTML content to a text file for reference<br>with open(&quot;imdb_selenium.txt&quot;, &quot;w&quot;, encoding=&quot;utf-8&quot;) as file:<br>    file.write(str(soup))<br>print(&quot;Page content has been saved to imdb_selenium.txt&quot;)<br><br># Extract movie data from the parsed HTML<br>movies_data = []<br>for movie in soup.find_all(&#39;div&#39;, class_=&#39;lister-item-content&#39;):<br>    title = movie.find(&#39;a&#39;).text<br>    genre = movie.find(&#39;span&#39;, class_=&#39;genre&#39;).text.strip()<br>    stars = movie.select_one(&#39;div.ipl-rating-star span.ipl-rating-star__rating&#39;).text<br>    runtime = movie.find(&#39;span&#39;, class_=&#39;runtime&#39;).text<br>    rating = movie.select_one(&#39;div.ipl-rating-star span.ipl-rating-star__rating&#39;).text<br>    movies_data.append([title, genre, stars, runtime, rating])<br><br># Create a Pandas DataFrame from the collected movie data<br>df = pd.DataFrame(movies_data, columns=[&#39;Title&#39;, &#39;Genre&#39;, &#39;Stars&#39;, &#39;Runtime&#39;, &#39;Rating&#39;])<br><br># Display the resulting DataFrame<br>print(df)<br><br># Close the Chrome driver<br>driver.quit()</pre><p>Final Output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*2K4HxrQJBgAcyS6Jc9M44A.png" /><figcaption>Web Scraping using selenium (Image by the Author)</figcaption></figure><p>The key to <strong><em>Selenium</em></strong> is in its <strong><em>Chrome options</em></strong>, which are settings for customizing the behavior of the Chrome browser controlled by Selenium WebDriver. These options enable control over aspects like incognito mode, window size, notifications, and more.</p><p>Here are some important Chrome options that you might find useful:</p><pre># Runs the browser in incognito (private browsing) mode.<br>chrome_options.add_argument(&quot;--incognito&quot;)<br><br># Runs the browser in headless mode, i.e., without a graphical user interface. <br># Useful for running Selenium tests in the background without opening a visible browser window.<br>chrome_options.add_argument(&quot;--headless&quot;)<br><br># Sets the initial window size of the browser.<br>chrome_options.add_argument(&quot;--window-size=1200x600&quot;)<br><br># Disables browser notifications.<br>chrome_options.add_argument(&quot;--disable-notifications&quot;)<br><br># Disables the infobar that appears at the top of the browser.<br>chrome_options.add_argument(&quot;--disable-infobars&quot;)<br><br># Disables browser extensions.<br>chrome_options.add_argument(&quot;--disable-extensions&quot;)<br><br># Disables the GPU hardware acceleration.<br>chrome_options.add_argument(&quot;--disable-gpu&quot;)<br><br># Disables web security features, which can be useful for testing on localhost without CORS issues.<br>chrome_options.add_argument(&quot;--disable-web-security&quot;)</pre><p>These options can be combined or used individually based on your requirements. When you create a webdriver.Chrome instance, you can pass these options using the options parameter:</p><pre>from selenium import webdriver<br><br>chrome_options = webdriver.ChromeOptions()<br>chrome_options.add_argument(&quot;--incognito&quot;)<br>chrome_options.add_argument(&quot;--headless&quot;)<br><br>driver = webdriver.Chrome(options=chrome_options)</pre><p>These options provide flexibility and control over the browser’s behavior when using Selenium for web automation or testing. Choose options based on your specific use case and requirements.</p><h3>Method 4: <strong>Requests and lxml</strong></h3><p><strong><em>lxml</em></strong> is a Python library linking with C libraries <strong><em>libxml2</em></strong> and <strong><em>libxslt</em></strong>, combining speed and XML features with a simple native Python API, similar to ElementTree but with added benefits.</p><pre>import requests<br>from lxml import html<br>import pandas as pd<br><br># Define the URL<br>url = &quot;https://www.imdb.com/list/ls566941243/&quot;<br><br># Send an HTTP request to the URL and get the response<br>response = requests.get(url)<br><br># Parse the HTML content using lxml<br>tree = html.fromstring(response.content)<br><br># Extract movie data from the parsed HTML<br>titles = tree.xpath(&#39;//h3[@class=&quot;lister-item-header&quot;]/a/text()&#39;)<br>genres = [&#39;, &#39;.join(genre.strip() for genre in genre_list.xpath(&quot;.//text()&quot;)) for genre_list in tree.xpath(&#39;//p[@class=&quot;text-muted text-small&quot;]/span[@class=&quot;genre&quot;]&#39;)]<br>ratings = tree.xpath(&#39;//div[@class=&quot;ipl-rating-star small&quot;]/span[@class=&quot;ipl-rating-star__rating&quot;]/text()&#39;)<br>runtimes = tree.xpath(&#39;//p[@class=&quot;text-muted text-small&quot;]/span[@class=&quot;runtime&quot;]/text()&#39;)<br><br># Create a dictionary with extracted data<br>data = {<br>    &#39;Title&#39;: titles,<br>    &#39;Genre&#39;: genres,<br>    &#39;Rating&#39;: ratings,<br>    &#39;Runtime&#39;: runtimes<br>}<br><br># Create a DataFrame from the dictionary<br>df = pd.DataFrame(data)<br><br># Display the resulting DataFrame<br>df.head()</pre><h3>Method 5: How to Use LangChain for Web Scraping</h3><p>I bet all the readers who are interested this article know about ChatGPT, BARD. LLM makes life simpler. You can use it for various tasks, like asking <em>‘Who is Donald Trump?’ or ‘Translate sentences from German to English,’</em> and get quick answers. The good news is you can also use them for Web Scraping. Here’s how.</p><p><em>👉 Helpful LangChain resources for this demo:</em></p><ul><li><a href="https://python.langchain.com/docs/integrations/document_transformers/beautiful_soup"><em>LangChain Beautiful Soup</em></a></li><li><a href="https://python.langchain.com/docs/use_cases/extraction"><em>LangChain Extraction</em></a></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/660/1*Seui-YR43HJ8e3J7nvzFAA.png" /><figcaption>Web Scraping using LangChain LLM (Image by the Author)</figcaption></figure><p>Brief explanations for each code line are provided in the comments.</p><pre>import os<br>import dotenv<br>import time<br><br># Load environment variables from a .env file<br>dotenv.load_dotenv()<br><br># Retrieve OpenAI and Comet key from environment variables<br>MY_OPENAI_KEY = os.getenv(&quot;MY_OPENAI_KEY&quot;)<br>MY_COMET_KEY = os.getenv(&quot;MY_COMET_KEY&quot;)</pre><p>In my LLM Project, I usually record outputs in a Comet Project. In this demo, I’m using just 01 URL. However, if you need to loop through multiple URLs, Comet LLM’s experiment tracking is very useful.</p><p><em>👉 Read more about </em><a href="https://www.comet.com/site/products/llmops/"><em>Comet LLM</em></a><em>.</em></p><p><em>👉 How to obtain the API keys: </em><a href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key"><em>OpenAI Help Center — Where can I find my API key?</em></a><em>; </em><a href="https://www.comet.com/docs/v2/api-and-sdk/rest-api/overview/"><em>CometLLM — Obtaining your API key</em></a></p><pre>import comet_llm<br><br># Initialize a Comet project<br>comet_llm.init(project=&quot;langchain-web-scraping&quot;,<br>               api_key=MY_COMET_KEY,<br>               )</pre><pre># Resolve async issues by applying nest_asyncio<br>import nest_asyncio<br>nest_asyncio.apply()<br><br># Import required modules from langchain<br>from langchain_openai import ChatOpenAI<br>from langchain_community.document_loaders import AsyncChromiumLoader<br>from langchain_community.document_transformers import BeautifulSoupTransformer<br>from langchain.text_splitter import RecursiveCharacterTextSplitter<br>from langchain.chains import create_extraction_chain<br><br># Define the URL<br>url = &quot;https://www.imdb.com/list/ls566941243/&quot;<br><br># Initialize ChatOpenAI instance with OpenAI API key<br>llm = ChatOpenAI(openai_api_key=MY_OPENAI_KEY)<br><br># Load HTML content using AsyncChromiumLoader<br>loader = AsyncChromiumLoader([url])<br>docs = loader.load()<br><br># Save the HTML content to a text file for reference<br>with open(&quot;imdb_langchain_html.txt&quot;, &quot;w&quot;, encoding=&quot;utf-8&quot;) as file:<br>    file.write(str(docs[0].page_content))<br>print(&quot;Page content has been saved to imdb_langchain_html.txt&quot;)<br><br># Transform the loaded HTML using BeautifulSoupTransformer<br>bs_transformer = BeautifulSoupTransformer()<br>docs_transformed = bs_transformer.transform_documents(<br>    docs, tags_to_extract=[&quot;h3&quot;, &quot;p&quot;]<br>)<br><br># Split the transformed documents using RecursiveCharacterTextSplitter<br>splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=1000, chunk_overlap=0)<br>splits = splitter.split_documents(docs_transformed)</pre><p>Please note that depending on your needs, you might want to explore the HTML layout to select the right tags_to_extract. In this demo, I am extracting movie title, genre, rating, and runtime, so I’ll go with the &lt;h3&gt; and &lt;p&gt; tags.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/784/1*W3x49FEVsPtabyHMIYhmEg.png" /></figure><p>Basically after obtaining the required HTML, we will ask LLM: <em>“Hey LLM, with this HTML, please fill in the information according to the schema below.”</em></p><pre># Define a JSON schema for movie data validation<br>schema = {<br>    &quot;properties&quot;: {<br>        &quot;movie_title&quot;: {&quot;type&quot;: &quot;string&quot;},<br>        &quot;stars&quot;: {&quot;type&quot;: &quot;integer&quot;},<br>        &quot;genre&quot;: {&quot;type&quot;: &quot;array&quot;, &quot;items&quot;: {&quot;type&quot;: &quot;string&quot;}},<br>        &quot;runtime&quot;: {&quot;type&quot;: &quot;string&quot;},<br>        &quot;rating&quot;: {&quot;type&quot;: &quot;string&quot;},<br>    },<br>    &quot;required&quot;: [&quot;movie_title&quot;, &quot;stars&quot;, &quot;genre&quot;, &quot;runtime&quot;, &quot;rating&quot;],<br>}<br><br>def extract_movie_data(content: str, schema: dict):<br>    &quot;&quot;&quot;<br>    Extract movie data from content using a specified JSON schema.<br><br>    Parameters:<br>    - content (str): Text content containing movie data.<br>    - schema (dict): JSON schema for validating the movie data.<br><br>    Returns:<br>    - dict: Extracted movie data.<br>    &quot;&quot;&quot;<br>    # Run the extraction chain with the provided schema and content<br>    start_time = time.time()<br>    extracted_content = create_extraction_chain(schema=schema, llm=llm).run(content)<br>    end_time = time.time()<br><br>    # Log metadata and output in the Comet project for tracking purposes<br>    comet_llm.log_prompt(<br>        prompt=str(content),<br>        metadata= {<br>            &quot;schema&quot;: schema<br>        },<br>        output= extracted_content,<br>        duration= end_time - start_time,<br>    )<br><br>    return extracted_content<br></pre><p>And finally, we’ve got the result:</p><pre># Extract movie data using the defined schema and the first split page content<br>extracted_content = extract_movie_data(schema=schema, content=splits[0].page_content)<br><br># Display the extracted movie data<br>extracted_content</pre><p>Final Output:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/444/1*YMqSmcNzlRlYWFkANnbspg.png" /><figcaption>Output: WebScraping using LangChain LLM (Image by the Author)</figcaption></figure><p>There’s a lot to discover about LLMs. Want more topics on LLM? Share your thoughts in the comments!</p><ul><li><a href="https://heartbeat.comet.ml/how-to-create-a-simple-chatbot-for-e-commerce-using-openai-aa0539b9875b">How to Create a Simple Chatbot for E-commerce Using OpenAI</a></li><li><a href="https://heartbeat.comet.ml/how-to-enhance-conversational-agents-with-memory-in-lang-chain-6aadd335b621">How to Enhance Conversational Agents with Memory in Lang Chain</a></li></ul><h3><em>❗</em>A Heads-up</h3><p>Web scraping is not as simple as you might think. You may face challenges along the way.</p><ol><li><strong>Dynamic website structures:</strong> Modern websites use dynamic JavaScript structures and require tools like Selenium for accurate data extraction.</li><li><strong>Anti-scraping</strong>: IP blocks and CAPTCHAs are common deterrents. Strategies such as IP address rotation can help overcome these obstacles.</li><li><strong>Legal and Ethical Considerations</strong>: To avoid legal repercussions, it is important to follow the website’s terms of use. Prioritize ethical practices and ask for permission.</li><li><strong>Data quality and consistency</strong>: Maintaining data quality while updating a website is an ongoing challenge. Update your scraping script regularly to ensure accurate and reliable extraction.</li></ol><h3>Conclusion</h3><p>Web scraping is worth a try. It may not seem like a formal job, but it’s actually a lot of fun using Python, JavaScript, and HTML. There are many ways to collect information from websites. I hope you will try more than just web scraping by implementing LLM techniques.</p><p><em>#WebScraping #DataExtraction #DataMining #WebDevelopment #LLM #LangChain</em></p><p><em>Editor’s Note: </em><a href="https://heartbeat.comet.ml/"><em>Heartbeat</em></a><em> is a contributor-driven online publication and community dedicated to providing premier educational resources for data science, machine learning, and deep learning practitioners. We’re committed to supporting and inspiring developers and engineers from all walks of life.</em></p><p><em>Editorially independent, Heartbeat is sponsored and published by </em><a href="http://comet.com/?utm_source=heartbeat&amp;utm_medium=referral&amp;utm_campaign=AMS_US_EN_AWA_heartbeat_EN"><em>Comet,</em></a><em> an MLOps platform that enables data scientists &amp; ML teams to track, compare, explain, &amp; optimize their experiments. We pay our contributors, and we don’t sell ads.</em></p><p><em>If you’d like to contribute, head on over to our</em><a href="https://heartbeat.comet.ml/call-for-contributors-fee7f5b80f3e"><em> call for contributors</em></a><em>. You can also sign up to receive our weekly newsletter (</em><a href="https://www.deeplearningweekly.com/"><em>Deep Learning Weekly</em></a><em>), check out the </em><a href="https://www.comet.com/site/blog/"><em>Comet blog</em></a><em>, join us on</em><a href="https://join.slack.com/t/fritz-ai-community/shared_invite/enQtNTY5NDM2MTQwMTgwLWU4ZDEwNTAxYWE2YjIxZDllMTcxMWE4MGFhNDk5Y2QwNTcxYzEyNWZmZWEwMzE4NTFkOWY2NTM0OGQwYjM5Y2U"><em> </em></a><a href="https://join.slack.com/t/cometml/shared_invite/zt-49v4zxxz-qHcTeyrMEzqZc5lQb9hgvw"><em>Slack</em></a><em>, and follow Comet on </em><a href="https://twitter.com/Cometml"><em>Twitter</em></a><em> and </em><a href="https://www.linkedin.com/company/comet-ml/"><em>LinkedIn</em></a><em> for resources, events, and much more that will help you build better ML models, faster.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=403a59fceea0" width="1" height="1" alt=""><hr><p><a href="https://heartbeat.comet.ml/web-scraping-with-5-different-methods-all-you-need-to-know-403a59fceea0">Web Scraping With 5 Different Methods: All You Need to Know</a> was originally published in <a href="https://heartbeat.comet.ml/">Heartbeat</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Decoding the Significance of Chaining in LLMOps]]></title>
            <link>https://heartbeat.comet.ml/decoding-the-significance-of-chaining-in-llmops-6d82c918e04c?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/6d82c918e04c</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[llmchain]]></category>
            <category><![CDATA[langchain]]></category>
            <category><![CDATA[llmops]]></category>
            <category><![CDATA[prompt-engineering]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Fri, 09 Feb 2024 12:01:26 GMT</pubDate>
            <atom:updated>2024-02-09T12:01:26.801Z</atom:updated>
            <content:encoded><![CDATA[<h4>Everything about Chaining in LLMs</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fN8G1YMbspfttT6BCWLmtw.png" /></figure><h3>Table of Contents</h3><p><em>I. LLM Chains</em></p><p><em>II. What is exactly Chaining in LLMOps and is it essential?</em></p><p><em>1. The Basics of Chaining</em></p><p><em>2. Core Chains in LLMOps</em></p><p><em>2.1. Prompt Chain</em></p><p><em>2.2. Tools Chain</em></p><p><em>2.3. Data Indexing Chain</em></p><p><em>2.4. Best Practices for Core Chains</em></p><p><em>III. Lang Chain: The Glue that Connects</em></p><blockquote>💡I write about Machine Learning on <a href="https://medium.com/@yennhi95zz/subscribe">Medium</a> || <a href="https://github.com/yennhi95zz">Github</a> || <a href="https://www.kaggle.com/nhiyen/code">Kaggle</a> || <a href="https://www.linkedin.com/in/yennhi95zz/">Linkedin</a>. 🔔 Follow “Nhi Yen” for future updates!</blockquote><p><em>👉 Get UNLIMITED access to every story on Medium with just $1/week — </em><a href="https://medium.com/@yennhi95zz/membership"><em>HERE</em></a></p><p>You may have come across terms like OpenAI, LLM, LLM Chain, LangChain, Llama Index, etc., but this is causing a bit of confusion. Let’s try to simplify things by understanding the basics of LLM and LLM Chains, what Chaining is.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*T-WLZ1nrw2e1oM5N" /><figcaption>Photo by <a href="https://unsplash.com/@_miltiadis_?utm_source=medium&amp;utm_medium=referral">Miltiadis Fragkidis</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>I. LLM Chains</h3><p>Using OpenAI models as an example, there are two distinct approaches to interacting with language models: Direct LLM Interface and the LLMChain Interface. Let’s look at the characteristics of each and decide which one to choose.</p><p><strong>1. Direct LLM Interface: Simplifying Ad-Hoc Tasks</strong></p><p>Essentially, LLM is a foundational class for interacting with language models. LLM streamlines the process by handling <strong><em>important low-level tasks</em></strong> such as rapid tokenization, API calls, and error handling.</p><p>Let’s illustrate this simplicity with a snippet:</p><pre>llm = OpenAI(temperature=0.9)    <br>if prompt:            <br>    response = llm(&quot;Who is Donald Trump?&quot;)<br>    st.write(response)</pre><p>LLM is ideal for basic language processing tasks because you can pass messages and start interacting with language models in just a few lines. By using instances of OpenAI classes directly, users can enter prompts with a variety of structures, making them suitable for flexible or ad hoc tasks. This model generates responses <strong><em>without requiring a predefined request format.</em></strong></p><p><em>👉 The article below is a showcase of using Direct LLM Interface. In the project, I used OpenAI GPT-3.5 Turbo model for natural language processing and </em><em>comet_llm to keep track of what users ask, how the bot responds, and how long each interaction takes.</em></p><p><a href="https://heartbeat.comet.ml/how-to-create-a-simple-chatbot-for-e-commerce-using-openai-aa0539b9875b">How to Create a Simple Chatbot for E-commerce Using OpenAI</a></p><p><em>👉 Check out Comet in action by looking through my previous hands-on projects:</em></p><ul><li><a href="https://www.comet.com/site/blog/customer-churn-with-continuous-experiment-tracking?utm_source=Heartbeat&amp;utm_content=NhiYen"><em>Enhancing Customer Churn Prediction with Continuous Experiment Tracking</em></a></li><li><a href="https://www.comet.com/site/blog/hyperparameter-tuning-a-key-for-optimizing-ml-performance?utm_source=Heartbeat&amp;utm_content=NhiYen"><em>Hyperparameter Tuning in Machine Learning: A Key to Optimize Model Performance</em></a></li><li><a href="https://medium.com/mlearning-ai/the-magic-of-model-stacking-boosting-machine-learning-performance-2f6719a0bfd8"><em>The Magic of Model Stacking: Boosting Machine Learning Performance</em></a></li><li><a href="https://medium.com/p/e1eb04e74eb5"><em>Logging — The Effective Management of Machine Learning Systems</em></a></li></ul><p><strong>2. LLMChain Interface: Level up the Game with Additional Logic</strong></p><p>Now let’s use LLMChain to level up. LLMChain is a sophisticated chain that encapsulates LLM and enhances its functionality with additional features. Think about message formatting, input/output analysis, and conversation management. LLMChain covers everything.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/419/1*d0cBHh_tkNPK6r-N7P_TEQ.png" /><figcaption>LLM vs. LLM Chain (Image by the Author)</figcaption></figure><p>The snippet below showcases its prowess:</p><pre>from langchain.prompts import PromptTemplate<br>from langchain.chains import LLMChain<br><br>template = &quot;Write me something about {topic}&quot;<br>topic_template = PromptTemplate(input_variables=[&#39;topic&#39;], template=template)<br>topic_chain = LLMChain(llm=llm, prompt=topic_template)<br>if prompt:    <br> response = topic_chain.run(question)<br> st.write(response)</pre><p>LLMChain is like a very smart tool that works in conjunction with LLM to facilitate complex language tasks. In the example above, using LLMChain with the <strong><em>PromptTemplate</em></strong> class adds an extra layer to keep things organized, especially for structured tasks. This method is best when you want a consistent format for your prompts. <strong><em>PromptTemplate</em></strong> allows you to define a structured message with specific details, and LLMChain uses this template to generate a response using the underlying model.</p><p>Choose LLMChain if you have a task that requires a specific request format. In addition to PromptTemplate, LLMChain provides additional functionality and allows you to enhance your tasks with features such as pre-processing and post-processing steps. I will explain it in detail in the next paragraphs in this article.</p><h3>II. What is exactly Chaining in LLMOps and is it essential?</h3><h4>1. The Basics of Chaining</h4><p>Chains are the secret sauce that transforms ordinary LLM interactions into powerful applications. When using LLMs such as ChatGPT, most people stick to a simple question and answer scenario. But to take things to the next level, developers are turning to chains, the process of connecting different components to enhance the functionality of an LLM.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/826/1*cPvDhK3I1isl-uN4FEbBtg.png" /><figcaption>Image by Author, with a help of multiple sources on Google Search</figcaption></figure><h4>2. Core Chains in LLMChain</h4><p>In LLMChain, 03 core chains form the backbone of the entire process: <strong><em>prompt chain, tools chain, and data indexing chain</em></strong>. These chains work together seamlessly to create a matrix-like structure that allows developers to connect and power different components.</p><p><strong>2.1. Prompt Chain</strong></p><p>Prompt chains are the starting point for LLMOps, where a developer creates specific instructions or prompts for LLM. It guides the language model to understand the desired user interaction and sets the context for subsequent chains. Creating effective prompts is critical to getting accurate and appropriate responses from your LLM.</p><p><em>👉 I also mentioned about </em><strong><em>“Guidelines for Developers on Prompting”</em></strong><em> in the article “</em><a href="https://www.comet.com/site/blog/create-a-simple-e-commerce-chatbot-with-openai?utm_source=Heartbeat&amp;utm_content=NhiYen"><strong><em>Create a Simple E-commerce Chatbot Using OpenAI + CometLLM</em></strong></a><strong><em>.”</em></strong><em> It’s useful for getting a deeper understanding of the Prompt Chain.</em></p><p><strong>2.2. Tool Chain</strong></p><p>The Tool Chain includes various development tools that enhance the functionality of LLM.</p><p><strong>Components:</strong></p><ul><li><strong>Extractive Tools: </strong>Used to extract specific information from the LLM’s responses.</li><li><strong>Transformative Tools: </strong>Responsible for transforming and refining the output generated by LLMs.</li><li><strong>Utility Tools: </strong>Additional tools that add functionalities like formatting, summarization, etc.</li><li><strong>Integration: </strong>Tools are integrated to ensure that the output from LLMs aligns with the desired application requirements.</li></ul><p><strong>2.3. Data Indexing Chain</strong></p><p>The data indexing chain is the backbone for efficiently storing and retrieving information from documents.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/661/1*e22B7HJ2wQR4EvCpzNUkvQ.png" /></figure><p><strong>Process:</strong></p><ul><li><strong>Chunking</strong>: Documents are split into manageable chunks for efficient processing.</li><li><strong>Embeddings</strong>: These chunks are converted into embeddings, which are numerical representations suitable for storage in vector databases.</li><li><strong>Vector Database</strong>: Specialized databases such as <strong><em>Pinecone, Chroma Database, Weaviate, FAISS, Milvus, Qrant, and Elasticsearch</em></strong> store these embeddings for fast and effective retrieval. These databases store document embeddings in a way that allows for fast and efficient retrieval. Although it may seem complicated, it is essentially a specialized database that is optimized to handle large amounts of data.</li></ul><p><strong>Role</strong>:</p><ul><li>You can search large amounts of data quickly, contributing to the efficiency of the LLMOps applications.</li></ul><p><strong>2.4. Best Practices for Core Chains</strong></p><ul><li>Balanced Prompts: Creating prompts that balance specificity and generality will help LLMs provide useful and diverse responses.</li><li>Tool Selection: Selecting and integrating tools that complement the required functionality of your application is critical to a smooth LLMOps workflow.</li><li>Optimized indexing: Tuning the data indexing process for efficient storage and retrieval can significantly improve application performance.</li></ul><h3>III. LangChain: The Glue that Connects</h3><p>I believe you all have heard of LangChain. It is an innovative tool for LLMOps that serves as a general-purpose interface for interacting with LLM. This acts as a connector, allowing developers to combine LLMs with other tools and databases. The key idea behind Lang Chain is to go beyond simple question-and-answer interactions and create applications that leverage the full potential of LLM.</p><p>LLMOps seamlessly integrates LLM, vector databases, and other tools around Lang Chain. The chaining process involves using a developer tool stack to connect models, databases, etc. to ultimately create a powerful LLM application.</p><p>Let’s take a look at a simplified version of LangChain below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/725/1*XA-rDPlBMr65NCjb5sQ2lQ.png" /><figcaption>Image by Author, with a help of multiple sources on Google Search</figcaption></figure><p>In addition to LangChain, the following important Chain players should be kept in mind:</p><ul><li>LangChain: Raised approximately $10 million in seed funding.</li><li>Llama Index: A remarkable open source tool.</li><li>HayStack: Received approximately $9.2 million in seed funding and debt financing.</li><li>AgentGPT : Level AI’s open source project, backed by a generous $20 million Series B funding in 2022, focused on call center applications.</li></ul><p><em>👉 You might be interested in </em><strong><em>“</em></strong><a href="https://medium.com/p/6aadd335b621"><strong><em>LangChain Conversation Memory Types</em></strong></a><strong><em>” i</em></strong><em>n another article.</em></p><p><a href="https://heartbeat.comet.ml/how-to-enhance-conversational-agents-with-memory-in-lang-chain-6aadd335b621">How to Enhance Conversational Agents with Memory in Lang Chain</a></p><h3>Conclusion</h3><p>To wrap it up, Chaining is the secret sauce to make LLM super powerful in everyday uses. LangChain is the top pick for developers wanting to make the most out of LLMOps, thanks to its flexible interface and easy connections. Digging deep into Chaining and LLM Developer tools can set you apart in job searches. Keep following for more insights and learning opportunities. Cheers!</p><p><em>#LLM #LLMChain #LLMOps #ChainingDecoded #DifferentiateLLM</em></p><p><em>Editor’s Note: </em><a href="https://heartbeat.comet.ml/"><em>Heartbeat</em></a><em> is a contributor-driven online publication and community dedicated to providing premier educational resources for data science, machine learning, and deep learning practitioners. We’re committed to supporting and inspiring developers and engineers from all walks of life.</em></p><p><em>Editorially independent, Heartbeat is sponsored and published by </em><a href="http://comet.com/?utm_source=heartbeat&amp;utm_medium=referral&amp;utm_campaign=AMS_US_EN_AWA_heartbeat_EN"><em>Comet,</em></a><em> an MLOps platform that enables data scientists &amp; ML teams to track, compare, explain, &amp; optimize their experiments. We pay our contributors, and we don’t sell ads.</em></p><p><em>If you’d like to contribute, head on over to our</em><a href="https://heartbeat.comet.ml/call-for-contributors-fee7f5b80f3e"><em> call for contributors</em></a><em>. You can also sign up to receive our weekly newsletter (</em><a href="https://www.deeplearningweekly.com/"><em>Deep Learning Weekly</em></a><em>), check out the </em><a href="https://www.comet.com/site/blog/"><em>Comet blog</em></a><em>, join us on</em><a href="https://join.slack.com/t/fritz-ai-community/shared_invite/enQtNTY5NDM2MTQwMTgwLWU4ZDEwNTAxYWE2YjIxZDllMTcxMWE4MGFhNDk5Y2QwNTcxYzEyNWZmZWEwMzE4NTFkOWY2NTM0OGQwYjM5Y2U"><em> </em></a><a href="https://join.slack.com/t/cometml/shared_invite/zt-49v4zxxz-qHcTeyrMEzqZc5lQb9hgvw"><em>Slack</em></a><em>, and follow Comet on </em><a href="https://twitter.com/Cometml"><em>Twitter</em></a><em> and </em><a href="https://www.linkedin.com/company/comet-ml/"><em>LinkedIn</em></a><em> for resources, events, and much more that will help you build better ML models, faster.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6d82c918e04c" width="1" height="1" alt=""><hr><p><a href="https://heartbeat.comet.ml/decoding-the-significance-of-chaining-in-llmops-6d82c918e04c">Decoding the Significance of Chaining in LLMOps</a> was originally published in <a href="https://heartbeat.comet.ml/">Heartbeat</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 Enhance Conversational Agents with Memory in Lang Chain]]></title>
            <link>https://heartbeat.comet.ml/how-to-enhance-conversational-agents-with-memory-in-lang-chain-6aadd335b621?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/6aadd335b621</guid>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[prompt-engineering]]></category>
            <category><![CDATA[llmops]]></category>
            <category><![CDATA[cometml]]></category>
            <category><![CDATA[langchain]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Fri, 26 Jan 2024 15:36:04 GMT</pubDate>
            <atom:updated>2024-01-26T15:36:04.757Z</atom:updated>
            <content:encoded><![CDATA[<h4>LangChain Conversation Memory Types: Pros &amp; Cons, and Code Examples</h4><p>When it comes to chatbots and conversational agents, the ability to retain and remember information is critical to creating fluid, human-like interactions. This article describes the concept of memory in Lang Chain and explores its importance, implementation, and various strategies for optimizing conversation flow.</p><blockquote>💡I write about Machine Learning on <a href="https://medium.com/@yennhi95zz/subscribe">Medium</a> || <a href="https://github.com/yennhi95zz">Github</a> || <a href="https://www.kaggle.com/nhiyen/code">Kaggle</a> || <a href="https://www.linkedin.com/in/yennhi95zz/">Linkedin</a>. 🔔 Follow “Nhi Yen” for future updates!</blockquote><blockquote>👉 Get UNLIMITED access to every story on Medium with just $1/week — <a href="https://medium.com/@yennhi95zz/membership"><strong>HERE</strong></a></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1pJAe7F36nNdJnT6" /><figcaption>Conversation Memory (Credit: <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a>)</figcaption></figure><p>👉 <em>I previously shared relevant articles on creating a basic chatbot without using Conversation Memory. You might find it interesting.</em></p><p><a href="https://www.comet.com/site/blog/create-a-simple-e-commerce-chatbot-with-openai/">Create a Simple E-commerce Chatbot With OpenAI</a></p><h3>Why Memory Matters in Conversational Agents</h3><p>When users interact with chatbots, they often expect a level of continuity and understanding similar to human conversations. This expectation includes the ability to refer to past information, which leads to the conversational agent’s need for memory. Memory allows the system to remember previous interactions, process abbreviations, and perform co-reference resolution, ensuring consistent, context-aware conversations.</p><h3>The Memory Challenge in Large Language Models</h3><p>Large language models like Lang Chain do not have their own memory. Unlike humans, who naturally retain information during conversations, these models operate on a rapid response mechanism. Attempts have been made to integrate memory into its Transformer model, but large-scale practical implementation remains a challenge.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/598/1*cXoHnRgshtvrd6N-u77Ing.png" /><figcaption>LangChain (Image Credit: <a href="https://blog.bytebytego.com/p/how-to-build-a-smart-chatbot-in-10">ALEX XU on blog.bytebytego.com</a>)</figcaption></figure><h3>Memory Strategies in Lang Chain</h3><p>Given a context that when a customer inquires about the customer service of a fashion store and expresses a problem with the jeans. This issue involves a stuck zipper and is similar to a hardware issue. I’ll ask the bot a list of questions for each LangChain memory type:</p><pre>1. Hey! I am Nhi.<br>2. How are you today?<br>3. I&#39;m doing well, thank you. I need your assistance.<br>4. I bought this pair of jeans, and there&#39;s a problem. <br>5. When I tried them on, the zipper got stuck, and now I can&#39;t unzip it.<br>6. It seems to be a problem with the zipper.</pre><p>In this experiment, I’ll use Comet LLM to record prompts, responses, and metadata for each memory type for performance optimization purposes. This allows me to track response duration, tokens, and cost for each interaction. View the full project <a href="https://www.comet.com/yennhi95zz/langchain-conversation-memory/prompts"><strong>HERE</strong></a>.</p><p>Comet LLM provides <a href="https://www.comet.com/docs/v2/">additional features</a> such as UI visualization, detailed chain execution logs, automatic tracking with OpenAI chat model, and user feedback analysis.</p><p>Find the complete code in this <a href="https://github.com/yennhi95zz/langchain-conversation-memory-code-examples"><strong>GitHub Repository</strong></a>.</p><p>To start, bring in the common libraries needed for all 6 memory types. Make sure you’ve installed the necessary Python packages in <strong><em>requirements.txt</em></strong> and have your OpenAI API and Comet API keys ready. (Reference: <a href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key"><em>OpenAI Help Center — Where can I find my API key?</em></a>; <a href="https://www.comet.com/docs/v2/api-and-sdk/rest-api/overview/"><em>CometLLM — Obtaining your API key</em></a>)</p><pre>import os<br>import dotenv<br>import comet_llm<br>from langchain.callbacks import get_openai_callback<br>import time<br>dotenv.load_dotenv()<br><br>MY_OPENAI_KEY = os.getenv(&quot;YOUR_OPENAI_KEY&quot;)<br>MY_COMET_KEY = os.getenv(&quot;YOUR_COMET_KEY&quot;)<br><br># Initialize a Comet project<br>comet_llm.init(project=&quot;YOUR COMET PROJECT NAME&quot;,<br>               api_key=MY_COMET_KEY)</pre><h3>1. Conversation Buffer Memory</h3><p>The simplest form of memory involves the creation of a talk buffer. In this approach, the model keeps a record of ongoing conversations and accumulates each user-agent interaction into a message. While effective for limited interactions, scalability becomes an issue for long conversations.</p><p>🎯 Implementation: Include the entire conversation in the prompt.</p><p>✅ Pros: Simple and effective for short interactions.</p><p>❌ Cons: Limited by token span; impractical for lengthy conversations.</p><pre>from langchain.chains.conversation.memory import ConversationBufferMemory<br>from langchain_openai import OpenAI<br>from langchain.chains import ConversationChain<br>from langchain.callbacks import get_openai_callback<br><br>llm = OpenAI(openai_api_key=MY_OPENAI_KEY,<br>             temperature=0,<br>             max_tokens = 256)<br><br>buffer_memory = ConversationBufferMemory()<br><br>conversation = ConversationChain(<br>    llm=llm,<br>    verbose=True,<br>    memory=buffer_memory<br>)</pre><p>Interact with the bot by inputting each prompt in conversation.predict(). Example:</p><pre>conversation.predict(input=&quot;Hey! I am Nhi.&quot;)</pre><pre>conversation.predict(input=&quot;How are you today?&quot;)</pre><pre>conversation.predict(input=&quot;I&#39;m doing well, thank you. I need your assistant.&quot;)</pre><p>Output after the 3rd prompt:</p><pre>&gt; Entering new ConversationChain chain...<br>Prompt after formatting:<br>The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.<br><br>Current conversation:<br>Human: Hey! I am Nhi.<br>AI:  Hi Nhi! My name is AI. It&#39;s nice to meet you. What can I do for you today?<br>Human: How are you today?<br>AI:  I&#39;m doing great, thanks for asking! I&#39;m feeling very excited about the new projects I&#39;m working on. How about you?<br>Human: I&#39;m doing well, thank you. I need your assistant.<br>AI:<br><br>&gt; Finished chain.<br>&#39; Sure thing! What kind of assistance do you need?&#39;</pre><p>ConversationBufferMemory allows conversations to grow with each turn and allows users to see the entire conversation history at any time. This approach allows ongoing interactions to be monitored and maintained, providing a simple but powerful form of memory for language models, especially in scenarios where the number of interactions with the system is limited.</p><pre>print(conversation.memory.buffer)</pre><p>Output:</p><pre>Human: Hey! I am Nhi.<br>AI:  Hi Nhi! My name is AI. It&#39;s nice to meet you. What can I do for you today?<br>Human: How are you today?<br>AI:  I&#39;m doing great, thanks for asking! I&#39;m feeling very excited about the new projects I&#39;m working on. How about you?<br>Human: I&#39;m doing well, thank you. I need your assistant.<br>AI:  Sure thing! What kind of assistance do you need?</pre><p>Use Comet LLM to complete the code and record relevant information for analysis purposes.</p><pre>def conversation_memory_buffer(prompt):<br>    with get_openai_callback() as cb:<br>        start_time = time.time()<br>        response = conversation.predict(input=prompt)<br>        end_time = time.time()<br>        print(f&quot;Response: {response}&quot;)<br>        print(f&quot;History: {conversation.memory.buffer}&quot;)<br><br>        # Log to comet_llm<br>        comet_llm.log_prompt(<br>            prompt=prompt,<br>            output=response,<br>            duration= end_time - start_time,<br>            prompt_template = conversation.prompt.template,<br>            metadata={<br>            &quot;memory_type&quot;: &quot;conversation_buffer_memory&quot;,<br>            &quot;history&quot;: conversation.memory.buffer,<br>            &quot;total_tokens&quot;: cb.total_tokens,<br>            &quot;prompt_tokens&quot;: cb.prompt_tokens,<br>            &quot;completion_tokens&quot;: cb.completion_tokens,<br>            &quot;total_cost_usd&quot;: cb.total_cost<br>            },<br>        )</pre><p>Call the function conversation_memory_buffer():</p><pre>Example:<br>conversation_memory_buffer(&quot;Hey! I am Nhi.&quot;)<br>conversation_memory_buffer(&quot;How are you today?&quot;)<br>conversation_memory_buffer(&quot;I&#39;m doing well, thank you. I need your assistant.&quot;)</pre><p>How the data is logged in Comet LLM:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/485/1*rA-zKN1cb4vEVhT2p_1oiA.png" /><figcaption>Input/ Output are log in Comet LLM (Image by the Author)</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/490/1*d7KgwOIc6kMgg1QPZyaC4g.png" /><figcaption>Also the metadata in LLM</figcaption></figure><h3>2. Conversation Summary Memory</h3><p>To overcome the scalability challenge, Conversation Summary Memory provides a solution. Rather than accumulating each interaction, the model generates a condensed summary of the essence of the conversation. This reduces the number of tokens and increases the sustainability of long-term interactions.</p><p>🎯 Implementation: Summarize the conversation to save tokens.</p><p>✅ Pros: Efficient token usage over time.</p><p>❌ Cons: May lose fine-grained details; suitable for concise interactions.</p><pre>from langchain.chains.conversation.memory import ConversationSummaryMemory<br>from langchain import OpenAI<br>from langchain.chains import ConversationChain<br>from langchain.callbacks import get_openai_callback<br><br># Create an instance of the OpenAI class with specified parameters<br>llm = OpenAI(openai_api_key=MY_OPENAI_KEY,<br>            temperature=0,<br>            max_tokens = 256)<br><br># Create an instance of the ConversationSummaryMemory class<br>summary_memory = ConversationSummaryMemory(llm=OpenAI(openai_api_key=MY_OPENAI_KEY))<br><br># Create an instance of the ConversationChain class, combining OpenAI, verbose mode, and memory<br>conversation = ConversationChain(<br>    llm=llm,<br>    verbose=True,<br>    memory=summary_memory<br>)</pre><p>Similar to ConversationBufferMemory, we’ll also interact with the bot by inputting each prompt in conversation.predict(). Example:</p><pre>conversation.predict(input=&quot;Hey! I am Nhi.&quot;)</pre><pre>conversation.predict(input=&quot;How are you today?&quot;)</pre><p>Output:</p><pre>&gt; Entering new ConversationChain chain...<br>Prompt after formatting:<br>The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.<br><br>Current conversation:<br><br>Nhi introduces themselves to the AI and the AI responds with a greeting, revealing its name to be AI. The AI offers to assist Nhi with any tasks and asks how it can help them today. The human then asks how the AI is doing, to which it responds that it is doing great and asks how it can be of assistance.<br>Human: I&#39;m doing well, thank you. I need your assistant.<br>AI:<br><br>&gt; Finished chain.<br>&#39; Absolutely! How can I help you today?&#39;</pre><p>The <strong><em>ConversationSummaryMemory</em></strong> generates the conversation summary over multiple interactions.</p><pre>Current conversation:<br>Nhi introduces themselves to the AI and the AI responds with a greeting, revealing its name to be AI. The AI offers to assist Nhi with any tasks and asks how it can help them today. The human then asks how the AI is doing, to which it responds that it is doing great and asks how it can be of assistance.</pre><p>The summaries capture key points of the conversation, including introductions, queries, and responses. As the conversation progresses, the model generates summarized versions, emphasizing that it tends to use fewer tokens over time. The summary’s ability is to retain essential information, making it useful for reviewing the conversation as a whole.</p><p>Additionally, we can access and print out the conversation summary.</p><pre>print(conversation.memory.buffer)</pre><p>Output:</p><pre>Nhi introduces themselves to the AI and the AI responds with a greeting, revealing its name to be AI. The AI offers to assist Nhi with any tasks and asks how it can help them today. The human asks how the AI is doing, to which it responds that it is doing great and asks how it can be of assistance. The human informs the AI that they need its assistance and the AI eagerly offers to help.</pre><p>Use Comet LLM to log important information for analysis purposes in your code.</p><pre>def conversation_summary_memory(prompt):<br>    with get_openai_callback() as cb:<br>        start_time = time.time()<br>        response = conversation.predict(input=prompt)<br>        end_time = time.time()<br>        print(f&quot;Response: {response}&quot;)<br>        print(f&quot;History: {conversation.memory.buffer}&quot;)<br><br>        # Log to comet_llm<br>        comet_llm.log_prompt(<br>            prompt=prompt,<br>            output=response,<br>            duration= end_time - start_time,<br>            prompt_template = conversation.prompt.template,<br>            metadata={<br>            &quot;memory_type&quot;: &quot;conversation_summary_memory&quot;,<br>            &quot;history&quot;: conversation.memory.buffer,<br>            &quot;total_tokens&quot;: cb.total_tokens,<br>            &quot;prompt_tokens&quot;: cb.prompt_tokens,<br>            &quot;completion_tokens&quot;: cb.completion_tokens,<br>            &quot;total_cost_usd&quot;: cb.total_cost<br>            },<br>        )</pre><p>Call the function conversation_memory_buffer():</p><pre>Example:<br>conversation_summary_memory(&quot;Hey! I am Nhi.&quot;)<br>conversation_summary_memory(&quot;How are you today?&quot;)<br>conversation_summary_memory(&quot;I&#39;m doing well, thank you. I need your assistant.&quot;)</pre><h3>3. Conversation Buffer Window Memory</h3><p>Conversation Buffer Window Memory is an alternative version of the conversation buffer approach, which involves setting a limit on the number of interactions considered within a memory buffer. This balances memory depth and token efficiency, and provides flexibility to adapt to conversation windows.</p><p>🎯 Implementation: Retain the last N interactions.</p><p>✅ Pros: Balances memory and token constraints.</p><p>❌ Cons: Potential loss of early conversation context.</p><pre>from langchain.chains.conversation.memory import ConversationBufferWindowMemory<br>from langchain import OpenAI<br>from langchain.chains import ConversationChain<br>from langchain.callbacks import get_openai_callback<br><br># Create an instance of the OpenAI class with specified parameters<br>llm = OpenAI(openai_api_key=MY_OPENAI_KEY,<br>            model_name=&#39;text-davinci-003&#39;,<br>            temperature=0,<br>            max_tokens = 256)<br><br># Create an instance of the ConversationBufferWindowMemory class<br># We set a low k=2, to only keep the last 2 interactions in memory<br>window_memory = ConversationBufferWindowMemory(k=2)<br><br># Create an instance of the ConversationChain class, combining OpenAI, verbose mode, and memory<br>conversation = ConversationChain(<br>    llm=llm,<br>    verbose=True,<br>    memory=window_memory<br>)</pre><p>Note that in this demo we will set a low value k=2 , but you can adjust it depending on the memory depth you need. Four prompts are introduced into the model in the following order:</p><pre>conversation.predict(input=&quot;Hey! I am Nhi.&quot;)</pre><pre>conversation.predict(input=&quot;I&#39;m doing well, thank you. I need your assistant.&quot;)</pre><pre>conversation.predict(input=&quot;I bought this pair of jeans, and there&#39;s a problem.&quot;)</pre><pre>conversation.predict(input=&quot;When I tried them on, the zipper got stuck, and now I can&#39;t unzip it.&quot;)</pre><p>In the demo, the prompt contains an ongoing conversation, and the model tracks a set number of recent interactions. However, only the last 02 interactions are considered, so the previous interactions are not preserved.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uUmaMrVdHRq4Zf4t3DNbjw.png" /></figure><p>Memory depth can be adjusted based on factors such as token usage and cost considerations. We compare our approach with previous approaches and emphasize selectively preserving recent interactions.</p><pre>print(conversation.memory.buffer)</pre><p>Output:</p><pre>Human: I bought this pair of jeans, and there&#39;s a problem.<br>AI:  Oh no! What kind of problem are you having with the jeans?<br>Human: When I tried them on, the zipper got stuck, and now I can&#39;t unzip it.<br>AI:  That sounds like a tricky problem. Have you tried lubricating the zipper with a bit of oil or WD-40? That might help loosen it up.</pre><p>Use Comet LLM to log important information for analysis in your code:</p><pre>def conversation_buffer_window_memory(prompt):<br>    with get_openai_callback() as cb:<br>        start_time = time.time()<br>        response = conversation.predict(input=prompt)<br>        end_time = time.time()<br>        print(f&quot;Response: {response}&quot;)<br>        print(f&quot;History: {conversation.memory.buffer}&quot;)<br><br>        # Log to comet_llm<br>        comet_llm.log_prompt(<br>            prompt=prompt,<br>            output=response,<br>            duration= end_time - start_time,<br>            prompt_template = conversation.prompt.template,<br>            metadata={<br>            &quot;memory_type&quot;: &quot;conversation_buffer_window_memory&quot;,<br>            &quot;history&quot;: conversation.memory.buffer,<br>            &quot;total_tokens&quot;: cb.total_tokens,<br>            &quot;prompt_tokens&quot;: cb.prompt_tokens,<br>            &quot;completion_tokens&quot;: cb.completion_tokens,<br>            &quot;total_cost_usd&quot;: cb.total_cost<br>            },<br>        )</pre><p>Call the function conversation_buffer_window_memory():</p><pre>Example:<br>conversation_buffer_window_memory(&quot;Hey! I am Nhi.&quot;)<br>conversation_buffer_window_memory(&quot;How are you today?&quot;)<br>conversation_buffer_window_memory(&quot;I&#39;m doing well, thank you. I need your assistant.&quot;)</pre><h3>4. Conversation Summary Buffer Memory: A Combination of Conversation Summary and Buffer Memory</h3><p>Conversation Summary Buffer Memory keeps a buffer of recent interactions in memory, but compiles them into a digest and uses both, rather than just removing old interactions completely.</p><p>🎯 Implementation: Merge summary and buffer for optimal memory usage.</p><p>✅ Pros: Provides a comprehensive view of recent and summarized interactions.</p><p>❌ Cons: Requires careful tuning for specific use cases.</p><pre>from langchain.chains.conversation.memory import ConversationSummaryBufferMemory<br>from langchain import OpenAI<br>from langchain.chains import ConversationChain<br>from langchain.callbacks import get_openai_callback<br><br><br># Create an instance of the OpenAI class with specified parameters<br>llm = OpenAI(openai_api_key=MY_OPENAI_KEY,<br>            temperature=0,<br>            max_tokens = 512)<br><br># Create an instance of the ConversationSummaryBufferMemory class<br># Setting k=2: Retains only the last 2 interactions in memory.<br># max_token_limit=40: Requires the installation of transformers.<br>summary_buffer_memory = ConversationSummaryBufferMemory(llm=OpenAI(openai_api_key=MY_OPENAI_KEY), max_token_limit=40)<br><br># Create an instance of the ConversationChain class, combining OpenAI, verbose mode, and memory<br>conversation = ConversationChain(<br>    llm=llm,<br>    memory=summary_buffer_memory,<br>    verbose=True<br>)</pre><p>Feed the model with 4 prompts in an order:</p><pre>conversation.predict(input=&quot;Hey! I am Nhi.&quot;)</pre><pre>conversation.predict(input=&quot;I bought this pair of jeans, and there&#39;s a problem.&quot;)</pre><pre>conversation.predict(input=&quot;When I tried them on, the zipper got stuck, and now I can&#39;t unzip it.&quot;)</pre><pre>conversation.predict(input=&quot;It seems to be a problem with the zipper.&quot;)</pre><p>The model retains the last 2 interactions and summarize the older ones as below:</p><pre>&gt; Entering new ConversationChain chain...<br>Prompt after formatting:<br>The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.<br><br>Current conversation:<br>System: <br>Nhi introduces herself to the AI, and the AI responds by introducing itself and expressing pleasure in meeting Nhi. Nhi mentions a problem with a pair of jeans she bought, and the AI asks for more details. Nhi explains that the zipper got stuck and now she can&#39;t unzip it.<br>AI:  That sounds like a tricky situation. Have you tried lubricating the zipper with a bit of oil or soap? That might help it move more smoothly.<br>Human: It seems to be a problem with the zipper.<br>AI:<br><br>&gt; Finished chain.<br>&#39; It sounds like the zipper is stuck. Have you tried lubricating it with a bit of oil or soap? That might help it move more smoothly.&#39;</pre><p>Print out the result:</p><pre>print(conversation.memory.moving_summary_buffer)</pre><p>Output:</p><pre>Nhi introduces themselves to the AI and the AI responds by introducing itself and offering assistance. Nhi explains a problem with a pair of jeans they bought, stating that the zipper is stuck and they can&#39;t unzip it. The AI suggests lubricating the zipper with oil or soap to help it move more smoothly or replacing it if that doesn&#39;t work.</pre><p>Use Comet LLM in your code to log important information for analysis:</p><pre>def conversation_summary_buffer_memory(prompt):<br>    with get_openai_callback() as cb:<br>        start_time = time.time()<br>        response = conversation.predict(input=prompt)<br>        end_time = time.time()<br>        print(f&quot;Response: {response}&quot;)<br>        print(f&quot;History: {conversation.memory.moving_summary_buffer}&quot;)<br><br>        # Log to comet_llm<br>        comet_llm.log_prompt(<br>            prompt=prompt,<br>            output=response,<br>            duration= end_time - start_time,<br>            prompt_template = conversation.prompt.template,<br>            metadata={<br>            &quot;memory_type&quot;: &quot;conversation_summary_buffer_memory&quot;,<br>            &quot;history&quot;: conversation.memory.moving_summary_buffer,<br>            &quot;total_tokens&quot;: cb.total_tokens,<br>            &quot;prompt_tokens&quot;: cb.prompt_tokens,<br>            &quot;completion_tokens&quot;: cb.completion_tokens,<br>            &quot;total_cost_usd&quot;: cb.total_cost<br>            },<br>        )</pre><p>Call the function conversation_summary_buffer_memory():</p><pre>Example:<br>conversation_summary_buffer_memory(&quot;Hey! I am Nhi.&quot;)<br>conversation_summary_buffer_memory(&quot;I bought this pair of jeans, and there&#39;s a problem.&quot;)<br>conversation_summary_buffer_memory(&quot;When I tried them on, the zipper got stuck, and now I can&#39;t unzip it.&quot;)<br>conversation_summary_buffer_memory(&quot;It seems to be a problem with the zipper.&quot;)</pre><h3>5. Conversation Knowledge Graph Memory</h3><p>Lang Chain goes beyond just conversation tracking and introduces knowledge graph memory. It builds a mini knowledge graph based on related information, creating nodes and connections to represent key entities. This method improves the model’s ability to understand and respond to situations.</p><p>🎯 Implementation: Extract relevant information and construct a knowledge graph.</p><p>✅ Pros: Enables structured information extraction.</p><p>❌ Cons: May require additional processing for complex scenarios.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/803/1*zRCHDlNCPXUUVuED9QjrXQ.png" /><figcaption>Knowledge Graph Memory in LLM (Image by the Author)</figcaption></figure><p>Python Code example:</p><pre>from langchain.chains.conversation.memory import ConversationKGMemory<br>from langchain import OpenAI<br>from langchain.chains import ConversationChain<br>from langchain.prompts.prompt import PromptTemplate<br>from langchain.callbacks import get_openai_callback<br><br># Create an instance of the OpenAI class with specified parameters<br>llm = OpenAI(openai_api_key=MY_OPENAI_KEY,<br>            temperature=0,<br>            max_tokens = 256)<br><br># Define a template for conversation prompts<br>template = &quot;&quot;&quot;<br>This is a friendly chat between a human and an AI. The AI shares details from its context. \n<br>If it doesn&#39;t know the answer, it honestly admits it. The AI sticks to information in the &#39;Relevant Information&#39; section and doesn&#39;t make things up. \n\n<br><br>Relevant Information: \n<br><br>{history}<br><br>Conversation: \n<br>Human: {input} \n<br>AI:&quot;&quot;&quot;<br><br># Create an instance of the PromptTemplate class with specified input variables and template<br>prompt = PromptTemplate(input_variables=[&quot;history&quot;, &quot;input&quot;], template=template)<br><br># Create an instance of the ConversationKGMemory class with the OpenAI instance<br>kg_memory = ConversationKGMemory(llm=llm)<br><br># Create an instance of the ConversationChain class, combining OpenAI, verbose mode, prompt, and memory<br>conversation = ConversationChain(<br>    llm=llm,<br>    verbose=True,<br>    prompt=prompt,<br>    memory=kg_memory<br>)</pre><pre>def conversation_kg_memory(prompt):<br>    with get_openai_callback() as cb:<br>        start_time = time.time()<br>        response = conversation.predict(input=prompt)<br>        end_time = time.time()<br>        print(f&quot;Response: {response}&quot;)<br>        print(f&quot;History: {str(conversation.memory.kg.get_triples())}&quot;)<br><br>        # Log to comet_llm<br>        comet_llm.log_prompt(<br>            prompt=prompt,<br>            output=response,<br>            duration= end_time - start_time,<br>            prompt_template = conversation.prompt.template,<br>            metadata={<br>            &quot;memory_type&quot;: &quot;conversation_kg_memory&quot;,<br>            &quot;history&quot;: str(conversation.memory.kg.get_triples()),<br>            &quot;total_tokens&quot;: cb.total_tokens,<br>            &quot;prompt_tokens&quot;: cb.prompt_tokens,<br>            &quot;completion_tokens&quot;: cb.completion_tokens,<br>            &quot;total_cost_usd&quot;: cb.total_cost<br>            },<br>        )</pre><h3>6. Entity Memory</h3><p>Similar to Knowledge Graph memory, entity memory extracts specific entities from the conversation, such as names, objects, or locations. This focused approach aids in understanding and responding to user queries with greater precision.</p><p>🎯 Implementation: Identify and store specific entities from the conversation.</p><p>✅ Pros: Facilitates extraction of key information for decision-making.</p><p>❌ Cons: Sensitivity to entity recognition accuracy.</p><pre>from langchain import OpenAI, ConversationChain<br>from langchain.chains.conversation.memory import ConversationEntityMemory<br>from langchain.chains.conversation.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE<br>from pydantic import BaseModel<br>from typing import List, Dict, Any<br>from langchain.callbacks import get_openai_callback<br><br># Print the template used for conversation prompts<br>ENTITY_MEMORY_CONVERSATION_TEMPLATE.template<br>print(ENTITY_MEMORY_CONVERSATION_TEMPLATE.template)<br><br># Create an instance of the OpenAI class with specified parameters<br>llm = OpenAI(openai_api_key=MY_OPENAI_KEY,<br>            temperature=0,<br>            max_tokens = 256)<br><br># Create an instance of the ConversationEntityMemory class with the OpenAI instance<br>entity_memory = ConversationEntityMemory(llm=llm)<br><br># Create an instance of the ConversationChain class, combining OpenAI, verbose mode, prompt, and memory<br>conversation = ConversationChain(<br>    llm=llm,<br>    verbose=True,<br>    prompt=ENTITY_MEMORY_CONVERSATION_TEMPLATE,<br>    memory=entity_memory<br>)</pre><p>Create a function to get the response and log important metadata using CometLLM:</p><pre>def conversation_entity_memory(prompt):<br>    with get_openai_callback() as cb:<br>        start_time = time.time()<br>        response = conversation.predict(input=prompt)<br>        end_time = time.time()<br>        print(f&quot;Response: {response}&quot;)<br>        print(f&quot;History: {conversation.memory.entity_store.store}&quot;)<br><br>        # Log to comet_llm<br>        comet_llm.log_prompt(<br>            prompt=prompt,<br>            output=response,<br>            duration= end_time - start_time,<br>            prompt_template = conversation.prompt.template,<br>            metadata={<br>            &quot;memory_type&quot;: &quot;conversation_entity_memory&quot;,<br>            &quot;entity_cache&quot;: conversation.memory.entity_cache,<br>            &quot;history&quot;: conversation.memory.entity_store.store,<br>            &quot;total_tokens&quot;: cb.total_tokens,<br>            &quot;prompt_tokens&quot;: cb.prompt_tokens,<br>            &quot;completion_tokens&quot;: cb.completion_tokens,<br>            &quot;total_cost_usd&quot;: cb.total_cost<br>            },<br>        )</pre><p>Call the function:</p><pre>conversation_entity_memory(&quot;Hi, this is Nhi. I bought this pair of jeans, and there&#39;s a problem. When I tried them on, the zipper got stuck, and now I can&#39;t unzip it.&quot;)</pre><p>The function returns the history, the matching response using Entity memory, and also logs metadata in Comet LLM as shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oJnvFtiyZpxKTv8hm9xEqg.png" /><figcaption>Response (Image by the Author)</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/516/1*8a5vY15esK-7AT0i7bSplA.png" /><figcaption>Input/Output logged in Comet LLM</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/501/1*UqRO5JXKQtKpyK3HUiaw6A.png" /><figcaption>Metadata logged in Comet LLM</figcaption></figure><h3><strong>Reference</strong></h3><ul><li>Find the complete code on this <a href="https://github.com/yennhi95zz/langchain-conversation-memory-code-examples"><strong>GitHub repository</strong></a>.</li><li>Experiment Tracking in <a href="https://www.comet.com/yennhi95zz/langchain-conversation-memory/prompts"><strong>Commet LLM Project</strong></a>.</li></ul><p><em>👉 Explore Comet in action by reviewing my past hands-on projects.</em></p><ul><li><a href="https://www.comet.com/site/blog/customer-churn-with-continuous-experiment-tracking/"><em>Enhancing Customer Churn Prediction with Continuous Experiment Tracking</em></a></li><li><a href="https://www.comet.com/site/blog/hyperparameter-tuning-a-key-for-optimizing-ml-performance/"><em>Hyperparameter Tuning in Machine Learning: A Key to Optimize Model Performance</em></a></li><li><a href="https://medium.com/mlearning-ai/the-magic-of-model-stacking-boosting-machine-learning-performance-2f6719a0bfd8"><em>The Magic of Model Stacking: Boosting Machine Learning Performance</em></a></li><li><a href="https://medium.com/p/e1eb04e74eb5"><em>Logging — The Effective Management of Machine Learning Systems</em></a></li></ul><h3>Conclusion</h3><p>Memory plays a fundamental role in enhancing the capabilities of conversational agents. By understanding and implementing Lang Chain’s different memory strategies, you can create more dynamic and context-sensitive chatbots. Whether you choose a buffer-based approach or leverage a knowledge graph, the key is to tailor your memory mechanisms to your specific use case and user expectations.</p><p>As the field of Natural Language Processing (NLP) continues to evolve, integrating memory into conversational agents remains a promising avenue for improving user experience.</p><p><em>#ConversationalAgents #LangChainMemory #ChatbotTips #LangChainConversations #MemoryOptimization</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6aadd335b621" width="1" height="1" alt=""><hr><p><a href="https://heartbeat.comet.ml/how-to-enhance-conversational-agents-with-memory-in-lang-chain-6aadd335b621">How to Enhance Conversational Agents with Memory in Lang Chain</a> was originally published in <a href="https://heartbeat.comet.ml/">Heartbeat</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Challenging Skills That Boost 10x Earnings for Tech Nerds]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@yennhi95zz/5-challenging-skills-that-boost-10x-earnings-for-tech-nerds-3a8d936985f8?source=rss-81c441aba61e------2"><img src="https://cdn-images-1.medium.com/max/2600/0*OahkkydTcV-D5TDA" width="6240"></a></p><p class="medium-feed-snippet">Aspiring 10x growth in 2024 in tech industry compared to 2023</p><p class="medium-feed-link"><a href="https://medium.com/@yennhi95zz/5-challenging-skills-that-boost-10x-earnings-for-tech-nerds-3a8d936985f8?source=rss-81c441aba61e------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://medium.com/@yennhi95zz/5-challenging-skills-that-boost-10x-earnings-for-tech-nerds-3a8d936985f8?source=rss-81c441aba61e------2</link>
            <guid isPermaLink="false">https://medium.com/p/3a8d936985f8</guid>
            <category><![CDATA[career-growth]]></category>
            <category><![CDATA[passive-income]]></category>
            <category><![CDATA[tech-skills]]></category>
            <category><![CDATA[ml-so-good]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Nhi Yen]]></dc:creator>
            <pubDate>Wed, 10 Jan 2024 07:43:59 GMT</pubDate>
            <atom:updated>2024-01-10T07:43:59.801Z</atom:updated>
        </item>
    </channel>
</rss>