<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rushank Savant</title>
    <description>The latest articles on Forem by Rushank Savant (@rushanksavant).</description>
    <link>https://forem.com/rushanksavant</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F849972%2F166490e0-ca17-4eae-9854-5801fb8c39b4.PNG</url>
      <title>Forem: Rushank Savant</title>
      <link>https://forem.com/rushanksavant</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rushanksavant"/>
    <language>en</language>
    <item>
      <title>Auto-Merging RAG: Hierarchical Retrieval ⛓️</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Mon, 11 May 2026 17:28:12 +0000</pubDate>
      <link>https://forem.com/rushanksavant/auto-merging-rag-hierarchical-retrieval-4dp1</link>
      <guid>https://forem.com/rushanksavant/auto-merging-rag-hierarchical-retrieval-4dp1</guid>
      <description>&lt;h2&gt;
  
  
  🚨 The Problem: Context Fragmentation
&lt;/h2&gt;

&lt;p&gt;Imagine a 50-page legal contract. If you chunk it into tiny 200-character pieces, one chunk might say: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The liability is capped at $1M."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another chunk might say: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"However, this cap does not apply to gross negligence."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your retriever only finds the first chunk, your AI will give a dangerously wrong answer because it lacks the &lt;strong&gt;Parent Context&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 The Solution: Hierarchical Parenting
&lt;/h2&gt;

&lt;p&gt;Auto-merging retrieval organizes data into a tree structure. &lt;br&gt;
You store small &lt;strong&gt;Child Chunks&lt;/strong&gt; (for high-precision searching) that are linked to larger &lt;strong&gt;Parent Chunks&lt;/strong&gt; (for broad context).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You index the document at multiple levels (e.g., small, medium, and large chunks).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;During retrieval, if the system finds that &lt;strong&gt;multiple child&lt;/strong&gt; chunks belonging to the same &lt;strong&gt;parent&lt;/strong&gt; have been retrieved, it "merges" them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instead of sending the fragmented children to the LLM, it sends the entire &lt;strong&gt;Parent Chunk&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  ⚕️ Real-Life Realistic Example: Medical Protocol Analysis
&lt;/h2&gt;

&lt;p&gt;Imagine a hospital system with a 200-page "Cardiology Emergency Protocol."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The User Query:&lt;/strong&gt; "What is the dosage for Epinephrine during a cardiac arrest for a patient with a history of hypertension?"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Challenge:&lt;/strong&gt; The dosage is listed in a small table, but the contraindications (the "history of hypertension" part) are in the preceding paragraphs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Hierarchical Approach:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Child Chunks: Individual sentences or table rows.&lt;/li&gt;
&lt;li&gt;Parent Chunks: The entire "Cardiac Arrest Sub-section" (2-3 pages).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Auto-Merge:&lt;/strong&gt; If the retriever hits the "Epinephrine dosage" row AND the "Hypertension warning" sentence, the system realizes they are both in the same sub-section and sends the entire protocol section to the LLM. This ensures the LLM sees the &lt;em&gt;full picture&lt;/em&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  🛠️ Practical Implementation with LangChain
&lt;/h2&gt;

&lt;p&gt;Following is a implementation of a 1-level tree i.e Parent and it's child(s) [no sub-child(s)]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chat_models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;init_chat_model&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.vectorstores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_huggingface&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HuggingFaceEndpointEmbeddings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.stores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;InMemoryStore&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_text_splitters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.documents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.retrievers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseRetriever&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.callbacks&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CallbackManagerForRetrieverRun&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="c1"&gt;# --- STEP 1: ULTRA-REALISTIC MEDICAL DATA ---
&lt;/span&gt;&lt;span class="n"&gt;medical_manual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
CARDIOVASCULAR PROTOCOL - VERSION 2026
SECTION 1.1: ACUTE MYOCARDIAL INFARCTION (AMI)
Diagnosis: Patient presents with retrosternal chest pressure, radiation to left arm, and diaphoresis. 
ECG Requirements: 12-lead ECG must be performed within 10 minutes of arrival. Look for ST-segment elevation &amp;gt;1mm.
Immediate Treatment: Oxygen saturation maintenance &amp;gt;94%. Aspirin 325mg (chewed). Nitroglycerin 0.4mg sublingual every 5 mins.
Contraindications: Do not use Nitroglycerin if SBP &amp;lt; 90mmHg or if patient has taken PDE5 inhibitors in 24h.

SECTION 1.2: ADULT CARDIAC ARREST (VF/pVT)
Protocol: Initiate high-quality CPR. Attach defibrillator. Shock at 200J (Biphasic).
Drug Therapy: Epinephrine 1mg IV/IO every 3-5 minutes. Amiodarone 300mg IV/IO bolus after 3rd shock.
Post-Resuscitation: If ROSC is achieved, initiate Targeted Temperature Management (32°C-36°C).
Warning: Excessive ventilation (over 10 breaths/min) decreases cardiac output and survival rates.

SECTION 2.1: HYPERTENSIVE CRISIS
Definition: SBP &amp;gt;180 mmHg or DBP &amp;gt;120 mmHg. 
Hypertensive Urgency: No end-organ damage. Treat with oral Labetalol 200mg.
Hypertensive Emergency: Evidence of end-organ damage (Stroke, Encephalopathy). 
Emergency Treatment: Labetalol IV 20mg bolus or Nicardipine IV infusion 5mg/h. 
Goal: Reduce Mean Arterial Pressure (MAP) by no more than 25% in the first hour to prevent cerebral ischemia.

SECTION 3.1: ANAPHYLAXIS EMERGENCY
Symptoms: Urticaria, angioedema, stridor, wheezing, or hypotension following allergen exposure.
Primary Treatment: Epinephrine 0.3mg (1:1000) IM in the lateral thigh. Repeat every 5-15 mins if no improvement.
Secondary Treatment: Diphenhydramine 25-50mg IV. Methylprednisolone 125mg IV.
Observation: Monitor for biphasic reactions for at least 4-6 hours post-symptom resolution.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;


&lt;span class="c1"&gt;# --- STEP 2: HIERARCHICAL SPLITTING ---
&lt;/span&gt;&lt;span class="n"&gt;parent_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;child_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Create parent and child docs with metadata links
&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;medical_manual&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;parent_docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;all_child_docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;docstore_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parent_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# one-level parent-child tree
&lt;/span&gt;    &lt;span class="n"&gt;parent_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;docstore_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;

    &lt;span class="c1"&gt;# Split each parent into children
&lt;/span&gt;    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;child_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_documents&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parent_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent_id&lt;/span&gt;
        &lt;span class="n"&gt;all_child_docs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# --- STEP 3: STORAGE ---
&lt;/span&gt;&lt;span class="n"&gt;embed_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HuggingFaceEndpointEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentence-transformers/all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;## this model returns 384 sized vector
&lt;/span&gt;    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feature-extraction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;vectorstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_child_docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embed_model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;docstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InMemoryStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;docstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docstore_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="c1"&gt;## mset stands for Multiple Set, a high-performance way to save a batch of key-value pairs into storage at once.
&lt;/span&gt;

&lt;span class="c1"&gt;# --- STEP 4: THE CUSTOM AUTO-MERGING RETRIEVER ---
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AutoMergingRetriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseRetriever&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;
    &lt;span class="n"&gt;docstore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InMemoryStore&lt;/span&gt;
    &lt;span class="n"&gt;merge_threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# If 3+ children found, return Parent
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_relevant_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                                &lt;span class="n"&gt;run_manager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CallbackManagerForRetrieverRun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="c1"&gt;# 1. Fetch top K small children
&lt;/span&gt;        &lt;span class="n"&gt;initial_hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;similarity_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 2. Track which parents are represented and how many times
&lt;/span&gt;        &lt;span class="n"&gt;parent_id_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parent_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;initial_hits&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent_id_map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;final_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;processed_parents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;initial_hits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;p_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parent_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# 3. MERGE LOGIC: If parent is frequent, "Zoom Out"
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p_id&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge_threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;processed_parents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;parent_doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;docstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mget&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;p_id&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent_doc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;final_results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent_doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;processed_parents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# 4. If not frequent enough, keep the precise child snippet
&lt;/span&gt;            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;p_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;processed_parents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;final_results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;final_results&lt;/span&gt;


&lt;span class="c1"&gt;# --- STEP 5: TEST RUN ---
&lt;/span&gt;&lt;span class="n"&gt;retriever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AutoMergingRetriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;docstore&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;docstore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Ask a query that touches multiple parts of one section
&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is the IV dosage for Labetalol and what is the target MAP reduction for high blood pressure?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; merged document(s).&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SOURCE: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;parent_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Child Node&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CONTENT: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Print snippet
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚖️ When to Use vs. When to Avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Use it when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The document structure matters:&lt;/strong&gt; Legal contracts, technical manuals, or textbooks where a paragraph only makes sense within its chapter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dense Information:&lt;/strong&gt; When specific facts (like numbers/dates) are scattered but related to a single theme.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High-Accuracy Needs:&lt;/strong&gt; When "half an answer" is worse than no answer (e.g., Medical or Compliance).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Avoid it when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simple FAQ datasets:&lt;/strong&gt; If your data is just short, independent Q&amp;amp;A pairs, hierarchy adds needless complexity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Low Latency is King:&lt;/strong&gt; Retrieving and merging larger blocks of text takes more time and uses more LLM tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unstructured "Messy" Data:&lt;/strong&gt; If your documents are random bullet points with no logical flow, a parent chunk might just be "noise".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Summary: Pros and Cons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🌟 Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Complete Context: Eliminates the "fragmentation" problem where LLMs miss surrounding warnings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;High Precision: Searching is still done on small chunks, so it's very "findable".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cleaner Logic: Allows the LLM to "read" like a human (sections/chapters) rather than "reading" snippets.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🔴 Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Token Cost: You end up sending more text to the LLM, which increases your API bill.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complexity: Harder to debug and requires managing two storage layers (Vector + Docstore).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Latency: Merging and fetching parent documents adds a few milliseconds to the RAG loop.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>langchain</category>
      <category>python</category>
    </item>
    <item>
      <title>Beyond Keywords: Mastering HyDE for Smarter Retrieval 🧠</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Sun, 10 May 2026 17:18:01 +0000</pubDate>
      <link>https://forem.com/rushanksavant/beyond-keywords-mastering-hyde-for-smarter-retrieval-3p5c</link>
      <guid>https://forem.com/rushanksavant/beyond-keywords-mastering-hyde-for-smarter-retrieval-3p5c</guid>
      <description>&lt;p&gt;If you’ve ever built a &lt;strong&gt;RAG&lt;/strong&gt; system, you’ve likely felt the frustration of the "Mismatch Problem". You ask a perfectly reasonable question, but it returns completely irrelevant documents.&lt;/p&gt;

&lt;p&gt;Why? Because your retrieval method is searching based upon your &lt;strong&gt;question's language&lt;/strong&gt;. In the vector world, these two things often don't look alike. &lt;br&gt;
&lt;strong&gt;Eg:&lt;/strong&gt; Users asking questions to retrieve context from a technical documentation (like company's legal policies)&lt;/p&gt;

&lt;p&gt;Today, we’re going to master &lt;strong&gt;HyDE (Hypothetical Document Embedding)&lt;/strong&gt;—a technique that flips the script by &lt;u&gt;"hallucinating"&lt;/u&gt; the answer before it even touches your database.&lt;/p&gt;




&lt;h2&gt;
  
  
  📝 What is HyDE?
&lt;/h2&gt;

&lt;p&gt;Instead of taking a user's question and searching for it directly, HyDE follows a three-step dance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Hallucination:&lt;/strong&gt; It asks an LLM to write a "fake" or &lt;strong&gt;hypothetical&lt;/strong&gt; answer to the user's question in document friendly language (using few-shot prompting).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Embedding:&lt;/strong&gt; It converts that "fake" answer into a vector.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Retrieval:&lt;/strong&gt; It searches your database for &lt;strong&gt;real&lt;/strong&gt; documents that look like that fake answer.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🧩 The Problem It Solves: Asymmetric Retrieval
&lt;/h2&gt;

&lt;p&gt;In standard search, we assume &lt;code&gt;vector(Question) ~ approx vector(Answer)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But in reality, questions are short, curious, and often informal. &lt;br&gt;
Answers are long, factual, and professional. &lt;br&gt;
This is &lt;strong&gt;Asymmetric Retrieval&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;HyDE turns an Asymmetric problem into a Symmetric one by making the query "look" like the data it’s trying to find.&lt;/p&gt;




&lt;h2&gt;
  
  
  📍 A Real-World Example: The Legal "Needle"
&lt;/h2&gt;

&lt;p&gt;Imagine you are building a RAG for a law firm. A junior associate asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What happens if a rival company takes over the vendor?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; The 5,000-page contract in your database doesn't use the word &lt;u&gt;"rival"&lt;/u&gt; or &lt;u&gt;"takes over"&lt;/u&gt;. It uses professional jargon like &lt;u&gt;"Change of Control Event"&lt;/u&gt;.&lt;/p&gt;

&lt;p&gt;A standard search might fail because these two vectors aren't close enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 The HyDE Solution:
&lt;/h3&gt;

&lt;p&gt;The LLM generates a "fake" clause: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"In the event of a Change of Control to a Restricted Entity, the Successor shall..."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system searches for that text.&lt;/p&gt;

&lt;p&gt;It immediately finds the correct legal page because the "fake" answer and the "real" document speak the &lt;strong&gt;same language&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Practical Implementation (The "Professional" Way)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chat_models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;init_chat_model&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_huggingface&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HuggingFaceEndpointEmbeddings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.vectorstores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;
&lt;span class="c1"&gt;# from langchain_classic.chains import HypotheticalDocumentEmbedder ## Not widely used, since custom functions give more flexibility
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.prompts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FewShotPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PromptTemplate&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.documents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Prompt prep: STYLE EXAMPLES (The "Linguistic DNA")
&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rival acquisition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;In the event of a Change of Control to a Restricted Entity...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sharing info with others&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Confidential Information shall not be disclosed to any third-party without prior written indemnification...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;example_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PromptTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;input_variables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User: {question}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Legal Style: {answer}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;hyde_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FewShotPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="c1"&gt;## Class provided by langchain for few-shot prompting
&lt;/span&gt;    &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;example_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;example_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a Legal Architect. Translate the query into formal contractual prose.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User: {question}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Legal Style:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;input_variables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# 2. MODELS &amp;amp; HYDE EMBEDDER
&lt;/span&gt;&lt;span class="n"&gt;llm_groq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;init_chat_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai/gpt-oss-120b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model_provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;groq&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;base_embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HuggingFaceEndpointEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentence-transformers/all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;## this model returns 384 sized vector
&lt;/span&gt;    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feature-extraction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# 3. The DUMMY Documents
# We add diverse sections to ensure the retriever can distinguish between them.
&lt;/span&gt;&lt;span class="n"&gt;legal_docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# THE TARGET: Change of Control
&lt;/span&gt;    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Section 45.1: Control Events. A &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Change of Control&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; occurs if a Restricted Entity acquires 51% of voting shares.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
             &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Corp_Bylaws.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;section&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Governance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="c1"&gt;# THE NOISE: Liability &amp;amp; Indemnity
&lt;/span&gt;    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Section 10.2: Limitation of Liability. Neither party shall be liable for indirect, incidental, or consequential damages.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
             &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MSA_Main.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;section&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Liability&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="c1"&gt;# THE NOISE: IP Rights
&lt;/span&gt;    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Section 5.4: Intellectual Property. All Work Product created during the Term shall be deemed &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Work Made for Hire&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; and owned by the Client.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
             &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MSA_Main.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;section&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;IP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="c1"&gt;# THE NOISE: Termination
&lt;/span&gt;    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Section 12.0: Termination for Convenience. Either party may terminate this agreement upon 90 days prior written notice.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
             &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Vendor_Agmt.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;section&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Term&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="c1"&gt;# THE NOISE: Confidentiality
&lt;/span&gt;    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Section 3.1: Non-Disclosure. The Receiver shall protect Confidential Information using the same degree of care as its own proprietary data.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
             &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NDA_Standard.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;section&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Privacy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="c1"&gt;# THE TARGET: Assignment/Successors
&lt;/span&gt;    &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Section 8.9: Successors and Assigns. This Agreement shall be binding upon and inure to the benefit of the Parties and their respective permitted successors.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
             &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Corp_Bylaws.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;section&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;General&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})]&lt;/span&gt;


&lt;span class="c1"&gt;# 4. INITIALIZE VECTOR STORE
&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;legal_docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                            &lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_embeddings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;collection_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production_legal_vault&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 


&lt;span class="c1"&gt;# 5. TEST THE RETRIEVAL
# Note: The query is vague and uses 0 keywords from the docs.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hyde_retrieval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. Generate the Hypothetical Document (The "Fake" Answer)
&lt;/span&gt;    &lt;span class="n"&gt;formatted_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hyde_prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;hypothetical_doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm_groq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatted_prompt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--- HYPOTHETICAL DOC GENERATED ---&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hypothetical_doc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Embed the "Fake" Doc and search the "Real" DB
&lt;/span&gt;    &lt;span class="c1"&gt;# We use base_embeddings here so the 'math' matches the stored data
&lt;/span&gt;    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;similarity_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hypothetical_doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;

&lt;span class="n"&gt;user_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What about sensitive or important data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s protection?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;final_docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hyde_retrieval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--- FINAL REAL DOCUMENT FOUND ---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Source: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;final_docs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Actual Text: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;final_docs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⌚ When to Use HyDE (and When to Skip It)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  ✅ Use it when:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Queries are vague or short:&lt;/strong&gt; If users type "refund" and your docs say "reimbursement protocols," HyDE will bridge that gap.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Terminology Mismatch:&lt;/strong&gt; Your users are "laymen" and your docs are "experts" (Medical, Legal, Engineering).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High-Stakes Accuracy:&lt;/strong&gt; When finding the right page is more important than saving a few pennies on API costs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ❌ Skip it when:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Factual/Number Lookups:&lt;/strong&gt; If a user asks "What was the revenue in 2023?", the LLM might hallucinate a fake number in the hypothetical doc, leading the search to the wrong year.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency is Critical:&lt;/strong&gt; HyDE requires an extra LLM call, which adds 1–2 seconds of "thinking time."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tight Budgets:&lt;/strong&gt; Every search now costs extra LLM tokens.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Summary: Pros &amp;amp; Cons
&lt;/h2&gt;

&lt;h4&gt;
  
  
  👍 Pros:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Superior Context:&lt;/strong&gt; Maps informal intent to formal data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zero Keyword Dependence:&lt;/strong&gt; You don't need exact word matches.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalable:&lt;/strong&gt; Works across thousands of pages without manual tagging.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  👎 Cons:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency:&lt;/strong&gt; Adds an extra step to the search process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hallucination Risk:&lt;/strong&gt; A "too-fake" answer can derail the search.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Increased token usage per query.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Happy coding! Have you tried HyDE in your projects? Let’s discuss in the comments below! 👇&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Day 14: Deployment &amp; LangSmith</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Sat, 09 May 2026 18:53:01 +0000</pubDate>
      <link>https://forem.com/rushanksavant/day-14-deployment-langsmith-7k8</link>
      <guid>https://forem.com/rushanksavant/day-14-deployment-langsmith-7k8</guid>
      <description>&lt;p&gt;When your LangGraph agent runs, a lot happens under the hood. If it gives a wrong answer, you need to know: Was it a bad retrieval? Did the tool fail? Or did the LLM just misinterpret the data?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LangSmith&lt;/strong&gt; allows you to trace every single step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tracing:&lt;/strong&gt; See the exact prompt sent and the raw JSON returned.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency:&lt;/strong&gt; Find out which node is slowing down your app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Track exactly how many tokens that "loop" consumed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Simply setting two environment variables in your &lt;code&gt;.env&lt;/code&gt; file enables tracing automatically. No code changes required!&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 2. LangServe: Turning Code into an API
&lt;/h2&gt;

&lt;p&gt;You can't give your users a Python script. You need a &lt;strong&gt;REST API&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;LangServe&lt;/strong&gt; helps you deploy your chains and graphs as a professional web service using FastAPI. &lt;br&gt;
It even gives you a built-in "Playground" UI to test your API in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langserve&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;add_routes&lt;/span&gt;
&lt;span class="c1"&gt;# Import your 'graph' from Day 13
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;my_agent&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt; 

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My AI Agent API&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# This creates /invoke, /stream, and /batch endpoints automatically!
&lt;/span&gt;&lt;span class="nf"&gt;add_routes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uvicorn&lt;/span&gt;
    &lt;span class="n"&gt;uvicorn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ✅ 3. The Production Checklist
&lt;/h2&gt;

&lt;p&gt;Before you hit "Deploy," ask yourself these three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Does it have a System Prompt?&lt;/strong&gt; Ensure your agent has clear "guardrails" (e.g., "Do not answer political questions").&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Is the Memory capped?&lt;/strong&gt; Use &lt;code&gt;WindowMemory&lt;/code&gt; or &lt;code&gt;SummaryMemory&lt;/code&gt; so your database doesn't explode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Are the Tools safe?&lt;/strong&gt; If your tool can delete data, make sure there is a "human-in-the-loop" check.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🎓 Graduation: Where to go from here?
&lt;/h2&gt;

&lt;p&gt;Two weeks ago, LangChain was a mystery. Now, it’s a tool in your belt. The field of AI moves fast, but the fundamentals you learned—&lt;strong&gt;Prompts, Models, Parsers, RAG, and Graphs&lt;/strong&gt;—are the pillars of the industry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Final Challenge:&lt;/strong&gt; Take everything you’ve built over the last 14 days and combine it. Build a "Personal Study Assistant" that can read your local PDFs (RAG), search the web (Tools), and remember your name (Memory).&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Day 14 Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LangSmith:&lt;/strong&gt; For debugging and tracing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LangServe:&lt;/strong&gt; For deploying as an API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Evaluations:&lt;/strong&gt; Testing your agent against "Golden Sets" of data to ensure it stays smart.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It has been an incredible journey. Keep building, keep breaking things, and most importantly, keep sharing your progress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The future is agentic. And you’re ready for it.&lt;/strong&gt; ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langchain</category>
      <category>langsmith</category>
      <category>langserver</category>
    </item>
    <item>
      <title>Small-to-Big RAG: Your AI Needs a Better Context 🧠</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Sat, 09 May 2026 09:55:18 +0000</pubDate>
      <link>https://forem.com/rushanksavant/small-to-big-rag-your-ai-needs-a-better-context-4cp1</link>
      <guid>https://forem.com/rushanksavant/small-to-big-rag-your-ai-needs-a-better-context-4cp1</guid>
      <description>&lt;p&gt;If your text chunks are too small, the AI misses the context. If they are too big, the search becomes "blurry" and inaccurate. To solve this, advanced developers use &lt;strong&gt;Small-to-Big Retrieval&lt;/strong&gt;. Two popular flavors are &lt;strong&gt;Sentence Window&lt;/strong&gt; and &lt;strong&gt;Parent Document Retrieval&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is the breakdown of how they work and which one you should choose.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤝 The Shared Secret: "Search Small, Read Big"
&lt;/h2&gt;

&lt;p&gt;Both techniques follow one rule: Search using a tiny, precise snippet, but give the LLM a large, context-rich block of text to read. It’s like searching a library index for a "keyword" but then pulling the whole "book" off the shelf to get the full story.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 1. Sentence Window Retrieval: The "Magnifying Glass"
&lt;/h2&gt;

&lt;p&gt;Imagine you are reading a novel. To understand a specific line of dialogue, you usually just need to know what happened a few seconds before and after.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt; You break your data into individual sentences. When the AI finds a relevant sentence, it automatically grabs the 3–5 sentences immediately surrounding it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Vibe:&lt;/strong&gt; Linear and local.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Narrative text, chat transcripts, or articles where ideas flow sentence-by-sentence.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🗺️ 2. Parent Document Retrieval: The "Map"
&lt;/h2&gt;

&lt;p&gt;Imagine a Technical Manual or a Legal Contract. A single sentence like "Tighten the bolt" is useless if the safety warning is at the top of the page. You don't just need the "neighboring sentences"; you need the &lt;strong&gt;whole section&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt; You create a hierarchy. You have &lt;strong&gt;Parent chunks&lt;/strong&gt; (like a full page) and &lt;strong&gt;Child chunks&lt;/strong&gt; (small paragraphs inside that page). The AI searches the "Children" but returns the "Parent" to the LLM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Vibe:&lt;/strong&gt; Structural and organized.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; PDFs, manuals, financial reports, and legal docs where sections are logically grouped.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Comparison Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Sentence Window&lt;/th&gt;
&lt;th&gt;Parent Document&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Show me what’s around this."&lt;/td&gt;
&lt;td&gt;"Show me the section this belongs to."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Flat/Linear&lt;/td&gt;
&lt;td&gt;Hierarchical (Big &amp;amp; Small)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Context is often hidden in metadata.&lt;/td&gt;
&lt;td&gt;Parents are stored in a separate database.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Books, Emails, Conversations.&lt;/td&gt;
&lt;td&gt;Technical Specs, Legal, Wiki pages.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Choose Sentence Window&lt;/strong&gt; if your data is "unstructured" and the context is always right next to the answer. It’s easier to set up and works great for simple Q&amp;amp;A.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Parent Document&lt;/strong&gt; if you are building an Enterprise-grade tool. It is more "stable" because it respects document boundaries (like chapters or headers), ensuring the LLM never gets a half-finished thought from a different page.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>langchain</category>
      <category>python</category>
    </item>
    <item>
      <title>Day 13: The Self-Correcting Agent — Building Loops with LangGraph 🔄</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Fri, 08 May 2026 17:39:23 +0000</pubDate>
      <link>https://forem.com/rushanksavant/day-13-the-self-correcting-agent-building-loops-with-langgraph-l4i</link>
      <guid>https://forem.com/rushanksavant/day-13-the-self-correcting-agent-building-loops-with-langgraph-l4i</guid>
      <description>&lt;p&gt;Yesterday, we learned that &lt;strong&gt;LangGraph&lt;/strong&gt; is all about nodes and edges. Today, we’re putting that into practice by building a &lt;strong&gt;Stateful Agent&lt;/strong&gt; that can actually "think," use a tool, and then decide if it needs to do more.&lt;/p&gt;

&lt;p&gt;In the old way (Chains), if a tool returned an error, the app crashed. In the LangGraph way, we create a loop where the agent sees the error and tries a different approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 The Agentic Loop: Thought → Action → Observation
&lt;/h2&gt;

&lt;p&gt;To build this, we need a graph that doesn't just go in a straight line. We need it to circle back.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Agent Node:&lt;/strong&gt; The LLM decides what to do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools Node:&lt;/strong&gt; If the LLM wants to use a tool, this node executes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Loop:&lt;/strong&gt; The result of the tool goes back to the Agent so it can "observe" the result and decide if it's done.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🛠️ Coding the Loop
&lt;/h2&gt;

&lt;p&gt;We'll use the &lt;code&gt;ToolNode&lt;/code&gt;—a pre-built helper from LangGraph—to make this easy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypedDict&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.graph.message&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;add_messages&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.prebuilt&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ToolNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools_condition&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatOpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.tools.tavily_search&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TavilySearchResults&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Define the State (Our notebook)
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# add_messages tells LangGraph to append new messages to history
&lt;/span&gt;    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;add_messages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Setup Tools and Model
&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TavilySearchResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;bind_tools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Define the Nodes
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chatbot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])]}&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Build the Graph
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chatbot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chatbot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# ToolNode automatically executes tool calls found in the messages
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ToolNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# 5. Define the Logic (The "Brain")
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chatbot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Conditional Edge: If the model called a tool, go to 'tools', 
# otherwise, go to 'END'.
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chatbot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools_condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Loop back! After using tools, go back to the chatbot to see if it's done
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chatbot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚡ Why &lt;code&gt;tools_condition&lt;/code&gt; is Magic
&lt;/h2&gt;

&lt;p&gt;This is a built-in "traffic controller." It looks at the last message from the AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If it contains a &lt;strong&gt;tool_call&lt;/strong&gt;, it sends the flow to the &lt;code&gt;tools&lt;/code&gt; node.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If it is a &lt;strong&gt;regular string&lt;/strong&gt;, it realizes the AI is finished and sends it to &lt;code&gt;END&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This prevents the AI from getting stuck in an infinite loop!&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Day 13 Summary
&lt;/h2&gt;

&lt;p&gt;Today, you built a truly autonomous agent. You learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cyclic Graphs:&lt;/strong&gt; How to point an edge back to a previous node.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ToolNode:&lt;/strong&gt; Automating the execution of AI-requested actions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conditional Routing:&lt;/strong&gt; Letting the graph decide its own path.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Your Homework:&lt;/strong&gt; Imagine the search tool returns "No results found." Because of the loop we built today, the AI can see that and try a different search query automatically. Try to prompt your agent to find something obscure and watch it work!&lt;/p&gt;

&lt;p&gt;See you tomorrow! ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langgraph</category>
      <category>python</category>
      <category>agents</category>
    </item>
    <item>
      <title>Day 12: Enter LangGraph — Moving from Chains to Cyclic Graphs 🕸️</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Thu, 07 May 2026 17:55:32 +0000</pubDate>
      <link>https://forem.com/rushanksavant/day-12-enter-langgraph-moving-from-chains-to-cyclic-graphs-5ano</link>
      <guid>https://forem.com/rushanksavant/day-12-enter-langgraph-moving-from-chains-to-cyclic-graphs-5ano</guid>
      <description>&lt;p&gt;Today, we leave the world of linear "Chains" and enter the most powerful evolution of the LangChain ecosystem: &lt;strong&gt;LangGraph&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you've been following along, you've noticed that Chains always go forward: &lt;strong&gt;A -&amp;gt; B -&amp;gt; C&lt;/strong&gt;. But real intelligence requires &lt;strong&gt;loops&lt;/strong&gt;. Think about how you work: you write code, you run it, it fails, so you go back and fix it. That's a cycle. LangGraph is designed to let AI agents do exactly that.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔄 Why LangGraph?
&lt;/h2&gt;

&lt;p&gt;Standard LangChain "Chains" are Directed Acyclic Graphs (DAGs). They can't loop.&lt;br&gt;
&lt;strong&gt;LangGraph&lt;/strong&gt; allows for &lt;strong&gt;cycles&lt;/strong&gt;, which are essential for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Self-Correction:&lt;/strong&gt; "I tried to search Google, but got no results. I'll try a different keyword."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Agent Collaboration:&lt;/strong&gt; "Agent A writes the code, Agent B reviews it and sends it back for edits."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Persistence:&lt;/strong&gt; Saving the state of a conversation so you can pause and resume it days later.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  🏗️ The Core Concepts
&lt;/h2&gt;

&lt;p&gt;To build with LangGraph, you need to understand three things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State:&lt;/strong&gt; A shared "notebook" (usually a Python dictionary) that all parts of your agent can read and write to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nodes:&lt;/strong&gt; Simple Python functions that take the current &lt;code&gt;State&lt;/code&gt;, do some work, and return an update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edges:&lt;/strong&gt; The "roads" between nodes. They decide which node to go to next.&lt;/p&gt;


&lt;h2&gt;
  
  
  🛠️ Building a Basic "Smart Assistant" Graph
&lt;/h2&gt;

&lt;p&gt;Let's build a graph where the AI decides whether to use a tool or just reply.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatOpenAI&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Define the State
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# This stores our message history
&lt;/span&gt;    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define a Node (The Brain)
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Build the Graph
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Add our node
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Define the flow
&lt;/span&gt;&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Compile it
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Run it!
&lt;/span&gt;&lt;span class="n"&gt;input_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain LangGraph in 10 words.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚡ The "Conditional" Edge: The Secret Sauce
&lt;/h2&gt;

&lt;p&gt;The real power comes when you add a &lt;strong&gt;Conditional Edge&lt;/strong&gt;. This is a function that looks at the AI's response and says:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"If the AI wants to use a tool → go to the &lt;strong&gt;Tools Node&lt;/strong&gt;."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"If the AI is finished → go to &lt;strong&gt;END&lt;/strong&gt;."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates the "Loop" that makes agents truly autonomous.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Day 12 Summary
&lt;/h2&gt;

&lt;p&gt;Today, you caught a glimpse of the "Brain" of modern AI agents. You learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chains vs. Graphs:&lt;/strong&gt; Why cycles are necessary for complex tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State Management:&lt;/strong&gt; How agents keep track of their "thoughts."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nodes &amp;amp; Edges:&lt;/strong&gt; The building blocks of an agentic workflow.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Your Homework:&lt;/strong&gt; Look at the code above. How would you add a "Review" node that checks the AI's answer for typos before sending it to the user?&lt;/p&gt;

&lt;p&gt;See you tomorrow! ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langgraph</category>
      <category>langchain</category>
      <category>python</category>
    </item>
    <item>
      <title>Why MCP is the "USB-C" of AI Tools</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Wed, 06 May 2026 17:57:37 +0000</pubDate>
      <link>https://forem.com/rushanksavant/why-mcp-is-the-usb-c-of-ai-tools-2gm3</link>
      <guid>https://forem.com/rushanksavant/why-mcp-is-the-usb-c-of-ai-tools-2gm3</guid>
      <description>&lt;p&gt;If you’ve been building with LangChain or OpenAI Functions, you’re used to defining tools as simple lists: &lt;code&gt;tools = [get_weather, send_email]&lt;/code&gt;. It works great for a weekend project, but what happens when your application grows?&lt;/p&gt;

&lt;p&gt;What if you want your tools to work in Claude Desktop, a custom Python script, and a TypeScript dashboard all at once? What if you need to update a tool's logic without redeploying your entire AI agent?&lt;/p&gt;

&lt;p&gt;That is where the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; comes in. Think of it as the USB-C of the AI world—a universal standard that lets any AI "host" talk to any "tool" server.&lt;/p&gt;

&lt;p&gt;Here is a simple breakdown of when you should move past simple tools and embrace MCP.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔌 1. The "USB-C" Effect (Standardization)
&lt;/h3&gt;

&lt;p&gt;In a standard setup, your tool is often locked into a specific library (like LangChain). With MCP, your tool lives on a server. Because it follows a universal protocol, the same server can provide tools to a LangChain agent, a Claude Desktop instance, and a custom-built robot simultaneously.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔄 2. Dynamic Tool Discovery
&lt;/h3&gt;

&lt;p&gt;Normally, you must pass a fixed list of tools to your agent. If you want to add a new feature, you have to change the code and reboot the app.&lt;br&gt;
With MCP, the agent "polls" the server. If you add a new tool to the server at 2:00 PM, the agent can see and use it at 2:01 PM without you touching a single line of code in the host application.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✂️ 3. Decoupled Logic and Updates
&lt;/h3&gt;

&lt;p&gt;When your tool logic lives inside the MCP server:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Host Independence:&lt;/strong&gt; If you fix a bug in the tool's math or update an API key, the host application doesn't need to be touched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Language Agnostic:&lt;/strong&gt; You can write a heavy data-processing tool in Rust or Go for performance, while keeping your AI logic in Python.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔒 4. Security and Stability
&lt;/h3&gt;

&lt;p&gt;MCP acts as a protective layer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Firewall:&lt;/strong&gt; You can deploy tools to a remote server and wrap them in a firewall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blast Radius:&lt;/strong&gt; If a tool has a vulnerability or crashes, it won't take down your main AI application. They are running in separate environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  📚 5. Sharing More Than Just Functions
&lt;/h3&gt;

&lt;p&gt;Standard tools are usually just "functions" (do X, get Y). MCP allows you to share:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt; Live log files, database schemas, or documents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompts:&lt;/strong&gt; Pre-written instruction templates that the server provides to the host.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ The One-Line Rule
&lt;/h2&gt;

&lt;p&gt;Use &lt;strong&gt;MCP&lt;/strong&gt; when building an &lt;strong&gt;"Ecosystem"&lt;/strong&gt; that needs to scale, stay secure, and remain flexible.&lt;br&gt;
Use &lt;strong&gt;Standard&lt;/strong&gt; Tools when building a &lt;strong&gt;"Prototype"&lt;/strong&gt; where speed of development is your only priority.&lt;/p&gt;




&lt;h2&gt;
  
  
  💼 Real-World Scenarios
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;✅ Use MCP for: "The Enterprise Data Hub"&lt;/strong&gt;&lt;br&gt;
Imagine building an AI for a bank. The AI needs to check balances, pull credit scores, and generate PDFs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; You want the "Credit Score" team to manage their own tool server. If they change their logic, the AI keeps working. You also need a strict security barrier between the AI and the sensitive financial databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Skip MCP for: "The Local PDF Summarizer"&lt;/strong&gt;&lt;br&gt;
Imagine a simple script that reads 5 PDFs on your laptop and extracts names using a regex function.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why:&lt;/strong&gt; Setting up a Client-Server architecture for a single function is massive overkill. A standard &lt;code&gt;@tool&lt;/code&gt; takes two seconds to write and requires zero infrastructure.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📝 Summary
&lt;/h2&gt;

&lt;p&gt;MCP moves us away from "hard-coding" AI capabilities and toward a world where tools are plug-and-play. If you are planning for the future of your app, start thinking in servers, not just lists.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langchain</category>
      <category>mcp</category>
      <category>agents</category>
    </item>
    <item>
      <title>Day 11: Conversational RAG — How to Chat with Your Documents 💬</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Wed, 06 May 2026 15:11:58 +0000</pubDate>
      <link>https://forem.com/rushanksavant/day-11-conversational-rag-how-to-chat-with-your-documents-43nm</link>
      <guid>https://forem.com/rushanksavant/day-11-conversational-rag-how-to-chat-with-your-documents-43nm</guid>
      <description>&lt;p&gt;Yesterday, we built a RAG chain that could answer a single question. But if you followed up with "Can you explain that further?", the AI would get confused. Why? Because it didn't have contextual history.&lt;/p&gt;

&lt;p&gt;Today, we solve the hardest part of RAG: &lt;strong&gt;Conversational Memory&lt;/strong&gt;. We'll teach the AI to understand that "it" or "that" refers to things mentioned earlier in the chat.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The Problem: The "Query Re-writing" Challenge
&lt;/h2&gt;

&lt;p&gt;If you ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"How does LangChain work?"&lt;/li&gt;
&lt;li&gt;"Can you give me an example of it?"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The retriever doesn't know what "it" is. It will literally search your database for the word "it," which is useless.&lt;/p&gt;

&lt;p&gt;To fix this, we add a step called &lt;strong&gt;History-Aware Retrieval&lt;/strong&gt;. The AI takes your follow-up question and the chat history, then "re-writes" it into a standalone question that the retriever can understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Step 1: Contextualizing the Question
&lt;/h2&gt;

&lt;p&gt;We create a sub-chain that looks at the history and the new question to produce a "search-friendly" query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chains&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_history_aware_retriever&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.prompts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MessagesPlaceholder&lt;/span&gt;

&lt;span class="c1"&gt;# The prompt that tells the AI to re-write the question if history exists
&lt;/span&gt;&lt;span class="n"&gt;contextualize_q_system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Given a chat history and the latest user question &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;which might reference context in the chat history, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;formulate a standalone question which can be understood &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;without the chat history. Do NOT answer the question.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;contextualize_q_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_messages&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contextualize_q_system_prompt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;MessagesPlaceholder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{input}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Wrap your existing retriever (from Day 9)
&lt;/span&gt;&lt;span class="n"&gt;history_aware_retriever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_history_aware_retriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contextualize_q_prompt&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛠️ Step 2: The Full Conversational Chain
&lt;/h2&gt;

&lt;p&gt;Now, we plug this into our document chain to create the final "Conversational RAG" flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chains&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_retrieval_chain&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chains.combine_documents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_stuff_documents_chain&lt;/span&gt;

&lt;span class="c1"&gt;# Standard Q&amp;amp;A prompt
&lt;/span&gt;&lt;span class="n"&gt;qa_system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are an assistant for question-answering tasks. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use the following pieces of retrieved context to answer the question.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{context}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;qa_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_messages&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qa_system_prompt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;MessagesPlaceholder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{input}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;question_answer_chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_stuff_documents_chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qa_prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The final chain!
&lt;/span&gt;&lt;span class="n"&gt;rag_chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_retrieval_chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history_aware_retriever&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;question_answer_chain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚀 Testing it Out
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.messages&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HumanMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AIMessage&lt;/span&gt;

&lt;span class="n"&gt;chat_history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="c1"&gt;# First Interaction
&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is LangSmith?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rag_chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chat_history&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Update History
&lt;/span&gt;&lt;span class="n"&gt;chat_history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nc"&gt;HumanMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;AIMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Follow-up (The AI now knows 'it' refers to LangSmith!)
&lt;/span&gt;&lt;span class="n"&gt;second_question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How do I get started with it?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rag_chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;second_question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chat_history&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎯 Day 11 Summary
&lt;/h2&gt;

&lt;p&gt;Today, you bridged the final gap in RAG. You learned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Contextualization:&lt;/strong&gt; Why "it" and "this" break standard retrievers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Query Re-writing:&lt;/strong&gt; Using an LLM to make search queries smarter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;create_history_aware_retriever&lt;/code&gt;: The specific LangChain tool for this job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Homework:&lt;/strong&gt; Try running the chain without updating the &lt;code&gt;chat_history&lt;/code&gt; list. Notice how the second answer becomes generic or fails—this proves how vital history is!&lt;/p&gt;

&lt;p&gt;See you tomorrow! ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langchain</category>
      <category>rag</category>
      <category>python</category>
    </item>
    <item>
      <title>Day 10: The Full RAG Chain — From Library to Answers 🔗</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Tue, 05 May 2026 17:59:24 +0000</pubDate>
      <link>https://forem.com/rushanksavant/day-10-the-full-rag-chain-from-library-to-answers-3m9d</link>
      <guid>https://forem.com/rushanksavant/day-10-the-full-rag-chain-from-library-to-answers-3m9d</guid>
      <description>&lt;p&gt;Yesterday, we built the "Library" (Vector Store). Today, we’re going to build the "Librarian."&lt;/p&gt;

&lt;p&gt;A Librarian doesn't just point you to a shelf; they go get the right book, read the relevant page, and explain it to you. In LangChain, we do this by connecting our &lt;strong&gt;Retriever&lt;/strong&gt; to our &lt;strong&gt;LLM&lt;/strong&gt; using a &lt;strong&gt;Retrieval Chain&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The 2-Step Architecture
&lt;/h2&gt;

&lt;p&gt;To make our AI answer questions based on our data, we need to link two distinct parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Retrieval Step:&lt;/strong&gt; Finding the most relevant chunks from our Vector Database.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Generation Step:&lt;/strong&gt; Feeding those chunks into the LLM as "Context" so it can craft an answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Step 1: The "Stuffing" Chain
&lt;/h2&gt;

&lt;p&gt;First, we need a way to tell the AI: "Here is a bunch of text (the context). Use it to answer this specific question." In LangChain, this is often called the &lt;code&gt;create_stuff_documents_chain&lt;/code&gt; because it "stuffs" all retrieved documents into the prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chains.combine_documents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_stuff_documents_chain&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.prompts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatPromptTemplate&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatOpenAI&lt;/span&gt;

&lt;span class="c1"&gt;# Define the "Instructional" prompt
&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Answer the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s question based ONLY on the provided context. 
If you don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t know the answer, say you don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t know.

Context: {context}
Question: {input}
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# This chain knows HOW to format the documents into the prompt
&lt;/span&gt;&lt;span class="n"&gt;document_chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_stuff_documents_chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛠️ Step 2: The Final Retrieval Chain
&lt;/h2&gt;

&lt;p&gt;Now, we link the "Librarian" (the document chain) to the "Library" (the retriever we built yesterday).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chains&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_retrieval_chain&lt;/span&gt;

&lt;span class="c1"&gt;# 'retriever' is the object we created in Day 9
&lt;/span&gt;&lt;span class="n"&gt;retrieval_chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_retrieval_chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;document_chain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Let's ask it something!
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retrieval_chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What are the main features of LangSmith?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧐 Why This is Better Than a Search Engine
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;- No Hallucinations:&lt;/strong&gt; Because we told the AI "Answer ONLY based on context," it won't make things up.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Privacy:&lt;/strong&gt; The data never leaves your "Vector Store" to train the model; it's only sent as a temporary reference during the query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Source Transparency:&lt;/strong&gt; The &lt;code&gt;response&lt;/code&gt; object actually contains a &lt;code&gt;context&lt;/code&gt; key that shows you exactly which snippets of text the AI used to find the answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Day 10 Summary
&lt;/h2&gt;

&lt;p&gt;Today, you built a production-ready AI feature! You learned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Document Chains:&lt;/strong&gt; How to format multiple text chunks for an LLM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Retrieval Chains:&lt;/strong&gt; How to automate the flow from "Question" to "Answer."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Groundedness:&lt;/strong&gt; How to prevent AI hallucinations using context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Homework:&lt;/strong&gt; Look at the &lt;code&gt;response["context"]&lt;/code&gt; metadata. Can you see which specific part of your document the AI liked the most?&lt;/p&gt;

&lt;p&gt;See you tomorrow! ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langchain</category>
      <category>rag</category>
      <category>python</category>
    </item>
    <item>
      <title>The Rise of the Machine Identity</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Mon, 04 May 2026 15:54:00 +0000</pubDate>
      <link>https://forem.com/rushanksavant/the-rise-of-the-machine-identity-4de7</link>
      <guid>https://forem.com/rushanksavant/the-rise-of-the-machine-identity-4de7</guid>
      <description>&lt;h2&gt;
  
  
  The Autonomous Paradox
&lt;/h2&gt;

&lt;p&gt;In 2026, we’ve moved past simple chatbots. We are building Production-Grade RAG pipelines and autonomous agents that can plan, execute, and iterate. But as an architect, I’ve noticed a glaring hole in our "Agentic" future: &lt;strong&gt;Identity Sprawl&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We are giving agents non-human identities (NHI) with "Full Admin" permissions just to ensure the RAG works smoothly. We are effectively building a workforce of privileged users that never sleep, never get tired, and—most importantly—never verify their own intent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem: The &lt;code&gt;.env&lt;/code&gt; Security Theater&lt;/strong&gt;&lt;br&gt;
Most "Agentic" workflows today rely on a precarious stack of environment variables. Your agent has your OpenAI key, your Pinecone credentials, and often, write-access to your GitHub or cloud infrastructure.&lt;/p&gt;

&lt;p&gt;If your development environment is compromised—even for a second—via a simple browser injection or a typosquatted library, those keys are gone. In the era of &lt;strong&gt;AI-driven social engineering&lt;/strong&gt;, an attacker doesn’t need to hack your code; they just need to "support" your agent into leaking its own context.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why "Human-in-the-Loop" is Failing
&lt;/h2&gt;

&lt;p&gt;We talk about keeping a "Human-in-the-Loop" (HITL) for safety. But if the "Loop" is a web-based dashboard or a browser extension, it’s a battlefield you don't control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Contextual Spoofing:&lt;/strong&gt; An attacker can alter the transaction description in a web UI so a malicious execution looks like a routine "Database Sync."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- The "All Green" Trap:&lt;/strong&gt; AI agents can now simulate perfectly "legitimate" behavior, passing every automated check while exfiltrating data in the background.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a "Zero-Trust" Agent Architecture
&lt;/h2&gt;

&lt;p&gt;To move from "Experimental" to "Production-Grade," we need to treat Agent Identities with the same rigor we treat Root access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Hardware-Gated Signing:&lt;/strong&gt; No autonomous agent should have the power to move assets or change critical infrastructure without a physical, isolated signature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Short-Lived Tokens:&lt;/strong&gt; Stop using long-lived API keys. Use OAuth flows that require periodic re-authorization via a trusted display.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Independent Interpretation:&lt;/strong&gt; We need "Transaction Interpreters" that decode raw hex and JSON payloads independently of the browser's OS. If you can't read what the agent is actually doing, don't sign it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 2026 Reality&lt;/strong&gt;&lt;br&gt;
The recent infrastructure compromises we’ve seen—from bridge exploits to "ClickFix" social engineering—prove that the "Front Door" (the user interface) is the weakest link.&lt;/p&gt;

&lt;p&gt;I’m currently rebuilding my local agent stack to move away from software-only keys. The goal is a &lt;strong&gt;"Zero-Software" Trust Boundary&lt;/strong&gt;. I’ll be sharing the technical teardown of this setup, including the Python implementation for hardware-gated RAG, in my next post.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Are you trusting your agents with your master keys, or are you building a firewall?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>devsecops</category>
      <category>rag</category>
    </item>
    <item>
      <title>Day 9: RAG — Giving Your AI a Private Library 📚</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Mon, 04 May 2026 15:34:32 +0000</pubDate>
      <link>https://forem.com/rushanksavant/day-9-rag-giving-your-ai-a-private-library-117o</link>
      <guid>https://forem.com/rushanksavant/day-9-rag-giving-your-ai-a-private-library-117o</guid>
      <description>&lt;p&gt;Have you ever asked an AI about something that happened this morning, or about a private document on your laptop, and it hallucinated an answer? That's because LLMs have a "cutoff date."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RAG&lt;/strong&gt; fixes this. Instead of trying to memorize the whole world, the AI "looks up" the relevant information in your documents before it answers. Today, we’ll build the foundation of a RAG pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ The 5 Steps of RAG
&lt;/h2&gt;

&lt;p&gt;To give an AI a library, we follow a simple assembly line:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Load:&lt;/strong&gt; Pulling data from a PDF, Website, or Text file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Split:&lt;/strong&gt; Breaking long documents into small, bite-sized "chunks."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Embed:&lt;/strong&gt; Converting those text chunks into numbers (vectors) that represent their meaning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Store:&lt;/strong&gt; Saving those numbers in a "Vector Database."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Retrieve:&lt;/strong&gt; Finding the right chunk when a user asks a question.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Step 1: Loading &amp;amp; Splitting
&lt;/h2&gt;

&lt;p&gt;AI can't read a 50-page PDF all at once. We have to "chunk" it so the AI only reads the relevant parts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.document_loaders&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WebBaseLoader&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_text_splitters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Load a webpage
&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WebBaseLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://docs.smith.langchain.com/user_guide&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Split it into 1000-character chunks
&lt;/span&gt;&lt;span class="n"&gt;text_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;splits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Created &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;splits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chunks of data.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Step 2: The "Brainy" Storage (Vector DB)
&lt;/h2&gt;

&lt;p&gt;We don't search for words; we search for &lt;strong&gt;meaning&lt;/strong&gt;. Using &lt;strong&gt;Embeddings&lt;/strong&gt;, the word "King" will be numerically close to the word "Queen," even if they are spelled differently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAIEmbeddings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.vectorstores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Create the "Library" (Vector Store) using your chunks
&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;splits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;OpenAIEmbeddings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Turn the library into a "Retriever"
&lt;/span&gt;&lt;span class="n"&gt;retriever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_retriever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎯 Day 9 Summary
&lt;/h2&gt;

&lt;p&gt;Today, you learned how to bridge the gap between static AI knowledge and your dynamic data. We covered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- The RAG Concept:&lt;/strong&gt; Why "Search + Generate" is better than just "Generate."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Document Loaders:&lt;/strong&gt; Bringing external data into Python.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Text Splitters:&lt;/strong&gt; Why chunking matters for accuracy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Vector Stores:&lt;/strong&gt; Searching by meaning, not just keywords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your Homework:&lt;/strong&gt; Find a long article online and try to load it using the &lt;code&gt;WebBaseLoader&lt;/code&gt;. See how many "chunks" it creates when you set the &lt;code&gt;chunk_size&lt;/code&gt; to 500!&lt;/p&gt;

&lt;p&gt;See you tomorrow! ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langchain</category>
      <category>python</category>
      <category>rag</category>
    </item>
    <item>
      <title>Day 8: Building Custom Tools — Teaching Your AI New Skills 🛠️</title>
      <dc:creator>Rushank Savant</dc:creator>
      <pubDate>Sun, 03 May 2026 19:30:42 +0000</pubDate>
      <link>https://forem.com/rushanksavant/day-8-building-custom-tools-teaching-your-ai-new-skills-284p</link>
      <guid>https://forem.com/rushanksavant/day-8-building-custom-tools-teaching-your-ai-new-skills-284p</guid>
      <description>&lt;p&gt;You’ve seen how agents can search the web, but what if you need your AI to interact with your specific company database, calculate a proprietary risk score, or even control a smart lightbulb in your house?&lt;/p&gt;

&lt;p&gt;For that, you need Custom Tools. Today, we’ll see how a simple Python decorator can bridge the gap between your local code and a LLM.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎨 The Magic of the &lt;code&gt;@tool&lt;/code&gt; Decorator
&lt;/h2&gt;

&lt;p&gt;The easiest way to create a tool in 2026 is using the &lt;code&gt;@tool&lt;/code&gt; decorator. When you wrap a function with this, LangChain automatically analyzes your code to tell the AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What the tool is called.&lt;/li&gt;
&lt;li&gt;What it does (based on your docstring).&lt;/li&gt;
&lt;li&gt;What arguments it needs (based on your type hints).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What are Decorators in python?
&lt;/h2&gt;

&lt;p&gt;In Python, decorators are a powerful design pattern that allows you to modify or enhance the behavior of a function, method, or class without permanently changing its original source code.&lt;/p&gt;

&lt;p&gt;Think of a decorator as a "wrapper" that can execute code before and after the original function runs. Following code will help you understand better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Before the function.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;After the function.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@my_decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;say_hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛠️ Step-by-Step: Creating a "Secret Multiplier" Tool
&lt;/h2&gt;

&lt;p&gt;Let’s build a tool that performs a calculation the AI couldn't possibly know—using a "secret constant" from our local environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_secret_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Calculates a business score by multiplying input by a secret company constant.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;secret_constant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;  &lt;span class="c1"&gt;# This could be from a database or API
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;secret_constant&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The secret business score is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Let's see what the AI sees!
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calculate_secret_score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calculate_secret_score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calculate_secret_score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Why Docstrings and Type Hints Matter
&lt;/h2&gt;

&lt;p&gt;In regular coding, docstrings are for other humans. In LangChain, &lt;strong&gt;docstrings are for the AI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your docstring is vague (e.g., &lt;code&gt;"Does math"&lt;/code&gt;), the AI won't know when to use the tool. If it’s specific (e.g., &lt;code&gt;"Use this tool when the user asks for a 'business score' or 'proprietary calculation'"&lt;/code&gt;), your agent becomes incredibly reliable.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ Plugging it into the Agent
&lt;/h2&gt;

&lt;p&gt;Once your tool is defined, you just add it to your tool list, exactly like we did yesterday.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatOpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.prebuilt&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_react_agent&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Define your custom skills
&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;calculate_secret_score&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Setup the brain
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Create the Agent
&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_react_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Test it!
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is the secret score for a value of 10?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎯 Day 8 Summary
&lt;/h2&gt;

&lt;p&gt;Today, you moved from "User" to "Creator." You learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;code&gt;@tool&lt;/code&gt; Decorator:&lt;/strong&gt; Converting functions to AI skills.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prompt Engineering via Docstrings:&lt;/strong&gt; Writing descriptions so the LLM knows when to call your tool.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration:&lt;/strong&gt; Adding your custom logic into a ReAct agent loop.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Your Homework:&lt;/strong&gt; Write a custom tool called &lt;code&gt;get_user_status&lt;/code&gt; that takes a &lt;code&gt;username&lt;/code&gt; and returns a fake status (like "Active" or "Away"). Try to get your agent to tell you the status of "Alex."&lt;/p&gt;

&lt;p&gt;See you tomorrow! ☕&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langchain</category>
      <category>python</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
