<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Evolve by Design]]></title><description><![CDATA[Evolve by Design]]></description><link>https://dharmarajrathinavel.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!gRzg!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2899d53-f680-4dcd-82d6-f361f72730ac_1024x1024.png</url><title>Evolve by Design</title><link>https://dharmarajrathinavel.substack.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 14 Aug 2026 08:41:48 GMT</lastBuildDate><atom:link href="https://dharmarajrathinavel.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Dharmaraj Rathinavel]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[dharmarajrathinavel@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[dharmarajrathinavel@substack.com]]></itunes:email><itunes:name><![CDATA[Dharmaraj Rathinavel]]></itunes:name></itunes:owner><itunes:author><![CDATA[Dharmaraj Rathinavel]]></itunes:author><googleplay:owner><![CDATA[dharmarajrathinavel@substack.com]]></googleplay:owner><googleplay:email><![CDATA[dharmarajrathinavel@substack.com]]></googleplay:email><googleplay:author><![CDATA[Dharmaraj Rathinavel]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Day 05 - Structured Output: Getting Predictable Data from LLMs]]></title><description><![CDATA[AgentiAI Made Easy series]]></description><link>https://dharmarajrathinavel.substack.com/p/agentic-ai-day-5</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/agentic-ai-day-5</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Wed, 12 Aug 2026 18:30:46 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/17b3a08f-1ebe-4b0d-a082-3c56712620b0_1280x672.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Alright, last stop in this series. So far every response we&#8217;ve gotten from a model has been plain text. Fine for a chatbot, but what if you&#8217;re building something that needs to actually use the model&#8217;s answer in code? Like filling a database, populating a UI, or feeding another function? Plain text just doesn&#8217;t cut it there. That&#8217;s exactly what Structured Output fixes. Let&#8217;s dig in.</p><div><hr></div><h2><strong>The problem with plain text responses</strong></h2><p>Let&#8217;s see what happens when we just ask a model a normal question.</p><pre><code><code>groq_model_name = os.getenv("GROQ_MODEL")
groq_model = init_chat_model(
    os.getenv("GROQ_MODEL"),
    model_provider="groq"
)
unstructured_response = groq_model.invoke("Give me details about the movie 'Jersey' acted by Nani.")
print(unstructured_response.content)</code></code></pre><p>You&#8217;ll get back a paragraph of text describing the movie, its plot, cast, release details, all mixed together in prose. Sounds fine to read, but try extracting just the release year out of that paragraph programmatically. You&#8217;d be writing fragile regex or string parsing, and it would break the moment the model phrases things slightly differently next time</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xQ8f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xQ8f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 424w, https://substackcdn.com/image/fetch/$s_!xQ8f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 848w, https://substackcdn.com/image/fetch/$s_!xQ8f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 1272w, https://substackcdn.com/image/fetch/$s_!xQ8f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xQ8f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png" width="1456" height="160" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:160,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56695,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209278346?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xQ8f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 424w, https://substackcdn.com/image/fetch/$s_!xQ8f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 848w, https://substackcdn.com/image/fetch/$s_!xQ8f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 1272w, https://substackcdn.com/image/fetch/$s_!xQ8f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fb3254-fc24-4220-ba69-eca2097a147f_2078x228.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Not great, right? This is exactly the kind of unpredictability that breaks production systems. Before moving forward,</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2><strong>The fix: give the model a schema</strong></h2><p>Instead of hoping the model&#8217;s text happens to contain what you need, you tell it exactly what shape of data to return. LangChain calls this Structured Output, and the most common way to do it is with <code>pydantic</code>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dUEU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dUEU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 424w, https://substackcdn.com/image/fetch/$s_!dUEU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 848w, https://substackcdn.com/image/fetch/$s_!dUEU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 1272w, https://substackcdn.com/image/fetch/$s_!dUEU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dUEU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png" width="1456" height="150" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:55066,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209278346?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dUEU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 424w, https://substackcdn.com/image/fetch/$s_!dUEU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 848w, https://substackcdn.com/image/fetch/$s_!dUEU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 1272w, https://substackcdn.com/image/fetch/$s_!dUEU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dd32bef-0eed-4946-b3c0-925a1be6aa49_2328x240.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3><strong>Step 1: Define your schema with Pydantic</strong></h3><pre><code><code>from pydantic import BaseModel, Field

class Movie(BaseModel):
    title: str = Field(..., description="The title of the movie")
    release_year: int = Field(..., description="The year the movie was released")
    genre: str = Field(..., description="The genre of the movie")</code></code></pre><p>Notice the <code>Field(..., description="...")</code> part. Just like a tool&#8217;s docstring tells the model when to use it, the description here tells the model exactly what each field means. Don&#8217;t skip these, they genuinely affect how accurate the output is.</p><h3><strong>Step 2: Ask the model to follow that schema</strong></h3><pre><code><code>structured_response = groq_model.with_structured_output(Movie).invoke(
    "Give me details about the movie 'Jersey' acted by Nani."
)
structured_response</code></code></pre><p>And now, instead of a paragraph, you get back a clean <code>Movie</code> object with exactly three fields, <code>title</code>, <code>release_year</code>, and <code>genre</code>. Nothing extra, nothing missing. That&#8217;s the whole point, predictable output that your code can rely on every single time.</p><p>What do you think happens if you need both the raw AI message and the structured data? Turns out, there&#8217;s an option for that too.</p><pre><code><code>structured_response_with_ai_message = groq_model.with_structured_output(
    Movie, include_raw=True
).invoke("Give me details about the movie 'Jersey' acted by Nani.")</code></code></pre><p>Setting <code>include_raw=True</code> gives you both, the full <code>AIMessage</code> (with metadata, token usage, all of it) and the parsed structured object. Handy when you want the clean data but also want to log or debug the raw response.</p><div><hr></div><h2><strong>Nested structured output</strong></h2><p>Here&#8217;s where it gets genuinely useful. Schemas aren&#8217;t limited to flat fields, you can nest them, just like you&#8217;d nest objects in any normal data model.</p><pre><code><code>class Player(BaseModel):
    name: str = Field(..., description="The name of the player")
    role: str = Field(..., description="The role of the player in the team. Ex: Batsman, Bowler, All-rounder, Wicket-keeper, Captain")

class Team(BaseModel):
    name: str = Field(..., description="The name of the team")
    players: list[Player] = Field(..., description="List of players in the team")

structured_response_nested = groq_model.with_structured_output(Team).invoke(
    "Give me best playing 11 of the Indian cricket team in batting order."
)
for player in structured_response_nested.players:
    print(f"{player.name} - {player.role}")</code></code></pre><p>Look at what&#8217;s happening here. <code>Team</code> contains a list of <code>Player</code> objects, and the model correctly fills in an entire list, each with its own <code>name</code> and <code>role</code>, all nested inside one clean response. This is genuinely powerful for anything like generating structured reports, populating UI components, or feeding data into another system, all without writing a single parser yourself.</p><div><hr></div><h2><strong>Pydantic isn&#8217;t the only option</strong></h2><p>Pydantic gives you the richest feature set, validation, descriptions, and nested structures, but it&#8217;s not the only way to define a schema. Here&#8217;s how the three options compare:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!69JP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!69JP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 424w, https://substackcdn.com/image/fetch/$s_!69JP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 848w, https://substackcdn.com/image/fetch/$s_!69JP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 1272w, https://substackcdn.com/image/fetch/$s_!69JP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!69JP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png" width="1456" height="467" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:467,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:241768,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209278346?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!69JP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 424w, https://substackcdn.com/image/fetch/$s_!69JP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 848w, https://substackcdn.com/image/fetch/$s_!69JP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 1272w, https://substackcdn.com/image/fetch/$s_!69JP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b9b97d5-76b2-42a5-b061-4cabed90e2cb_2574x826.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The good news? Once you&#8217;ve defined the schema, using it is basically the same regardless of which approach you picked. For <code>TypedDict</code> and <code>Dataclass</code>, you plug the schema into <code>create_agent()</code> using <code>response_format</code> instead of calling <code>.with_structured_output()</code> directly:</p><pre><code><code>agent = create_agent(
    model=groq_model,
    response_format=Movie   # Movie schema, defined using any of the three approaches
)</code></code></pre><p>So really, the only thing that changes across all three approaches is how you write the schema itself. Everything downstream stays the same.</p><div><hr></div><h2><strong>Recap</strong></h2><ul><li><p>Plain text responses are unpredictable and fragile to parse, structured output fixes that.</p></li><li><p>Define a schema using Pydantic&#8217;s <code>BaseModel</code> and <code>Field</code>, then call <code>model.with_structured_output(&lt;Schema&gt;)</code>.</p></li><li><p>Use <code>include_raw=True</code> if you want both the full AI message and the parsed structured data.</p></li><li><p>Schemas can be nested, letting the model return complex, structured objects like a full team of players.</p></li><li><p>Pydantic, TypedDict, and Dataclass all work as schema options, only the schema definition changes, everything else stays consistent.</p></li></ul><p>Not bad at all. You&#8217;ve now gone from a single <code>invoke()</code> call all the way to building agents that use tools, understand structured conversations, and return clean, predictable data.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-5?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-5?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-5?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p></p>]]></content:encoded></item><item><title><![CDATA[Day 04 - Messages: The Language Models Actually Understand]]></title><description><![CDATA[LangChain Made Easy series]]></description><link>https://dharmarajrathinavel.substack.com/p/agentic-ai-day-4</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/agentic-ai-day-4</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Sun, 09 Aug 2026 18:30:06 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5a6c7c58-edae-4356-a71e-f7c52448985c_1280x672.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So far in this series, we&#8217;ve been calling <code>model.invoke("some text")</code> and getting an answer back. That works fine for quick one off questions. But real conversations need more structure than just a plain string. That structure is called a Message, and understanding it properly will make a real difference in how well your agent behaves.</p><p>Let&#8217;s break it down.</p><div><hr></div><h2><strong>What is a message, really?</strong></h2><p>A message is the basic unit of context that a model works with. Every single message, whether it&#8217;s from a human, the AI, or a system instruction, is built from three parts:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n3U_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n3U_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 424w, https://substackcdn.com/image/fetch/$s_!n3U_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 848w, https://substackcdn.com/image/fetch/$s_!n3U_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 1272w, https://substackcdn.com/image/fetch/$s_!n3U_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n3U_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png" width="560" height="168.76712328767124" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:264,&quot;width&quot;:876,&quot;resizeWidth&quot;:560,&quot;bytes&quot;:44518,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209277175?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!n3U_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 424w, https://substackcdn.com/image/fetch/$s_!n3U_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 848w, https://substackcdn.com/image/fetch/$s_!n3U_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 1272w, https://substackcdn.com/image/fetch/$s_!n3U_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1989776d-96f1-449c-9d60-adbce9cbc6e7_876x264.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Here&#8217;s the good part. LangChain gives you one standard message format that works the same way regardless of which provider you&#8217;re using underneath. So whether it&#8217;s OpenAI, Gemini, or Groq answering, your code dealing with messages doesn&#8217;t have to change.</p><p>You&#8217;ve actually already seen this without realizing it. Every time you call <code>.invoke()</code>, the response you get back isn&#8217;t just plain text, it&#8217;s an actual message object.</p><pre><code><code>groq_model.invoke("Hello, how are you?")   # Returns an AIMessage</code></code></pre><p>That response has a type, <code>ai</code>, because the model generated it. Makes sense, right?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2><strong>The four message types</strong></h2><p>LangChain gives you four message types, all available from <code>langchain.messages</code>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zoqv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zoqv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 424w, https://substackcdn.com/image/fetch/$s_!zoqv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 848w, https://substackcdn.com/image/fetch/$s_!zoqv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 1272w, https://substackcdn.com/image/fetch/$s_!zoqv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zoqv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png" width="609" height="205.0841889117043" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:328,&quot;width&quot;:974,&quot;resizeWidth&quot;:609,&quot;bytes&quot;:59800,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209277175?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zoqv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 424w, https://substackcdn.com/image/fetch/$s_!zoqv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 848w, https://substackcdn.com/image/fetch/$s_!zoqv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 1272w, https://substackcdn.com/image/fetch/$s_!zoqv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2aac40f1-253f-48ed-a95d-1bde31c57742_974x328.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Notice how each one has a clear job. You wouldn&#8217;t put user input inside a <code>SystemMessage</code>, and you wouldn&#8217;t expect the model&#8217;s answer to show up as a <code>HumanMessage</code>. Keeping these separate is exactly what lets the model understand who said what in a conversation.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KvKk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KvKk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 424w, https://substackcdn.com/image/fetch/$s_!KvKk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 848w, https://substackcdn.com/image/fetch/$s_!KvKk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 1272w, https://substackcdn.com/image/fetch/$s_!KvKk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KvKk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png" width="1404" height="338" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:338,&quot;width&quot;:1404,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59264,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209277175?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!KvKk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 424w, https://substackcdn.com/image/fetch/$s_!KvKk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 848w, https://substackcdn.com/image/fetch/$s_!KvKk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 1272w, https://substackcdn.com/image/fetch/$s_!KvKk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13a78ef-22c7-441b-be9d-c545e90b2d63_1404x338.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div><hr></div><h2><strong>Text prompts vs message prompts</strong></h2><p>Ok, here&#8217;s where it gets practical. There are two ways to send input to a model, and beginners often don&#8217;t realize there&#8217;s a difference.</p><h3><strong>Option 1: Text prompts</strong></h3><p>This is what we&#8217;ve been doing so far, just sending a plain string.</p><pre><code><code>groq_model.invoke("Hello, how are you?")</code></code></pre><p>Use this when:</p><ul><li><p>You want to send a single, standalone message</p></li><li><p>You don&#8217;t care about keeping any conversation history</p></li><li><p>You just want a quick, one off response</p></li></ul><p>Simple and fast. But it has no memory of anything before it.</p><h3><strong>Option 2: Message prompts</strong></h3><p>This is where you send a list of messages instead of a single string, giving the model actual context to work with.</p><pre><code><code>from langchain.messages import SystemMessage, HumanMessage

conversation = [
    SystemMessage("You are a helpful assistant. Don't be rude to the user."),
    HumanMessage("Hello!")
]

groq_model.invoke(conversation)</code></code></pre><p>Here&#8217;s what actually comes back when you run this:</p><pre><code><code>AIMessage(
    content='Hello! How can I help you today?',
    additional_kwargs={'reasoning_content': 'The user says "Hello!" The assistant should respond politely.'},
    response_metadata={
        'token_usage': {'completion_tokens': 31, 'prompt_tokens': 89, 'total_tokens': 120, ...},
        'model_name': 'openai/gpt-oss-20b',
        'finish_reason': 'stop', ...
    },
    id='lc_run--019fb61b-cafa-7750-bbe0-82500e8f8576-0',
    tool_calls=[], invalid_tool_calls=[],
    usage_metadata={'input_tokens': 89, 'output_tokens': 31, 'total_tokens': 120, ...}
)</code></code></pre><p>Look at all that detail packed into one response. You get the actual <code>content</code>, but also <code>response_metadata</code> (token counts, which model generated it, why it stopped), and <code>usage_metadata</code> (a clean breakdown of input versus output tokens). This is exactly the kind of information you&#8217;d want if you&#8217;re tracking cost or debugging behavior in production.</p><p>You&#8217;ll also notice <code>reasoning_content</code> in there, which basically shows how the model interpreted the system prompt before responding. Pretty useful for understanding why the model answered the way it did.</p><p>Use message prompts when:</p><ul><li><p>You need to maintain a proper conversation with history</p></li><li><p>You want to set clear rules for how the model should behave</p></li><li><p>You&#8217;re building anything beyond a single throwaway question</p></li></ul><div><hr></div><h2><strong>Why your system prompt quality actually matters</strong></h2><p>Here&#8217;s a small but important detail. The example above showed <code>reasoning_content</code> referencing the system prompt directly. That&#8217;s not a coincidence.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WwOg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WwOg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 424w, https://substackcdn.com/image/fetch/$s_!WwOg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 848w, https://substackcdn.com/image/fetch/$s_!WwOg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 1272w, https://substackcdn.com/image/fetch/$s_!WwOg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WwOg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png" width="674" height="154.61263736263737" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/acc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:334,&quot;width&quot;:1456,&quot;resizeWidth&quot;:674,&quot;bytes&quot;:148310,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209277175?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WwOg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 424w, https://substackcdn.com/image/fetch/$s_!WwOg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 848w, https://substackcdn.com/image/fetch/$s_!WwOg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 1272w, https://substackcdn.com/image/fetch/$s_!WwOg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facc42ebe-a2ae-4de4-b0fd-7f5359c385b6_2556x586.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>The more clearly you define your </strong><code>SystemMessage</code><strong>, the better and more consistent the model performs.</strong></p><p><strong>Vague system promptClear system prompt</strong>&#8220;You are an assistant.&#8221;&#8220;You are a customer support assistant for an e-commerce app. Be concise, polite, and never make up order details you don&#8217;t have.&#8221;Model behavior is inconsistent across runsModel stays on-brand and predictable</p><p>Think of the system prompt as the model&#8217;s job description. A vague job description gets vague results. A specific one gets specific, reliable behavior. This is genuinely one of the highest leverage things you can improve in any LLM application, and it costs you nothing extra to write it properly.</p><div><hr></div><h2><strong>Recap</strong></h2><ul><li><p>A message has three parts, role, content, and metadata, and LangChain standardizes this across every provider.</p></li><li><p>There are four message types, <code>SystemMessage</code>, <code>HumanMessage</code>, <code>AIMessage</code>, and <code>ToolMessage</code>, each with a clear, distinct job.</p></li><li><p>Text prompts (plain strings) work for quick, one off questions with no memory needed.</p></li><li><p>Message prompts (a list of message objects) are what you use for real conversations with context and history.</p></li><li><p>A clear, specific <code>SystemMessage</code> genuinely improves how consistent and reliable your model&#8217;s behavior is.</p></li></ul><p>So basically, once you start thinking in messages instead of plain strings, your agents start feeling a lot more like real conversations instead of disconnected one liners.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-4?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-4?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-4?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p><strong>Up next in the series:</strong> we&#8217;ll wrap up this series with Structured Output, how to make a model return exactly the data shape you want, instead of a wall of unpredictable text. <a href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-5">Catch it here!</a></p>]]></content:encoded></item><item><title><![CDATA[Day 03 - Tools: Giving Your Agent Real-World Superpowers]]></title><description><![CDATA[LangChain Made Easy series]]></description><link>https://dharmarajrathinavel.substack.com/p/agentic-ai-day-3</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/agentic-ai-day-3</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Thu, 06 Aug 2026 18:31:30 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/eda3c8b8-366c-463d-9f41-34d7cd433225_1280x672.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ok, so in the first post of this series, we built an agent using <code>create_agent()</code> and gave it a tool called <code>get_weather</code>. That was one way to hand a model a tool. But here&#8217;s the thing, that&#8217;s not the only way. You can actually give tools directly to a model too, without wrapping everything inside <code>create_agent()</code>.</p><p>In this post, we&#8217;re going deep into Tools. What they are, how to create them properly, and two different ways to actually use them. Let&#8217;s get into it.</p><div><hr></div><h2><strong>So, what exactly is a tool?</strong></h2><p>Think of a tool as a regular Python function that you hand over to the model, and say &#8220;hey, use this whenever you need it.&#8221; The model itself doesn&#8217;t run your Python code. It just decides when a tool is needed, and with what input, then your code runs it and hands the result back.</p><p>Tools can do pretty much anything you can code:</p><ul><li><p>Fetch live data from an API (weather, stock prices, news)</p></li><li><p>Query a database</p></li><li><p>Do a calculation the model can&#8217;t reliably do on its own</p></li><li><p>Even call another LLM</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FGMr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FGMr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 424w, https://substackcdn.com/image/fetch/$s_!FGMr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 848w, https://substackcdn.com/image/fetch/$s_!FGMr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 1272w, https://substackcdn.com/image/fetch/$s_!FGMr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FGMr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png" width="1456" height="353" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:353,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:60884,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209275722?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FGMr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 424w, https://substackcdn.com/image/fetch/$s_!FGMr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 848w, https://substackcdn.com/image/fetch/$s_!FGMr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 1272w, https://substackcdn.com/image/fetch/$s_!FGMr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd37d5a2-7d0f-4605-83bf-1c19fb7ce197_1742x422.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Simple enough, right? Now let&#8217;s actually build one. But, make sure you</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2><strong>Creating a tool</strong></h2><p>Here&#8217;s the entire recipe. You write a normal Python function, and slap a <code>@tool</code> decorator on top of it.</p><pre><code><code>from langchain.tools import tool

@tool
def get_current_weather(location: str) -&gt; str:
    """
    Get the current weather for a given location.
    """
    return f"The current weather in {location} is 25&#176;C and sunny."</code></code></pre><p>That&#8217;s it. That <code>@tool</code> decorator is doing the heavy lifting here, it converts your plain function into something the model can understand and call.</p><p>Now, remember what we said in Post 1 about docstrings? Same rule applies here, and honestly it matters even more now. The docstring is not a comment for your teammates to read later. It is literally what the model reads to decide &#8220;should I use this tool right now, or not?&#8221;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TlJm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TlJm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 424w, https://substackcdn.com/image/fetch/$s_!TlJm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 848w, https://substackcdn.com/image/fetch/$s_!TlJm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 1272w, https://substackcdn.com/image/fetch/$s_!TlJm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TlJm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png" width="1304" height="240" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:240,&quot;width&quot;:1304,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49292,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209275722?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TlJm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 424w, https://substackcdn.com/image/fetch/$s_!TlJm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 848w, https://substackcdn.com/image/fetch/$s_!TlJm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 1272w, https://substackcdn.com/image/fetch/$s_!TlJm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7caf96d8-dada-4c94-ade9-e80e9963708a_1304x240.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>So don&#8217;t treat the docstring as an afterthought. Write it like you&#8217;re explaining the tool to someone who has never seen your code.</p><div><hr></div><h2><strong>Let&#8217;s create a few more tools</strong></h2><p>One tool is boring. Let&#8217;s make three, so the model actually has to think about which one fits the question.</p><pre><code><code>@tool
def get_current_weather_tool(location: str) -&gt; str:
    """
    Get the current weather in a given location
    """
    return f"The current weather in {location} is sunny with a temperature of 25&#176;C."

@tool
def get_stock_price_tool(stock_symbol: str) -&gt; str:
    """
    Get the current stock price of a given stock symbol
    """
    return f"The current stock price of {stock_symbol} is $150."

@tool
def get_news_tool(topic: str) -&gt; str:
    """
    Get the latest news on a given topic
    """
    return f"The latest news on {topic} is that the stock market is up by 2% today."</code></code></pre><p>Notice each one does something completely different, weather, stock prices, news. That&#8217;s on purpose. In a bit, we&#8217;ll ask the model questions and watch it pick the correct tool on its own.</p><div><hr></div><h2><strong>Now, the interesting part: binding tools directly to a model</strong></h2><p>In Post 1, we passed tools into <code>create_agent()</code>, and the agent handled everything behind the scenes. But what if you don&#8217;t want a full agent? What if you just want a plain chat model that can call tools when needed?</p><p>That&#8217;s where <code>bind_tools()</code> comes in.</p><pre><code><code>import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

load_dotenv(override=True)

os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY")
os.environ["GROQ_API_KEY"] = os.getenv("GROQ_API_KEY")

google_model_name = os.getenv("GOOGLE_MODEL")
google_model = init_chat_model(
    google_model_name,
    model_provider="google_genai"
)

google_model_with_tools = google_model.bind_tools(
    [get_current_weather_tool, get_stock_price_tool, get_news_tool]
)</code></code></pre><p>What&#8217;s happening here? We took a plain chat model, <code>google_model</code>, and called <code>.bind_tools()</code> on it, passing in our list of tools. Now this new object, <code>google_model_with_tools</code>, knows those three tools exist and can decide to use them whenever it needs to.</p><p>So basically, this is the &#8220;lighter&#8221; way of giving a model tool access, no full agent setup required.</p><div><hr></div><h2><strong>Ok, now what? Let&#8217;s actually test it</strong></h2><p>Here&#8217;s where it gets fun. We&#8217;ll ask three completely different questions and watch what the model decides to do each time.</p><pre><code><code>tool_response = google_model_with_tools.invoke("What is the current weather in New York?")
print(tool_response.type)  # ai

tool_calls = tool_response.tool_calls

if tool_calls:
    for tool_call in tool_calls:
        print(f"Tool: {tool_call['name']}")
        print(f"Args: {tool_call['args']}")
else:
    print("No tool calls were made for this response.")</code></code></pre><p>Run this, and you&#8217;ll see the model correctly picks <code>get_current_weather_tool</code>, with <code>location</code> set to <code>New York</code>. It didn&#8217;t guess. It matched the question against the docstrings of all three tools and picked the one that actually fits.</p><p>Let&#8217;s try another one.</p><pre><code><code>tool_response = google_model_with_tools.invoke("What is the current stock price of PYPL?")

tool_calls = tool_response.tool_calls

if tool_calls:
    for tool_call in tool_calls:
        print(f"Tool: {tool_call['name']}")
        print(f"Args: {tool_call['args']}")
else:
    print("No tool calls were made for this response.")</code></code></pre><p>This time it picks <code>get_stock_price_tool</code>, with <code>stock_symbol</code> set to <code>PYPL</code>. Notice how it also figured out the right argument name and value from a plain English question. That&#8217;s not magic, it&#8217;s the model reading your function&#8217;s type hints and docstring together.</p><p>And here&#8217;s a fun one to try.</p><pre><code><code>tool_response = google_model_with_tools.invoke("Who won the IPL-2025?")

tool_calls = tool_response.tool_calls

if tool_calls:
    for tool_call in tool_calls:
        print(f"Tool: {tool_call['name']}")
        print(f"Args: {tool_call['args']}")
else:
    print("No tool calls were made for this response.")</code></code></pre><p>What do you think happens here? We don&#8217;t have a tool for IPL match results, only weather, stock, and news. So depending on the model, it might either call <code>get_news_tool</code> with <code>topic</code> set to something like &#8220;IPL 2025&#8221; since that is the closest fit, or it might make no tool call at all and just answer from its own memory. Either way, this shows you something important: the model only picks from what you gave it. If none of your tools genuinely fit, don&#8217;t expect a miracle.</p><div><hr></div><h2><strong>Two ways to use tools, side by side</strong></h2><p>Let&#8217;s put both approaches next to each other, since it&#8217;s easy to mix them up as a beginner.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nJa_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nJa_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 424w, https://substackcdn.com/image/fetch/$s_!nJa_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 848w, https://substackcdn.com/image/fetch/$s_!nJa_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 1272w, https://substackcdn.com/image/fetch/$s_!nJa_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nJa_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png" width="1456" height="392" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:392,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:192978,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209275722?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nJa_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 424w, https://substackcdn.com/image/fetch/$s_!nJa_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 848w, https://substackcdn.com/image/fetch/$s_!nJa_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 1272w, https://substackcdn.com/image/fetch/$s_!nJa_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1173c93-c057-40c6-a9fd-1abc56abb669_2572x692.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Neither one is &#8220;better.&#8221; It really depends on how much control you want versus how much you want LangChain to handle for you.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2atQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2atQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 424w, https://substackcdn.com/image/fetch/$s_!2atQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 848w, https://substackcdn.com/image/fetch/$s_!2atQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 1272w, https://substackcdn.com/image/fetch/$s_!2atQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2atQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png" width="429" height="471.9795918367347" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1186,&quot;width&quot;:1078,&quot;resizeWidth&quot;:429,&quot;bytes&quot;:100098,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209275722?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2atQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 424w, https://substackcdn.com/image/fetch/$s_!2atQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 848w, https://substackcdn.com/image/fetch/$s_!2atQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 1272w, https://substackcdn.com/image/fetch/$s_!2atQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62473906-ba71-406f-b793-3477657bd8ae_1078x1186.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Notice the difference in that last box. With <code>bind_tools()</code>, the model just tells you which tool it wants to call and with what arguments, it does not actually run the tool for you. You are responsible for executing the function yourself and feeding the result back if needed. With <code>create_agent()</code>, all of that is handled automatically behind the scenes.</p><div><hr></div><h2><strong>One thing worth repeating</strong></h2><p>We&#8217;ve said this before, but it deserves repeating here: <strong>the model is not reading your code. It is reading your docstring</strong>, your function name, your parameter names, and your type hints. That&#8217;s the entire &#8220;instruction manual&#8221; it has.</p><p>So a quick checklist before you ship any tool:</p><ul><li><p>Does the function name clearly describe what it does?</p></li><li><p>Does the docstring explain exactly when to use it?</p></li><li><p>Are the parameter names and types clear (<code>location: str</code>, not <code>x: str</code>)?</p></li><li><p>Would a stranger reading only the docstring know when to call this?</p></li></ul><p>If you can say yes to all four, your tool is production ready.</p><div><hr></div><h2><strong>Recap</strong></h2><ul><li><p>A tool is just a Python function decorated with <code>@tool</code>, that a model can choose to call.</p></li><li><p>The docstring is what tells the model what the tool does and when to use it, so write it carefully.</p></li><li><p>You can bind tools directly to a model using <code>bind_tools()</code>, without needing a full agent.</p></li><li><p>The model reads your question, compares it against every tool&#8217;s docstring, and picks the best match, or none at all if nothing fits.</p></li><li><p><code>create_agent()</code> and <code>bind_tools()</code> both work, just at different levels of control.</p></li></ul><p>Not bad, right? You now know two solid ways to give your model real world abilities.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-3?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-3?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-3?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p><strong>Up next in the series:</strong> we&#8217;ll look at Messages, the actual format models use to understand conversations, and why getting this right matters more than most beginners realize. <a href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-4">Catch it here!</a></p>]]></content:encoded></item><item><title><![CDATA[Day 02 - Invoke, Stream, and Batch: Ways to Talk to an LLM]]></title><description><![CDATA[LangChain Made Easy series]]></description><link>https://dharmarajrathinavel.substack.com/p/agentic-ai-day-2</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/agentic-ai-day-2</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Mon, 03 Aug 2026 18:30:21 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8838ac5f-ae21-4c1e-b365-409c57eb5471_1280x672.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ok, so in Post 1 we built an agent and got it talking to a model behind the scenes. But we skipped over something pretty important: how do you actually load a model in the first place, and once it&#8217;s loaded, in how many ways can you actually talk to it?</p><p>Turns out, there&#8217;s more than one way. In this post, we&#8217;ll cover how to load models from different providers using one single function, and then we&#8217;ll look at three different ways to call a model, <code>invoke()</code>, <code>stream()</code>, and <code>batch()</code>. Each one fits a different situation, and picking the wrong one can actually hurt your app&#8217;s user experience. Let&#8217;s get into it.</p><div><hr></div><h2><strong>Loading a model, the LangChain way</strong></h2><p>Here&#8217;s the thing. OpenAI, Google Gemini, and Groq all have their own SDKs, their own quirks, their own way of setting things up. If you were doing this manually, you&#8217;d be writing separate code for each one.</p><p>LangChain gives you a single function, <code>init_chat_model()</code>, that works across all of them. You just tell it which model and which provider, and it handles the rest.</p><pre><code><code>import os
from dotenv import load_dotenv

load_dotenv(override=True)

os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY")
os.environ["GROQ_API_KEY"] = os.getenv("GROQ_API_KEY")

from langchain.chat_models import init_chat_model</code></code></pre><h3><strong>Loading OpenAI</strong></h3><pre><code><code>open_ai_model_name = os.getenv("OPENAI_MODEL")
openai_model = init_chat_model(
    os.getenv("OPENAI_MODEL"),
    model_provider="openai"
)
output1 = openai_model.invoke("Hello, how are you?")
print(f"Output from {open_ai_model_name}: \n{output1.content}")</code></code></pre><h3><strong>Loading Google Gemini</strong></h3><pre><code><code>%pip install -U langchain-google-genai

google_model_name = os.getenv("GOOGLE_MODEL")
google_model = init_chat_model(
    os.getenv("GOOGLE_MODEL"),
    model_provider="google_genai"
)
output2 = google_model.invoke("Hello, how are you?")
print(f"Output from {google_model_name}: \n{output2.content}")</code></code></pre><h3><strong>Loading Groq</strong></h3><pre><code><code>groq_model_name = os.getenv("GROQ_MODEL")
groq_model = init_chat_model(
    os.getenv("GROQ_MODEL"),
    model_provider="groq"
)
output3 = groq_model.invoke("Hello, how are you?")
print(f"Output from {groq_model_name}: \n{output3.content}")</code></code></pre><p>Notice something? All three blocks look almost identical. Only the model name and <code>model_provider</code> change. That&#8217;s the whole point of <code>init_chat_model()</code>, one consistent way to load any provider, so switching providers later is basically a one line change.</p><p>So basically, once you learn this pattern once, you know it for every provider LangChain supports. Nice, right?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2><strong>Now, how do you actually talk to the model?</strong></h2><p>Once your model is loaded, you have three different methods to get a response out of it: <code>invoke()</code>, <code>stream()</code>, and <code>batch()</code>. Let&#8217;s go through each one, because picking the right one matters more than you&#8217;d think.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F2zL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F2zL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 424w, https://substackcdn.com/image/fetch/$s_!F2zL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 848w, https://substackcdn.com/image/fetch/$s_!F2zL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 1272w, https://substackcdn.com/image/fetch/$s_!F2zL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F2zL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png" width="489" height="363.0336" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/da1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:928,&quot;width&quot;:1250,&quot;resizeWidth&quot;:489,&quot;bytes&quot;:79642,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209274822?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F2zL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 424w, https://substackcdn.com/image/fetch/$s_!F2zL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 848w, https://substackcdn.com/image/fetch/$s_!F2zL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 1272w, https://substackcdn.com/image/fetch/$s_!F2zL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda1b0a15-1430-4169-b6e9-c1a5b0dc0b76_1250x928.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3><strong>1. </strong><code>invoke()</code><strong>, the straightforward one</strong></h3><p>This is what we&#8217;ve been using so far. You send a question, and you wait until the entire response is fully generated, then you get it all at once.</p><pre><code><code>google_model_name = os.getenv("GOOGLE_MODEL")
google_model = init_chat_model(
    os.getenv("GOOGLE_MODEL"),
    model_provider="google_genai"
)
output = google_model.invoke("Hello, how are you?")
print(f"Output from {google_model_name}: \n{output.content}")</code></code></pre><p>Simple, but here&#8217;s the catch. If the response is long, the user just stares at a blank screen until it&#8217;s fully ready. Not exactly a great experience for something like a chatbot.</p><h3><strong>2. </strong><code>stream()</code><strong>, the &#8220;type as you go&#8221; one</strong></h3><p>Ever noticed how ChatGPT&#8217;s answer appears word by word instead of popping up all at once? That&#8217;s streaming. Most models support this, and LangChain makes it easy to tap into.</p><pre><code><code>for chunk in google_model.stream("How to get a call from Google/Microsoft HR? Please guide under 5 lines."):
    print(chunk.text, end="", flush=True)
# end - Append this at the end of each chunk
# flush - Flush the output buffer to ensure that the text is printed immediately</code></code></pre><p>What&#8217;s happening here? <code>stream()</code> returns an iterator, not a single final answer. Every time a new chunk of text is generated, it gets yielded immediately, and your loop prints it right away. The <code>end=""</code> keeps everything on the same line instead of adding a new line after every chunk, and <code>flush=True</code> makes sure Python prints it instantly instead of holding it in a buffer.</p><p>This is what you&#8217;d want for any user facing chat interface. Feels faster, even if the total time is the same.</p><h3><strong>3. </strong><code>batch()</code><strong>, the &#8220;many questions at once&#8221; one</strong></h3><p>What if you have a whole list of questions and you want answers to all of them, without writing a loop and calling <code>invoke()</code> five separate times? That&#8217;s exactly what <code>batch()</code> is for.</p><pre><code><code>responses = google_model.batch([
    "Which team won IPL 2026?",
    "Which is the best cricket stadium in India?",
    "How Sanju Samson performed in 2026 World Cup?"
], config = {
    "max_concurrency": 2    # Only 2 requests will be sent to the model at a time. The rest will be queued and sent when one of the previous requests is completed.
})

for response in responses:
    print(response.content)</code></code></pre><p>You pass in a list of prompts, and you get back a list of responses, in the same order. The <code>max_concurrency</code> setting controls how many requests go out at the same time. Set it to 2, and only 2 questions are being processed simultaneously, the rest wait in a queue until a slot frees up.</p><p>Why would you even limit concurrency? Because most providers have rate limits. Fire off fifty requests at once, and you might just get blocked. <code>max_concurrency</code> lets you control the pace.</p><div><hr></div><h2><strong>Picking the right one</strong></h2><p>Here&#8217;s a quick table to keep handy:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zipc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zipc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 424w, https://substackcdn.com/image/fetch/$s_!zipc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 848w, https://substackcdn.com/image/fetch/$s_!zipc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 1272w, https://substackcdn.com/image/fetch/$s_!zipc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zipc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png" width="1456" height="463" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:463,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:215709,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209274822?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zipc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 424w, https://substackcdn.com/image/fetch/$s_!zipc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 848w, https://substackcdn.com/image/fetch/$s_!zipc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 1272w, https://substackcdn.com/image/fetch/$s_!zipc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F482adc41-bdbb-4302-9304-eb6b123d0615_2576x820.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There&#8217;s no universally &#8220;best&#8221; one here. It genuinely depends on what you&#8217;re building. A backend script that summarizes a document overnight? <code>invoke()</code> is fine. A live chatbot your users are staring at? <code>stream()</code> will feel a lot better. Running the same prompt against a hundred different inputs? <code>batch()</code> saves you a ton of manual looping.</p><div><hr></div><h2><strong>Recap</strong></h2><ul><li><p><code>init_chat_model()</code> gives you one consistent way to load OpenAI, Gemini, Groq, or any other supported provider.</p></li><li><p><code>invoke()</code> waits for the full response and hands it back in one go.</p></li><li><p><code>stream()</code> returns the response piece by piece, as it&#8217;s being generated, great for chat style interfaces.</p></li><li><p><code>batch()</code> takes a list of prompts and returns a list of responses, with <code>max_concurrency</code> controlling how many run at once.</p></li></ul><p>Ok, now what? You know how to load a model and talk to it in three different ways. Time to make it smarter.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-2?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-2?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-2?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p><strong>Up next in the series:</strong> we&#8217;re going to look at Messages, the actual format models use to understand a conversation, and why the words you choose in a system prompt matter more than most beginners realize. <a href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-3">Catch it here!</a></p>]]></content:encoded></item><item><title><![CDATA[Day 01 - LangChain Fundamentals: Setting Up and Building Your First AI Agent]]></title><description><![CDATA[AgenticAI Made Easy series]]></description><link>https://dharmarajrathinavel.substack.com/p/agentic-ai-day-1</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/agentic-ai-day-1</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Fri, 31 Jul 2026 18:30:34 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9e24328b-4040-46ec-8037-341564e65ed5_1280x672.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A Quick intro: I'm learning Agentic AI, from scratch, no prior background in this space. This series is basically me documenting that journey as I go, one topic at a time. I'll share whatever I learn, in the simplest way I can explain it.</p><p>Alright, let&#8217;s start from zero. No prior LangChain knowledge needed here. I&#8217;m going to walk you through this the same way I&#8217;d explain it to a friend who just asked me, &#8220;hey, what even is LangChain, and why does everyone keep talking about agents?&#8221;</p><p>By the end of this post, you will have built your very first working AI agent. Let&#8217;s go.</p><div><hr></div><h2><strong>So, what problem does LangChain actually solve?</strong></h2><p>Here&#8217;s the thing. Large Language Models like GPT, Gemini, or Llama are genuinely powerful. But the moment you try to use them inside a real application, things get messy fast. You end up having to handle:</p><ul><li><p>Connecting to different providers (OpenAI, Google, Groq, and so on)</p></li><li><p>Formatting conversation history so the model doesn&#8217;t lose context</p></li><li><p>Letting the model call external tools like APIs or databases</p></li><li><p>Parsing whatever the model sends back into something your app can actually use</p></li></ul><p>Now imagine writing all of that from scratch, for every single provider you want to support. Sounds exhausting, right? That is exactly the problem LangChain was built to solve.</p><p><strong>LangChain is basically a framework that hands you ready-made tools and abstractions so you don&#8217;t have to build all this plumbing yourself.</strong></p><p>Think of it like this:</p><p><strong>Without LangChainWith LangChain</strong>Write custom code for each LLM providerOne consistent interface works across all providersManually manage conversation historyMessage objects handle this for youManually parse tool callsTools are handled automaticallyReinvent agent logic every time<code>create_agent()</code> gives you a working agent in a few lines</p><p>Makes sense so far? Good. Let&#8217;s get our hands dirty.</p><div><hr></div><h2><strong>Step one: setting up your project</strong></h2><p>Before we write a single line of &#8220;real&#8221; code, let&#8217;s set up a clean environment. Trust me on this, it will save you headaches later when your projects start piling up and their dependencies start clashing with each other.</p><p>We&#8217;re going to use <code>uv</code>, a fast Python package and virtual environment manager.</p><pre><code><code># Install uv if you don't have it already
brew install uv</code></code></pre><p>Once that&#8217;s installed, go to your project folder and run:</p><pre><code><code># Initialize the project
uv init

# Create a virtual environment
uv venv

# Activate the virtual environment (macOS)
source .venv/bin/activate

# Install the latest version of all dependencies listed in requirements.txt
uv add -r requirements.txt

# Install one specific dependency
uv add ipykernel

# Deactivate the virtual environment when done
deactivate</code></code></pre><p>Now you might be wondering, what actually is a virtual environment? In simple terms, it&#8217;s just an isolated folder that holds all the packages your project needs, kept separate from every other project on your machine. That <code>.venv</code> folder you just created? It&#8217;s basically the same idea as <code>node_modules</code> in Node.js or <code>target</code> in Java. It just quietly stores your dependencies without mixing them into the rest of your system.</p><p>Ok, environment is ready. Now what?</p><div><hr></div><h2><strong>Why do LLMs even need &#8220;agents&#8221;?</strong></h2><p>Let&#8217;s start with the simplest possible Generative AI setup. You give it an input, the LLM processes it, you get an output. That&#8217;s it.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xz7e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xz7e!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 424w, https://substackcdn.com/image/fetch/$s_!xz7e!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 848w, https://substackcdn.com/image/fetch/$s_!xz7e!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 1272w, https://substackcdn.com/image/fetch/$s_!xz7e!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xz7e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png" width="1456" height="220" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35440,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209260286?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xz7e!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 424w, https://substackcdn.com/image/fetch/$s_!xz7e!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 848w, https://substackcdn.com/image/fetch/$s_!xz7e!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 1272w, https://substackcdn.com/image/fetch/$s_!xz7e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67730d7f-970b-46ed-b649-c7019d71b1b7_1614x244.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This works great when the task only needs the model&#8217;s existing knowledge. But here&#8217;s the catch. LLMs have what&#8217;s called a knowledge cutoff. They simply don&#8217;t know about anything that happened after their training data ends, and they have zero access to live, real time information.</p><p>So watch what happens here:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EEDY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EEDY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 424w, https://substackcdn.com/image/fetch/$s_!EEDY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 848w, https://substackcdn.com/image/fetch/$s_!EEDY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 1272w, https://substackcdn.com/image/fetch/$s_!EEDY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EEDY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png" width="1456" height="224" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:224,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47212,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209260286?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EEDY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 424w, https://substackcdn.com/image/fetch/$s_!EEDY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 848w, https://substackcdn.com/image/fetch/$s_!EEDY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 1272w, https://substackcdn.com/image/fetch/$s_!EEDY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcad52b80-8fd4-493e-9202-22b95baa610b_1572x242.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>See the problem? The model just shrugs. It has no idea what happened in today&#8217;s match because that information didn&#8217;t exist when it was trained.</p><p>So, how do we fix this? Simple. We let the LLM reach outside itself. It calls an API, queries a database, uses some other tool, whatever gets the job done, and brings that fresh information back into the conversation.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s7m0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s7m0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 424w, https://substackcdn.com/image/fetch/$s_!s7m0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 848w, https://substackcdn.com/image/fetch/$s_!s7m0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 1272w, https://substackcdn.com/image/fetch/$s_!s7m0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s7m0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png" width="1456" height="311" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:311,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84203,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/209260286?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!s7m0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 424w, https://substackcdn.com/image/fetch/$s_!s7m0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 848w, https://substackcdn.com/image/fetch/$s_!s7m0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 1272w, https://substackcdn.com/image/fetch/$s_!s7m0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01470d44-f64e-4101-9b87-ba6485dd019d_2256x482.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And that, right there, is basically what an Agent is. <strong>An agent is an LLM that can decide, on its own, to reach for an external tool when it needs to.</strong></p><p>It&#8217;s not just answering from memory anymore. It&#8217;s making small decisions like:</p><ul><li><p>Which tool should I use here?</p></li><li><p>What information am I still missing?</p></li><li><p>How do I combine what the tool gave me into a proper final answer?</p></li></ul><p>Pretty neat, right? Before moving forward,</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2><strong>Quick history lesson: agents before LangChain</strong></h2><p>Before frameworks like LangChain came along, people used a pattern called <strong>ReAct</strong> (short for Reason and Act) to build this &#8220;think, use a tool, look at the result, repeat&#8221; loop by hand. It worked, sure, but it meant a lot of manual wiring every single time.</p><p>LangChain took that whole pattern and squeezed it into one function: <code>create_agent()</code>. That&#8217;s it. Let&#8217;s actually build one.</p><div><hr></div><h2><strong>Building your first agent</strong></h2><p>I&#8217;m going to break this down into small steps so nothing feels overwhelming.</p><h3><strong>Step 1: Check your setup</strong></h3><pre><code><code>import langchain, sys

print("LangChain:", langchain.__version__)
print("Python:", sys.version)
print("Executable:", sys.executable)
print("LangChain path:", langchain.__file__)</code></code></pre><p>This just confirms LangChain is installed properly and shows you which Python environment you&#8217;re actually running in. Nothing fancy, just a sanity check.</p><h3><strong>Step 2: Load your API keys</strong></h3><p>Every LLM provider needs an API key so it knows the request is coming from you. Store these in a <code>.env</code> file and load them like this:</p><pre><code><code>import os
from dotenv import load_dotenv

load_dotenv(override=True)

os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY")
os.environ["GROQ_API_KEY"] = os.getenv("GROQ_API_KEY")
os.environ["MODEL"] = os.getenv("MODEL")</code></code></pre><p>One important thing before we move on. Never, ever hardcode your API keys directly into your code. Keep them in a <code>.env</code> file, and make sure that file is added to <code>.gitignore</code> so it never accidentally ends up on GitHub.</p><h3><strong>Step 3: Create an agent with no tools</strong></h3><p>Let&#8217;s start simple.</p><pre><code><code>from langchain.agents import create_agent
from langchain_groq import ChatGroq

model = ChatGroq(
    model="openai/gpt-oss-20b",
    api_key=os.environ["GROQ_API_KEY"]
)

agent = create_agent(
    model=model,
    tools=[],   # No tools provided
    system_prompt="You are a helpful assistant."
)</code></code></pre><p>At this point, our agent is really just a chatbot wearing an &#8220;agent&#8221; costume. It has no way of reaching outside its own knowledge. Let&#8217;s fix that.</p><h3><strong>Step 4: Give the agent a tool</strong></h3><pre><code><code>def get_weather(location):
    """
    A simple tool to get the weather information for a given location.
    """
    print(f"&gt;&gt;&gt; TOOL CALLED for {location}")
    return f"The weather in {location} is sunny with a temperature of 25&#176;C."

agent = create_agent(
    model=model,
    tools=[get_weather],   # Introduce a tool to get weather information
    system_prompt="You are a helpful assistant."
)</code></code></pre><h3><strong>Step 5: Run the agent and see what happens</strong></h3><pre><code><code># Query that needs the tool
message_1 = "What is the current condition in Chennai?"
output_1 = agent.invoke({"messages": [{"role": "user", "content": message_1}]})["messages"][-1].content
print(f"Me: {message_1}\nAgent: {output_1}")

# Query that does NOT need the tool
message_2 = "What is the capital of France?"
output_2 = agent.invoke({"messages": message_2})["messages"][-1].content
print(f"Me: {message_2}\nAgent: {output_2}")</code></code></pre><p>Here&#8217;s what&#8217;s interesting. For the first question, the agent actually calls <code>get_weather</code>, because answering it properly needs live, real world data. For the second question, it already knows the answer from training, so it just skips the tool entirely and answers directly.</p><p>So basically, the agent is making a judgment call every single time. Cool, right?</p><div><hr></div><h2><strong>Ok but how does the model know which tool to call?</strong></h2><p>This is probably the most common question beginners ask me at this point. And the answer is refreshingly simple: <strong>the docstring</strong>.</p><pre><code><code>def get_weather(location):
    """
    A simple tool to get the weather information for a given location.
    """</code></code></pre><p>That little bit of text inside the triple quotes isn&#8217;t just there for humans reading your code. The model actually reads it to figure out what the tool does and when it should be used. So writing a clear, accurate docstring isn&#8217;t optional, it directly affects how well your agent performs.</p><p><strong>Docstring qualityResult</strong>Missing or vagueModel may not call the tool at all, or calls the wrong oneClear and specificModel reliably picks the right tool at the right moment</p><p>What do you think happens if two tools have similar, vague docstrings? Yep, the model gets confused about which one to pick. So take your time writing them well.</p><div><hr></div><h2><strong>You&#8217;re not limited to just one tool</strong></h2><p>An agent can juggle multiple tools at once. You just pass a list, and the model figures out which one fits the situation:</p><pre><code><code>agent = create_agent(
    model=model,
    tools=[get_weather, get_stock_price, get_latest_news],
    system_prompt="You are a helpful assistant."
)</code></code></pre><p>The model looks at the user&#8217;s question, compares it against each tool&#8217;s docstring, and picks whichever one actually fits, or none at all, if the question doesn&#8217;t need a tool in the first place.</p><div><hr></div><h2><strong>Let&#8217;s recap what we covered</strong></h2><ul><li><p>LangChain removes the repetitive plumbing of working with LLMs directly.</p></li><li><p>Use <code>uv</code> to create a clean, isolated environment for your project.</p></li><li><p>LLMs have a knowledge cutoff, and agents solve this by calling external tools for live information.</p></li><li><p><code>create_agent()</code> builds a working agent in just a few lines of code.</p></li><li><p>The tool&#8217;s DocString is what actually tells the model when and how to use it.</p></li></ul><p>Not bad for a first post, right? You now technically know how to build a working AI agent.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-1?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/agentic-ai-day-1?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-1?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p><strong>Up next in the series:</strong> we&#8217;re going to look at the three different ways to actually talk to a model, <code>invoke()</code>, <code>stream()</code>, and <code>batch()</code>, and figure out exactly when you&#8217;d reach for each one. <a href="https://dharmarajrathinavel.substack.com/p/agentic-ai-day-2">Catch it here!</a></p>]]></content:encoded></item><item><title><![CDATA[Join Strategies]]></title><description><![CDATA[How Databases Actually Execute JOIN Queries]]></description><link>https://dharmarajrathinavel.substack.com/p/join-strategies</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/join-strategies</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Sat, 14 Feb 2026 18:00:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tL-Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Relational databases allow developers to express complex data relationships using simple declarative SQL syntax. A <code>JOIN</code> clause describes <em>what</em> result is expected, but it deliberately avoids specifying <em>how</em> the database should compute it. The responsibility of converting this high-level intent into an efficient execution plan lies with the query optimizer. At the core of this process are <strong>join strategies</strong> &#8212; physical algorithms that determine how rows from multiple tables are combined during query execution.</p><p>Understanding join strategies provides deep insight into database performance, execution planning, and system design trade-offs.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tL-Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tL-Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tL-Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tL-Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tL-Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tL-Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg" width="1369" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1369,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:139087,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/187967747?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tL-Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tL-Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tL-Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tL-Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe34d7fe5-02ac-49a4-977b-86fe10e9cd84_1369x768.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h4>From Client Query to Execution Engine</h4><p>When a client application submits a SQL query, it travels through multiple internal stages before reaching execution. The database first parses the SQL and constructs a logical query plan that represents the relational operations required to produce the result. This plan is then fed into the query optimizer, which explores multiple physical execution strategies and selects the lowest-cost plan based on statistics, available memory, indexes, and estimated I/O.</p><p>Once a physical plan is chosen, the execution engine carries out the operations by fetching data pages from disk or memory buffers, applying filters, performing joins, and producing the result stream. Join strategies are selected at this optimization stage and directly influence execution latency, memory usage, and system throughput.</p><div><hr></div><h4>1. Nested Loop Join</h4><p>The nested loop join is the most straightforward join strategy. It works by scanning one table and, for each row, scanning the second table to find matching rows.</p><p>Conceptually, the algorithm can be represented as:</p><pre><code><code>for (Row a : tableA) {
    for (Row b : tableB) {
        if (a.key.equals(b.key)) {
            emit(a, b);
        }
    }
}</code></code></pre><p>This approach has a time complexity of <strong>O(N &#215; M)</strong>, making it impractical for large datasets. However, when one of the tables is very small, or when an index exists on the join key of the larger table, nested loop joins become highly efficient.</p><p>With indexing, the inner scan becomes an index lookup:</p><pre><code><code>for (Row a : tableA) {
    Row b = indexLookup(tableB, a.key);
    if (b != null) {
        emit(a, b);
    }
}</code></code></pre><p>This reduces complexity to <strong>O(N log M)</strong>, often outperforming more complex strategies when selective indexes exist. Nested loop joins are therefore common in OLTP systems, where point lookups dominate.</p><ul><li><p>Very fast when:</p><ul><li><p>One table is tiny</p></li></ul></li><li><p>Disaster when:</p><ul><li><p>Both tables are large</p></li></ul></li></ul><div><hr></div><h4>2. Hash Join</h4><p>Hash join is optimized for equality-based joins on large datasets. The algorithm builds a hash table from the smaller input and then probes it using rows from the larger input.</p><p>In the build phase, rows from the smaller table are hashed into memory:</p><pre><code><code>Map&lt;Key, List&lt;Row&gt;&gt; hash = new HashMap&lt;&gt;();
for (Row c : customers) {
    hash.computeIfAbsent(c.id, k -&gt; new ArrayList&lt;&gt;()).add(c);
}</code></code></pre><p>In the probe phase, the larger table is scanned, and each row is matched using the hash map:</p><pre><code><code>for (Row o : orders) {
    List&lt;Row&gt; matches = hash.get(o.customerId);
    if (matches != null) {
        for (Row c : matches) {
            emit(o, c);
        }
    }
}</code></code></pre><p>This strategy runs in <strong>O(N + M)</strong> time and requires memory proportional to the size of the smaller table. If the hash table does not fit into memory, modern databases use partitioned or hybrid hash joins that spill to disk.</p><p>Hash joins dominate analytical workloads and batch processing systems, where full table scans are common and sufficient memory is available.</p><div><hr></div><h4>3. Merge Join</h4><p>Merge join relies on both inputs being sorted on the join key. Once sorted, the two streams are traversed sequentially, similar to the merge step of merge sort.</p><pre><code><code>sort(tableA);
sort(tableB);

int i = 0, j = 0;

while (i &lt; tableA.size() &amp;&amp; j &lt; tableB.size()) {
    if (tableA.get(i).key == tableB.get(j).key) {
        emit(tableA.get(i), tableB.get(j));
        i++; j++;
    } else if (tableA.get(i).key &lt; tableB.get(j).key) {
        i++;
    } else {
        j++;
    }
}</code></code></pre><p>If the inputs are already sorted via index scans, merge join becomes extremely efficient, requiring only sequential I/O. Otherwise, the sorting cost dominates, leading to <strong>O(N log N + M log M)</strong> complexity.</p><p>Merge joins excel in range queries, time-series workloads, and analytical pipelines where sorted access patterns are common.</p><ul><li><p>Perfect for:</p><ul><li><p>Sorted datasets</p></li></ul></li><li><p>Bottleneck:</p><ul><li><p>Sorting cost</p></li></ul></li></ul><div><hr></div><h4>How the Query Optimizer Selects a Join Strategy</h4><p>The optimizer evaluates multiple candidate plans by estimating their total cost, which includes disk I/O, CPU usage, memory consumption, and intermediate data size. Using table statistics, histograms, and cardinality estimates, it determines which strategy will minimize execution time and resource consumption.</p><p>If a small dimension table joins a massive fact table, the optimizer favors hash joins. When selective indexes exist, nested loop joins dominate. When sorted access paths are available, merge joins are preferred.</p><p>This decision is dynamic and recalculated for each query, ensuring that execution adapts to evolving data sizes and distributions.</p><div><hr></div><h4>End-to-End Example</h4><p>A Java application executing a simple join:</p><pre><code><code>String sql = """
SELECT o.id, c.name
FROM orders o
JOIN customers c ON o.customer_id = c.id
""";

PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();</code></code></pre><p>Behind this simple interface, the database parses the query, optimizes the execution plan, selects a join strategy, fetches pages from disk into memory buffers, performs the join using one of the physical algorithms, and streams the result back to the client. The choice of join strategy largely determines whether this operation completes in milliseconds or seconds.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for more on Database Internals.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[8. LinkedIn]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/linkedin</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/linkedin</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Sun, 11 Jan 2026 05:30:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!x1dR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kicked off 2026 by designing the High-Level Architecture of LinkedIn.</p><p>I&#8217;d love your feedback and suggestions to make it more production-grade!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x1dR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x1dR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 424w, https://substackcdn.com/image/fetch/$s_!x1dR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 848w, https://substackcdn.com/image/fetch/$s_!x1dR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 1272w, https://substackcdn.com/image/fetch/$s_!x1dR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x1dR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png" width="728" height="526.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/72bc59f8-25ae-4455-ac5f-c118cdd760fd_2268x1640.png&quot;,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1053,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:462548,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/184183748?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F72bc59f8-25ae-4455-ac5f-c118cdd760fd_2268x1640.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!x1dR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 424w, https://substackcdn.com/image/fetch/$s_!x1dR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 848w, https://substackcdn.com/image/fetch/$s_!x1dR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 1272w, https://substackcdn.com/image/fetch/$s_!x1dR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F465d8e9b-cd53-459b-b85c-a9e00c2e73df_2268x1640.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Design LinkedIn</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/linkedin/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/linkedin/comments"><span>Leave a comment</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[7. Notification Service]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/notification-service</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/notification-service</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Fri, 07 Nov 2025 14:30:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!8CGU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>End of the week and one more design added to my 30-day challenge.<br>This time, I explored how to build a Notification Service that reliably handles email, SMS, and push notifications at scale.</p><p>I&#8217;d love your feedback and suggestions to make it more production-grade!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8CGU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8CGU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 424w, https://substackcdn.com/image/fetch/$s_!8CGU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 848w, https://substackcdn.com/image/fetch/$s_!8CGU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 1272w, https://substackcdn.com/image/fetch/$s_!8CGU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8CGU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png" width="3024" height="1177" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1177,&quot;width&quot;:3024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:452831,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/178245734?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a9a041-91f6-4b3a-8d62-d2d3b84779f7_3024x1964.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8CGU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 424w, https://substackcdn.com/image/fetch/$s_!8CGU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 848w, https://substackcdn.com/image/fetch/$s_!8CGU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 1272w, https://substackcdn.com/image/fetch/$s_!8CGU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1199eb79-f879-4b35-b1ca-37cee05c9995_3024x1177.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Design a Notification Service</figcaption></figure></div><p>PS: Used multiple queues to make the architecture visually clean.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/notification-service/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/notification-service/comments"><span>Leave a comment</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[6. Proximity Service]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/proximity-service</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/proximity-service</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Thu, 06 Nov 2025 15:31:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!NxcA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd14e0b2-1fde-4765-b96c-c909d348fc93_2518x1560.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Followed by my previous design, I&#8217;ve now designed a <strong>Proximity Service</strong>, a system that helps users discover nearby attractions, add new places, and share reviews.</p><p>This design focuses on geo-based search, efficient indexing, and low-latency lookups to ensure high scalability and availability.</p><p>I&#8217;d love your feedback or suggestions to make it more production-ready as part of my <strong>30-day system design challenge</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Xus7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Xus7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 424w, https://substackcdn.com/image/fetch/$s_!Xus7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 848w, https://substackcdn.com/image/fetch/$s_!Xus7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 1272w, https://substackcdn.com/image/fetch/$s_!Xus7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Xus7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png" width="1456" height="902" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fd14e0b2-1fde-4765-b96c-c909d348fc93_2518x1560.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:902,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:442638,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/177868285?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd14e0b2-1fde-4765-b96c-c909d348fc93_2518x1560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Xus7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 424w, https://substackcdn.com/image/fetch/$s_!Xus7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 848w, https://substackcdn.com/image/fetch/$s_!Xus7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 1272w, https://substackcdn.com/image/fetch/$s_!Xus7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F220de021-3ef6-4f1e-abe4-9ad193a523c1_2518x1560.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design of Proximity Service</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/proximity-service/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/proximity-service/comments"><span>Leave a comment</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[5. Video Streaming Platform]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/video-streaming-system</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/video-streaming-system</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Wed, 05 Nov 2025 00:00:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tSu6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever wondered what goes into building a platform <em>like</em> Netflix?<br>Here&#8217;s my take on designing a Video Streaming System that focuses on low-latency playback and high availability to serve users efficiently.</p><p>I&#8217;d love your feedback &#8212; how would you improve or scale this further?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tSu6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tSu6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 424w, https://substackcdn.com/image/fetch/$s_!tSu6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 848w, https://substackcdn.com/image/fetch/$s_!tSu6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 1272w, https://substackcdn.com/image/fetch/$s_!tSu6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tSu6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png" width="3024" height="1879" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1419498-4452-4687-b863-fdac61989d84_3024x1879.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1879,&quot;width&quot;:3024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:694202,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/177971081?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15374fd7-33b2-42ce-bc90-fd9f7f53cccd_3024x1964.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tSu6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 424w, https://substackcdn.com/image/fetch/$s_!tSu6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 848w, https://substackcdn.com/image/fetch/$s_!tSu6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 1272w, https://substackcdn.com/image/fetch/$s_!tSu6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba94960d-58c2-4e42-8439-af631a51b2bb_3024x1879.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design of Netflix</figcaption></figure></div><p><strong>PS:</strong> Used multiple queues in the diagram to keep the flow visually clear.</p>]]></content:encoded></item><item><title><![CDATA[4. E-commerce System]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/e-commerce-system</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/e-commerce-system</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Tue, 04 Nov 2025 14:31:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!jsNx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Continuing my 30-day system design challenge, here&#8217;s what I designed today.</p><p>I&#8217;d love your thoughts! <br>How would you rate this design and what improvements or trade-offs would you suggest to make it more production-grade? Your feedback will help me refine my approach throughout this challenge.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jsNx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jsNx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 424w, https://substackcdn.com/image/fetch/$s_!jsNx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 848w, https://substackcdn.com/image/fetch/$s_!jsNx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 1272w, https://substackcdn.com/image/fetch/$s_!jsNx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jsNx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png" width="728" height="485.16129032258067" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/923c78a9-a78c-46f1-8d1e-f776069d5eb7_3024x1964.png&quot;,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1880,&quot;width&quot;:2821,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:697477,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/177958716?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F923c78a9-a78c-46f1-8d1e-f776069d5eb7_3024x1964.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jsNx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 424w, https://substackcdn.com/image/fetch/$s_!jsNx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 848w, https://substackcdn.com/image/fetch/$s_!jsNx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 1272w, https://substackcdn.com/image/fetch/$s_!jsNx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43a374d4-9010-4623-9927-5c0d374feb09_2821x1880.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design of Amazon</figcaption></figure></div><p><strong>PS</strong>: Used multiple queues in the diagram to make the design visually cleaner.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/e-commerce-system/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/e-commerce-system/comments"><span>Leave a comment</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[3. Instagram]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/3-instagram</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/3-instagram</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Mon, 03 Nov 2025 15:31:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!OSEv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd12878-221a-4b95-82c3-01e2bd40809c_2336x1692.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Stopped using Instagram and started <strong>designing</strong> it instead &#128516;</p><p>I&#8217;d love your feedback or suggestions to make it more <strong>real-world and scalable</strong> as part of my <strong>30-day system design challenge</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TFvC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TFvC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 424w, https://substackcdn.com/image/fetch/$s_!TFvC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 848w, https://substackcdn.com/image/fetch/$s_!TFvC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!TFvC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TFvC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png" width="1456" height="1055" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/afd12878-221a-4b95-82c3-01e2bd40809c_2336x1692.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1055,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:456106,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/177776633?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafd12878-221a-4b95-82c3-01e2bd40809c_2336x1692.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TFvC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 424w, https://substackcdn.com/image/fetch/$s_!TFvC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 848w, https://substackcdn.com/image/fetch/$s_!TFvC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 1272w, https://substackcdn.com/image/fetch/$s_!TFvC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea60d682-641e-463e-999c-ecc418f2c96f_2336x1692.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design of Instagram</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/3-instagram/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/3-instagram/comments"><span>Leave a comment</span></a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[2. Ride Sharing System]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/ride-sharing-system</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/ride-sharing-system</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Sun, 02 Nov 2025 06:30:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!uzTw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6e8a926-926d-485d-94ba-85f60cac41b7_2046x1578.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Following by &#8220;<em>Hotel Booking System&#8221;</em>, I&#8217;ve now designed a <strong>Ride Sharing System</strong> inspired by platforms like Uber and Rapido.</p><p>This design focuses on scalability, real-time updates, and modular service communication using Queues and WebSocket.</p><p>I&#8217;d love your feedback, suggestions, or alternate approaches to make it more production-ready and robust. Your insights will help me refine my system design thinking.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SS3K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SS3K!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 424w, https://substackcdn.com/image/fetch/$s_!SS3K!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 848w, https://substackcdn.com/image/fetch/$s_!SS3K!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 1272w, https://substackcdn.com/image/fetch/$s_!SS3K!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SS3K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png" width="728" height="556.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0f06903c-3be7-4fa1-9865-50fa00373420_2044x1562.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1113,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:438991,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/177738844?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f06903c-3be7-4fa1-9865-50fa00373420_2044x1562.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SS3K!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 424w, https://substackcdn.com/image/fetch/$s_!SS3K!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 848w, https://substackcdn.com/image/fetch/$s_!SS3K!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 1272w, https://substackcdn.com/image/fetch/$s_!SS3K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc747cf6-cd5a-4115-ac8b-b24afaa9e8e5_2044x1562.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design of Ride Sharing System</figcaption></figure></div><p><em>PS: I&#8217;ve used multiple queues in the diagram just to make the flow clearer and easier to understand visually.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/ride-sharing-system/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/ride-sharing-system/comments"><span>Leave a comment</span></a></p><div class="directMessage button" data-attrs="{&quot;userId&quot;:225555193,&quot;userName&quot;:&quot;Dharmaraj Rathinavel&quot;,&quot;canDm&quot;:null,&quot;dmUpgradeOptions&quot;:null,&quot;isEditorNode&quot;:true}" data-component-name="DirectMessageToDOM"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[1. Hotel Reservation System]]></title><description><![CDATA[#SystemDesign]]></description><link>https://dharmarajrathinavel.substack.com/p/1-hotel-reservation-system</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/1-hotel-reservation-system</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Sat, 01 Nov 2025 06:30:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Mg1B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd262a76-1a8b-4602-b431-65b9cf93e276_2166x1680.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here&#8217;s my first design, a <strong>Hotel Booking System</strong>. </p><p>I&#8217;d love your feedback or suggestions to make it more scalable and production-ready. Your insights will help me refine my thought process.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EH1o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EH1o!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 424w, https://substackcdn.com/image/fetch/$s_!EH1o!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 848w, https://substackcdn.com/image/fetch/$s_!EH1o!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 1272w, https://substackcdn.com/image/fetch/$s_!EH1o!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EH1o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png" width="728" height="564.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/becfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abdd8c82-c8a1-4901-8027-018a073b9066_2166x1680.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1129,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:350899,&quot;alt&quot;:&quot;High Level Design of Hotel Booking System&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://dharmarajrathinavel.substack.com/i/177711082?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabdd8c82-c8a1-4901-8027-018a073b9066_2166x1680.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="High Level Design of Hotel Booking System" title="High Level Design of Hotel Booking System" srcset="https://substackcdn.com/image/fetch/$s_!EH1o!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 424w, https://substackcdn.com/image/fetch/$s_!EH1o!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 848w, https://substackcdn.com/image/fetch/$s_!EH1o!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 1272w, https://substackcdn.com/image/fetch/$s_!EH1o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecfef92-8983-44dc-b06c-04d08526fc30_2166x1680.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design of Hotel Booking System</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/1-hotel-reservation-system/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/1-hotel-reservation-system/comments"><span>Leave a comment</span></a></p><div class="directMessage button" data-attrs="{&quot;userId&quot;:225555193,&quot;userName&quot;:&quot;Dharmaraj Rathinavel&quot;,&quot;canDm&quot;:null,&quot;dmUpgradeOptions&quot;:null,&quot;isEditorNode&quot;:true}" data-component-name="DirectMessageToDOM"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Evolve by Design! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Behind the Scenes of PostgreSQL: How Your Data Stays Safe]]></title><description><![CDATA[How Your Data Stays Safe?]]></description><link>https://dharmarajrathinavel.substack.com/p/behind-the-scenes-of-postgresql-how</link><guid isPermaLink="false">https://dharmarajrathinavel.substack.com/p/behind-the-scenes-of-postgresql-how</guid><dc:creator><![CDATA[Dharmaraj Rathinavel]]></dc:creator><pubDate>Thu, 05 Jun 2025 16:20:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gRzg!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2899d53-f680-4dcd-82d6-f361f72730ac_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When we run a query like <code>INSERT INTO users VALUES (...)</code>, we rarely think about what happens under the hood. But PostgreSQL is doing a lot of intelligent work to make sure your data isn&#8217;t lost&#8212;even during crashes. At the heart of this safety mechanism is something called <strong>Write-Ahead Logging (WAL)</strong>.</p><p>Let&#8217;s explore how it all works&#8212;from the moment a client makes a request to the way PostgreSQL stores and protects your data.</p><div><hr></div><h2>&#9997;&#65039; Logging Before Writing: The Core Idea</h2><p>PostgreSQL uses a method called <strong>Write-Ahead Logging</strong>. As the name suggests, <strong>changes are first written to a log before they are written to the actual database files</strong>.</p><p>This log is known as <strong>WAL</strong>, and it lives in a separate directory (usually <code>pg_wal/</code>).</p><p>Here&#8217;s what happens when you make a change:</p><ol><li><p>You run a query (e.g., insert a new row).</p></li><li><p>PostgreSQL creates a <strong>WAL entry describing this change</strong>.</p></li><li><p>This WAL entry is stored <strong>in memory first</strong> (WAL buffer).</p></li><li><p>It is <strong>flushed to disk</strong> as soon as:</p><ul><li><p>The transaction is committed</p></li><li><p>The buffer is full</p></li><li><p>A checkpoint happens</p></li></ul></li></ol><p>The <strong>main database files are updated later</strong>. That&#8217;s why WAL is essential for crash recovery.</p><div><hr></div><h2>Why This Matters: The Purpose of WAL</h2><p>The main goals of WAL are:</p><ul><li><p><strong>Crash Recovery</strong>: If PostgreSQL crashes, it <strong>replays the WAL logs</strong> to restore the last consistent state.</p></li><li><p><strong>Durability</strong>: Once a transaction is committed, the log entry is flushed, making the commit permanent&#8212;even if the database crashes right after.</p></li><li><p><strong>Replication</strong>: WAL files are shipped to <em>replica servers</em> to mirror the primary database.</p></li><li><p><strong>Performance</strong>: Writing to the WAL (which is sequential and fast) is much quicker than updating many random places in the database.</p></li></ul><p>In short, WAL helps PostgreSQL strike a balance between <strong>safety and speed</strong>.</p><div><hr></div><h2>When Does WAL Hit the Disk?</h2><p>Although changes are first written to the <strong>WAL buffer</strong> (RAM), PostgreSQL ensures the buffer is flushed to disk at the right times to avoid data loss.</p><p>WAL gets flushed,</p><ul><li><p><strong>On every COMMIT</strong>: A transaction is not considered "done" until its WAL records are safely written to disk.</p></li><li><p><strong>When WAL buffer is full</strong>: PostgreSQL doesn&#8217;t let it overflow&#8212;it flushes to disk.</p></li><li><p><strong>During Checkpoints</strong>: A background process called the <strong>checkpointer</strong> ensures that both WAL and dirty pages (modified memory pages) are flushed periodically.</p></li></ul><p>This guarantees that data won&#8217;t be lost even if power goes off right after a <code>COMMIT</code>.</p><div><hr></div><h2>Inside a WAL Entry: What Gets Logged?</h2><p>Each WAL entry contains just enough information for PostgreSQL to <strong>replay a change</strong>.</p><p>While the actual WAL file is binary, conceptually, it includes:</p><ul><li><p>Transaction ID</p></li><li><p>Operation type (INSERT, DELETE, etc.)</p></li><li><p>Affected table and page</p></li><li><p>Row-level data (before/after)</p></li></ul><p>&#129504; Think of it like a <strong>mini instruction</strong>:</p><blockquote><p>&#8220;Hey, I just inserted a row into the <code>orders</code> table. Here&#8217;s what I changed.&#8221;</p></blockquote><p>Here&#8217;s a mock version of what it would look like if it were readable:</p><pre><code><code>TXID: 1589
Operation: INSERT
Table: orders
Row: {order_id: 9812, total: 499.00}
</code></code></pre><div><hr></div><h2>Meet the Log Sequence Number (LSN)</h2><p>Each WAL entry has a unique <strong>Log Sequence Number (LSN)</strong>&#8212;a kind of &#8220;address&#8221; pointing to a specific position in the WAL file.</p><h5>Purpose of LSN:</h5><ul><li><p>Helps PostgreSQL know <strong>how far the WAL has been written or replayed</strong>.</p></li><li><p>Replication uses it to decide what changes replicas have already received.</p></li><li><p>Checkpoints record the current LSN to indicate up to where data is safely on disk.</p></li></ul><p>An LSN looks like this:  &lt;log segment&gt;<code>/</code>&lt;offset&gt;. Example: <code>0/16D328F0</code> </p><ul><li><p>LSNs <strong>don&#8217;t increment by 1</strong>. They grow based on how much data is written. Some operations write more to WAL and increase LSN faster.</p></li></ul><div><hr></div><h2>The Silent Guardian: PostgreSQL Checkpointer</h2><p>The <strong>checkpointer</strong> is a background process that periodically:</p><ul><li><p>Flushes all dirty memory pages to disk</p></li><li><p>Flushes WAL up to the current LSN</p></li><li><p>Writes a <strong>checkpoint record</strong> to the WAL</p></li></ul><p>Why this matters:</p><blockquote><p>Checkpoints reduce how far PostgreSQL needs to go back when replaying WAL during a crash. <strong>Instead of replaying all logs from the beginning,</strong> it starts from the last checkpoint.</p></blockquote><p>Checkpoints are crucial for <strong>speeding up recovery</strong> and keeping the WAL size under control.</p><div><hr></div><h2>Replaying WAL: Bringing PostgreSQL Back to Life</h2><p>When PostgreSQL starts after a crash, it performs <strong>WAL replay</strong> to ensure data consistency.</p><p>Recovery Steps are as follows.</p><ol><li><p>Find the <strong>last checkpoint</strong> and its LSN.</p></li><li><p>Start reading WAL from that point.</p></li><li><p>Apply all operations (INSERT, UPDATE, etc.) in sequence.</p></li><li><p>Stop once it reaches the last flushed WAL entry.</p></li></ol><p>This process is automatic and ensures that the database reflects <strong>all committed transactions</strong>, even if the actual data files weren't updated yet.</p><p>Similarly, <strong>replica servers</strong> also replay WAL entries to stay in sync with the primary.</p><div><hr></div><h3>In Simple Words&#8230;</h3><p>If PostgreSQL were a person keeping a diary:</p><ul><li><p>Every time it thinks of a change, it first <strong>writes it in the diary</strong> (WAL).</p></li><li><p>It then makes the change to the actual house (data file) <strong>a bit later</strong>.</p></li><li><p>If the house catches fire, it can <strong>rebuild everything from the diary</strong>.</p></li><li><p>It marks &#8220;milestones&#8221; in the diary (checkpoints) to avoid reading from page 1 every time.</p></li></ul><div><hr></div><h3>Final Thoughts</h3><p>PostgreSQL's WAL system is the <strong>unsung hero</strong> of database reliability. It ensures that even in the face of hardware failures, crashes, or power losses, your data remains safe, recoverable, and consistent.</p><p>Knowing how WAL, LSN, and checkpoints work not only helps you understand PostgreSQL better but also prepares you to debug, optimize, and design reliable systems.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/behind-the-scenes-of-postgresql-how?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading Dharmaraj&#8217;s Substack! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://dharmarajrathinavel.substack.com/p/behind-the-scenes-of-postgresql-how?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://dharmarajrathinavel.substack.com/p/behind-the-scenes-of-postgresql-how?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div>]]></content:encoded></item></channel></rss>